Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/smoke-test/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fi

export DOCKER_BUILDKIT=1
echo "(*) Installing @devcontainer/cli"
npm install -g @devcontainers/cli
npm install --global @devcontainers/cli@0.88.0

echo "Building Dev Container"
ID_LABEL="test-container=${TEMPLATE_ID}"
Expand Down
89 changes: 89 additions & 0 deletions .github/scripts/publish-devcontainer-assets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env bash

set -euo pipefail

registry="${1:-}"
namespace="${2:-}"

if [[ -z "${registry}" || -z "${namespace}" ]]; then
echo "Usage: $0 <registry> <namespace>" >&2
exit 1
fi

for command in devcontainer jq oras; do
if ! command -v "${command}" >/dev/null 2>&1; then
echo "${command} is required." >&2
exit 1
fi
done

collection_ref="${registry}/${namespace}:latest"
work_dir="$(mktemp -d)"
trap 'rm -rf "${work_dir}"' EXIT

feature_collection_dir="${work_dir}/features"
template_collection_dir="${work_dir}/templates"
combined_collection_dir="${work_dir}/combined"
verified_collection_dir="${work_dir}/verified"
mkdir -p \
"${feature_collection_dir}" \
"${template_collection_dir}" \
"${combined_collection_dir}" \
"${verified_collection_dir}"

echo "Publishing Features to ${registry}/${namespace}"
devcontainer features publish features/src \
--registry "${registry}" \
--namespace "${namespace}"
oras pull "${collection_ref}" --output "${feature_collection_dir}"

echo "Publishing Templates to ${registry}/${namespace}"
devcontainer templates publish templates/src \
--registry "${registry}" \
--namespace "${namespace}"
oras pull "${collection_ref}" --output "${template_collection_dir}"

feature_collection="${feature_collection_dir}/devcontainer-collection.json"
template_collection="${template_collection_dir}/devcontainer-collection.json"
combined_collection="${combined_collection_dir}/devcontainer-collection.json"
config_file="${combined_collection_dir}/config.json"

jq -s \
'{
sourceInformation: (.[1].sourceInformation // .[0].sourceInformation),
features: (.[0].features // []),
templates: (.[1].templates // [])
}' \
"${feature_collection}" \
"${template_collection}" > "${combined_collection}"

printf '{}\n' > "${config_file}"

feature_count="$(find features/src -mindepth 2 -maxdepth 2 -name devcontainer-feature.json | wc -l)"
template_count="$(find templates/src -mindepth 2 -maxdepth 2 -name devcontainer-template.json | wc -l)"

jq -e \
--argjson feature_count "${feature_count}" \
--argjson template_count "${template_count}" \
'(.features | length) == $feature_count and (.templates | length) == $template_count' \
"${combined_collection}" >/dev/null

echo "Publishing combined collection metadata to ${collection_ref}"
(
cd "${combined_collection_dir}"
oras push "${collection_ref}" \
--config "config.json:application/vnd.devcontainers" \
--annotation "com.github.package.type=devcontainer_collection" \
"devcontainer-collection.json:application/vnd.devcontainers.collection.layer.v1+json"
)

oras pull "${collection_ref}" --output "${verified_collection_dir}"
verified_collection="${verified_collection_dir}/devcontainer-collection.json"

jq -e \
--argjson feature_count "${feature_count}" \
--argjson template_count "${template_count}" \
'(.features | length) == $feature_count and (.templates | length) == $template_count' \
"${verified_collection}" >/dev/null

echo "Verified combined collection metadata with ${feature_count} Feature(s) and ${template_count} Template(s)."
67 changes: 42 additions & 25 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ jobs:

- uses: actions/checkout@v6

- name: Install devcontainer CLI
run: npm install --global @devcontainers/cli@0.88.0

- name: Set release version
id: bump
run: |
Expand All @@ -69,17 +72,20 @@ jobs:
echo 'EOF'
} >> "$GITHUB_OUTPUT"

- name: "Generate Template Docs"
uses: devcontainers/action@v1
with:
base-path-to-templates: "./templates/src"
generate-docs: "true"
- name: Generate Template Docs
run: |
devcontainer templates generate-docs \
--project-folder templates/src \
--github-owner "${GITHUB_REPOSITORY_OWNER}" \
--github-repo "${GITHUB_REPOSITORY#*/}"

- name: "Generate Feature Docs"
uses: devcontainers/action@v1
with:
base-path-to-features: "./features/src"
generate-docs: "true"
- name: Generate Feature Docs
run: |
devcontainer features generate-docs \
--project-folder features/src \
--namespace "${GITHUB_REPOSITORY}" \
--github-owner "${GITHUB_REPOSITORY_OWNER}" \
--github-repo "${GITHUB_REPOSITORY#*/}"

- name: Verify release versions
env:
Expand Down Expand Up @@ -109,27 +115,38 @@ jobs:
echo "archive_name=$(basename "${archive_path}")"
} >> "$GITHUB_OUTPUT"

