Release to npm #36
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release to npm | |
| on: | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to publish (e.g., 0.8.6). If not provided, uses git tag.' | |
| required: false | |
| type: string | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| with: | |
| submodules: recursive | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| registry-url: 'https://registry.npmjs.org' | |
| - name: Set version from tag or input | |
| run: | | |
| # Check if version was provided via workflow_dispatch input | |
| if [[ -n "${{ inputs.version }}" ]]; then | |
| INPUT_VERSION="${{ inputs.version }}" | |
| # Remove 'v' prefix if present | |
| VERSION=${INPUT_VERSION#v} | |
| echo "Using version from workflow input: $VERSION" | |
| elif [[ "$GITHUB_REF" == refs/tags/* ]]; then | |
| TAG_VERSION=${GITHUB_REF#refs/tags/} | |
| # Remove 'v' prefix if present | |
| VERSION=${TAG_VERSION#v} | |
| echo "Using version from git tag: $VERSION" | |
| else | |
| echo "No version provided and not building from a tag, using default version" | |
| VERSION="0.0.0" | |
| fi | |
| echo "Setting version to: $VERSION" | |
| npm --no-git-tag-version version "$VERSION" || exit 1 | |
| echo "PACKAGE_VERSION=$VERSION" >> $GITHUB_ENV | |
| - name: Build | |
| run: | | |
| echo "Publishing version: $PACKAGE_VERSION" | |
| cat package.json | grep -A2 '"name"' | |
| npm ci | |
| npm run codegen | |
| npm run build:release | |
| - name: Get NPM token via OIDC | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const https = require('https'); | |
| const fs = require('fs'); | |
| // Get OIDC token from GitHub | |
| console.log('Getting OIDC token from GitHub...'); | |
| const token = await core.getIDToken('https://registry.npmjs.org'); | |
| console.log('Successfully got OIDC token'); | |
| // Exchange it with NPM | |
| console.log('Exchanging OIDC token for NPM access token...'); | |
| return new Promise((resolve, reject) => { | |
| const postData = JSON.stringify({}); | |
| const options = { | |
| hostname: 'registry.npmjs.org', | |
| path: '/-/npm/v1/security/oidc/token', | |
| method: 'POST', | |
| headers: { | |
| 'Authorization': `Bearer ${token}`, | |
| 'Content-Type': 'application/json', | |
| 'Content-Length': Buffer.byteLength(postData) | |
| } | |
| }; | |
| const req = https.request(options, (res) => { | |
| let body = ''; | |
| res.on('data', chunk => body += chunk); | |
| res.on('end', () => { | |
| try { | |
| const data = JSON.parse(body); | |
| if (res.statusCode !== 200) { | |
| console.log('NPM returned status:', res.statusCode); | |
| console.log('Response:', body); | |
| throw new Error(`NPM returned ${res.statusCode}`); | |
| } | |
| if (!data.token) { | |
| throw new Error('No token in NPM response'); | |
| } | |
| console.log('Got NPM token, updating .npmrc'); | |
| const npmrcPath = `${process.env.HOME}/.npmrc`; | |
| let npmrc = fs.readFileSync(npmrcPath, 'utf8'); | |
| npmrc += `\n//registry.npmjs.org/:_authToken=${data.token}\n`; | |
| fs.writeFileSync(npmrcPath, npmrc); | |
| console.log('Updated .npmrc with auth token'); | |
| resolve(); | |
| } catch (err) { | |
| reject(err); | |
| } | |
| }); | |
| }); | |
| req.on('error', reject); | |
| req.write(postData); | |
| req.end(); | |
| }); | |
| - name: Publish to NPM | |
| run: npm publish --provenance --access public |