Repository navigation
122 lines (108 loc) · 4.97 KB
/
Copy pathruvector-publish.yml
File metadata and controls
122 lines (108 loc) · 4.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
name: Publish ruvector to npm
# Publishes the `ruvector` npm package. Triggered manually (workflow_dispatch)
# or by pushing a `ruvector-v*` tag. Gated: builds, verifies the dist layout,
# runs the full test suite, and refuses to publish a version that already
# exists on npm (out-of-band publishes of 0.2.27-0.2.29 happened without tags —
# this guard prevents silent clobber/no-op, see issue #523 follow-up).
on:
workflow_dispatch:
inputs:
version:
description: 'Version to publish (must match package.json, e.g. 0.2.30)'
required: true
type: string
dry_run:
description: 'If true, run all gates + npm publish --dry-run only'
required: false
default: false
type: boolean
push:
tags:
- 'ruvector-v*'
permissions:
contents: read
id-token: write
jobs:
publish:
runs-on: ubuntu-latest
defaults:
run:
working-directory: npm/packages/ruvector
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci --no-workspaces || npm install --no-workspaces
- name: Build
run: npm run build
- name: Verify dist layout
run: npm run verify-dist
- name: Test (integration + CLI + contract + pool)
run: |
npm test
node --test tests/*.test.mjs
- name: Version guard (refuse to clobber a published version)
run: |
LOCAL=$(node -p "require('./package.json').version")
echo "Local version: $LOCAL"
if npm view "ruvector@$LOCAL" version >/dev/null 2>&1; then
# A dry run only exercises the pipeline (incl. the GCP token fetch).
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
echo "::warning::ruvector@$LOCAL is already published; continuing because this is a dry run."
else
echo "::error::ruvector@$LOCAL is already published on npm. Bump the version first."
exit 1
fi
fi
# If dispatched with an explicit version, it must match package.json.
INPUT="${{ github.event.inputs.version }}"
if [ -n "$INPUT" ] && [ "$INPUT" != "$LOCAL" ]; then
echo "::error::Input version ($INPUT) != package.json ($LOCAL)."
exit 1
fi
# The npm token is read from GCP Secret Manager (cognitum-20260110/NPM_TOKEN),
# the canonical copy, instead of a GitHub secret that kept drifting from it.
# The WIF provider only admits this workflow file on main or a ruvector-v* tag.
- name: Authenticate to GCP
id: gcp
uses: google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed
with:
workload_identity_provider: projects/186366152200/locations/global/workloadIdentityPools/github-ruvector-publish/providers/github
service_account: ruvector-npm-publisher@cognitum-20260110.iam.gserviceaccount.com
token_format: access_token
- name: Fetch npm token from GCP Secret Manager
env:
ACCESS_TOKEN: ${{ steps.gcp.outputs.access_token }}
run: |
TOKEN=$(curl -fsS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"https://secretmanager.googleapis.com/v1/projects/cognitum-20260110/secrets/NPM_TOKEN/versions/latest:access" \
| node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>process.stdout.write(Buffer.from(JSON.parse(s).payload.data,'base64').toString().trim()))")
if [ -z "$TOKEN" ]; then echo "::error::empty NPM_TOKEN from Secret Manager"; exit 1; fi
echo "::add-mask::$TOKEN"
# GITHUB_ENV only reaches later steps, so pass the token explicitly here.
NPM_USER=$(NODE_AUTH_TOKEN="$TOKEN" npm whoami) || { echo "::error::npm rejected the NPM_TOKEN from Secret Manager"; exit 1; }
echo "npm user: $NPM_USER"
echo "NODE_AUTH_TOKEN=$TOKEN" >> "$GITHUB_ENV"
- name: Publish (dry-run)
if: ${{ github.event.inputs.dry_run == 'true' }}
run: npm publish --access public --dry-run
- name: Publish
if: ${{ github.event.inputs.dry_run != 'true' }}
run: npm publish --access public
- name: Verify on the registry
if: ${{ github.event.inputs.dry_run != 'true' }}
run: |
# #1007: the job's conclusion must mean "it is on the registry".
VERSION=$(node -p "require('./package.json').version")
for i in $(seq 1 72); do
if npm view "ruvector@${VERSION}" version >/dev/null 2>&1; then
echo "verified ruvector@${VERSION}"; exit 0
fi
echo "waiting for ruvector@${VERSION} to propagate (attempt ${i}/72)..."
sleep 10
done
echo "::error::ruvector@${VERSION} is not resolvable on npm"
exit 1