Skip to content

Publish the release when a re-pushed tag leaves it as a draft - #42

Merged
imanimanyara merged 1 commit into
mainfrom
fix/clear-draft-flag-on-release-edit
Nov 8, 2026
Merged

imanimanyara merged 1 commit into
mainfrom
fix/clear-draft-flag-on-release-edit

Conversation

@imanimanyara

Copy link
Copy Markdown
Member

Summary

Deleting a tag reverts its GitHub release to a draft — it keeps its body and assets and stops being visible — and gh release edit leaves that flag exactly as it finds it. So an edit after a tag is deleted and re-pushed goes green having republished nothing: correct tag, invisible release.

This repository already shows the residue. gh release list returns v1.0.0 and v1.0.1 as drafts, from 2026-08-24, left behind when those tags were withdrawn in the floor-to-v0.1.0 reset. The drafts outlived the tags: neither tag exists on the remote any more.

It was found as a live failure in laranail/validation-js on 2026-11-08, whose release had to be published by hand (validation-js#35). Here v0.1.1, the current release, is published — so nothing is hidden today.

Nothing else reports that state. The tag resolves, composer installs, and composer tag-currency passes, because none of them reads the release — so a failed run is not the only way to end up with a correct tag and no release. A successful one will do it too.

What changed

Two call sites, because both edit a release:

  • release.yml on its update path.
  • release-benchmark.yml when it injects the benchmark table. This one also runs by workflow_dispatch, which can reach a release that is a draft — on the release: released path it cannot, since that event only fires for a published release.

Plus:

  • tests/ReleaseWorkflowTest.php (new) asserts the flag across every workflow file rather than these two call sites, so a workflow added later inherits the rule. It counts the files it read (floor 13), fails when no gh release edit matches at all, and requires at least two commands, so a call site that disappears fails too.
  • docs/release.md gains "A deleted tag leaves its release behind as a draft", naming the two orphans; the CHANGELOG records it under [Unreleased].
  • release.yml's first comment claimed v0.1.0 "is force-pushed on every change". v0.1.1 was cut on 2026-11-02, so that premise no longer holds — the idempotence it argued for still does, for a re-pushed tag, so only the premise changed.

Proof the guard can fail

Each defect injected separately, restored byte-exact, green again after each:

Injected Result
release.yml loses the flag 1 failed (7 assertions)
only release-benchmark.yml loses it 1 failed (6 assertions)
the workflow glob stops matching 1 failed (2 assertions)
the matcher no longer finds the command 1 failed (3 assertions)
one call site disappears entirely 1 failed (5 assertions)
restored 1 passed (7 assertions)

Gates

laranail-pint --test passed · phpstan analyse (level max) 0 errors · rector process --dry-run clean, with this file's two rewrites applied rather than left for the chore: rector job.

composer test: 6155 passed of 6280, 123 skipped, 2 failed — StringRuleTest::it validates string with activeUrl and FluentRuleTest::it validates activeUrl shortcut. Both need DNS, and this sandbox has none: php -r 'var_dump(checkdnsrr("google.com", "A"));' prints bool(false), so active_url cannot pass locally regardless of the change. They are unrelated to this diff, which touches two workflows, two docs and one new test file.

The local vendor directory also held laranail/package-tools v0.1.2 against a declared ^0.1.10, so the suite could not boot until composer update was run. A stale local install, not a repository change.

Deleting a tag reverts its GitHub release to a draft -- it keeps its
body and assets and stops being visible -- and `gh release edit`
leaves that flag exactly as it finds it. So an edit after a tag is
deleted and re-pushed goes green having republished nothing: correct
tag, invisible release.

This repository shows the residue of that mechanism already. The
v1.0.0 and v1.0.1 releases have been drafts since those tags were
withdrawn, and they outlived the tags themselves. It was found as a
live failure in laranail/validation-js, whose release had to be
published by hand.

Both editing paths now pass --draft=false: release.yml when it
updates an existing release, and release-benchmark.yml when it
injects the table, which runs by workflow_dispatch too and so can
reach a draft.

Nothing else reports that state. The tag resolves, composer installs
and the tag-currency check passes, because none of them reads the
release -- so the guard reads every workflow file rather than these
two call sites, counts the files, and requires at least two commands
so a call site that disappears fails too.

The first comment in release.yml said v0.1.0 is force-pushed on every
change. v0.1.1 was cut on 2026-11-02, so that premise no longer holds;
the idempotence it argued for still does, for a re-pushed tag.
Copilot AI balanced review requested due to automatic review settings November 8, 2026 04:10

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown

Benchmark results

Scenario Optimizations Native Laravel Optimized Speedup Δ vs base
Product import — 500 items, simple rules Wildcard, fast-check 190.7ms 3.4ms ~56x -8%
Nested order lines — 1000 orders × 5 line items Wildcard, fast-check (nested) 932.5ms 21.0ms ~44x -9%
Event scheduling — 100 items, field-ref dates Wildcard, partial fast-check 32.8ms 1.3ms ~25x -13%
Article submission — 50 items, custom Rule objects Wildcard only 11.1ms 3.2ms ~4x -9%
Conditional import — 100 items, 47 conditional fields Wildcard, pre-evaluation 255.6ms 54.6ms ~5x -12%
Login form — 3 fields, no wildcards Fast-check (flat) 0.2ms 0.0ms ~9x —

@imanimanyara
imanimanyara merged commit c1452b5 into main Nov 8, 2026
10 checks passed
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.

2 participants