docs(skills/create-pr): infer Linear ticket from context, skip pre-cr… #864
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: Publish to npm | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ["!**"] | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version to publish (e.g., 0.1.0, 0.1.0-beta.1). Leave empty to auto-calculate." | |
| required: false | |
| type: string | |
| dist-tag: | |
| description: "npm dist-tag (e.g., latest, dev, beta)" | |
| required: true | |
| default: "latest" | |
| type: string | |
| concurrency: | |
| group: npm-publish | |
| cancel-in-progress: false | |
| jobs: | |
| publish: | |
| name: Publish packages to npm | |
| runs-on: ubuntu-latest | |
| # Safety net: only publish from main, even though push trigger is already constrained | |
| if: github.ref == 'refs/heads/main' | |
| permissions: | |
| contents: write # Required to create the GitHub Release + tag for stable publishes | |
| id-token: write # Required for npm OIDC Trusted Publishing | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Setup mise | |
| uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4.0.1 | |
| with: | |
| cache: true | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@91ab88e2619ed1f46221f0ba42d1492c02baf788 # v6.0.6 | |
| - name: Configure npm | |
| run: pnpm config set registry https://registry.npmjs.org | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Determine version | |
| id: version | |
| env: | |
| GITHUB_EVENT_NAME: ${{ github.event_name }} | |
| INPUT_VERSION: ${{ github.event.inputs.version }} | |
| INPUT_TAG: ${{ github.event.inputs.dist-tag }} | |
| run: | | |
| if [ -n "$INPUT_VERSION" ]; then | |
| echo "Using provided version: $INPUT_VERSION" | |
| # Validate version format (semantic versioning) | |
| if ! echo "$INPUT_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$'; then | |
| echo "Error: Invalid version format. Must match semantic versioning (e.g., 1.0.0 or 1.0.0-beta.1)" | |
| exit 1 | |
| fi | |
| # Validate dist-tag format (alphanumeric, hyphen, underscore only) | |
| if ! echo "$INPUT_TAG" | grep -qE '^[a-zA-Z0-9_-]+$'; then | |
| echo "Error: Invalid dist-tag format. Must contain only alphanumeric characters, hyphens, and underscores" | |
| exit 1 | |
| fi | |
| # Use heredoc to safely write to GITHUB_OUTPUT (prevents injection) | |
| { | |
| echo "version<<EOF" | |
| echo "$INPUT_VERSION" | |
| echo "EOF" | |
| echo "tag<<EOF" | |
| echo "$INPUT_TAG" | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| else | |
| echo "No version provided, calculating..." | |
| node scripts/determine-version.ts | |
| fi | |
| - name: Set package versions | |
| run: node scripts/set-version.ts "${{ steps.version.outputs.version }}" | |
| - name: Build packages | |
| run: pnpm build | |
| # Publish-time gate (FR7.1 of init follow-up): packs every publishable | |
| # workspace package and verifies the resolved package.json contains no | |
| # `workspace:*` or `catalog:` dependency specifiers. `pnpm publish` | |
| # rewrites these on its own, but `npm publish` (and some CI flows) | |
| # don't — and a single leaked specifier breaks downstream installs. | |
| # This gate fails the publish before anything reaches the registry. | |
| - name: Check publish dependency specifiers | |
| run: pnpm check:publish-deps | |
| # NODE_AUTH_TOKEN is intentionally NOT set. npm detects the OIDC environment | |
| # (id-token: write) and authenticates via Trusted Publishing automatically. | |
| # Setting NODE_AUTH_TOKEN to any value -- even empty string -- would block OIDC. | |
| # | |
| # Enable npm provenance attestations for each published package. | |
| # This requires a public source repository (npm rejects provenance from private repos). | |
| - name: Publish packages | |
| env: | |
| NPM_CONFIG_PROVENANCE: "true" | |
| run: pnpm -r publish --access public --tag "${{ steps.version.outputs.tag }}" --no-git-checks | |
| # Emit a GitHub Release for stable publishes only (dist-tag `latest`). | |
| # Dev / PR / beta builds publish to npm but do not produce a Release — | |
| # those would drown out the changelog signal. The Release is created at | |
| # $GITHUB_SHA so the tag points at the same commit the publish ran from. | |
| # `--generate-notes` populates the body from merged-PR titles since the | |
| # previous release tag (auto-discovered). | |
| # | |
| # Idempotent on workflow rerun: if a Release for `v$VERSION` already exists | |
| # (e.g. a previous run published to npm but failed before this step), edit | |
| # it in place rather than re-creating it. `gh release edit` doesn't support | |
| # `--generate-notes`, so on rerun the existing notes are preserved — that's | |
| # the right trade-off versus failing the rerun outright. | |
| - name: Create GitHub Release for stable publishes | |
| if: ${{ steps.version.outputs.tag == 'latest' }} | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION: ${{ steps.version.outputs.version }} | |
| run: | | |
| if gh release view "v$VERSION" >/dev/null 2>&1; then | |
| gh release edit "v$VERSION" \ | |
| --target "$GITHUB_SHA" \ | |
| --title "v$VERSION" | |
| else | |
| gh release create "v$VERSION" \ | |
| --target "$GITHUB_SHA" \ | |
| --title "v$VERSION" \ | |
| --generate-notes | |
| fi |