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
109 changes: 109 additions & 0 deletions .github/actions/bazel-cache/action.yml
Original file line number Diff line number Diff line change
@@ -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 }}-
23 changes: 19 additions & 4 deletions .github/workflows/release-test.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions npm_modules/cli/src/commands/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
12 changes: 5 additions & 7 deletions tools/ci/release_test.sh
Original file line number Diff line number Diff line change
@@ -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.
#
Expand Down Expand Up @@ -40,17 +40,15 @@ 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"
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).
Expand Down
Loading