singularity-forge/.github/workflows/pipeline.yml
TÂCHES 6eccae3b4b fix(ci): skip publish when version already exists on npm (#1166)
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>
2026-03-18 09:26:38 -06:00

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