diff --git a/.github/workflows/ci-rerun.yml b/.github/workflows/ci-rerun.yml index de65c8312..3652ce909 100644 --- a/.github/workflows/ci-rerun.yml +++ b/.github/workflows/ci-rerun.yml @@ -21,6 +21,7 @@ permissions: jobs: test: runs-on: ubuntu-latest + timeout-minutes: 15 steps: - name: Fetch PR metadata id: pr @@ -65,6 +66,7 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 22 + cache: 'npm' - name: Fix stale lockfile entries run: | @@ -85,10 +87,36 @@ jobs: " - name: Install dependencies - run: npm install + run: | + success=false + for i in 1 2 3; do + if npm install; then + success=true + break + fi + echo "Retry $i/3 — npm install failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm install failed after 3 attempts" + exit 1 + fi - name: Install docs dependencies - run: npm ci + run: | + success=false + for i in 1 2 3; do + if npm ci; then + success=true + break + fi + echo "Retry $i/3 — npm ci failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm ci failed after 3 attempts" + exit 1 + fi working-directory: docs - name: Install Playwright browsers diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index 5be0c225c..773754e39 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -11,8 +11,40 @@ permissions: contents: read jobs: + # ── Path filter for conditional job execution ────────────────────────── + # Detects which areas of the repo changed so downstream jobs can skip + # when their inputs haven't changed (e.g., skip docs-quality on code-only PRs). + changes: + runs-on: ubuntu-latest + timeout-minutes: 3 + outputs: + docs: ${{ steps.filter.outputs.docs }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Detect changed paths + id: filter + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + BASE="${{ github.event.pull_request.base.sha }}" + HEAD="${{ github.event.pull_request.head.sha }}" + CHANGED=$(git diff --name-only "$BASE"..."$HEAD") + else + # On push, compare against parent commit + CHANGED=$(git diff --name-only HEAD~1...HEAD 2>/dev/null || echo "docs/") + fi + if echo "$CHANGED" | grep -qE '^(docs/|README\.md|\.markdownlint|\.cspell|cspell\.json)'; then + echo "docs=true" >> "$GITHUB_OUTPUT" + else + echo "docs=false" >> "$GITHUB_OUTPUT" + fi + docs-quality: + needs: changes + if: "!cancelled() && (github.event_name == 'push' || needs.changes.outputs.docs == 'true')" runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v4 @@ -21,7 +53,20 @@ jobs: node-version: 22 - name: Install docs tools - run: npm install --no-save markdownlint-cli2 cspell + run: | + success=false + for i in 1 2 3; do + if npm install --no-save markdownlint-cli2 cspell; then + success=true + break + fi + echo "Retry $i/3 — npm install failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm install failed after 3 attempts" + exit 1 + fi - name: Lint docs markdown run: npx markdownlint-cli2 @@ -31,12 +76,14 @@ jobs: test: runs-on: ubuntu-latest + timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 + cache: 'npm' - name: Fix stale lockfile entries run: | @@ -57,10 +104,36 @@ jobs: " - name: Install dependencies - run: npm install + run: | + success=false + for i in 1 2 3; do + if npm install; then + success=true + break + fi + echo "Retry $i/3 — npm install failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm install failed after 3 attempts" + exit 1 + fi - name: Install docs dependencies - run: npm ci + run: | + success=false + for i in 1 2 3; do + if npm ci; then + success=true + break + fi + echo "Retry $i/3 — npm ci failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm ci failed after 3 attempts" + exit 1 + fi working-directory: docs - name: Install Playwright browsers @@ -138,6 +211,7 @@ jobs: # ────────────────────────────────────────────────────────────────────── if: github.event_name == 'pull_request' runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v4 with: @@ -218,6 +292,7 @@ jobs: # ────────────────────────────────────────────────────────────────────── if: github.event_name == 'pull_request' runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v4 with: @@ -424,6 +499,7 @@ jobs: publish-policy: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v4 @@ -470,6 +546,7 @@ jobs: # ────────────────────────────────────────────────────────────────────── if: github.event_name == 'pull_request' runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v4 @@ -554,6 +631,7 @@ jobs: # ────────────────────────────────────────────────────────────────────── if: github.event_name == 'pull_request' runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v4 @@ -659,6 +737,7 @@ jobs: # ────────────────────────────────────────────────────────────────────── if: github.event_name == 'pull_request' runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/squad-insider-publish.yml b/.github/workflows/squad-insider-publish.yml index 05e86a6fe..1b6ffbc76 100644 --- a/.github/workflows/squad-insider-publish.yml +++ b/.github/workflows/squad-insider-publish.yml @@ -11,6 +11,7 @@ permissions: jobs: build: runs-on: ubuntu-latest + timeout-minutes: 10 strategy: matrix: node-version: [20] @@ -20,9 +21,23 @@ jobs: - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} + cache: 'npm' - name: Install dependencies - run: npm ci + run: | + success=false + for i in 1 2 3; do + if npm ci; then + success=true + break + fi + echo "Retry $i/3 — npm ci failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm ci failed after 3 attempts" + exit 1 + fi - name: Build run: npm run build @@ -30,6 +45,7 @@ jobs: test: needs: build runs-on: ubuntu-latest + timeout-minutes: 15 strategy: matrix: node-version: [20] @@ -39,9 +55,23 @@ jobs: - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} + cache: 'npm' - name: Install dependencies - run: npm ci + run: | + success=false + for i in 1 2 3; do + if npm ci; then + success=true + break + fi + echo "Retry $i/3 — npm ci failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm ci failed after 3 attempts" + exit 1 + fi - name: Run tests run: npm test @@ -49,6 +79,7 @@ jobs: publish: needs: test runs-on: ubuntu-latest + timeout-minutes: 10 strategy: matrix: node-version: [20] @@ -59,9 +90,33 @@ jobs: with: node-version: ${{ matrix.node-version }} registry-url: 'https://registry.npmjs.org' + cache: 'npm' + + - name: Validate npm token + run: | + if [ -z "$NODE_AUTH_TOKEN" ]; then + echo "::error::NPM_TOKEN secret is not configured — publish will fail" + exit 1 + fi + echo "✅ NPM_TOKEN is set" + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Install dependencies - run: npm ci + run: | + success=false + for i in 1 2 3; do + if npm ci; then + success=true + break + fi + echo "Retry $i/3 — npm ci failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm ci failed after 3 attempts" + exit 1 + fi - name: Build packages run: npm -w packages/squad-sdk run build && npm -w packages/squad-cli run build diff --git a/.github/workflows/squad-npm-publish.yml b/.github/workflows/squad-npm-publish.yml index 876f3bb09..14b353235 100644 --- a/.github/workflows/squad-npm-publish.yml +++ b/.github/workflows/squad-npm-publish.yml @@ -15,6 +15,7 @@ jobs: preflight: name: Pre-publish dependency validation runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v4 with: @@ -77,6 +78,7 @@ jobs: name: CLI packaging smoke test needs: preflight runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v4 with: @@ -84,8 +86,22 @@ jobs: - uses: actions/setup-node@v4 with: node-version: 22 + cache: 'npm' - name: Install dependencies - run: npm ci + run: | + success=false + for i in 1 2 3; do + if npm ci; then + success=true + break + fi + echo "Retry $i/3 — npm ci failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm ci failed after 3 attempts" + exit 1 + fi - name: Build run: npm run build env: @@ -102,6 +118,7 @@ jobs: name: Publish @bradygaster/squad-sdk needs: [preflight, smoke-test] runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v4 with: @@ -110,6 +127,16 @@ jobs: with: node-version: 22 registry-url: 'https://registry.npmjs.org' + cache: 'npm' + - name: Validate npm token + run: | + if [ -z "$NODE_AUTH_TOKEN" ]; then + echo "::error::NPM_TOKEN secret is not configured — publish will fail" + exit 1 + fi + echo "✅ NPM_TOKEN is set" + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Determine version id: version run: | @@ -122,7 +149,20 @@ jobs: echo "version=${VERSION}" >> "$GITHUB_OUTPUT" echo "Publishing version: ${VERSION}" - name: Install dependencies - run: npm ci + run: | + success=false + for i in 1 2 3; do + if npm ci; then + success=true + break + fi + echo "Retry $i/3 — npm ci failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm ci failed after 3 attempts" + exit 1 + fi - name: Build squad-sdk run: npm -w packages/squad-sdk run build - name: Verify package version matches target @@ -152,6 +192,7 @@ jobs: name: Publish @bradygaster/squad-cli needs: [preflight, smoke-test, publish-sdk] runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v4 with: @@ -160,6 +201,16 @@ jobs: with: node-version: 22 registry-url: 'https://registry.npmjs.org' + cache: 'npm' + - name: Validate npm token + run: | + if [ -z "$NODE_AUTH_TOKEN" ]; then + echo "::error::NPM_TOKEN secret is not configured — publish will fail" + exit 1 + fi + echo "✅ NPM_TOKEN is set" + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Determine version id: version run: | @@ -172,7 +223,20 @@ jobs: echo "version=${VERSION}" >> "$GITHUB_OUTPUT" echo "Publishing version: ${VERSION}" - name: Install dependencies - run: npm ci + run: | + success=false + for i in 1 2 3; do + if npm ci; then + success=true + break + fi + echo "Retry $i/3 — npm ci failed, retrying in 5s..." + sleep 5 + done + if [ "$success" = false ]; then + echo "::error::npm ci failed after 3 attempts" + exit 1 + fi - name: "Guard against file: dependencies" run: | SDK_DEP=$(node -p "require('./packages/squad-cli/package.json').dependencies['@bradygaster/squad-sdk']")