Skip to content

Commit 9abaeb5

Browse files
authored
feat: add workflow to test features in isolated containers (#19)
* feat: add workflow to test features in isolated containers Signed-off-by: Jonatan Mata <jonmatum@gmail.com> * fix: restructure repo to match devcontainer features standard layout Signed-off-by: Jonatan Mata <jonmatum@gmail.com> * test: update workflow Signed-off-by: Jonatan Mata <jonmatum@gmail.com> * test: update workflow Signed-off-by: Jonatan Mata <jonmatum@gmail.com> * test: update workflow Signed-off-by: Jonatan Mata <jonmatum@gmail.com> * test: starter kit Signed-off-by: Jonatan Mata <jonmatum@gmail.com> * test: starter kit Signed-off-by: Jonatan Mata <jonmatum@gmail.com> --------- Signed-off-by: Jonatan Mata <jonmatum@gmail.com>
1 parent 4adb445 commit 9abaeb5

40 files changed

+1025
-60
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2025 Jonatan Mata
3+
Copyright (c) 2022 Microsoft Corporation
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 170 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,188 @@
1-
# DevContainer Features
1+
# Dev Container Features: Self Authoring Template
22

3-
Reusable, production-ready DevContainer features for cloud, full-stack, DevOps, and infrastructure development environments.
4-
Modular, portable, and compatible with Amazon Linux, Ubuntu, and Debian-based systems.
3+
> This repo provides a starting point and example for creating your own custom [dev container Features](https://containers.dev/implementors/features/), hosted for free on GitHub Container Registry. The example in this repository follows the [dev container Feature distribution specification](https://containers.dev/implementors/features-distribution/).
4+
>
5+
> To provide feedback to the specification, please leave a comment [on spec issue #70](https://github.com/devcontainers/spec/issues/70). For more broad feedback regarding dev container Features, please see [spec issue #61](https://github.com/devcontainers/spec/issues/61).
56
6-
> **Compatible with:** Amazon Linux • Ubuntu • Debian
7+
## Example Contents
78

8-
## Features Included
9+
This repository contains a _collection_ of two Features - `hello` and `color`. These Features serve as simple feature implementations. Each sub-section below shows a sample `devcontainer.json` alongside example usage of the Feature.
910

10-
- Shell environment (Zsh, Oh My Zsh, Powerlevel10k, syntax highlighting, autosuggestions)
11-
- AWS CLI v2
12-
- Terraform with tfswitch
13-
- OpenTofu (Terraform fork)
14-
- Python via pyenv (with optional pipenv)
15-
- Node.js via nvm
16-
- Pre-commit setup
11+
### `hello`
1712

18-
Each tool is packaged as an independent, composable DevContainer Feature.
13+
Running `hello` inside the built container will print the greeting provided to it via its `greeting` option.
1914

20-
## Usage
15+
```jsonc
16+
{
17+
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
18+
"features": {
19+
"ghcr.io/devcontainers/feature-starter/hello:1": {
20+
"greeting": "Hello"
21+
}
22+
}
23+
}
24+
```
25+
26+
```bash
27+
$ hello
28+
29+
Hello, user.
30+
```
31+
32+
### `color`
2133

22-
You can directly reference features from this repository using the `gh:` prefix in your `devcontainer.json`:
34+
Running `color` inside the built container will print your favorite color to standard out.
2335

24-
```json
25-
"features": {
26-
"gh:jonmatum/devcontainer-features/features/python:1.0.0": {
27-
"version": "3.11.9",
28-
"pipenv": true
29-
},
30-
"gh:jonmatum/devcontainer-features/features/aws:1.0.0": {},
31-
"gh:jonmatum/devcontainer-features/features/terraform:1.0.0": {},
32-
"gh:jonmatum/devcontainer-features/features/shell:1.0.0": {}
36+
```jsonc
37+
{
38+
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
39+
"features": {
40+
"ghcr.io/devcontainers/feature-starter/color:1": {
41+
"favorite": "green"
42+
}
43+
}
3344
}
3445
```
3546

36-
Replace the feature ID and version according to what you need.
37-
38-
## Structure
39-
40-
```text
41-
features/
42-
shell/
43-
feature.json
44-
install.sh
45-
aws/
46-
feature.json
47-
install.sh
48-
python/
49-
feature.json
50-
install.sh
51-
terraform/
52-
feature.json
53-
install.sh
54-
opentofu/
55-
feature.json
56-
install.sh
57-
node/
58-
feature.json
59-
install.sh
47+
```bash
48+
$ color
49+
50+
my favorite color is green
51+
```
52+
53+
## Repo and Feature Structure
54+
55+
Similar to the [`devcontainers/features`](https://github.com/devcontainers/features) repo, this repository has a `src` folder. Each Feature has its own sub-folder, containing at least a `devcontainer-feature.json` and an entrypoint script `install.sh`.
56+
57+
```
58+
├── src
59+
│ ├── hello
60+
│ │ ├── devcontainer-feature.json
61+
│ │ └── install.sh
62+
│ ├── color
63+
│ │ ├── devcontainer-feature.json
64+
│ │ └── install.sh
65+
| ├── ...
66+
│ │ ├── devcontainer-feature.json
67+
│ │ └── install.sh
68+
...
69+
```
70+
71+
An [implementing tool](https://containers.dev/supporting#tools) will composite [the documented dev container properties](https://containers.dev/implementors/features/#devcontainer-feature-json-properties) from the feature's `devcontainer-feature.json` file, and execute in the `install.sh` entrypoint script in the container during build time. Implementing tools are also free to process attributes under the `customizations` property as desired.
72+
73+
### Options
74+
75+
All available options for a Feature should be declared in the `devcontainer-feature.json`. The syntax for the `options` property can be found in the [devcontainer Feature json properties reference](https://containers.dev/implementors/features/#devcontainer-feature-json-properties).
76+
77+
For example, the `color` feature provides an enum of three possible options (`red`, `gold`, `green`). If no option is provided in a user's `devcontainer.json`, the value is set to "red".
78+
79+
```jsonc
80+
{
81+
// ...
82+
"options": {
83+
"favorite": {
84+
"type": "string",
85+
"enum": [
86+
"red",
87+
"gold",
88+
"green"
89+
],
90+
"default": "red",
91+
"description": "Choose your favorite color."
92+
}
93+
}
94+
}
95+
```
96+
97+
Options are exported as Feature-scoped environment variables. The option name is captialized and sanitized according to [option resolution](https://containers.dev/implementors/features/#option-resolution).
98+
99+
```bash
100+
#!/bin/bash
101+
102+
echo "Activating feature 'color'"
103+
echo "The provided favorite color is: ${FAVORITE}"
104+
105+
...
106+
```
107+
108+
## Distributing Features
109+
110+
### Versioning
111+
112+
Features are individually versioned by the `version` attribute in a Feature's `devcontainer-feature.json`. Features are versioned according to the semver specification. More details can be found in [the dev container Feature specification](https://containers.dev/implementors/features/#versioning).
113+
114+
### Publishing
115+
116+
> NOTE: The Distribution spec can be [found here](https://containers.dev/implementors/features-distribution/).
117+
>
118+
> While any registry [implementing the OCI Distribution spec](https://github.com/opencontainers/distribution-spec) can be used, this template will leverage GHCR (GitHub Container Registry) as the backing registry.
119+
120+
Features are meant to be easily sharable units of dev container configuration and installation code.
121+
122+
This repo contains a **GitHub Action** [workflow](.github/workflows/release.yaml) that will publish each Feature to GHCR.
123+
124+
*Allow GitHub Actions to create and approve pull requests* should be enabled in the repository's `Settings > Actions > General > Workflow permissions` for auto generation of `src/<feature>/README.md` per Feature (which merges any existing `src/<feature>/NOTES.md`).
125+
126+
By default, each Feature will be prefixed with the `<owner/<repo>` namespace. For example, the two Features in this repository can be referenced in a `devcontainer.json` with:
127+
128+
```
129+
ghcr.io/devcontainers/feature-starter/color:1
130+
ghcr.io/devcontainers/feature-starter/hello:1
131+
```
132+
133+
The provided GitHub Action will also publish a third "metadata" package with just the namespace, eg: `ghcr.io/devcontainers/feature-starter`. This contains information useful for tools aiding in Feature discovery.
134+
135+
'`devcontainers/feature-starter`' is known as the feature collection namespace.
136+
137+
### Marking Feature Public
138+
139+
Note that by default, GHCR packages are marked as `private`. To stay within the free tier, Features need to be marked as `public`.
140+
141+
This can be done by navigating to the Feature's "package settings" page in GHCR, and setting the visibility to 'public`. The URL may look something like:
142+
143+
```
144+
https://github.com/users/<owner>/packages/container/<repo>%2F<featureName>/settings
60145
```
61146

62-
## Roadmap
147+
<img width="669" alt="image" src="https://user-images.githubusercontent.com/23246594/185244705-232cf86a-bd05-43cb-9c25-07b45b3f4b04.png">
148+
149+
### Adding Features to the Index
63150

64-
- Add additional features for Kubernetes tooling
65-
- Publish metadata to DevContainer Feature Registry (when available)
66-
- Improve auto-detection of CPU architecture
67-
- Add CI validation workflows
151+
If you'd like your Features to appear in our [public index](https://containers.dev/features) so that other community members can find them, you can do the following:
68152

69-
## License
153+
* Go to [github.com/devcontainers/devcontainers.github.io](https://github.com/devcontainers/devcontainers.github.io)
154+
* This is the GitHub repo backing the [containers.dev](https://containers.dev/) spec site
155+
* Open a PR to modify the [collection-index.yml](https://github.com/devcontainers/devcontainers.github.io/blob/gh-pages/_data/collection-index.yml) file
70156

71-
Licensed under the [MIT License](LICENSE).
157+
This index is from where [supporting tools](https://containers.dev/supporting) like [VS Code Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) and [GitHub Codespaces](https://github.com/features/codespaces) surface Features for their dev container creation UI.
72158

73-
---
159+
#### Using private Features in Codespaces
74160

75-
> echo 'Pura Vida & Happy Coding!";
161+
For any Features hosted in GHCR that are kept private, the `GITHUB_TOKEN` access token in your environment will need to have `package:read` and `contents:read` for the associated repository.
162+
163+
Many implementing tools use a broadly scoped access token and will work automatically. GitHub Codespaces uses repo-scoped tokens, and therefore you'll need to add the permissions in `devcontainer.json`
164+
165+
An example `devcontainer.json` can be found below.
166+
167+
```jsonc
168+
{
169+
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
170+
"features": {
171+
"ghcr.io/my-org/private-features/hello:1": {
172+
"greeting": "Hello"
173+
}
174+
},
175+
"customizations": {
176+
"codespaces": {
177+
"repositories": {
178+
"my-org/private-features": {
179+
"permissions": {
180+
"packages": "read",
181+
"contents": "read"
182+
}
183+
}
184+
}
185+
}
186+
}
187+
}
188+
```
File renamed without changes.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
echo "Fetching main branch to compare..."
5+
git fetch origin main
6+
7+
echo "Detecting modified features..."
8+
MODIFIED_FEATURES=$(git diff --name-only origin/main -- 'src/**' | grep '^src/' | cut -d/ -f2 | sort -u || true)
9+
10+
if [ -z "$MODIFIED_FEATURES" ]; then
11+
echo "No features modified. Skipping tests."
12+
exit 0
13+
fi
14+
15+
echo "Modified features detected: $MODIFIED_FEATURES"
16+
17+
for feature_name in $MODIFIED_FEATURES; do
18+
echo "==============================="
19+
echo "Testing feature: $feature_name"
20+
echo "==============================="
21+
22+
TEMP_DIR=$(mktemp -d)
23+
mkdir -p "$TEMP_DIR/src/$feature_name"
24+
mkdir -p "$TEMP_DIR/test"
25+
26+
cp -r src/"$feature_name"/* "$TEMP_DIR/src/$feature_name/"
27+
28+
# Create dummy test script if not present
29+
cat <<EOF > "$TEMP_DIR/test/test.sh"
30+
#!/bin/bash
31+
echo "Test for feature: $feature_name"
32+
EOF
33+
chmod +x "$TEMP_DIR/test/test.sh"
34+
35+
devcontainer features test -f "$TEMP_DIR/src/$feature_name" -i mcr.microsoft.com/devcontainers/base:ubuntu
36+
done
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Validate Features in Clean Containers
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'src/**'
7+
- '.github/workflows/test-features.yml'
8+
- '.github/scripts/test-features.sh'
9+
push:
10+
branches:
11+
- main
12+
paths:
13+
- 'src/**'
14+
- '.github/workflows/test-features.yml'
15+
- '.github/scripts/test-features.sh'
16+
17+
permissions:
18+
contents: read
19+
20+
jobs:
21+
test-features:
22+
name: Test Devcontainer Features
23+
runs-on: ubuntu-latest
24+
steps:
25+
- name: Checkout repository
26+
uses: actions/checkout@v4
27+
28+
- name: Set up Node.js (for Dev Container CLI)
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: '20'
32+
33+
- name: Install Dev Container CLI
34+
run: npm install -g @devcontainers/cli
35+
36+
- name: Run feature tests
37+
run: bash .github/scripts/test-features.sh
File renamed without changes.
File renamed without changes.

legacy/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Jonatan Mata
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)