From 08820211f1a8def728f2df1443f959012eb34f45 Mon Sep 17 00:00:00 2001 From: "Dina Berry (MSFT)" Date: Sat, 28 Mar 2026 18:49:50 -0700 Subject: [PATCH 1/5] feat(ci): add samples build validation gate (#111) Closes #103 Adds samples-build CI job that validates all 11 samples compile when SDK changes. - Loops samples/ directories with npm install/build/test - Feature-flagged via skip-samples-build label - 15-minute timeout, --ignore-scripts, npm cache - Accepted Copilot suggestions: cache-dependency-path, workspace root install Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/squad-ci.yml | 130 +++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index 910830866..983e1c4cb 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -213,6 +213,136 @@ jobs: if: steps.flag.outputs.skip == 'false' && !contains(github.event.pull_request.labels.*.name, 'skip-exports-check') && steps.changes.outputs.skip != 'true' run: node scripts/check-exports-map.mjs + samples-build: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: 'npm' + cache-dependency-path: | + package-lock.json + samples/**/package-lock.json + + - name: Check feature flag + id: flag + # Default: gate is ENABLED. Set vars.SQUAD_SAMPLES_CI to "false" + # to explicitly disable. + run: | + if [ "${{ vars.SQUAD_SAMPLES_CI }}" = "false" ]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Samples build gate disabled via vars.SQUAD_SAMPLES_CI" + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + + - name: Check skip label + if: steps.flag.outputs.skip == 'false' + id: label + run: | + SKIP="false" + LABELS='${{ toJSON(github.event.pull_request.labels.*.name) }}' + if echo "$LABELS" | grep -q "skip-samples-ci"; then + SKIP="true" + echo "Skipping samples build gate (skip-samples-ci label present)" + fi + echo "skip=$SKIP" >> "$GITHUB_OUTPUT" + + - name: Check for SDK source changes + if: steps.flag.outputs.skip == 'false' && steps.label.outputs.skip != 'true' + id: changes + run: | + BASE="${{ github.event.pull_request.base.sha }}" + HEAD="${{ github.event.pull_request.head.sha }}" + SDK_CHANGED=$(git diff --name-only "$BASE"..."$HEAD" | grep -E '^packages/squad-sdk/src/' || true) + if [ -z "$SDK_CHANGED" ]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "No SDK source changes detected -- samples build not applicable" + else + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "SDK source files changed:" + echo "$SDK_CHANGED" + fi + + - name: Install root dependencies and build SDK + if: steps.flag.outputs.skip == 'false' && steps.label.outputs.skip != 'true' && steps.changes.outputs.skip != 'true' + run: | + npm ci --ignore-scripts + npm run build -w packages/squad-sdk + + - name: Build and test samples + if: steps.flag.outputs.skip == 'false' && steps.label.outputs.skip != 'true' && steps.changes.outputs.skip != 'true' + run: | + FAILED=0 + PASSED=0 + SKIPPED=0 + + for sample_dir in samples/*/; do + sample=$(basename "$sample_dir") + + if [ ! -f "$sample_dir/package.json" ]; then + echo "::notice::[$sample] No package.json -- skipping" + SKIPPED=$((SKIPPED + 1)) + continue + fi + + HAS_BUILD=$(node -e "const p=require('./$sample_dir/package.json'); process.exit(p.scripts?.build ? 0 : 1)" 2>/dev/null && echo "true" || echo "false") + HAS_TEST=$(node -e "const p=require('./$sample_dir/package.json'); process.exit(p.scripts?.test ? 0 : 1)" 2>/dev/null && echo "true" || echo "false") + + if [ "$HAS_BUILD" = "false" ] && [ "$HAS_TEST" = "false" ]; then + echo "::notice::[$sample] No build or test scripts -- skipping" + SKIPPED=$((SKIPPED + 1)) + continue + fi + + echo "" + echo "=========================================" + echo "[$sample] Installing dependencies..." + echo "=========================================" + if ! (cd "$sample_dir" && npm install --ignore-scripts 2>&1); then + echo "::error::[$sample] npm install failed" + FAILED=$((FAILED + 1)) + continue + fi + + if [ "$HAS_BUILD" = "true" ]; then + echo "[$sample] Running build..." + if ! (cd "$sample_dir" && npm run build 2>&1); then + echo "::error::[$sample] npm run build failed" + FAILED=$((FAILED + 1)) + continue + fi + fi + + if [ "$HAS_TEST" = "true" ]; then + echo "[$sample] Running tests..." + if ! (cd "$sample_dir" && npm test 2>&1); then + echo "::error::[$sample] npm test failed" + FAILED=$((FAILED + 1)) + continue + fi + fi + + echo "::notice::[$sample] Passed" + PASSED=$((PASSED + 1)) + done + + echo "" + echo "=========================================" + echo "Samples build summary: $PASSED passed, $FAILED failed, $SKIPPED skipped" + echo "=========================================" + + if [ "$FAILED" -gt 0 ]; then + echo "::error::$FAILED sample(s) failed build/test validation" + exit 1 + fi + publish-policy: runs-on: ubuntu-latest steps: From e4226de70c1db351be6cc18514776e7162c4c12a Mon Sep 17 00:00:00 2001 From: "Dina Berry (MSFT)" Date: Sat, 28 Mar 2026 19:03:47 -0700 Subject: [PATCH 2/5] Update .github/workflows/squad-ci.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/squad-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index 983e1c4cb..37c1c272b 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -190,6 +190,7 @@ jobs: echo "skip=false" >> "$GITHUB_OUTPUT" fi + - name: Check for SDK source changes if: steps.flag.outputs.skip == 'false' && !contains(github.event.pull_request.labels.*.name, 'skip-exports-check') id: changes From 4730c5a32ca84c718024de229fda56c83441e7f9 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 19:12:32 -0700 Subject: [PATCH 3/5] fix: scope PR to samples-build gate only Remove changelog-gate and exports-map-check from this PR's diff. Those gates are in PR #673. This PR should only add samples-build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/squad-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index 37c1c272b..983e1c4cb 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -190,7 +190,6 @@ jobs: echo "skip=false" >> "$GITHUB_OUTPUT" fi - - name: Check for SDK source changes if: steps.flag.outputs.skip == 'false' && !contains(github.event.pull_request.labels.*.name, 'skip-exports-check') id: changes From 46f626cd6d1a2743a9c1dc14022d85df69b2c4aa Mon Sep 17 00:00:00 2001 From: "Dina Berry (MSFT)" Date: Sat, 28 Mar 2026 19:17:14 -0700 Subject: [PATCH 4/5] Update .github/workflows/squad-ci.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/squad-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index 983e1c4cb..29c4e3358 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -305,7 +305,7 @@ jobs: echo "=========================================" echo "[$sample] Installing dependencies..." echo "=========================================" - if ! (cd "$sample_dir" && npm install --ignore-scripts 2>&1); then + if ! (cd "$sample_dir" && if [ -f package-lock.json ]; then npm ci; else npm install; fi 2>&1); then echo "::error::[$sample] npm install failed" FAILED=$((FAILED + 1)) continue From d6c8d7cfb1c7976a8df778f6c29d09afbd144ce9 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 19:20:57 -0700 Subject: [PATCH 5/5] fix: patch npm-registry samples to use local SDK in CI Copilot review found that samples using @bradygaster/squad-sdk from npm registry (autonomous-pipeline, cost-aware-router) were not validated against the PR's SDK changes. This step rewrites their package.json to use file:../../packages/squad-sdk before running builds and tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/squad-ci.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index 29c4e3358..1ba27e56a 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -276,6 +276,27 @@ jobs: npm ci --ignore-scripts npm run build -w packages/squad-sdk + - name: Patch npm-registry samples to use local SDK + if: steps.flag.outputs.skip == 'false' && steps.label.outputs.skip != 'true' && steps.changes.outputs.skip != 'true' + shell: bash + run: | + for pkg in samples/*/package.json; do + if grep -q '"@bradygaster/squad-sdk"' "$pkg" && ! grep -q 'file:' "$pkg"; then + node -e " + const fs = require('fs'); + const p = JSON.parse(fs.readFileSync('$pkg', 'utf8')); + if (p.dependencies?.['@bradygaster/squad-sdk']) { + p.dependencies['@bradygaster/squad-sdk'] = 'file:../../packages/squad-sdk'; + } + if (p.devDependencies?.['@bradygaster/squad-sdk']) { + p.devDependencies['@bradygaster/squad-sdk'] = 'file:../../packages/squad-sdk'; + } + fs.writeFileSync('$pkg', JSON.stringify(p, null, 2) + '\n'); + " + echo "Patched $pkg to use local SDK" + fi + done + - name: Build and test samples if: steps.flag.outputs.skip == 'false' && steps.label.outputs.skip != 'true' && steps.changes.outputs.skip != 'true' run: |