├── .devcontainer └── devcontainer.json ├── .github ├── actions │ └── smoke-test │ │ ├── action.yaml │ │ ├── build.sh │ │ └── test.sh └── workflows │ ├── release.yaml │ └── test-pr.yaml ├── LICENSE ├── README.md ├── src ├── color │ ├── .devcontainer │ │ └── devcontainer.json │ ├── README.md │ └── devcontainer-template.json └── hello │ ├── .devcontainer │ ├── Dockerfile │ └── devcontainer.json │ ├── README.md │ └── devcontainer-template.json └── test ├── color └── test.sh ├── hello └── test.sh └── test-utils └── test-utils.sh /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // More info: https://containers.dev/implementors/json_reference/ 2 | { 3 | "image": "mcr.microsoft.com/devcontainers/javascript-node:1-18-bullseye", 4 | "features": { 5 | "ghcr.io/devcontainers/features/docker-in-docker:2": {} 6 | }, 7 | "customizations": { 8 | "vscode": { 9 | "extensions": [ 10 | "mads-hartmann.bash-ide-vscode", 11 | "dbaeumer.vscode-eslint" 12 | ] 13 | } 14 | }, 15 | "postCreateCommand": "npm install -g @devcontainers/cli" 16 | } 17 | -------------------------------------------------------------------------------- /.github/actions/smoke-test/action.yaml: -------------------------------------------------------------------------------- 1 | name: 'Smoke test' 2 | inputs: 3 | template: 4 | description: 'Template to test' 5 | required: true 6 | 7 | runs: 8 | using: composite 9 | steps: 10 | - name: Checkout main 11 | id: checkout_release 12 | uses: actions/checkout@v3 13 | 14 | - name: Build template 15 | id: build_template 16 | shell: bash 17 | run: ${{ github.action_path }}/build.sh ${{ inputs.template }} 18 | 19 | - name: Test template 20 | id: test_template 21 | shell: bash 22 | run: ${{ github.action_path }}/test.sh ${{ inputs.template }} -------------------------------------------------------------------------------- /.github/actions/smoke-test/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | TEMPLATE_ID="$1" 3 | 4 | set -e 5 | 6 | shopt -s dotglob 7 | 8 | SRC_DIR="/tmp/${TEMPLATE_ID}" 9 | cp -R "src/${TEMPLATE_ID}" "${SRC_DIR}" 10 | 11 | pushd "${SRC_DIR}" 12 | 13 | # Configure templates only if `devcontainer-template.json` contains the `options` property. 14 | OPTION_PROPERTY=( $(jq -r '.options' devcontainer-template.json) ) 15 | 16 | if [ "${OPTION_PROPERTY}" != "" ] && [ "${OPTION_PROPERTY}" != "null" ] ; then 17 | OPTIONS=( $(jq -r '.options | keys[]' devcontainer-template.json) ) 18 | 19 | if [ "${OPTIONS[0]}" != "" ] && [ "${OPTIONS[0]}" != "null" ] ; then 20 | echo "(!) Configuring template options for '${TEMPLATE_ID}'" 21 | for OPTION in "${OPTIONS[@]}" 22 | do 23 | OPTION_KEY="\${templateOption:$OPTION}" 24 | OPTION_VALUE=$(jq -r ".options | .${OPTION} | .default" devcontainer-template.json) 25 | 26 | if [ "${OPTION_VALUE}" = "" ] || [ "${OPTION_VALUE}" = "null" ] ; then 27 | echo "Template '${TEMPLATE_ID}' is missing a default value for option '${OPTION}'" 28 | exit 1 29 | fi 30 | 31 | echo "(!) Replacing '${OPTION_KEY}' with '${OPTION_VALUE}'" 32 | OPTION_VALUE_ESCAPED=$(sed -e 's/[]\/$*.^[]/\\&/g' <<<"${OPTION_VALUE}") 33 | find ./ -type f -print0 | xargs -0 sed -i "s/${OPTION_KEY}/${OPTION_VALUE_ESCAPED}/g" 34 | done 35 | fi 36 | fi 37 | 38 | popd 39 | 40 | TEST_DIR="test/${TEMPLATE_ID}" 41 | if [ -d "${TEST_DIR}" ] ; then 42 | echo "(*) Copying test folder" 43 | DEST_DIR="${SRC_DIR}/test-project" 44 | mkdir -p ${DEST_DIR} 45 | cp -Rp ${TEST_DIR}/* ${DEST_DIR} 46 | cp -Rp test/test-utils/* ${DEST_DIR} 47 | fi 48 | 49 | export DOCKER_BUILDKIT=1 50 | echo "(*) Installing @devcontainer/cli" 51 | npm install -g @devcontainers/cli 52 | 53 | echo "Building Dev Container" 54 | ID_LABEL="test-container=${TEMPLATE_ID}" 55 | devcontainer up --id-label ${ID_LABEL} --workspace-folder "${SRC_DIR}" 56 | -------------------------------------------------------------------------------- /.github/actions/smoke-test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | TEMPLATE_ID="$1" 3 | set -e 4 | 5 | SRC_DIR="/tmp/${TEMPLATE_ID}" 6 | echo "Running Smoke Test" 7 | 8 | ID_LABEL="test-container=${TEMPLATE_ID}" 9 | devcontainer exec --workspace-folder "${SRC_DIR}" --id-label ${ID_LABEL} /bin/sh -c 'set -e && if [ -f "test-project/test.sh" ]; then cd test-project && if [ "$(id -u)" = "0" ]; then chmod +x test.sh; else sudo chmod +x test.sh; fi && ./test.sh; else ls -a; fi' 10 | 11 | # Clean up 12 | docker rm -f $(docker container ls -f "label=${ID_LABEL}" -q) 13 | rm -rf "${SRC_DIR}" 14 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: "Release Dev Container Templates & Generate Documentation" 2 | on: 3 | workflow_dispatch: 4 | 5 | jobs: 6 | deploy: 7 | if: ${{ github.ref == 'refs/heads/main' }} 8 | runs-on: ubuntu-latest 9 | permissions: 10 | packages: write 11 | contents: write 12 | pull-requests: write 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: "Publish Templates" 17 | uses: devcontainers/action@v1 18 | with: 19 | publish-templates: "true" 20 | base-path-to-templates: "./src" 21 | generate-docs: "true" 22 | 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | 26 | - name: Create PR for Documentation 27 | id: push_image_info 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | run: | 31 | set -e 32 | echo "Start." 33 | 34 | # Configure git and Push updates 35 | git config --global user.email github-actions[bot]@users.noreply.github.com 36 | git config --global user.name github-actions[bot] 37 | git config pull.rebase false 38 | 39 | branch=automated-documentation-update-$GITHUB_RUN_ID 40 | git checkout -b $branch 41 | message='Automated documentation update' 42 | 43 | # Add / update and commit 44 | git add */**/README.md 45 | git commit -m 'Automated documentation update [skip ci]' || export NO_UPDATES=true 46 | 47 | # Push 48 | if [ "$NO_UPDATES" != "true" ] ; then 49 | git push origin "$branch" 50 | gh pr create --title "$message" --body "$message" 51 | fi 52 | -------------------------------------------------------------------------------- /.github/workflows/test-pr.yaml: -------------------------------------------------------------------------------- 1 | name: "CI - Test Templates" 2 | on: 3 | pull_request: 4 | 5 | jobs: 6 | detect-changes: 7 | runs-on: ubuntu-latest 8 | outputs: 9 | templates: ${{ steps.filter.outputs.changes }} 10 | steps: 11 | - uses: dorny/paths-filter@v2 12 | id: filter 13 | with: 14 | filters: | 15 | color: ./**/color/** 16 | hello: ./**/hello/** 17 | 18 | test: 19 | needs: [detect-changes] 20 | runs-on: ubuntu-latest 21 | continue-on-error: true 22 | strategy: 23 | matrix: 24 | templates: ${{ fromJSON(needs.detect-changes.outputs.templates) }} 25 | steps: 26 | - uses: actions/checkout@v3 27 | 28 | - name: Smoke test for '${{ matrix.templates }}' 29 | id: smoke_test 30 | uses: ./.github/actions/smoke-test 31 | with: 32 | template: "${{ matrix.templates }}" 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Microsoft Corporation 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dev Container Templates: Self Authoring Guide 2 | 3 | > This repo provides a starting point and example for creating your own custom [Dev Container Templates](https://containers.dev/implementors/templates), hosted for free on GitHub Container Registry. The example in this repository follows the [Dev Container Template distribution specification](https://containers.dev/implementors/templates-distribution/). 4 | > 5 | > To provide feedback on the distribution spec, please leave a comment [on spec issue #71](https://github.com/devcontainers/spec/issues/71). 6 | 7 | ## Repo and Template Structure 8 | 9 | This repository contains a _collection_ of two Templates - `hello` and `color`. These Templates serve as simple template implementations which helps containerize the project. Similar to the [`devcontainers/templates`](https://github.com/devcontainers/templates) repo, this repository has a `src` folder. Each Template has its own sub-folder, containing at least a `devcontainer-template.json` and `.devcontainer/devcontainer.json`. 10 | 11 | ``` 12 | ├── src 13 | │ ├── color 14 | │ │ ├── devcontainer-template.json 15 | │ │ └──| .devcontainer 16 | │ │ └── devcontainer.json 17 | │ ├── hello 18 | │ │ ├── devcontainer-template.json 19 | │ │ └──| .devcontainer 20 | │ │ ├── devcontainer.json 21 | │ │ └── Dockerfile 22 | | ├── ... 23 | │ │ ├── devcontainer-template.json 24 | │ │ └──| .devcontainer 25 | │ │ └── devcontainer.json 26 | ├── test 27 | │ ├── color 28 | │ │ └── test.sh 29 | │ ├── hello 30 | │ │ └── test.sh 31 | │ └──test-utils 32 | │ └── test-utils.sh 33 | ... 34 | ``` 35 | 36 | ### Options 37 | 38 | All available options for a Template should be declared in the `devcontainer-template.json`. The syntax for the `options` property can be found in the [devcontainer Template json properties reference](https://containers.dev/implementors/templates#devcontainer-templatejson-properties). 39 | 40 | For example, the `color` Template provides three possible options (`red`, `gold`, `green`), where the default value is set to "red". 41 | 42 | ```jsonc 43 | { 44 | // ... 45 | "options": { 46 | "favorite": { 47 | "type": "string", 48 | "description": "Choose your favorite color.", 49 | "proposals": [ 50 | "red", 51 | "gold", 52 | "green" 53 | ], 54 | "default": "red" 55 | } 56 | } 57 | } 58 | ``` 59 | 60 | An [implementing tool](https://containers.dev/supporting#tools) will use the `options` property from [the documented Dev Container Template properties](https://containers.dev/implementors/templates#devcontainer-templatejson-properties) for customizing the Template. See [option resolution example](https://containers.dev/implementors/templates#option-resolution-example) for details. 61 | 62 | ## Distributing Templates 63 | 64 | **Note**: *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/