fix(ci): address 5 pipeline integrity issues from release audit (#4119)

- version-stamp.mjs: regenerate package-lock.json after dev version stamp
  (mirrors the same fix applied to bump-version.mjs in #4116)

- bump-version.mjs: regenerate root and web/package-lock.json after version
  bump so both lockfiles are always in sync at release time

- pipeline.yml: add post-bump validation step that verifies all package.json
  files parse as valid JSON before the release commit is made

- pipeline.yml: split "Commit, tag, and push" — commit+tag+rebase happen
  before build, but git push is deferred until after build and npm publish
  both succeed, preventing a broken tag from landing on main

- pipeline.yml: emit a :⚠️: annotation when live LLM tests fail so
  failures are visible in the Actions UI instead of silently swallowed

Closes #4118

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher 2026-04-13 08:56:12 -04:00 committed by GitHub
parent 202a1cb11e
commit a75167fab2
3 changed files with 38 additions and 10 deletions

View file

@ -177,7 +177,7 @@ jobs:
- name: Run live LLM tests (optional)
continue-on-error: true
run: npm run test:live
run: npm run test:live || echo "::warning::Live LLM tests failed — non-blocking, but worth investigating"
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
@ -197,21 +197,26 @@ jobs:
RELEASE_VERSION: ${{ steps.release.outputs.version }}
run: node scripts/bump-version.mjs "$RELEASE_VERSION"
- name: Validate package files after version bump
run: |
node -e "require('./package.json')" && \
node -e "require('./packages/pi-coding-agent/package.json')" && \
node -e "require('./pkg/package.json')" && \
echo "All package.json files are valid"
- name: Update CHANGELOG.md
run: node scripts/update-changelog.mjs /tmp/changelog-entry.md
- name: Commit, tag, and push
- name: Commit and tag release
env:
RELEASE_VERSION: ${{ steps.release.outputs.version }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add package.json package-lock.json CHANGELOG.md native/npm/*/package.json pkg/package.json packages/pi-coding-agent/package.json
git add package.json package-lock.json web/package-lock.json CHANGELOG.md native/npm/*/package.json pkg/package.json packages/pi-coding-agent/package.json
git commit -m "release: v${RELEASE_VERSION}"
git tag "v${RELEASE_VERSION}"
git pull --rebase origin main
git push origin main
git push origin "v${RELEASE_VERSION}"
- name: Build release
run: npm run build
@ -231,6 +236,13 @@ jobs:
fi
}
- name: Push release commit and tag
env:
RELEASE_VERSION: ${{ steps.release.outputs.version }}
run: |
git push origin main
git push origin "v${RELEASE_VERSION}"
- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -3,7 +3,7 @@
* Bump version in package.json, then sync platform packages and pkg/package.json.
* Usage: node scripts/bump-version.mjs <new-version>
*/
import { readFileSync, writeFileSync } from "fs";
import { readFileSync, writeFileSync, existsSync } from "fs";
import { resolve, dirname } from "path";
import { execSync } from "child_process";
import { fileURLToPath } from "url";
@ -38,7 +38,14 @@ execSync("node native/scripts/sync-platform-versions.cjs", { cwd: root, stdio: "
// 4. Sync pkg/package.json (reads from pi-coding-agent)
execSync("node scripts/sync-pkg-version.cjs", { cwd: root, stdio: "inherit" });
// 5. Regenerate package-lock.json to match the new version.
// 5. Regenerate root package-lock.json to match the new version.
// --package-lock-only updates the lockfile in-place without touching node_modules.
execSync("npm install --package-lock-only", { cwd: root, stdio: "inherit" });
execSync("npm install --package-lock-only --ignore-scripts", { cwd: root, stdio: "inherit" });
console.log(`[bump-version] package-lock.json regenerated at ${newVersion}`);
// 6. Regenerate web/package-lock.json if the web app is present.
const webDir = resolve(root, "web");
if (existsSync(webDir)) {
execSync("npm install --package-lock-only --ignore-scripts", { cwd: webDir, stdio: "inherit" });
console.log(`[bump-version] web/package-lock.json regenerated`);
}

View file

@ -1,5 +1,10 @@
import { readFileSync, writeFileSync } from "fs";
import { execFileSync } from "child_process";
import { execFileSync, execSync } from "child_process";
import { fileURLToPath } from "url";
import { dirname, resolve } from "path";
const __dirname = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dirname, "..");
const pkgPath = new URL("../package.json", import.meta.url);
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
@ -9,5 +14,9 @@ const devVersion = `${pkg.version}-dev.${shortSha}`;
pkg.version = devVersion;
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
console.log(`Stamped version: ${devVersion}`);
// Regenerate package-lock.json to reflect the stamped dev version.
// --package-lock-only updates the lockfile in-place without touching node_modules.
execSync("npm install --package-lock-only --ignore-scripts", { cwd: root, stdio: "inherit" });
console.log(`[version-stamp] package-lock.json regenerated at ${devVersion}`);