Skip to content

feat(ui-scripts): allow pr-snapshot to publish at an operator-supplied prerelease version#2556

Draft
balzss wants to merge 1 commit into
masterfrom
tagged-release
Draft

feat(ui-scripts): allow pr-snapshot to publish at an operator-supplied prerelease version#2556
balzss wants to merge 1 commit into
masterfrom
tagged-release

Conversation

@balzss
Copy link
Copy Markdown
Contributor

@balzss balzss commented May 12, 2026

Summary

Adds two optional inputs — custom_version and dist_tag — to the existing pr-snapshot path of the release workflow. When set, they override the auto-computed snapshot version and the default pr-snapshot dist-tag, letting an operator publish an exact prerelease (e.g. 11.7.3-SECURITY.0) to npmjs under a non-latest tag.

  • release_to_npm.yml: two new optional workflow_dispatch inputs, passed through to the pr-release job.
  • _pr-release-reusable.yml: accepts the inputs, validates them, and forwards as --customVersion / --distTag to the publish script.
  • publish.js: new --customVersion / --distTag flags; the snapshot publish path uses the supplied values when present; a single validateCustomVersionInputs() helper enforces the guards.

No new workflow file, no new release_type choice, no new function in publish.js. The existing pr-snapshot behavior is unchanged when the new inputs are blank.

Why

The companion piece to coordinated-disclosure: a security fix is first published to a private registry under a prerelease version like 11.7.3-SECURITY.0 (see #2555 draft, and the bump-script work in #2554). After embargo, the fix lands publicly as a regular patch (e.g. 11.7.4). Some consumers — OSS projects that don't use our private registry — should still be able to install the exact prerelease they originally pinned to.

This change lets us mirror that exact version onto npmjs under the security dist-tag without touching latest. Same source, same version string, different registry — affected consumers can switch their resolution from the private registry to npmjs without modifying package.json.

Why the pr-snapshot path (and not a new workflow)

Initially I implemented this as a separate tagged-release choice with its own reusable workflow. On a second look, the pr-snapshot path already does ~90% of what's needed: bumps to a non-stable version, publishes under a non-latest tag, no git tag pushed for non-chore(release) commits. Bolting onto pr-snapshot as optional overrides means ~50 fewer lines and one fewer workflow file, with no meaningful UX loss — the operator picks pr-snapshot and fills in the two inputs.

Safety rails

Guard Where
dist_tag cannot be latest Workflow input description, validate step, validateCustomVersionInputs
custom_version must be valid semver validateCustomVersionInputs
custom_version must be a prerelease (refuses 11.7.4 etc. so we can never accidentally take over a stable version slot) validateCustomVersionInputs
dist_tag required when custom_version is set (prevents publishing a custom version under the default pr-snapshot tag by mistake) validateCustomVersionInputs
Inputs reach the shell via env: not ${{ }} interpolation in run: (prevents command injection from workflow_dispatch input values) _pr-release-reusable.yml
OIDC auth + --provenance preserved reuses existing publish plumbing unchanged

Coordination

Test Plan

  • pnpm exec ui-scripts publish --help shows the new flags.
  • --customVersion=notasemver → rejected (invalid semver).
  • --customVersion=11.7.4 (stable) → rejected (must be prerelease).
  • --customVersion=11.7.3-SECURITY.0 --distTag=latest → rejected.
  • --customVersion=11.7.3-SECURITY.0 (no --distTag) → rejected.
  • --distTag=latest alone → rejected.
  • No flags → existing pr-snapshot behavior unchanged.
  • End-to-end: trigger pr-snapshot manually with the new inputs against a test branch; confirm packages publish to npmjs at the supplied version under the supplied tag.
  • Confirm latest resolution on npmjs is unaffected after a tagged publish runs.

Status

Draft. Two commits on the branch (initial separate-workflow implementation + the refactor that collapses it onto pr-snapshot); since this repo squash-merges, only the final state matters at merge time. Keep draft until end-to-end smoke test and #2554 landing.


🤖 Generated with Claude Code

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 12, 2026

PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://instructure.design/pr-preview/pr-2556/

Built to branch gh-pages at 2026-05-12 13:21 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions
Copy link
Copy Markdown

Visual regression report

No changes.

Status Count
Unchanged 32
Changed 0
New 0
Removed 0

📊 View full report

Baselines come from the visual-baselines branch. They refresh on every merge to master.

github-actions Bot pushed a commit that referenced this pull request May 12, 2026
@balzss balzss changed the title feat(ui-scripts): add tagged-release flow for exact prerelease publishes to npm feat(ui-scripts): allow pr-snapshot to publish at an operator-supplied prerelease version May 12, 2026
…d prerelease version

Adds two optional inputs to the pr-snapshot workflow_dispatch path:
custom_version (e.g. 11.7.3-SECURITY.0) and dist_tag (e.g. security).
When set, they override the auto-computed snapshot version and the
default pr-snapshot dist-tag.

Use case: mirror a previously-published private security release onto
the public registry under a non-latest dist-tag, so open-source
consumers who pinned to a prerelease version from the private registry
can switch their resolution to npmjs without changing package.json.

Workflow plumbing:
  - release_to_npm.yml: two new optional inputs forwarded to the
    pr-release job
  - _pr-release-reusable.yml: accepts the inputs, validates them, and
    forwards as --customVersion / --distTag (via env vars to avoid
    shell-injection from workflow_dispatch input values)

publish.js:
  - new --customVersion / --distTag flags
  - publishSnapshotVersion uses customVersion when supplied, else
    falls back to calculateNextSnapshotVersion as today
  - validateCustomVersionInputs() enforces guards: valid semver,
    prerelease only (refuses stable versions so we can never take
    over a future stable slot), distTag not 'latest', distTag
    required when customVersion is set

Existing pr-snapshot behavior is unchanged when the new inputs are
blank. OIDC auth + --provenance preserved.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@balzss balzss self-assigned this May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant