name: Dashboard on: workflow_dispatch: {} # Publish a main commit the path filter below misses push: branches: [main] paths: - "Dockerfile.dashboard" - "packages/dashboard/**" # The image runs whatever `packages/test-support` held when it was # built, and the dashboard's manifest reader is in there. Without this # the deployed dashboard keeps reading manifests by a rule the # publisher has stopped writing to. - "packages/test-support/**" - "scripts/ci-gantt.ts" - "deno.jsonc" - "deno.lock" - ".dockerignore" - ".github/actions/deno-setup/**" - ".github/actions/deno-install/**" - ".github/workflows/dashboard-image.yml" permissions: contents: read concurrency: group: dashboard-${{ github.ref }} cancel-in-progress: true jobs: tests: name: Tests runs-on: ubuntu-latest timeout-minutes: 15 steps: # A manual run can name any ref. Publishing moves the `latest` tag that # the deployment follows, so a run on another ref stops here, before # anything from that ref is checked out or run. - name: ๐Ÿ”Ž Verify the run is on main if: ${{ github.ref != 'refs/heads/main' }} run: | echo "The dashboard image publishes only from main; this run is on ${GITHUB_REF}." >&2 exit 1 - name: ๐Ÿ“ฅ Checkout source commit uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: ๐Ÿฆ• Setup Deno uses: ./.github/actions/deno-setup - name: ๐Ÿ” Install dependencies uses: ./.github/actions/deno-install # The CI workflow's lanes run these tests on the same commit, in the # `workspace-unit` suite, and record them there. Repeating that recording # here would file each of those tests twice against one commit, so this # job writes no test records: it sets no spool directory, wraps nothing # in `run-recorded`, and ships no artifact. The relay does not follow # this workflow. - name: ๐Ÿงช Test dashboard working-directory: packages/dashboard run: deno task test publish: name: Publish image needs: [tests] runs-on: ubuntu-latest timeout-minutes: 30 permissions: contents: read id-token: write env: IMAGE: us-central1-docker.pkg.dev/commontools-core/containers/dev-dashboard steps: - name: ๐Ÿ“ฅ Checkout source commit uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: ๐Ÿ”‘ Authenticate to Google Cloud id: auth uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 with: project_id: commontools-core workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }} service_account: ${{ vars.GCP_SERVICE_ACCOUNT }} token_format: access_token create_credentials_file: false - name: ๐Ÿ”‘ Login to Artifact Registry uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: registry: us-central1-docker.pkg.dev username: oauth2accesstoken password: ${{ steps.auth.outputs.access_token }} - name: โš™๏ธ Setup Docker Buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - name: ๐Ÿ” Resolve existing immutable image id: existing env: ACCESS_TOKEN: ${{ steps.auth.outputs.access_token }} shell: bash run: | result=$(curl --silent --show-error --output /dev/null --head \ --header "Authorization: Bearer ${ACCESS_TOKEN}" \ --header 'Accept: application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v2+json' \ --write-out '%header{docker-content-digest}\n%{http_code}' \ "https://us-central1-docker.pkg.dev/v2/commontools-core/containers/dev-dashboard/manifests/${GITHUB_SHA}") digest=${result%%$'\n'*} status=${result##*$'\n'} case "$status" in 200) [[ "$digest" =~ ^sha256:[a-f0-9]{64}$ ]] echo "exists=true" >> "$GITHUB_OUTPUT" echo "digest=$digest" >> "$GITHUB_OUTPUT" ;; 404) echo "exists=false" >> "$GITHUB_OUTPUT" ;; *) echo "Artifact Registry manifest lookup failed with HTTP $status" >&2 exit 1 ;; esac # The labels record which workflow run published the image, and from # which commit. They live in the image config, which the digest covers, # so moving a tag cannot change them. The infra repository's # k8s/scripts/verify-image-provenance.sh reads them back and checks them # against GitHub before the digest is deployed. - name: ๐Ÿ—๏ธ Build and push dashboard image id: build if: ${{ steps.existing.outputs.exists != 'true' }} uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . file: Dockerfile.dashboard platforms: linux/amd64 push: true build-args: | DASHBOARD_GIT_COMMIT=${{ github.sha }} tags: | ${{ env.IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}:latest labels: | org.opencontainers.image.source=https://github.com/${{ github.repository }} org.opencontainers.image.revision=${{ github.sha }} dev.commontools.provenance.repository=${{ github.repository }} dev.commontools.provenance.ref=${{ github.ref }} dev.commontools.provenance.event=${{ github.event_name }} dev.commontools.provenance.workflow-ref=${{ github.workflow_ref }} dev.commontools.provenance.run-id=${{ github.run_id }} dev.commontools.provenance.run-attempt=${{ github.run_attempt }} - name: ๐Ÿš€ Promote existing image to latest if: ${{ steps.existing.outputs.exists == 'true' }} env: EXISTING_DIGEST: ${{ steps.existing.outputs.digest }} run: docker buildx imagetools create --tag "${IMAGE}:latest" "${IMAGE}@${EXISTING_DIGEST}" - name: โœ… Resolve published digest id: result env: BUILT_DIGEST: ${{ steps.build.outputs.digest }} EXISTING_DIGEST: ${{ steps.existing.outputs.digest }} shell: bash run: | digest="${BUILT_DIGEST:-$EXISTING_DIGEST}" [[ "$digest" =~ ^sha256:[a-f0-9]{64}$ ]] echo "digest=$digest" >> "$GITHUB_OUTPUT" - name: ๐Ÿ“Š Report immutable image reference env: DIGEST: ${{ steps.result.outputs.digest }} run: | { echo "### Dashboard image published" echo echo "- Tag: \`${IMAGE}:${GITHUB_SHA}\`" echo "- Digest: \`${IMAGE}@${DIGEST}\`" } >> "$GITHUB_STEP_SUMMARY"