- name: "Publish Features"
uses: devcontainers/action@v1
with:
publish-features: ${{ steps.settings.outputs.dry_run != 'true' }}
validate-only: ${{ steps.settings.outputs.dry_run == 'true' }}
base-path-to-features: "./features/src"
disable-repo-tagging: "true"
- name: Validate Feature publishing metadata
if: ${{ steps.settings.outputs.dry_run == 'true' }}
run: |
devcontainer features package features/src \
--output-folder "${RUNNER_TEMP}/features" \
--force-clean-output-folder

- name: Install ORAS
if: ${{ steps.settings.outputs.dry_run != 'true' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: "Publish Templates"
ORAS_VERSION: "1.3.3"
ORAS_SHA256: "9ce999f8d2de03fc03968b29d743077a58783e545e5eaa53917ca177352d0e59"
run: |
archive="${RUNNER_TEMP}/oras.tar.gz"
curl --fail --silent --show-error --location \
"https://github.com/oras-project/oras/releases/download/v${ORAS_VERSION}/oras_${ORAS_VERSION}_linux_amd64.tar.gz" \
--output "${archive}"
echo "${ORAS_SHA256} ${archive}" | sha256sum --check
tar --extract --gzip --file "${archive}" --directory "${RUNNER_TEMP}" oras
echo "${RUNNER_TEMP}" >> "${GITHUB_PATH}"

- name: Log in to GHCR
if: ${{ steps.settings.outputs.dry_run != 'true' }}
uses: devcontainers/action@v1
with:
publish-templates: "true"
base-path-to-templates: "./templates/src"
disable-repo-tagging: "true"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: echo "${GH_TOKEN}" | oras login ghcr.io --username "${GITHUB_ACTOR}" --password-stdin

- name: Publish Dev Container assets
if: ${{ steps.settings.outputs.dry_run != 'true' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash .github/scripts/publish-devcontainer-assets.sh ghcr.io "${GITHUB_REPOSITORY}"

- name: Upload release source bundle
if: ${{ github.event_name == 'release' }}
Expand Down
36 changes: 21 additions & 15 deletions .github/workflows/test-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ jobs:
- uses: actions/checkout@v6

- name: Install devcontainer CLI
run: npm install -g @devcontainers/cli
run: npm install --global @devcontainers/cli@0.88.0

- name: Validate feature metadata
run: bash features/test/test_all.sh

- name: Validate Feature publishing metadata
uses: devcontainers/action@v1
with:
validate-only: "true"
base-path-to-features: "./features/src"
run: |
devcontainer features package features/src \
--output-folder "${RUNNER_TEMP}/features" \
--force-clean-output-folder

gen-docs:
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
Expand All @@ -48,17 +48,23 @@ jobs:
ref: ${{ github.head_ref }}
token: ${{ secrets.CI_BOT_TOKEN }}

- name: "Generate Template Docs"
uses: devcontainers/action@v1
with:
base-path-to-templates: "./templates/src"
generate-docs: "true"
- name: Install devcontainer CLI
run: npm install --global @devcontainers/cli@0.88.0

- name: "Generate Feature Docs"
uses: devcontainers/action@v1
with:
base-path-to-features: "./features/src"
generate-docs: "true"
- name: Generate Template Docs
run: |
devcontainer templates generate-docs \
--project-folder templates/src \
--github-owner "${GITHUB_REPOSITORY_OWNER}" \
--github-repo "${GITHUB_REPOSITORY#*/}"

- name: Generate Feature Docs
run: |
devcontainer features generate-docs \
--project-folder features/src \
--namespace "${GITHUB_REPOSITORY}" \
--github-owner "${GITHUB_REPOSITORY_OWNER}" \
--github-repo "${GITHUB_REPOSITORY#*/}"

- uses: stefanzweifel/git-auto-commit-action@v7
with:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ XWayland setups are auto-detected from the mounted runtime directory.
## Workflows

- `.github/workflows/test-pr.yaml`: smoke tests template changes, validates features, and refreshes generated docs on pull requests
- `.github/workflows/release.yaml`: publishes from GitHub release runs, attaches a versioned source bundle to the release, and also supports manual versioned runs with a dry-run mode that only bumps manifests and regenerates docs in the workflow workspace
- `.github/workflows/release.yaml`: publishes Features and Templates with the Dev Container CLI, combines their discovery metadata under one OCI collection, attaches a versioned source bundle to GitHub releases, and supports manual dry runs