From 89f1e2099935c874f0bf13834c4f70280fbfd5ef Mon Sep 17 00:00:00 2001 From: Allison Thackston <73732028+althack@users.noreply.github.com> Date: Sun, 24 May 2026 16:56:33 -0700 Subject: [PATCH] Improve the release workflow --- .github/scripts/package-release-bundle.sh | 20 ++++ .github/scripts/set-devcontainer-version.sh | 35 ++++++ .github/workflows/release.yaml | 112 +++++++++++++++++++- README.md | 2 +- 4 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 .github/scripts/package-release-bundle.sh create mode 100755 .github/scripts/set-devcontainer-version.sh diff --git a/.github/scripts/package-release-bundle.sh b/.github/scripts/package-release-bundle.sh new file mode 100644 index 0000000..1916d3d --- /dev/null +++ b/.github/scripts/package-release-bundle.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +version="${1:-}" +output_dir="${2:-dist}" + +if [[ -z "${version}" ]]; then + echo "Usage: $0 [output-dir]" >&2 + exit 1 +fi + +mkdir -p "${output_dir}" + +archive_path="${output_dir}/devcontainers-${version}.tar.gz" + +# Archive the tracked workspace as it exists after version stamping and doc generation. +git ls-files -z | tar --null -czf "${archive_path}" -T - + +echo "${archive_path}" diff --git a/.github/scripts/set-devcontainer-version.sh b/.github/scripts/set-devcontainer-version.sh new file mode 100755 index 0000000..2f2b06d --- /dev/null +++ b/.github/scripts/set-devcontainer-version.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +set -euo pipefail + +raw_version="${1:-}" + +if [[ -z "${raw_version}" ]]; then + echo "Usage: $0 " >&2 + exit 1 +fi + +version="${raw_version#v}" + +if [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then + echo "Version must look like semver, for example 1.2.3 or 1.2.3-rc.1" >&2 + exit 1 +fi + +mapfile -t manifest_files < <( + find features/src templates/src -type f \ + \( -name 'devcontainer-feature.json' -o -name 'devcontainer-template.json' \) \ + | sort +) + +if [[ "${#manifest_files[@]}" -eq 0 ]]; then + echo "No devcontainer manifest files found." >&2 + exit 1 +fi + +for manifest_file in "${manifest_files[@]}"; do + tmp_file="$(mktemp)" + jq --arg version "${version}" '.version = $version' "${manifest_file}" > "${tmp_file}" + mv "${tmp_file}" "${manifest_file}" + echo "Updated ${manifest_file} to version ${version}" +done diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4251ce8..60a24aa 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,19 +1,98 @@ name: "Release Dev Container Features And Templates" on: workflow_dispatch: + inputs: + version: + description: "Release version to publish, for example 1.2.3" + required: true + type: string + dry_run: + description: "Run the release flow without publishing packages or committing version updates" + required: false + default: true + type: boolean + + release: + types: + - published jobs: deploy: - if: ${{ github.ref == 'refs/heads/main' }} + if: ${{ github.event_name == 'release' || github.ref == 'refs/heads/main' || github.event.inputs.dry_run == 'true' }} runs-on: ubuntu-latest permissions: packages: write contents: write pull-requests: write steps: + - name: Resolve release settings + id: settings + env: + INPUT_VERSION: ${{ inputs.version }} + INPUT_DRY_RUN: ${{ inputs.dry_run }} + RELEASE_TAG: ${{ github.event.release.tag_name }} + run: | + set -euo pipefail + + if [[ "${GITHUB_EVENT_NAME}" == "release" ]]; then + raw_version="${RELEASE_TAG}" + dry_run="false" + mode="release" + else + raw_version="${INPUT_VERSION}" + dry_run="${INPUT_DRY_RUN:-true}" + + if [[ "${dry_run}" == "true" ]]; then + mode="dry-run" + else + mode="manual-release" + fi + fi + + version="${raw_version#v}" + + { + echo "version=${version}" + echo "dry_run=${dry_run}" + echo "mode=${mode}" + } >> "$GITHUB_OUTPUT" + - uses: actions/checkout@v6 + - name: Set release version + id: bump + run: | + bash .github/scripts/set-devcontainer-version.sh "${{ steps.settings.outputs.version }}" + { + echo 'manifest_files<> "$GITHUB_OUTPUT" + + - name: "Generate Template Docs" + uses: devcontainers/action@v1 + with: + base-path-to-templates: "./templates/src" + generate-docs: "true" + + - name: "Generate Feature Docs" + uses: devcontainers/action@v1 + with: + base-path-to-features: "./features/src" + generate-docs: "true" + + - name: Package release source bundle + if: ${{ github.event_name == 'release' }} + id: package + run: | + archive_path="$(bash .github/scripts/package-release-bundle.sh "${{ steps.settings.outputs.version }}")" + { + echo "archive_path=${archive_path}" + echo "archive_name=$(basename "${archive_path}")" + } >> "$GITHUB_OUTPUT" + - name: "Publish Features" + if: ${{ steps.settings.outputs.dry_run != 'true' }} uses: devcontainers/action@v1 with: publish-features: "true" @@ -23,6 +102,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: "Publish Templates" + if: ${{ steps.settings.outputs.dry_run != 'true' }} uses: devcontainers/action@v1 with: publish-templates: "true" @@ -30,3 +110,33 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload release source bundle + if: ${{ github.event_name == 'release' }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload "${{ github.event.release.tag_name }}" "${{ steps.package.outputs.archive_path }}" --clobber + + - name: Summarize release run + run: | + { + echo "### Release workflow" + echo "" + echo "- Mode: ${{ steps.settings.outputs.mode }}" + echo "- Version: ${{ steps.settings.outputs.version }}" + echo "- Publish packages: ${{ steps.settings.outputs.dry_run != 'true' }}" + echo "- Attach source bundle to release: ${{ github.event_name == 'release' }}" + echo "" + echo "Updated manifest files:" + echo '```text' + printf '%s\n' "${{ steps.bump.outputs.manifest_files }}" + echo '```' + if [[ "${{ github.event_name }}" == "release" ]]; then + echo "" + echo "Release asset:" + echo '```text' + printf '%s\n' "${{ steps.package.outputs.archive_name }}" + echo '```' + fi + } >> "$GITHUB_STEP_SUMMARY" diff --git a/README.md b/README.md index 152f9a1..10323b2 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,4 @@ Devcontainer templates repository focused on robotics and simulation. ## Workflows - `.github/workflows/test-pr.yaml`: smoke tests template changes, validates features, and refreshes generated docs on pull requests -- `.github/workflows/release.yaml`: publishes features and templates to GHCR on manual dispatch from `main` +- `.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