Skip to content

Block pre-release CLI versions from triggering docs updates - #1211

Open
Duncanma wants to merge 6 commits into
mainfrom
duncan/trigger-docs-prerelease-gate
Open

Duncanma wants to merge 6 commits into
mainfrom
duncan/trigger-docs-prerelease-gate

Conversation

@Duncanma

Copy link
Copy Markdown

Summary

trigger-docs.yml fires on release: types: [published], which GitHub sends for pre-releases too. v1.9.0-rc.1 (run #38) and v1.9.0 published with the pre-release flag set (run #39) both dispatched update-cli-docs.yml in temporalio/documentation; run #38 opened an unwanted docs PR (documentation#5312, now closed unmerged).

Two related defects in the same file, fixed alongside the gate:

Why not just add prerelease == false to the existing published trigger?

That fixes the reported symptom but opens a silent gap: promoting a release from pre-release to full release emits released, not published, so the GA docs update would never fire — published already fired while it was a pre-release and won't fire again. types: [released] fires on a direct full-release publish and on a pre-release → release promotion, and never for a pre-release, with no double-fire risk.

Changes (3 commits, reviewable independently)

  1. Block pre-release CLI versions from triggering docs updatespublishedreleased, plus a job-level if: gate that also rejects drafts and side-channel tags (v1.8.3-server-1.32.0-162.0, v1.7.4-standalone-nexus-operations, v1.6.3-serverless, and similar) built from feature branches, as defense in depth. workflow_dispatch stays exempt so docs can still be backfilled on demand.
  2. Source the release tag from the release payload, not github.ref_name — adds a required release_tag input for workflow_dispatch and sources RELEASE_TAG from the release payload's tag_name or the new input.
  3. Move interpolated values into env: — hygiene, consistent with how github.actor is already handled.

Verification

Checked every release in the repo's history against the new gate logic via the GitHub API: every pre-release and side-channel tag in history already carries prerelease: true, so the gate would have blocked all of them; no full release (prerelease: false) has ever carried a hyphenated tag suffix, so the tag-shape check hasn't excluded anything unexpected historically.

A gated-out release shows as a skipped (grey) run rather than a failure, so release managers aren't paged by a deliberate skip.

Companion PR in temporalio/documentation: #5326, a receiver-side guard on update-cli-docs.yml that validates the tag independent of this fix.

Test plan

  • Confirm a pre-release publish (e.g. a future -rc. tag) shows the update job as skipped, not failed
  • Confirm a workflow_dispatch run still proceeds and reaches temporalio/documentation
  • After merge, promote v1.9.0 from pre-release to full release and confirm exactly one docs PR appears

trigger-docs.yml fired on release `published`, which GitHub sends for
pre-releases too. v1.9.0-rc.1 (run #38) and v1.9.0 published as a
pre-release (run #39) both dispatched update-cli-docs.yml in
temporalio/documentation; run #38 opened an unwanted docs PR.

Switch to `released`, which fires on a direct full-release publish and
on a pre-release-to-release promotion, but never for a pre-release.
Add a job-level gate that also rejects drafts and side-channel tags
(v1.8.3-server-1.32.0-162.0, v1.7.4-standalone-nexus-operations,
v1.6.3-serverless, and similar) built from feature branches, as
defense in depth behind the event-type change. workflow_dispatch stays
exempt so docs can still be backfilled on demand.
github.ref_name resolves to the selected branch on a manual dispatch,
not a tag: run #37 dispatched cli_release_tag=main to
temporalio/documentation. Add a required release_tag input for
workflow_dispatch, and source RELEASE_TAG from the release payload's
tag_name on the release event or from the new input on dispatch.
secrets.GITHUB_TOKEN and the get_user step outputs were interpolated
directly into run: blocks, unlike github.actor in the same file, which
already goes through env:. Route them the same way to avoid shell
injection from a value GitHub Actions doesn't sanitize before
substitution.
@Duncanma
Duncanma requested a review from a team as a code owner September 14, 2026 21:35
@CLAassistant

CLAassistant commented Sep 14, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Comment thread .github/workflows/trigger-docs.yml
prerelease/draft/tag-shape don't rule out a hotfix to an older minor
line (patching v1.7.x after v1.8.0 is already GA, for example) — that's
a real full release, but generating docs from it would overwrite the
newer version's command reference.

The release payload has no "is latest" field (confirmed against the
live API: a release object exposes prerelease/draft/tag_name/etc., but
nothing about latest status), so compare the tag against
GET /releases/latest instead, in a step rather than the job-level `if:`
since expressions can't make API calls. workflow_dispatch stays exempt,
consistent with the existing gate: backfilling an older tag on purpose
is a deliberate choice, not something to second-guess.
if: |
github.repository == 'temporalio/cli'
&& (github.event_name == 'workflow_dispatch'
|| (github.event.release.prerelease == false

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this live in a fork (github.com/Duncanma/cli) rather than trusting the docs. Findings:

  • A fresh pre-release publish fires created + prereleased + published — never released, and with types: [released] the workflow doesn't even start a run for it (not skipped — no run at all).
  • Promoting an existing pre-release to a full release (prerelease: true → false, the flow you described) does fire released — confirmed via github.event.action logged directly from an Actions run, not inferred from the public events feed (which is a less reliable signal here — it shows published for these edits too, so it's not a good proxy).
  • Doing that promotion together with --latest (your actual flow: mark pre-release, attach assets, then flip to latest) still fires released. It doesn't get suppressed by the make_latest change.
  • The job-level if: correctly skipped every one of these on the fork (github.repository == 'temporalio/cli' is false there), so nothing could reach the real temporalio/documentation repo during testing.

One caveat worth recording: of 4 promotion tests, the very first one (the first release ever created on the fresh fork) produced no event at all even after several minutes — looks like one-time webhook registration lag on a brand-new repo, not a pattern, since the next 3 all fired within under a minute. Worth keeping in mind if released is ever silent for a real release — check a bit later before assuming the gate is broken.

Also added a commit for your "check for latest" idea: make_latest isn't actually in the release payload (confirmed against the live API — a release object exposes prerelease/draft/tag_name/etc., nothing about latest status), so I added a step that compares the tag against GET /releases/latest and skips if it doesn't match. This closes a gap prerelease/draft/tag-shape alone don't cover: a hotfix to an older minor line (e.g. patching v1.7.x after v1.8.0 is GA) is a real full release and would otherwise regenerate docs from an older version, overwriting the newer one's command reference.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5039847c40

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/trigger-docs.yml Outdated
Comparing the release tag against GET /releases/latest trusts the
make_latest marker, which is metadata someone can set independently of
version order. An older-line hotfix published with --latest=true would
satisfy that equality check while still being exactly the release this
gate exists to reject (caught in review: #1211).

List all non-draft, non-prerelease tags and version-sort them instead,
so the check reflects actual version order rather than a marker that
can be mis-set.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 28b801d42f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/trigger-docs.yml
The highest-version query only filtered on draft/prerelease, not tag
shape. If a side-channel tag (v2.0.0-serverless) were ever published
with prerelease: false, sort -V ranks it above the real v2.0.0
(confirmed empirically), so it would win the "highest" comparison and
silently skip every future GA release's docs update (caught in review:
#1211).

Apply the same strict vX.Y.Z tag-shape filter the job-level gate
already uses to the release list before sorting.
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.

3 participants