|
| 1 | +--- |
| 2 | +layout: implementors |
| 3 | +title: "Dev container Features contribution and discovery [proposal]" |
| 4 | +shortTitle: "Features distribution" |
| 5 | +author: Microsoft |
| 6 | +index: 6 |
| 7 | +--- |
| 8 | + |
| 9 | +> Note: This section provides information on a currently active proposal. See the [Features distribution proposal in the spec repo](https://github.com/devcontainers/spec/issues/61) for input and links to other proposed improvements. |
| 10 | +
|
| 11 | +This specification defines a pattern where community members and organizations can author and self-publish [dev container 'features'](./features.md). |
| 12 | + |
| 13 | +Goals include: |
| 14 | + |
| 15 | +- For community authors, a "self-served" mechanism for dev container feature publishing, either publicly or privately. |
| 16 | +- For users, the ability to validate the integrity of previously fetched assets. |
| 17 | +- For users, the ability for a user to pin to a particular version (absolute, or semantic version) of a feature to allow for consistent, repeatable environments. |
| 18 | +- The ability to standardize publishing such that [supporting tools](../supporting.md) may implement mechanisms for feature discoverability. |
| 19 | + |
| 20 | +## <a href="#source-code" name="source-code" class="anchor"> Source Code </a> |
| 21 | + |
| 22 | +Features source code is stored in a git repository. |
| 23 | + |
| 24 | +For ease of authorship and maintenance, [1..n] features can share a single git repository. This set of features is referred to as a collection, and will share the same [`devcontainer-collection.json`](#devcontainer-collection.json) file and 'namespace' (eg. `<owner>/<repo>`). |
| 25 | + |
| 26 | +Source code for the set follows the example file structure below: |
| 27 | + |
| 28 | +``` |
| 29 | +. |
| 30 | +├── README.md |
| 31 | +├── src |
| 32 | +│ ├── dotnet |
| 33 | +│ │ ├── devcontainer-feature.json |
| 34 | +│ │ ├── install.sh |
| 35 | +│ │ └── ... |
| 36 | +| ├ |
| 37 | +│ ├── go |
| 38 | +│ │ ├── devcontainer-feature.json |
| 39 | +│ │ └── install.sh |
| 40 | +| ├── ... |
| 41 | +│ │ ├── devcontainer-feature.json |
| 42 | +│ │ └── install.sh |
| 43 | +├── test |
| 44 | +│ ├── dotnet |
| 45 | +│ │ ├── test.sh |
| 46 | +│ │ └── ... |
| 47 | +│ └── go |
| 48 | +│ | └── test.sh |
| 49 | +| ├── ... |
| 50 | +│ │ └── test.sh |
| 51 | +├── ... |
| 52 | +``` |
| 53 | + |
| 54 | +Where `src` is a directory containing a sub-folder with the name of the feature (e.g. `src/dotnet` or `src/go`) with at least a file named `devcontainer-feature.json` that contains the feature metadata, and an `install.sh` script that implementing tools will use as the entrypoint to install the feature. Each sub-directory should be named such that it matches the `id` field of the `devcontainer-feature.json`. Other files can also be included in the feature's sub-directory, and will be included during the [packaging step](#packaging) alongside the two required files. Any files that are not part of the feature's sub-directory (e.g. outside of `src/dotnet`) will not included in the [packaging step](#packaging). |
| 55 | + |
| 56 | +Optionally, a mirrored `test` directory can be included with an accompanying `test.sh` script. Implementing tools may use this to run tests against the given feature. |
| 57 | + |
| 58 | +## <a href="#versioning" name="versioning" class="anchor"> Versioning </a> |
| 59 | + |
| 60 | +Each feature is individually [versioned according to the semver specification](https://semver.org/). The `version` property in the respective `devcontainer-feature.json` file is parsed to determine if the feature should be republished. |
| 61 | + |
| 62 | +Tooling that handles publishing features will not republish features if that exact version has already been published; however, tooling must republish major and minor versions in accordance with the semver specification. |
| 63 | + |
| 64 | +## <a href="#packaging" name="packaging" class="anchor"> Packaging </a> |
| 65 | + |
| 66 | +Features are distributed as tarballs. The tarball contains the entire contents of the feature sub-directory, including the `devcontainer-feature.json`, `install.sh`, and any other files in the directory. |
| 67 | + |
| 68 | +The tarball is named `devcontainer-feature-<id>.tgz`, where `<id>` is the feature's `id` field. |
| 69 | + |
| 70 | +A reference implementation for packaging and distributing features is provided as a GitHub Action (https://github.com/devcontainers/action). |
| 71 | + |
| 72 | +### <a href="#devcontainer-collection-json" name="devcontainer-collection-json" class="anchor"> devcontainer-collection.json </a> |
| 73 | + |
| 74 | +The `devcontainer-collection.json` is an auto-generated metadata file. |
| 75 | + |
| 76 | +| Property | Type | Description | |
| 77 | +| :--- | :--- | :--- | |
| 78 | +| sourceInformation | object | Metadata from the implementing packaging tool. | |
| 79 | +| features | array | The list of features that are contained in this collection.| |
| 80 | + |
| 81 | +Each features's `devcontainer-feature.json` metadata file is appended into the `features` top-level array. |
| 82 | + |
| 83 | +## <a href="#distribution" name="distribution" class="anchor"> Distribution </a> |
| 84 | + |
| 85 | +There are several supported ways to distribute features. Distribution is handled by the implementing packaging tool. |
| 86 | + |
| 87 | +A user references a distributed feature in a `devcontainer.json` as defined in ['referencing a feature'](./features.md#referencing-a-feature). |
| 88 | + |
| 89 | +### <a href="#oci-registry" name="oci-registry" class="anchor"> OCI Registry </a> |
| 90 | + |
| 91 | +An OCI registry that implements the [OCI Artifact Distribution Specification](https://github.com/opencontainers/distribution-spec) serves as the primary distribution mechanism for features. |
| 92 | + |
| 93 | +Each packaged feature is pushed to the registry following the naming convention `<registry>/<namespace>/<id>[:version]`, where version is the major, minor, and patch version of the feature, according to the semver specification. |
| 94 | + |
| 95 | +> The `namespace` is a unique indentifier for the collection of features. There are no strict rules for the `namespace`; however, one pattern is to set `namespace` equal to source repository's `<owner>/<repo>`. |
| 96 | +
|
| 97 | +A custom media type `application/vnd.devcontainers` and `application/vnd.devcontainers.layer.v1+tar` are used as demonstrated below. |
| 98 | + |
| 99 | +For example, the `go` feature in the `devcontainers/features` namespace at version `1.2.3` would be pushed to the ghcr.io OCI registry. |
| 100 | + |
| 101 | +_NOTE: The example below uses [`oras`](https://oras.land/) for demonstration purposes. A supporting tool should directly implement the required functionality from the aforementioned OCI artifact distribution specification._ |
| 102 | +```bash |
| 103 | +# ghcr.io/devcontainers/features/go:1 |
| 104 | +REGISTRY=ghcr.io |
| 105 | +NAMESPACE=devcontainers/features |
| 106 | +FEATURE=go |
| 107 | + |
| 108 | +ARTIFACT_PATH=devcontainer-feature-go.tgz |
| 109 | + |
| 110 | +for VERSION in 1 1.2 1.2.3 latest |
| 111 | +do |
| 112 | + oras push ${REGISTRY}/${NAMESPACE}/${FEATURE}:${VERSION} \ |
| 113 | + --manifest-config /dev/null:application/vnd.devcontainers \ |
| 114 | + ./${ARTIFACT_PATH}:application/vnd.devcontainers.layer.v1+tar |
| 115 | +done |
| 116 | +``` |
| 117 | + |
| 118 | +`Namespace` is the globally identifiable name for the collection of features. (eg: `owner/repo` for the source code's git repository). |
| 119 | + |
| 120 | +The auto-generated `devcontainer-collection.json` is pushed to the registry with the same `namespace` as above and no accompanying `feature` name. The collection file is always tagged as `latest`. |
| 121 | + |
| 122 | +```bash |
| 123 | +# ghcr.io/devcontainers/features |
| 124 | +REGISTRY=ghcr.io |
| 125 | +NAMESPACE=devcontainers/features |
| 126 | + |
| 127 | +oras push ${REGISTRY}/${NAMESPACE}:latest \ |
| 128 | + --manifest-config /dev/null:application/vnd.devcontainers \ |
| 129 | + ./devcontainer-collection.json.:application/vnd.devcontainers.layer.v1+json |
| 130 | +``` |
| 131 | + |
| 132 | +### <a href="#directly-reference-tarball" name="directly-reference-tarball" class="anchor"> Directly Reference Tarball </a> |
| 133 | + |
| 134 | +A feature can be referenced directly in a user's [`devcontainer.json`](./spec.md/#a-hrefdevcontainerjson-namedevcontainerjson-classanchor-devcontainerjson-a) file by an HTTP or HTTPS URI that points to the tarball from the [package step](#packaging). |
| 135 | + |
| 136 | +### <a href="#addendum-locally-referenced" name="addendum-locally-referenced" class="anchor"> Addendum: Locally Referenced </a> |
| 137 | + |
| 138 | +To aid in feature authorship, or in instances where a feature should not be published externally, individual features can be referenced locally from the project's file tree. |
| 139 | + |
| 140 | +A feature can be referenced directly in a user's [`devcontainer.json`](./spec.md/#a-hrefdevcontainerjson-namedevcontainerjson-classanchor-devcontainerjson-a) by relative path _inside_ the project directory. A local feature may not be referenced outside of the project directory (`../` is not allowed), nor is an absolute path allowed. |
| 141 | + |
| 142 | +The provided relative path is a path to the folder containing the feature's `devcontainer-feature.json` and `install.sh` file. |
0 commit comments