Skip to content

Commit 29c3852

Browse files
joshspicerjkeech
andauthored
[Proposal] 'Features' Distribution Specification (#66)
* update features reference * distribution * various updates * @samruddhikhandale comments * @alexdima comments and much more detail on options * clearer * goals * @edgonmsft comments addressed' * spelling * update goals * apply @jkeech suggestions Co-authored-by: John Keech <[email protected]> * note about compatibility with base images Co-authored-by: John Keech <[email protected]>
1 parent 7ff8d1f commit 29c3852

File tree

2 files changed

+307
-71
lines changed

2 files changed

+307
-71
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Community Contribution and Discovery of Dev Container Features
2+
3+
This specification defines a pattern where community members and organizations can author and self-publish [dev container 'features'](./devcontainer-features.md).
4+
5+
Goals include:
6+
7+
- For community authors, a "self-served" mechanism for dev container feature publishing, either publicly or privately.
8+
- For users, the ability to validate the integrity of previously fetched assets.
9+
- 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.
10+
- The ability to standardize publishing such that [supporting tools](../docs/specs/supporting-tools.md) may implement mechanisms for feature discoverability.
11+
12+
## Source Code
13+
14+
Features source code is stored in a git repository.
15+
16+
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>`).
17+
18+
Source code for the set follows the example file structure below:
19+
20+
```
21+
.
22+
├── README.md
23+
├── src
24+
│ ├── dotnet
25+
│ │ ├── devcontainer-feature.json
26+
│ │ ├── install.sh
27+
│ │ └── ...
28+
| ├
29+
│ ├── go
30+
│ │ ├── devcontainer-feature.json
31+
│ │ └── install.sh
32+
| ├── ...
33+
│ │ ├── devcontainer-feature.json
34+
│ │ └── install.sh
35+
├── test
36+
│ ├── dotnet
37+
│ │ ├── test.sh
38+
│ │ └── ...
39+
│ └── go
40+
│ | └── test.sh
41+
| ├── ...
42+
│ │ └── test.sh
43+
├── ...
44+
```
45+
46+
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).
47+
48+
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.
49+
50+
## Versioning
51+
52+
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.
53+
54+
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.
55+
56+
## Packaging
57+
58+
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.
59+
60+
The tarball is named `devcontainer-feature-<id>.tgz`, where `<id>` is the feature's `id` field.
61+
62+
A reference implementation for packaging and distributing features is provided as a GitHub Action (https://github.com/devcontainers/action).
63+
64+
65+
### devcontainer-collection.json
66+
67+
The `devcontainer-collection.json` is an auto-generated metadata file.
68+
69+
| Property | Type | Description |
70+
| :--- | :--- | :--- |
71+
| sourceInformation | object | Metadata from the implementing packaging tool. |
72+
| features | array | The list of features that are contained in this collection.|
73+
74+
Each features's `devcontainer-feature.json` metadata file is appended into the `features` top-level array.
75+
76+
## Distribution
77+
78+
There are several supported ways to distribute features. Distribution is handled by the implementing packaging tool.
79+
80+
A user references a distributed feature in a `devcontainer.json` as defined in ['referencing a feature'](./devcontainer-features.md#Referencing-a-feature).
81+
82+
### OCI Registry
83+
84+
An OCI registry that implements the [OCI Artifact Distribution Specification](https://github.com/opencontainers/distribution-spec) serves as the primary distribution mechanism for features.
85+
86+
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.
87+
88+
> 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>`.
89+
90+
A custom media type `application/vnd.devcontainers` and `application/vnd.devcontainers.layer.v1+tar` are used as demonstrated below.
91+
92+
For example, the `go` feature in the `devcontainers/features` namespace at version `1.2.3` would be pushed to the ghcr.io OCI registry.
93+
94+
_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._
95+
```bash
96+
# ghcr.io/devcontainers/features/go:1
97+
REGISTRY=ghcr.io
98+
NAMESPACE=devcontainers/features
99+
FEATURE=go
100+
101+
ARTIFACT_PATH=devcontainer-feature-go.tgz
102+
103+
for VERSION in 1 1.2 1.2.3 latest
104+
do
105+
oras push ${REGISTRY}/${NAMESPACE}/${FEATURE}:${VERSION} \
106+
--manifest-config /dev/null:application/vnd.devcontainers \
107+
./${ARTIFACT_PATH}:application/vnd.devcontainers.layer.v1+tar
108+
done
109+
110+
```
111+
112+
`Namespace` is the globally identifiable name for the collection of features. (eg: `owner/repo` for the source code's git repository).
113+
114+
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`.
115+
116+
```bash
117+
# ghcr.io/devcontainers/features
118+
REGISTRY=ghcr.io
119+
NAMESPACE=devcontainers/features
120+
121+
oras push ${REGISTRY}/${NAMESPACE}:latest \
122+
--manifest-config /dev/null:application/vnd.devcontainers \
123+
./devcontainer-collection.json.:application/vnd.devcontainers.layer.v1+json
124+
```
125+
126+
### Directly Reference Tarball
127+
128+
A feature can be referenced directly in a user's [`devcontainer.json`](/docs/specs/devcontainer-reference.md#devcontainerjson) file by an HTTP or HTTPS URI that points to the tarball from the [package step](#packaging).
129+
130+
### Addendum: Locally Referenced
131+
132+
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.
133+
134+
A feature can be referenced directly in a user's [`devcontainer.json`](/docs/specs/devcontainer-reference.md#devcontainerjson) 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.
135+
136+
The provided relative path is a path to the folder containing the feature's `devcontainer-feature.json` and `install.sh` file.

0 commit comments

Comments
 (0)