Skip to content

Release script - #1723

Merged
sequba merged 29 commits into
release/3.4.0from
feature/release-script-publish
Aug 6, 2026
Merged

sequba merged 29 commits into
release/3.4.0from
feature/release-script-publish

Conversation

@sequba

@sequba sequba commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements the publish half of the release automation and makes code-freeze genuinely re-runnable.

On the base branch, release.sh publish is a placeholder that prints "not implemented yet" and exits 1 — everything after the freeze (the merges, the tag, the npm publish, the sibling-repo updates) was still manual. This PR implements it end to end, and hardens code-freeze so a run that fails part-way resumes instead of starting over.

Both commands mirror the ClickUp release process doc, with the deliberate deviations listed below.

Note

Base is release/3.4.0, not develop — this is an exception. The release-script work is stacked on the 3.4.0 freeze commit (bad1bfa1), so release/3.4.0 is the only base that yields a clean two-file diff. Targeting develop would drag in the 3.4.0 version bump, its CHANGELOG/release-notes entries and ~1,950 lines of lock-file churn.

Base This PR
script/release/release.sh 430 lines 1,174 lines
script/release/release-README.md 106 lines 380 lines
publish command stub, exit 1 fully implemented

No files outside script/release/ are touched.

What's new — the publish command

Step Does
1 Merges release/<version> into master as a merge commit, unless already merged
2 Annotated tag <version> on master, unless it already exists in master's (or origin/master's) history
3 Merges release/<version> into develop
4 Reinstalls, rebuilds and runs verify:publish-package from master
5 Pushes master, develop and the tag in one atomic push, before the npm publish
6 Merges the release branch back in hyperformula-tests (into master and develop), pushed atomically
7 The point of no return — typed confirmation, then npm publish, then waits for registry visibility
8 Updates hyperformula-demos: lock files on develop, then merges into the M.m.x branch
9 Leaves you on develop, where the next cycle starts

code-freeze hardening

  • Resumable. Every step checks whether it is already done and skips with a = marker, so a failed run is recovered by re-running the same command rather than unpicking a half-finished freeze.
  • The tests-repo branch moved from step 10 to step 2. test/fetch-tests.sh pulls the matching branch from origin, so a release/<version> that an earlier attempt created locally but never pushed made every resume fail. Creating and pushing it before test:setup-private runs fixes that, and publishes the branch for CI and for whoever adds tests during the freeze that much sooner.
  • The release type is classified against origin/develop, not the working tree — on a resumed freeze the tree already carries the bump, which used to read as a patch and silently skip the demos and CodeSandbox work.
  • Stages named paths, not git add ., so unrelated work in your tree cannot ride along into the release commit.
  • Rejects a date that does not exist. 2026-02-30 passed the YYYY-MM-DD regex and reached ht.config.js verbatim while the release notes said March 2.

Safety model

  • Dry run is the default. Nothing changes without --real-run. Every mutating command is printed as a $ line; generated content (the new CHANGELOG section, the release-notes entry, every rewritten demo URL as -/+) is previewed so it can be proofread first.
  • Three-repo preflight. Both sibling clones must be present, clean, on a reachable origin, carrying the branches the run will move and the script it will execute inside them. This is checked before anything moves — in publish the demos script runs after the irreversible npm publish, so a wrong --demos-dir has to be caught up front or not at all.
  • Divergence is an error, never a merge. Getting onto a branch fast-forwards or creates; it never invents a merge commit on develop or a shared version branch. A local release/<v> that disagrees with origin's is fatal, so a late fix pushed to the freeze branch cannot be silently dropped.
  • The merged commit is pinned in the preflight, so the later steps merge exactly the commit the checks verified.
  • Prereleases stay off latest. A plain x.y.z publishes under latest; anything with an rc suffix publishes under next and the GitHub release link carries &prerelease=1.

Recorded failures

Anything you need to act on is recorded and re-printed as a [ ] item at the top of the closing checklist — a lone marker line mid-run scrolls past in an output that also holds a full install, build and test log. Two kinds, and only one means the run fell short:

  • ! the script could not do it — a target file has been restructured, or [Unreleased] is empty. These change the closing banner, so a freeze that fell short cannot sign off as if it hadn't.
  • i worth checking — the run did its job, but something deserves a look (a resume from a dirty tree, a demos branch publish had to create). Listed without changing the banner, so an ordinary resume does not announce itself as a failure.

