Update Arcane Release Assets #2688
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Update Arcane Release Assets | |
| on: | |
| schedule: | |
| - cron: '*/30 * * * *' | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| id-token: write | |
| jobs: | |
| update-release-assets: | |
| if: ${{ github.repository_owner == 'getarcaneapp' && github.actor != 'getarcaneappbot' }} | |
| runs-on: depot-ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Fetch releases list | |
| id: releases | |
| run: | | |
| set -euo pipefail | |
| RELEASES_JSON=/tmp/releases.json | |
| curl -sSL \ | |
| -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "https://api.github.com/repos/getarcaneapp/arcane/releases?per_page=100" \ | |
| -o "$RELEASES_JSON" | |
| echo "releases_json=$RELEASES_JSON" >> "$GITHUB_OUTPUT" | |
| - name: Check current assets | |
| id: check | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| RELEASES_JSON="${{ steps.releases.outputs.releases_json }}" | |
| VERSION=$(jq -r '[.[] | select(.draft == false and .prerelease == false)][0].tag_name // ""' "$RELEASES_JSON") | |
| if [[ -z "$VERSION" ]]; then | |
| echo "No releases found in $RELEASES_JSON" >&2 | |
| exit 1 | |
| fi | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| CHANGELOG_UP_TO_DATE=false | |
| shopt -s nullglob | |
| CHANGELOG_FILES=(content/changelog/*.md) | |
| if (( ${#CHANGELOG_FILES[@]} > 0 )); then | |
| CHANGELOG_UP_TO_DATE=true | |
| while IFS= read -r tag; do | |
| if ! grep -qE "^##[[:space:]]+$tag\\b" "${CHANGELOG_FILES[@]}"; then | |
| CHANGELOG_UP_TO_DATE=false | |
| break | |
| fi | |
| done < <(jq -r '.[] | select(.draft == false and .prerelease == false) | .tag_name' "$RELEASES_JSON") | |
| fi | |
| SBOM_UP_TO_DATE=false | |
| if [[ -f static/sbom/version.txt ]]; then | |
| CURRENT=$(cat static/sbom/version.txt) | |
| if [[ "$CURRENT" == "$VERSION" ]]; then | |
| SBOM_UP_TO_DATE=true | |
| fi | |
| fi | |
| if [[ "$CHANGELOG_UP_TO_DATE" == "true" && "$SBOM_UP_TO_DATE" == "true" ]]; then | |
| echo "skip_all=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip_all=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| if [[ "$CHANGELOG_UP_TO_DATE" == "true" ]]; then | |
| echo "do_changelog=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "do_changelog=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| if [[ "$SBOM_UP_TO_DATE" == "true" ]]; then | |
| echo "do_sbom=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "do_sbom=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Update changelog | |
| if: steps.check.outputs.do_changelog == 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| RELEASES_JSON="${{ steps.releases.outputs.releases_json }}" REPO="getarcaneapp/arcane" CHANGELOG_DIR="content/changelog" bash scripts/update-changelog.sh | |
| - name: Checkout arcane repo | |
| if: steps.check.outputs.do_sbom == 'true' | |
| uses: actions/checkout@v7 | |
| with: | |
| repository: getarcaneapp/arcane | |
| ref: ${{ steps.check.outputs.version }} | |
| path: arcane | |
| fetch-depth: 1 | |
| - name: Set up Go | |
| if: steps.check.outputs.do_sbom == 'true' | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: arcane/go.mod | |
| - name: Set up just | |
| if: steps.check.outputs.do_sbom == 'true' | |
| uses: extractions/setup-just@v4 | |
| - name: Generate config.json | |
| if: steps.check.outputs.do_sbom == 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cd arcane | |
| just docs config ../static/config.json | |
| - name: Extract SBOMs from published images | |
| if: steps.check.outputs.do_sbom == 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| VERSION="${{ steps.check.outputs.version }}" | |
| mkdir -p static/sbom/manager static/sbom/agent | |
| # Pull the SBOM attestations attached to the published images, so | |
| # the data matches exactly what ships. On a multi-platform tag, | |
| # `.SBOM` is a map keyed by platform, each entry holding the SPDX | |
| # document. jq pretty-prints to avoid compact single-line JSON in | |
| # repo diffs; -e fails the job if a platform has no attestation. | |
| for image in manager agent; do | |
| if [[ "$image" == "manager" ]]; then | |
| ref="ghcr.io/getarcaneapp/arcane:$VERSION" | |
| else | |
| ref="ghcr.io/getarcaneapp/arcane-headless:$VERSION" | |
| fi | |
| sboms=$(docker buildx imagetools inspect "$ref" --format '{{ json .SBOM }}') | |
| for spec in \ | |
| "linux/amd64:linux_amd64" \ | |
| "linux/arm64:linux_arm64" \ | |
| "linux/arm/v7:linux_armv7" \ | |
| "linux/riscv64:linux_riscv64" | |
| do | |
| platform="${spec%:*}" | |
| out="static/sbom/$image/${spec##*:}.spdx.json" | |
| if ! jq -e --arg p "$platform" '.[$p].SPDX' <<< "$sboms" > "$out"; then | |
| echo "No SBOM attestation for $platform in $ref" >&2 | |
| exit 1 | |
| fi | |
| done | |
| done | |
| - name: Write SBOM metadata and cleanup | |
| if: steps.check.outputs.do_sbom == 'true' | |
| run: | | |
| set -euo pipefail | |
| VERSION="${{ steps.check.outputs.version }}" | |
| # Save version | |
| echo "$VERSION" > static/sbom/version.txt | |
| # Create metadata file | |
| cat > static/sbom/metadata.json << EOF | |
| { | |
| "version": "$VERSION", | |
| "updated": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", | |
| "images": { | |
| "manager": { | |
| "name": "ghcr.io/getarcaneapp/arcane", | |
| "architectures": ["linux/amd64", "linux/arm64", "linux/arm/v7", "linux/riscv64"], | |
| "sbomFiles": { | |
| "amd64": "/sbom/manager/linux_amd64.spdx.json", | |
| "arm64": "/sbom/manager/linux_arm64.spdx.json", | |
| "armv7": "/sbom/manager/linux_armv7.spdx.json", | |
| "riscv64": "/sbom/manager/linux_riscv64.spdx.json" | |
| } | |
| }, | |
| "agent": { | |
| "name": "ghcr.io/getarcaneapp/arcane-headless", | |
| "architectures": ["linux/amd64", "linux/arm64", "linux/arm/v7", "linux/riscv64"], | |
| "sbomFiles": { | |
| "amd64": "/sbom/agent/linux_amd64.spdx.json", | |
| "arm64": "/sbom/agent/linux_arm64.spdx.json", | |
| "armv7": "/sbom/agent/linux_armv7.spdx.json", | |
| "riscv64": "/sbom/agent/linux_riscv64.spdx.json" | |
| } | |
| } | |
| } | |
| } | |
| EOF | |
| echo "SBOM files generated for $VERSION" | |
| ls -la static/sbom/ | |
| ls -la static/sbom/manager/ | |
| ls -la static/sbom/agent/ | |
| # Clean up cloned repo | |
| rm -rf arcane | |
| - name: Check for changes | |
| id: changes | |
| if: steps.check.outputs.skip_all != 'true' | |
| run: | | |
| if [[ -n "$(git status --porcelain -- content/changelog.md content/changelog/ static/config.json static/sbom/)" ]]; then | |
| echo "has_changes=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "has_changes=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Create pull request | |
| if: steps.changes.outputs.has_changes == 'true' | |
| uses: peter-evans/create-pull-request@v8 | |
| with: | |
| token: ${{ secrets.ARCANE_BOT_TOKEN }} | |
| commit-message: 'chore(release): update assets for ${{ steps.check.outputs.version }}' | |
| committer: 'getarcaneappbot <info@getarcane.app>' | |
| author: 'getarcaneappbot <info@getarcane.app>' | |
| signoff: true | |
| title: 'chore(release): update assets for ${{ steps.check.outputs.version }}' | |
| body: | | |
| Updates Arcane release assets for ${{ steps.check.outputs.version }}. | |
| ## Changes | |
| - Changelog entry (if new) | |
| - Generated `static/config.json` (if changed) | |
| - SBOM files for manager and agent images (if new) | |
| --- | |
| *This PR was automatically generated.* | |
| branch: 'chore/release-assets-${{ steps.check.outputs.version }}' | |
| base: main | |
| labels: 'docs(changelog),chore(config),chore(sbom)' | |
| add-paths: | | |
| content/changelog.md | |
| content/changelog/ | |
| static/config.json | |
| static/sbom/ | |
| delete-branch: true |