ReMe/.github/workflows/_release-npm-plugin.yml
jinliyl 9ad3dafce5
Some checks failed
CI / DSH plugin / Validate DSH plugin (push) Has been cancelled
CI / OpenClaw plugin / Validate OpenClaw plugin (push) Has been cancelled
CI / Python packages / Build and verify distributions (push) Has been cancelled
CI / Python quality / GitHub Actions (push) Has been cancelled
CI / Python quality / Pre-commit (push) Has been cancelled
CI / Python tests / Unit Tests - py3.11 (push) Has been cancelled
CI / Python tests / Unit Tests - py3.12 (push) Has been cancelled
CI / Python tests / Unit Tests - py3.13 (push) Has been cancelled
CI / Python tests / Unit Tests - py3.14 (push) Has been cancelled
CI / ReMe Studio / Studio checks (push) Has been cancelled
CI / Windows / CLI smoke - py3.11 (push) Has been cancelled
Deploy / Documentation / Build documentation (push) Has been cancelled
Security / CodeQL / Analyze javascript-typescript (push) Has been cancelled
Security / CodeQL / Analyze python (push) Has been cancelled
Deploy / Documentation / deploy (push) Has been cancelled
chore(ci): harden and split workflows (#539)
* chore(ci): harden and split workflows

* fix(ci): support token-based npm publishing

* test: make disappearing resource check portable

* fix(ci): make Studio releases recoverable

* fix(ci): stop Studio publishing on cancellation
2026-09-11 18:21:49 +08:00

155 lines
5.4 KiB
YAML

name: _Release npm plugin
on:
workflow_call:
inputs:
directory:
description: Repository-relative package directory
required: true
type: string
package_name:
description: Exact public npm package name
required: true
type: string
artifact_name:
description: Prefix for the packed package artifact
required: true
type: string
version:
description: Exact package.json version; an optional v prefix is accepted
required: true
type: string
npm_tag:
description: npm distribution tag
required: true
type: string
use_npm_token:
description: Use the npm environment NPM_TOKEN instead of Trusted Publishing
required: false
default: false
type: boolean
validate_clawhub:
description: Validate the package against the ClawHub contract
required: false
default: false
type: boolean
outputs:
version:
description: Normalized package version
value: ${{ jobs.build.outputs.version }}
secrets:
NPM_TOKEN:
description: Optional bootstrap or recovery token for npm publishing
required: false
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
outputs:
version: ${{ steps.validate.outputs.version }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24.16.0"
cache: npm
cache-dependency-path: ${{ inputs.directory }}/package-lock.json
- name: Validate package identity and version
id: validate
working-directory: ${{ inputs.directory }}
env:
EXPECTED_NAME: ${{ inputs.package_name }}
RELEASE_VERSION: ${{ inputs.version }}
NPM_TAG: ${{ inputs.npm_tag }}
run: |
node --input-type=module <<'JS'
import { appendFileSync, readFileSync } from 'node:fs';
const manifest = JSON.parse(readFileSync('package.json', 'utf8'));
const expected = process.env.RELEASE_VERSION.replace(/^v/, '');
if (manifest.name !== process.env.EXPECTED_NAME) {
throw new Error(`Expected ${process.env.EXPECTED_NAME}, found ${manifest.name}`);
}
if (manifest.version !== expected) throw new Error(`package.json is ${manifest.version}, workflow input is ${expected}`);
if (manifest.version.includes('-') !== (process.env.NPM_TAG === 'next')) {
throw new Error('Prereleases must use next; stable releases must use latest');
}
appendFileSync(process.env.GITHUB_OUTPUT, `version=${manifest.version}\n`);
JS
- run: npm ci
working-directory: ${{ inputs.directory }}
- name: Validate package
working-directory: ${{ inputs.directory }}
run: |
npm run format:check
npm run lint
npm run typecheck
npm test
npm run test:package
- name: Validate ClawHub contract
if: inputs.validate_clawhub
working-directory: ${{ inputs.directory }}
run: npx --yes clawhub@0.23.3 package validate . --json
- name: Pack
working-directory: ${{ inputs.directory }}
run: |
mkdir -p "$RUNNER_TEMP/plugin-package"
npm pack --pack-destination "$RUNNER_TEMP/plugin-package"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ inputs.artifact_name }}-${{ steps.validate.outputs.version }}
path: ${{ runner.temp }}/plugin-package/*.tgz
if-no-files-found: error
publish:
if: github.ref == 'refs/heads/main'
needs: build
runs-on: ubuntu-latest
timeout-minutes: 10
environment: npm
permissions:
contents: read
id-token: write
steps:
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
registry-url: https://registry.npmjs.org
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ inputs.artifact_name }}-${{ needs.build.outputs.version }}
path: dist/plugin
- name: Reject an existing package version
env:
PACKAGE_NAME: ${{ inputs.package_name }}
PACKAGE_VERSION: ${{ needs.build.outputs.version }}
run: |
if npm view "${PACKAGE_NAME}@${PACKAGE_VERSION}" version >/dev/null 2>&1; then
echo "${PACKAGE_NAME}@${PACKAGE_VERSION} already exists" >&2
exit 1
fi
- name: Publish to npm with Trusted Publishing
if: ${{ !inputs.use_npm_token }}
env:
NPM_TAG: ${{ inputs.npm_tag }}
run: npm publish dist/plugin/*.tgz --access public --tag "$NPM_TAG" --provenance
- name: Publish to npm with NPM_TOKEN
if: inputs.use_npm_token
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TAG: ${{ inputs.npm_tag }}
run: |
if [[ -z "${NODE_AUTH_TOKEN}" ]]; then
echo "NPM_TOKEN is required when use_npm_token is enabled" >&2
exit 1
fi
npm publish dist/plugin/*.tgz --access public --tag "$NPM_TAG" --provenance