Deliberate deviations from the process doc

  • hyperformula-tests gets its own release/<version> branch, which publish merges back into master and develop. The doc still describes pointing its master at develop by hand. The ClickUp doc needs updating to match.
  • release/<v> is never deleted — the branch is kept in both repositories, unlike git flow release finish.
  • Deploying the docs to staging is not automated and is not on either checklist; the "test the code examples on staging" item assumes you have done it.

How to verify

Dry run is the default, so both commands can be previewed safely against a real clone:

npm run release -- code-freeze 3.5.0 2026-09-30
npm run release -- publish 3.4.0

Each prints its preflight, a plan, every command it would run, and the exact content it would write. shellcheck is clean and bash -n passes.

Review status

A full review of the final implementation was run against the process doc. Four findings are fixed in this branch:

  • Perl's -T text heuristic could silently drop a real markdown file from the demo-URL rewrite, under-reporting the file count with no warning.
  • publish's preflight checks ran before step "Preflight", so a failure reaching the ERR trap was attributed to "startup" instead — inconsistent with code-freeze.
  • The README described the tag check as master-only, where the script also accepts origin/master's history.
  • The README claimed the script prints every command; read-only state checks and the in-place node/perl edits are not echoed verbatim.

Follow-ups (not in this PR)

  • git push --atomic origin master develop --tags pushes all local tags, not just refs/tags/<version>. A stray local tag gets published as a side effect, and one tag conflicting with origin aborts the entire release push.
  • The staging-deploy step is neither automated nor on the manual checklist, while the checklist still says "test the code examples on staging" — the prerequisite is invisible.
  • Publishing from a clone with no local release branch produces merge messages reading Merge branch 'origin/release/<v>' instead of release/<v>.

Note

Medium Risk
Changes automate irreversible npm publish and multi-repo git merges/tags; mitigations include dry-run default, preflight pinning, typed confirmation, and atomic pushes, but operator error or partial failure still needs careful resume.

Overview
Replaces the publish stub with an end-to-end flow: merge release/<version> into master and develop, tag, build and run verify:publish-package, atomic push of branches and tags (before npm), merge back in hyperformula-tests, typed npm publish confirmation ( latest vs next for prereleases), then update hyperformula-demos.

code-freeze is reworked to be resumable (skip steps with = when already done) instead of exiting when release/<version> exists. The tests repo branch is created and pushed in step 2 (before test:setup-private). Major/minor detection uses origin/develop, commits use named paths not git add ., and invalid calendar dates are rejected.

Both commands share new infrastructure: warning register (! / i in the closing checklist), checkout_branch / resolve_branch / merge_release_into, strict sibling-repo preflight (fixed test/hyperformula-tests path; demos script verified before publish), and expanded release-README.md documenting behavior vs the script.

Reviewed by Cursor Bugbot for commit fc55734. Bugbot is set up for automated code reviews on this repo. Configure here.

sequba and others added 29 commits August 4, 2026 15:31
shellcheck SC2209: 'patch' is also a command name, so the unquoted assignment
reads as a possible typo for RELEASE_TYPE=$(patch).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…uirement

release-README.md described publish as an unimplemented placeholder and
code-freeze's old, non-idempotent behaviour. Bring it up to date: a "Before
you start" section on the sibling-clone preflight both commands share, a
corrected code-freeze step list (resume logic, per-step skips, test:jest not
test), full publish documentation (options, preflight, the nine steps, the
manual checklist), and Notes covering re-runnability and the deliberate
divergence from the ClickUp process doc for hyperformula-tests. Drops the
stale advice to delete release/<version> to redo a freeze - that bail-out no
longer exists.

Also documents the sibling-clone requirement in code-freeze's --help text.
…e resume

Adds a warning register, factors the repeated branch handling into shared
helpers, and fixes the code-freeze ordering that broke every resume.

- warn/note register: 'warn' records a soft failure (the run could not do
  something), 'note' an advisory (worth checking). Both re-print as '[ ]'
  items at the top of the closing checklist, and a soft failure changes the
  closing banner, so a freeze that fell short cannot sign off as if it had
  not. Backed by temp files so subshells and the node here-doc can append.
