From 5cefabde4e93a17ba3d7afbd74927b75c098b7ec Mon Sep 17 00:00:00 2001 From: Carson Holgate Date: Wed, 24 Jun 2026 10:01:00 -0700 Subject: [PATCH 1/2] Update release test CI to use default pinned versions Cherry-pick CI changes from main onto the release branch: - release-test.yml: add bazel-cache action, permissions, concurrency group, rename job to "Bootstrap with default pinned versions" - release_test.sh: remove --valdiVersion=main / --valdiWidgetsVersion=main overrides so the test uses the CLI's default pinned tags - Add .github/actions/bazel-cache/action.yml (new dependency) The old workflow bootstrapped from main (bleeding edge) which broke when main's resvg_libs strip_prefix diverged from the archive structure. --- .github/actions/bazel-cache/action.yml | 109 +++++++++++++++++++++++++ .github/workflows/release-test.yml | 23 +++++- tools/ci/release_test.sh | 12 ++- 3 files changed, 133 insertions(+), 11 deletions(-) create mode 100644 .github/actions/bazel-cache/action.yml diff --git a/.github/actions/bazel-cache/action.yml b/.github/actions/bazel-cache/action.yml new file mode 100644 index 000000000..fe2f4db1a --- /dev/null +++ b/.github/actions/bazel-cache/action.yml @@ -0,0 +1,109 @@ +name: 'Configure Bazel Cache' +description: 'Set up GCS remote cache and optional disk cache for Bazel builds' + +inputs: + gcp_project_id: + description: 'GCP project ID' + required: true + workload_identity_provider: + description: 'Full workload identity provider resource name' + required: true + service_account: + description: 'GCP service account email' + required: true + cache_bucket: + description: 'GCS bucket name for remote cache' + required: true + cache_key: + description: 'Cache key prefix for disk cache via actions/cache. Omit to skip disk cache.' + required: false + default: '' + +runs: + using: 'composite' + steps: + - name: Authenticate to Google Cloud + id: auth + continue-on-error: true + uses: google-github-actions/auth@v2 + with: + project_id: ${{ inputs.gcp_project_id }} + workload_identity_provider: ${{ inputs.workload_identity_provider }} + service_account: ${{ inputs.service_account }} + token_format: 'access_token' + + - name: Configure Bazel remote cache + shell: bash + env: + AUTH_OUTCOME: ${{ steps.auth.outcome }} + CACHE_BUCKET: ${{ inputs.cache_bucket }} + ACCESS_TOKEN: ${{ steps.auth.outputs.access_token }} + EVENT_NAME: ${{ github.event_name }} + run: | + # Always write config=ci for non-remote flags (circuit breaker, etc.) + echo "build --config=ci" >> .bazelrc.local + + # Write cache config to a job-specific file. Bootstrapped projects + # (e.g. /tmp/valdi_app) import this via try-import in ~/.bazelrc, + # avoiding races when concurrent jobs share a runner. + CACHE_RC="/tmp/bazelrc-cache-${GITHUB_RUN_ID}-${GITHUB_JOB}" + > "$CACHE_RC" + echo "BAZEL_CACHE_RC=$CACHE_RC" >> "$GITHUB_ENV" + + if [ "$AUTH_OUTCOME" != "success" ]; then + echo "Auth skipped (expected for fork PRs). Building without remote cache." + exit 0 + fi + + # Checkout directory config + echo "build --remote_cache=https://storage.googleapis.com/$CACHE_BUCKET" >> .bazelrc.local + echo "build \"--remote_header=Authorization=Bearer $ACCESS_TOKEN\"" >> .bazelrc.local + # Only upload cache results on push (trusted) events, not pull requests + if [ "$EVENT_NAME" = "push" ] || [ "$EVENT_NAME" = "workflow_dispatch" ] || [ "$EVENT_NAME" = "release" ]; then + echo "build --remote_upload_local_results=true" >> .bazelrc.local + else + echo "build --remote_upload_local_results=false" >> .bazelrc.local + fi + + # Point ~/.bazelrc to the job-specific file via try-import. + # Single atomic write — no truncation window for concurrent jobs. + echo "try-import $CACHE_RC" > ~/.bazelrc + + # Cache config for bootstrapped projects (discovered via try-import above) + echo "build --remote_cache=https://storage.googleapis.com/$CACHE_BUCKET" >> "$CACHE_RC" + echo "build \"--remote_header=Authorization=Bearer $ACCESS_TOKEN\"" >> "$CACHE_RC" + echo "build --experimental_circuit_breaker_strategy=failure" >> "$CACHE_RC" + if [ "$EVENT_NAME" = "push" ] || [ "$EVENT_NAME" = "workflow_dispatch" ] || [ "$EVENT_NAME" = "release" ]; then + echo "build --remote_upload_local_results=true" >> "$CACHE_RC" + else + echo "build --remote_upload_local_results=false" >> "$CACHE_RC" + fi + + - name: Prune and configure disk cache + if: inputs.cache_key != '' + shell: bash + run: | + # Prune old cache files to prevent unbounded growth on persistent runners + find "$HOME/.cache/bazel/disk" -type f -atime +7 -delete 2>/dev/null || true + find "$HOME/.cache/bazel/repo" -type f -atime +7 -delete 2>/dev/null || true + + echo "build:ci --disk_cache=$HOME/.cache/bazel/disk" >> .bazelrc.local + echo "build:ci --repository_cache=$HOME/.cache/bazel/repo" >> .bazelrc.local + if [ -n "$BAZEL_CACHE_RC" ]; then + echo "build --disk_cache=$HOME/.cache/bazel/disk" >> "$BAZEL_CACHE_RC" + echo "build --repository_cache=$HOME/.cache/bazel/repo" >> "$BAZEL_CACHE_RC" + fi + + - name: Mount Bazel cache + if: inputs.cache_key != '' && runner.environment == 'github-hosted' + uses: actions/cache@v4 + continue-on-error: true + with: + path: | + ~/.cache/bazel/disk + ~/.cache/bazel/repo + ~/.cache/bazelisk + key: bazel-${{ runner.os }}-${{ inputs.cache_key }}-${{ hashFiles('MODULE.bazel', '**/*.bzl') }}-${{ github.run_id }} + restore-keys: | + bazel-${{ runner.os }}-${{ inputs.cache_key }}-${{ hashFiles('MODULE.bazel', '**/*.bzl') }}- + bazel-${{ runner.os }}-${{ inputs.cache_key }}- diff --git a/.github/workflows/release-test.yml b/.github/workflows/release-test.yml index 40f9821ed..098da3720 100644 --- a/.github/workflows/release-test.yml +++ b/.github/workflows/release-test.yml @@ -1,6 +1,5 @@ -# Run before cutting a release: bootstrap an app from bleeding edge (main) of -# the public GitHub Valdi/Valdi_Widgets, build and test. Ensures "if we cut a -# release now, things won't fail." +# Release test: bootstrap an app using the CLI's default pinned versions, +# build and test. Validates the exact user experience of `valdi bootstrap`. name: Release Test (Public GitHub) on: @@ -18,9 +17,17 @@ on: - 'tools/ci/release_test.sh' - '.github/workflows/release-test.yml' +permissions: + contents: read + id-token: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: release-test: - name: Bootstrap from main (bleeding edge), build & test + name: Bootstrap with default pinned versions, build & test runs-on: macos-latest steps: @@ -29,6 +36,14 @@ jobs: with: lfs: true + - name: Configure Bazel cache + uses: ./.github/actions/bazel-cache + with: + gcp_project_id: ${{ vars.GCP_PROJECT_ID }} + workload_identity_provider: ${{ vars.WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ vars.GCP_SERVICE_ACCOUNT }} + cache_bucket: ${{ vars.BAZEL_CACHE_BUCKET }} + - name: Setup Node.js uses: actions/setup-node@v4 with: diff --git a/tools/ci/release_test.sh b/tools/ci/release_test.sh index 6a353def3..96b9216a8 100755 --- a/tools/ci/release_test.sh +++ b/tools/ci/release_test.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash # -# Release test: bootstrap an app from the bleeding edge (main) of the public -# GitHub Valdi/Valdi_Widgets, build it, and run tests. Use this before cutting -# a release to verify that if we cut a release now from main, things won't fail. +# Release test: bootstrap an app using the CLI's default pinned versions, +# build it, and run tests. Validates the exact flow a user would experience +# when running `valdi bootstrap` after installing the published CLI. # # Usage: run from repo root (open_source). Requires Node, Bazel, and (on macOS) Xcode. # @@ -40,8 +40,8 @@ npm ci npm run build cd "$OPEN_SOURCE_DIR" -# Bootstrap app using bleeding edge (main) from public GitHub (no -l, so no local path) -echo "Bootstrapping app (bleeding edge / main from public GitHub)..." +# Bootstrap app using the CLI's default pinned versions (no version overrides) +echo "Bootstrapping app (default pinned versions)..." mkdir -p "$APP_DIR" rm -rf "${APP_DIR:?}"/* "${APP_DIR:?}"/.[!.]* 2>/dev/null || true cd "$APP_DIR" @@ -49,8 +49,6 @@ node "$CLI_DIR/dist/index.js" bootstrap \ -y \ "-n=$PROJECT_NAME" \ -t=ui_application \ - --valdiVersion=main \ - --valdiWidgetsVersion=main \ --with-cleanup # Verify the project references public GitHub (not local). From 190efed5600862e084bb603e12cbfe12aa915461 Mon Sep 17 00:00:00 2001 From: Carson Holgate Date: Wed, 24 Jun 2026 10:05:07 -0700 Subject: [PATCH 2/2] Bump default release tags from beta-0.0.3 to beta-0.1.0 The release branch was cut from beta-0.1.0 which still had beta-0.0.3 as the default tags. The release test now uses pinned defaults, so these must point to a version with MODULE.bazel support (beta-0.0.3 predates bzlmod). --- npm_modules/cli/src/commands/bootstrap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npm_modules/cli/src/commands/bootstrap.ts b/npm_modules/cli/src/commands/bootstrap.ts index 02b840b64..b142cfc51 100644 --- a/npm_modules/cli/src/commands/bootstrap.ts +++ b/npm_modules/cli/src/commands/bootstrap.ts @@ -57,9 +57,9 @@ const VALDI_GIT_URL = 'https://github.com/Snapchat/Valdi'; const VALDI_WIDGETS_GIT_URL = 'https://github.com/Snapchat/Valdi_Widgets'; /** Pinned Valdi release used by default for reproducible bootstraps. Bump when cutting a new Valdi release. */ -const DEFAULT_VALDI_RELEASE_TAG = 'beta-0.0.3'; +const DEFAULT_VALDI_RELEASE_TAG = 'beta-0.1.0'; /** Pinned Valdi_Widgets release used by default. Should match the Valdi release cycle. */ -const DEFAULT_VALDI_WIDGETS_RELEASE_TAG = 'beta-0.0.3'; +const DEFAULT_VALDI_WIDGETS_RELEASE_TAG = 'beta-0.1.0'; function isAlreadyInitialized(): boolean {