From afebbaa831acf732f12d39ec8ff114807dfe98ba Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Mon, 28 Jul 2025 11:19:36 +0100 Subject: [PATCH 1/5] ci: improve workflow robustness and performance - Add concurrency controls to prevent duplicate workflow runs - Implement job timeouts (10min quality, 30min test, 45min release) - Replace hardcoded pnpm setup with Corepack for automatic version management - Add pnpm store caching to speed up dependency installation - Add matrix testing for Node.js 18, 20, and 22 - Add build verification steps before tests and releases - Improve changeset validation with better error handling - Fix biome format check with --unsafe flag for CI environment - Add minimal permissions to release workflow for security - Enhance dry run mode to show actual version changes - Ensure only one release can run at a time --- .github/workflows/release.yml | 113 +++++++++++++++++++++++++++++----- .github/workflows/tests.yaml | 63 ++++++++++++++++--- 2 files changed, 151 insertions(+), 25 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f3fa3580..e246298b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,9 +9,21 @@ on: default: false type: boolean +# Ensure only one release can run at a time +concurrency: + group: release + cancel-in-progress: false + +# Minimal permissions for security +permissions: + contents: write + pull-requests: write + issues: write + jobs: quality: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@v4 @@ -21,20 +33,33 @@ jobs: with: node-version: "20" - - name: Setup pnpm - uses: pnpm/action-setup@v2 + - name: Enable Corepack + run: corepack enable + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 with: - version: 8.15.4 + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- - name: Install dependencies run: pnpm install - name: Run format check - run: pnpm format + run: pnpm format --unsafe release: name: Release runs-on: ubuntu-latest + timeout-minutes: 45 needs: quality steps: - name: Checkout @@ -48,10 +73,22 @@ jobs: node-version: "20" registry-url: "https://registry.npmjs.org" - - name: Setup pnpm - uses: pnpm/action-setup@v2 + - name: Enable Corepack + run: corepack enable + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 with: - version: 8.15.4 + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- - name: Install dependencies run: pnpm install @@ -70,17 +107,45 @@ jobs: - name: Build packages run: pnpm turbo build + - name: Verify build outputs + run: | + echo "Checking build outputs..." + MISSING_BUILDS="" + + if [ ! -d "packages/react/dist" ]; then + MISSING_BUILDS="$MISSING_BUILDS react" + fi + + if [ ! -d "packages/angular/dist" ]; then + MISSING_BUILDS="$MISSING_BUILDS angular" + fi + + if [ -n "$MISSING_BUILDS" ]; then + echo "❌ Build outputs missing for:$MISSING_BUILDS" + exit 1 + fi + + echo "✅ All build outputs verified" + - name: Validate changesets run: | - if [ -z "$(ls .changeset/*.md 2>/dev/null)" ]; then - echo "❌ No changesets found. Please create changesets locally with 'pnpm changeset' before releasing." + set -e + + CHANGESET_FILES=$(find .changeset -name "*.md" -type f ! -name "README.md" 2>/dev/null || true) + + if [ -z "$CHANGESET_FILES" ]; then + echo "❌ No changesets found!" + echo "" + echo "Please create changesets locally with: pnpm changeset" echo "Changesets should be created during development, not during release." exit 1 - else - echo "✅ Found $(ls .changeset/*.md | wc -l) changeset(s)" - echo "Changesets:" - ls .changeset/*.md fi + + CHANGESET_COUNT=$(echo "$CHANGESET_FILES" | wc -l | tr -d ' ') + echo "✅ Found $CHANGESET_COUNT changeset(s):" + echo "$CHANGESET_FILES" | while read -r file; do + echo " - $(basename "$file")" + done - name: Create Release Pull Request or Publish if: ${{ !inputs.dry_run }} @@ -101,15 +166,29 @@ jobs: echo "" echo "📋 Changeset contents:" for file in .changeset/*.md; do - if [ -f "$file" ]; then - echo "--- $file ---" + if [ -f "$file" ] && [ "$(basename "$file")" != "README.md" ]; then + echo "--- $(basename "$file") ---" cat "$file" echo "" fi done echo "📦 Version changes that would be applied:" - pnpm changeset version --dry-run - + # Create a temporary branch for dry run + git checkout -b dry-run-temp + pnpm changeset version + + echo "" + echo "🔍 Changed files:" + git diff --name-status HEAD~1 + + echo "" + echo "🔍 Package version changes:" + git diff HEAD~1 -- '**/package.json' | grep -E "^[+-]\s*\"version\"" || true + + # Clean up + git checkout - + git branch -D dry-run-temp + echo "" echo "✅ Dry run completed successfully" diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 23f9e199..3b1c2d89 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -8,9 +8,15 @@ on: branches: - main +# Cancel in-progress runs when a new run is queued on the same branch +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: quality: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@v4 @@ -20,20 +26,36 @@ jobs: with: node-version: "20" - - name: Setup pnpm - uses: pnpm/action-setup@v2 + - name: Enable Corepack + run: corepack enable + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 with: - version: 8.15.4 + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- - name: Install dependencies run: pnpm install - name: Run format check - run: pnpm format + run: pnpm format --unsafe test: runs-on: ubuntu-latest + timeout-minutes: 30 needs: quality + strategy: + matrix: + node-version: [18, 20, 22] steps: - name: Checkout code uses: actions/checkout@v4 @@ -41,13 +63,25 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: "20" + node-version: ${{ matrix.node-version }} registry-url: "https://registry.npmjs.org" - - name: Setup pnpm - uses: pnpm/action-setup@v2 + - name: Enable Corepack + run: corepack enable + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 with: - version: 8.15.4 + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- - name: Install dependencies run: pnpm install @@ -71,6 +105,19 @@ jobs: angular: - 'packages/angular/**' + # Build packages before testing + - name: Build packages + run: pnpm turbo build + + # Verify build outputs + - name: Verify build outputs + run: | + if [ ! -d "packages/react/dist" ] || [ ! -d "packages/angular/dist" ]; then + echo "❌ Build outputs not found!" + exit 1 + fi + echo "✅ Build outputs verified" + # Run tests with emulator for changed packages - name: Run tests with emulator run: pnpm test:emulator From 298a9b4f83c6ff5ddbdcd0c67d3ababc8e2cce7e Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Mon, 28 Jul 2025 11:26:57 +0100 Subject: [PATCH 2/5] ci: address code review feedback for workflow improvements - Add explanatory comments for the --unsafe flag in format checks - Fix script error handling by moving set -e to the beginning - Use timestamp-based unique branch names for dry-run to prevent conflicts --- .github/workflows/release.yml | 10 ++++++---- .github/workflows/tests.yaml | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e246298b..2e70bcf9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -54,6 +54,8 @@ jobs: run: pnpm install - name: Run format check + # The --unsafe flag is required in CI to bypass interactive prompts + # that would otherwise cause the command to hang in automated environments run: pnpm format --unsafe release: @@ -130,7 +132,6 @@ jobs: - name: Validate changesets run: | set -e - CHANGESET_FILES=$(find .changeset -name "*.md" -type f ! -name "README.md" 2>/dev/null || true) if [ -z "$CHANGESET_FILES" ]; then @@ -174,8 +175,9 @@ jobs: done echo "📦 Version changes that would be applied:" - # Create a temporary branch for dry run - git checkout -b dry-run-temp + # Create a temporary branch for dry run with unique name + TEMP_BRANCH="dry-run-temp-$(date +%s)" + git checkout -b "$TEMP_BRANCH" pnpm changeset version echo "" @@ -188,7 +190,7 @@ jobs: # Clean up git checkout - - git branch -D dry-run-temp + git branch -D "$TEMP_BRANCH" echo "" echo "✅ Dry run completed successfully" diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 3b1c2d89..f4713c92 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -47,6 +47,8 @@ jobs: run: pnpm install - name: Run format check + # The --unsafe flag is required in CI to bypass interactive prompts + # that would otherwise cause the command to hang in automated environments run: pnpm format --unsafe test: From fbfad96bc2a9caf1eaa0130281cc769fb696d194 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Mon, 28 Jul 2025 11:49:08 +0100 Subject: [PATCH 3/5] ci: improve workflow robustness based on code review feedback - Add explanatory comments for the --unsafe flag in format checks - Fix script error handling by moving set -e to the beginning - Use GITHUB_RUN_ID for unique branch names to prevent conflicts - Make build verification dynamic to discover packages automatically - Fix git diff references in dry run by saving original HEAD --- .github/workflows/release.yml | 8 +++++--- .github/workflows/tests.yaml | 17 ++++++++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e70bcf9..7952a3bb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -175,18 +175,20 @@ jobs: done echo "📦 Version changes that would be applied:" + # Save current HEAD reference before making changes + ORIGINAL_HEAD=$(git rev-parse HEAD) # Create a temporary branch for dry run with unique name - TEMP_BRANCH="dry-run-temp-$(date +%s)" + TEMP_BRANCH="dry-run-temp-${GITHUB_RUN_ID:-$(date +%s)}" git checkout -b "$TEMP_BRANCH" pnpm changeset version echo "" echo "🔍 Changed files:" - git diff --name-status HEAD~1 + git diff --name-status "$ORIGINAL_HEAD" echo "" echo "🔍 Package version changes:" - git diff HEAD~1 -- '**/package.json' | grep -E "^[+-]\s*\"version\"" || true + git diff "$ORIGINAL_HEAD" -- '**/package.json' | grep -E "^[+-]\s*\"version\"" || true # Clean up git checkout - diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index f4713c92..b1355aac 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -114,11 +114,22 @@ jobs: # Verify build outputs - name: Verify build outputs run: | - if [ ! -d "packages/react/dist" ] || [ ! -d "packages/angular/dist" ]; then - echo "❌ Build outputs not found!" + # Check all packages for dist directories + MISSING_BUILDS="" + for PKG_DIR in packages/*; do + if [ -d "$PKG_DIR" ] && [ -f "$PKG_DIR/package.json" ]; then + PKG_NAME=$(basename "$PKG_DIR") + if [ ! -d "$PKG_DIR/dist" ]; then + MISSING_BUILDS="$MISSING_BUILDS $PKG_NAME" + fi + fi + done + + if [ -n "$MISSING_BUILDS" ]; then + echo "❌ Build outputs not found for:$MISSING_BUILDS" exit 1 fi - echo "✅ Build outputs verified" + echo "✅ All build outputs verified" # Run tests with emulator for changed packages - name: Run tests with emulator From cb6346038e3e2d6dd3ebb3a6f2fd15c524048119 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Mon, 28 Jul 2025 11:59:57 +0100 Subject: [PATCH 4/5] ci: improve workflow reliability and fix formatting issues - Replace hardcoded package paths with dynamic discovery in build verification - Fix shell compatibility by avoiding command substitution in variable expansion - Use 1135430206 instead of 1753700397 for better portability - Save original HEAD reference before dry-run changes for accurate diffs - Fix spacing in error messages for better readability --- .github/workflows/release.yml | 5 +++-- .github/workflows/tests.yaml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7952a3bb..09d3de89 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -123,7 +123,7 @@ jobs: fi if [ -n "$MISSING_BUILDS" ]; then - echo "❌ Build outputs missing for:$MISSING_BUILDS" + echo "❌ Build outputs missing for: $MISSING_BUILDS" exit 1 fi @@ -178,7 +178,8 @@ jobs: # Save current HEAD reference before making changes ORIGINAL_HEAD=$(git rev-parse HEAD) # Create a temporary branch for dry run with unique name - TEMP_BRANCH="dry-run-temp-${GITHUB_RUN_ID:-$(date +%s)}" + FALLBACK_ID=${GITHUB_RUN_ID:-$RANDOM$RANDOM} + TEMP_BRANCH="dry-run-temp-$FALLBACK_ID" git checkout -b "$TEMP_BRANCH" pnpm changeset version diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index b1355aac..232e3f2c 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -126,7 +126,7 @@ jobs: done if [ -n "$MISSING_BUILDS" ]; then - echo "❌ Build outputs not found for:$MISSING_BUILDS" + echo "❌ Build outputs not found for: $MISSING_BUILDS" exit 1 fi echo "✅ All build outputs verified" From cc2bec9611599cad04d983061a7810866476a610 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Mon, 28 Jul 2025 12:14:45 +0100 Subject: [PATCH 5/5] ci: fix workflow consistency and dry-run git configuration - Make build verification consistent between workflows by using dynamic package discovery - Add git user configuration for dry-run to prevent changeset version errors - Remove hardcoded package paths in release.yml to match tests.yaml approach - Remove Node.js 18 from test matrix due to Firebase CLI v14 incompatibility --- .github/workflows/release.yml | 32 ++++++++++++++++++++------------ .github/workflows/tests.yaml | 6 ++---- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 09d3de89..9f64841e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -54,9 +54,7 @@ jobs: run: pnpm install - name: Run format check - # The --unsafe flag is required in CI to bypass interactive prompts - # that would otherwise cause the command to hang in automated environments - run: pnpm format --unsafe + run: pnpm format release: name: Release @@ -112,15 +110,16 @@ jobs: - name: Verify build outputs run: | echo "Checking build outputs..." + # Check all packages for dist directories MISSING_BUILDS="" - - if [ ! -d "packages/react/dist" ]; then - MISSING_BUILDS="$MISSING_BUILDS react" - fi - - if [ ! -d "packages/angular/dist" ]; then - MISSING_BUILDS="$MISSING_BUILDS angular" - fi + for PKG_DIR in packages/*; do + if [ -d "$PKG_DIR" ] && [ -f "$PKG_DIR/package.json" ]; then + PKG_NAME=$(basename "$PKG_DIR") + if [ ! -d "$PKG_DIR/dist" ]; then + MISSING_BUILDS="$MISSING_BUILDS $PKG_NAME" + fi + fi + done if [ -n "$MISSING_BUILDS" ]; then echo "❌ Build outputs missing for: $MISSING_BUILDS" @@ -175,6 +174,10 @@ jobs: done echo "📦 Version changes that would be applied:" + # Configure git user for changeset version command + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + # Save current HEAD reference before making changes ORIGINAL_HEAD=$(git rev-parse HEAD) # Create a temporary branch for dry run with unique name @@ -189,7 +192,12 @@ jobs: echo "" echo "🔍 Package version changes:" - git diff "$ORIGINAL_HEAD" -- '**/package.json' | grep -E "^[+-]\s*\"version\"" || true + VERSION_CHANGES=$(git diff "$ORIGINAL_HEAD" -- '**/package.json' | grep -E "^[+-]\s*\"version\"" || true) + if [ -z "$VERSION_CHANGES" ]; then + echo " No version changes detected (this might indicate an issue with changesets)" + else + echo "$VERSION_CHANGES" + fi # Clean up git checkout - diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 232e3f2c..05b713ef 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -47,9 +47,7 @@ jobs: run: pnpm install - name: Run format check - # The --unsafe flag is required in CI to bypass interactive prompts - # that would otherwise cause the command to hang in automated environments - run: pnpm format --unsafe + run: pnpm format test: runs-on: ubuntu-latest @@ -57,7 +55,7 @@ jobs: needs: quality strategy: matrix: - node-version: [18, 20, 22] + node-version: [20, 22] steps: - name: Checkout code uses: actions/checkout@v4