- checkout_branch, resolve_branch and merge_develop_into_version_branch:
  one implementation each for "get onto a branch", "name the ref a release
  is read from" and "carry demos' develop onto M.m.x". These replaced four
  hand-written copies of the same decision that had each drifted.
- require_script: the preflight now checks a sibling clone carries the
  script the run will execute. It matters most for publish, whose demos
  script runs after the npm publish that cannot be undone.
- code-freeze: create and push release/<version> in hyperformula-tests in
  step 2 rather than step 10. fetch-tests.sh pulls the matching branch from
  origin, so a branch an earlier attempt created locally but never pushed
  made every resume fail there.
- Preflight: report both missing sibling clones, reject a date that does
  not exist, and treat a dirty tree as fatal for a fresh real freeze while
  exempting a dry run and a resume.
- release-README.md: document both preflights and the recorded-failure
  markers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@netlify

netlify Bot commented Aug 6, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for hyperformula-dev-docs ready!

Name Link
🔨 Latest commit fc55734
🔍 Latest deploy log https://app.netlify.com/projects/hyperformula-dev-docs/deploys/6a742e7e6473830007c43209
😎 Deploy Preview https://deploy-preview-1723--hyperformula-dev-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
hyperformula-docs fc55734 Aug 06 2026, 06:49 AM

@github-actions

github-actions Bot commented Aug 6, 2026 •

Copy link
Copy Markdown

Performance comparison of head (fc55734) vs base (bad1bfa)

                                     testName |    base |    head | change
--------------------------------------------------------------------------
                                      Sheet A |  492.13 |  504.89 | +2.59%
                                      Sheet B |   161.6 |  163.91 | +1.43%
                                      Sheet T |  144.71 |  145.95 | +0.86%
                                Column ranges |  475.21 |  480.29 | +1.07%
                                Sorted lookup | 14367.4 | 14486.6 | +0.83%
Sheet A:  change value, add/remove row/column |   16.55 |   16.96 | +2.48%
 Sheet B: change value, add/remove row/column |  142.13 |  133.97 | -5.74%
                   Column ranges - add column |  157.99 |   148.3 | -6.13%
                Column ranges - without batch |  476.25 |  453.71 | -4.73%
                        Column ranges - batch |  117.56 |   115.3 | -1.92%

@sequba
sequba marked this pull request as ready for review August 6, 2026 09:27
@sequba
sequba merged commit 7df5d0b into release/3.4.0 Aug 6, 2026
33 of 34 checks passed
@sequba
sequba deleted the feature/release-script-publish branch August 6, 2026 09:27
@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.31%. Comparing base (bad1bfa) to head (fc55734).
⚠️ Report is 5 commits behind head on release/3.4.0.

Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff               @@
##           release/3.4.0    #1723   +/-   ##
==============================================
  Coverage          97.31%   97.31%           
==============================================
  Files                195      195           
  Lines              15734    15734           
  Branches            3456     3456           
==============================================
  Hits               15312    15312           
  Misses               414      414           
  Partials               8        8           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fc55734. Configure here.

Comment thread script/release/release.sh
const head = rnLines.slice(0, idx).join('\n').replace(/\s+$/, '');
const tail = rnLines.slice(idx).join('\n').replace(/^\n+/, '').replace(/\s+$/, '');
fs.writeFileSync(rnPath, head + '\n\n' + entry + '\n\n' + tail + '\n');
console.log(' added "## ' + v + '" to ' + rnPath);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Empty notes pass on resume

Medium Severity

When [Unreleased] has no bullets, step 7 still writes an empty release-notes.md stub after warning. A later resume sees that heading, skips with already has, and does not re-check for content, so warning_count stays 0 and the freeze can sign off as ready with empty notes still committed.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fc55734. Configure here.

Comment thread script/release/release.sh
# explicitly instead of declaring the local branch authoritative: otherwise a
# colleague's commit on a shared branch is silently ignored here and
# surfaces as a raw non-fast-forward rejection at the next push.
run git merge --ff-only "origin/$1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale sync without fetch

Low Severity

When a branch has no upstream, sync_branch fast-forwards to origin/&lt;branch&gt; without fetching first. The demos steps call this on develop with no prior fetch, so a cold or stale remote-tracking ref can be treated as current even though the comment says this path exists to pick up remote moves.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fc55734. Configure here.

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