Multiple CI completions on the same commit trigger duplicate Pipeline runs. The second run fails with E403 because the version was already published. Fix by checking npm registry before attempting publish, and enable cancel-in-progress to avoid redundant runs. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
199 lines
6 KiB
YAML
199 lines
6 KiB
YAML
name: Pipeline
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows: ["CI"]
|
|
types: [completed]
|
|
branches: [main]
|
|
|
|
concurrency:
|
|
group: pipeline-${{ github.sha }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: write
|
|
packages: write
|
|
|
|
jobs:
|
|
dev-publish:
|
|
name: Dev Publish
|
|
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: ghcr.io/gsd-build/gsd-ci-builder:latest
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
outputs:
|
|
dev-version: ${{ steps.stamp.outputs.version }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Mark workspace safe for git
|
|
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 22
|
|
registry-url: https://registry.npmjs.org
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Build
|
|
run: npm run build
|
|
|
|
- name: Stamp dev version and sync platform packages
|
|
id: stamp
|
|
run: |
|
|
npm run pipeline:version-stamp
|
|
npm run sync-platform-versions
|
|
echo "version=$(node -e 'process.stdout.write(require("./package.json").version)')" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Publish @dev
|
|
run: |
|
|
VERSION=$(node -e 'process.stdout.write(require("./package.json").version)')
|
|
if npm view "gsd-pi@${VERSION}" version 2>/dev/null; then
|
|
echo "Version ${VERSION} already published — skipping"
|
|
else
|
|
npm publish --tag dev
|
|
fi
|
|
env:
|
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
|
|
- name: Smoke test (local)
|
|
run: |
|
|
chmod +x dist/loader.js
|
|
export GSD_SMOKE_BINARY="$(pwd)/dist/loader.js"
|
|
npm run test:smoke
|
|
|
|
test-verify:
|
|
name: Test & Verify
|
|
needs: dev-publish
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 22
|
|
registry-url: https://registry.npmjs.org
|
|
|
|
- name: Install gsd-pi@dev globally
|
|
run: npm install -g gsd-pi@dev
|
|
|
|
- name: Run smoke tests (against installed binary)
|
|
run: |
|
|
export GSD_SMOKE_BINARY=$(which gsd)
|
|
npm run test:smoke
|
|
env:
|
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Run fixture tests
|
|
run: npm run test:fixtures
|
|
|
|
- name: Promote to @next
|
|
run: npm dist-tag add gsd-pi@${{ needs.dev-publish.outputs.dev-version }} next
|
|
env:
|
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
|
|
- name: Log in to GHCR
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Build and push runtime Docker image
|
|
run: |
|
|
docker build --target runtime \
|
|
-t ghcr.io/gsd-build/gsd-pi:next \
|
|
-t ghcr.io/gsd-build/gsd-pi:${{ needs.dev-publish.outputs.dev-version }} \
|
|
.
|
|
docker push ghcr.io/gsd-build/gsd-pi:next
|
|
docker push ghcr.io/gsd-build/gsd-pi:${{ needs.dev-publish.outputs.dev-version }}
|
|
|
|
prod-release:
|
|
name: Production Release
|
|
needs: [dev-publish, test-verify]
|
|
runs-on: ubuntu-latest
|
|
environment: prod
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 22
|
|
registry-url: https://registry.npmjs.org
|
|
|
|
- name: Run live LLM tests (optional)
|
|
continue-on-error: true
|
|
run: npm run test:live
|
|
env:
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
GSD_LIVE_TESTS: "1"
|
|
|
|
- name: Promote to @latest
|
|
run: npm dist-tag add gsd-pi@${{ needs.dev-publish.outputs.dev-version }} latest
|
|
env:
|
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
|
|
- name: Log in to GHCR
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Tag runtime Docker image as latest
|
|
run: |
|
|
docker pull ghcr.io/gsd-build/gsd-pi:${{ needs.dev-publish.outputs.dev-version }}
|
|
docker tag ghcr.io/gsd-build/gsd-pi:${{ needs.dev-publish.outputs.dev-version }} ghcr.io/gsd-build/gsd-pi:latest
|
|
docker push ghcr.io/gsd-build/gsd-pi:latest
|
|
|
|
- name: Extract base version
|
|
id: base-version
|
|
run: |
|
|
echo "version=$(echo '${{ needs.dev-publish.outputs.dev-version }}' | sed 's/-dev\..*//')" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Create GitHub Release
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
gh release create "v${{ steps.base-version.outputs.version }}" \
|
|
--title "v${{ steps.base-version.outputs.version }}" \
|
|
--generate-notes \
|
|
--latest
|
|
|
|
update-builder:
|
|
name: Update CI Builder Image
|
|
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Check for Dockerfile changes
|
|
id: check
|
|
run: |
|
|
CHANGED=$(git diff --name-only ${{ github.event.workflow_run.head_sha }}~1 ${{ github.event.workflow_run.head_sha }} -- Dockerfile || echo "")
|
|
echo "changed=$([[ -n \"$CHANGED\" ]] && echo 'true' || echo 'false')" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Log in to GHCR
|
|
if: steps.check.outputs.changed == 'true'
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Build and push CI builder image
|
|
if: steps.check.outputs.changed == 'true'
|
|
run: |
|
|
docker build --target builder \
|
|
-t ghcr.io/gsd-build/gsd-ci-builder:latest \
|
|
.
|
|
docker push ghcr.io/gsd-build/gsd-ci-builder:latest
|