#2224: publish the Homebrew formula as part of the release - #2223
#2224: publish the Homebrew formula as part of the release#2223maybeec wants to merge 4 commits into
Conversation
…e release Homebrew is a primary distribution channel, so the formula is published synchronously by this workflow instead of by a decoupled follow-up automation whose failures nobody notices. The tap has been stuck at 2026.04.002 since May because that automation silently produced unmergeable pull requests. - resolve the release version once in a dedicated job and pass it to every downstream job. .mvn/maven.config is rewritten twice during the release, so re-deriving the version later resolved a different value depending on the point in time, and the same value was called next_version in one step and current_version in the next. - wait until the deployment is published instead of merely validated. mvn deploy returned as soon as Central had validated the bundle, so the GitHub release notes already linked to Maven Central URLs that were not resolvable yet. - replace the nexus-staging configuration for the retired OSSRH host s01.oss.sonatype.org with the central-publishing plugin that actually performs the deployment. - compute the formula checksums from the archives that were just deployed and verify that Central serves the same bytes. - render, audit, install and test the formula on macOS before pushing it to the tap, so the tap is never left in a broken state. - add the missing linux-arm64 download to the release notes.
Coverage Report for CI Build 30393724658Coverage decreased (-0.008%) to 72.585%Details
Uncovered ChangesNo uncovered changes found. Coverage Regressions1 previously-covered line in 1 file lost coverage.
Coverage Stats💛 - Coveralls |
Note for the reviewer: what has and has not been executed
What has been verified:
If you want the release-side path exercised before the next release, the Publish formula One deviation worth knowing aboutThe formula was intended to reference |
hohwille
left a comment
There was a problem hiding this comment.
@maybeec thanks for your PR. Great stuff. I really appreciate this automation since I am too overloaded to keep track of manual processes for such extra details. 👍
As you already outlined we have a dependency to the homebrew PR that needs to be merged first. I also left some review comments to clarify before merge.
| # Homebrew is a primary distribution channel for IDEasy. The formula is therefore published as | ||
| # part of this release and not by a decoupled follow-up automation: if it cannot be published, | ||
| # this release fails and the failure is visible right here. | ||
| await-central: | ||
| name: Await publication on Maven Central | ||
| runs-on: ubuntu-latest | ||
| needs: [ resolve-version, release ] | ||
| steps: | ||
| - name: Checkout Homebrew tap | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: devonfw/homebrew-IDEasy | ||
| token: ${{ secrets.ACTION_PUSH_TOKEN }} | ||
| - name: Wait until the release archives are served by Maven Central | ||
| run: | | ||
| ./wait-for-central.sh "${{ needs.resolve-version.outputs.release_version }}" \ | ||
| "${{ needs.release.outputs.sha_mac_arm64 }}" \ | ||
| "${{ needs.release.outputs.sha_mac_x64 }}" \ | ||
| "${{ needs.release.outputs.sha_linux_arm64 }}" \ | ||
| "${{ needs.release.outputs.sha_linux_x64 }}" | ||
|
|
||
| verify-homebrew: | ||
| name: Verify Homebrew formula | ||
| needs: [ resolve-version, release, await-central ] | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| os: [ macos-latest, macos-15-intel ] | ||
| runs-on: ${{ matrix.os }} | ||
| steps: | ||
| - name: Checkout Homebrew tap | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: devonfw/homebrew-IDEasy | ||
| token: ${{ secrets.ACTION_PUSH_TOKEN }} | ||
| - name: Render formula | ||
| run: | | ||
| ./render-formula.sh "${{ needs.resolve-version.outputs.release_version }}" \ | ||
| "${{ needs.release.outputs.sha_mac_arm64 }}" \ | ||
| "${{ needs.release.outputs.sha_mac_x64 }}" \ | ||
| "${{ needs.release.outputs.sha_linux_arm64 }}" \ | ||
| "${{ needs.release.outputs.sha_linux_x64 }}" | ||
| - name: Set up Homebrew | ||
| uses: Homebrew/actions/setup-homebrew@master | ||
| - name: Audit formula | ||
| run: brew audit --strict --online --formula ./Formula/ideasy.rb | ||
| - name: Install formula | ||
| run: brew install --formula ./Formula/ideasy.rb | ||
| - name: Test formula | ||
| run: brew test --formula ./Formula/ideasy.rb | ||
|
|
||
| publish-homebrew: | ||
| name: Publish Homebrew formula | ||
| runs-on: ubuntu-latest | ||
| needs: [ resolve-version, release, verify-homebrew ] | ||
| steps: | ||
| - name: Checkout Homebrew tap | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: devonfw/homebrew-IDEasy | ||
| token: ${{ secrets.ACTION_PUSH_TOKEN }} | ||
| - name: Render formula | ||
| run: | | ||
| ./render-formula.sh "${{ needs.resolve-version.outputs.release_version }}" \ | ||
| "${{ needs.release.outputs.sha_mac_arm64 }}" \ | ||
| "${{ needs.release.outputs.sha_mac_x64 }}" \ | ||
| "${{ needs.release.outputs.sha_linux_arm64 }}" \ | ||
| "${{ needs.release.outputs.sha_linux_x64 }}" | ||
| - name: Commit and push formula | ||
| env: | ||
| RELEASE_VERSION: ${{ needs.resolve-version.outputs.release_version }} | ||
| run: | | ||
| if git diff --quiet -- Formula/ideasy.rb; then | ||
| echo "Formula already up to date for ${RELEASE_VERSION}, nothing to publish." | ||
| exit 0 | ||
| fi | ||
| git config user.email ${{ secrets.BUILD_USER_EMAIL }} | ||
| git config user.name ${{ secrets.BUILD_USER }} | ||
| git add Formula/ideasy.rb | ||
| git commit -m "ideasy ${RELEASE_VERSION}" | ||
| git push |
There was a problem hiding this comment.
looks like a complete copy&past duplication of devonfw/homebrew-IDEasy#8 to me.
Can't we just invoke the workflow from homebrew-IDEasy avoiding all the duplication?
Who will ensure that if this needs to be changed it will be updated consistently in both repos?
There was a problem hiding this comment.
You are right, and it is fixed: the three jobs are gone, replaced by a single call to a reusable
workflow in the tap.
publish-homebrew:
needs: [ resolve-version, release ]
uses: devonfw/homebrew-IDEasy/.github/workflows/publish-formula.yml@main
with:
version: ${{ needs.resolve-version.outputs.release_version }}
sha_mac_arm64: ${{ needs.release.outputs.sha_mac_arm64 }}
...
secrets: inheritWhy not simply invoking the workflow — that was the reason for the duplication, and it is worth
recording. Dispatching the tap workflow (gh workflow run / workflow_dispatch) returns immediately
with no status. This job would go green whatever happens over there, and an IDEasy release would
succeed with a stale Homebrew channel that nobody notices — exactly the failure mode this PR exists
to remove. Recovering the signal would mean hand-rolling a polling loop.
uses: does not have that problem: the called workflow's jobs run as part of this run, and a
failure there fails this job and with it the release. It cannot even be silenced by accident, since
continue-on-error is not supported on a job that calls a reusable workflow. So we get the
deduplication you are asking for and the loud failure. Both repositories are public and in the same
org, so the cross-repository call and secrets: inherit work.
To answer "who keeps them consistent": nobody has to any more. The sequence now exists once, in
devonfw/homebrew-IDEasy@c47074a, next to the formula and the scripts it renders. The release owns
when to publish, the tap owns how. Worth noting the logic was never duplicated — render-formula.sh
and wait-for-central.sh only ever existed in the tap; what was duplicated was ~70 lines of YAML
wiring around them.
The manual workflow_dispatch entry point stays, on the same workflow, as the recovery path for
catching up or re-publishing. Without checksums passed in it takes them from Maven Central; with them
it verifies Central serves exactly the released bytes.
Two consequences to be aware of:
- This makes the merge order hard, not just advisory:
@maincannot resolve until
#4: publish the formula synchronously from the IDEasy release homebrew-IDEasy#8 is merged. @mainpins the release to the tap's moving branch, so a bad commit on the tap could break a
release. Pinning to a tag or commit SHA would be safer at the cost of bumping it on every change.
Happy to switch if you prefer that trade-off.
Co-authored-by: Jörg Hohwiller <hohwille@users.noreply.github.com>
- use RELEASE_VERSION directly instead of shadowing it in a lower case variable. - call the publishing sequence of the tap as a reusable workflow instead of duplicating its jobs here. Calling it with 'uses' keeps the failure loud: a failure there fails this job and with it the release, which dispatching a separate workflow run would not. - reduce the deploy profile to the waiting behaviour that is actually added here. The plugin, its extension, publishingServerId and autoPublish are inherited from the deploy profile of com.devonfw:maven-parent, as the effective POM confirms.
This PR fixes #2224
Homebrew users are stuck on 2026.04.002:
brew upgrade ideasyreports "already installed" becausethe tap has not been updated since May. The tap's own polling automation opened five pull requests
that all carry empty
sha256fields and that nobody merges. That is fixed on the tap side indevonfw/homebrew-IDEasy#8; this PR makes the release actually publish the formula.
Interpretation this PR is based on: Homebrew is a primary distribution channel for IDEasy. A
decoupled post-processing automation running after the release can fail unnoticed — as it did for
three months. So publishing the formula becomes a synchronous part of this workflow: if it cannot be
published, the release run is red.
Implemented changes:
Resolve the release version exactly once.
.mvn/maven.configwas parsed independently inthree places, and it is rewritten twice during the run (to the release version, then to the next
snapshot). The same number was called
next_versioninbuild-nativesandcurrent_versioninthe release step, and anything reading the file afterwards resolves a different version depending
on when it runs. A new
resolve-versionjob publishesrelease_versionandsnapshot_versionasjob outputs, and every downstream job consumes them.
Wait until the deployment is published, not merely validated (precondition for everything
below — see the note at the end).
central-publishing-maven-plugindefaults towaitUntil=validated, somvn deployreturns as soon as Central has validated the bundle. In the2026.07.002 run the GitHub release — whose notes link directly to
repo1.maven.org— was createdseven seconds after validation, well before those URLs resolved. The
deployprofile now setsautoPublish+waitUntil=publishedwithwaitMaxTime=3600.Drop the dead OSSRH configuration. The
deployprofile configurednexus-staging-maven-pluginagainsts01.oss.sonatype.org, which was retired on 2025-06-30. Therelease log confirms it is vestigial: the actual publishing is done by
central-publishing:0.8.0inherited from
com.devonfw:maven-parent. It is replaced by an explicitcentral-publishingconfiguration, keeping
publishingServerId=repositoryso the existingSONATYPE_USERNAME/SONATYPE_PASSWORDcredentials from.mvn/settings.xmlcontinue to apply.Publish the formula from the release. Three new jobs after
release:await-central— waits until all four archives are served byrepo1and verifies thechecksums match the artifacts that were just deployed.
verify-homebrew— renders the formula and runsbrew audit --strict --online,brew installandbrew testonmacos-latestandmacos-15-intel.publish-homebrew— pushes the formula to the tap, only after verification passed, so the tapis never left broken.
Checksums are computed from the archives in
cli/target/that were just deployed — the exact bytesCentral will serve — so nothing is downloaded to build the formula.
Add the missing
linux-arm64download to the release notes. The assembly(
cli/src/main/assembly/release-linux-arm64.xml) has been built and deployed for a while but waslisted nowhere.
The tap is checked out with
ACTION_PUSH_TOKEN, the same secret already used to push todevonfw/ide-urlsinupdate-urls.ymlandupdate-cve.yml. If its scope does not coverdevonfw/homebrew-IDEasy, this is a one-line change to a different secret.Testing instructions
The release workflow only runs on
workflow_dispatch, so the end-to-end path is first exercised bythe next release. What can be checked before that:
resolve-version→build-natives→release→await-central→verify-homebrew→publish-homebrew. No job re-derives the version.mvn -N -Pdeploy validatepasses with the new publishing plugin configuration../wait-for-central.sh 2026.07.002verifies against the real2026.07.002 artifacts, and
render-formula.shrejects the empty-version and empty-checksuminputs that produced the stale bot PRs.
publish-homebrewmust push the new version to the tap, andbrew update && brew upgrade ideasymust upgrade.Checklist for this PR
mvn clean testlocally all tests pass and build is successful (no production code touched;mvn -N -Pdeploy validateverified the POM change)#«issue-id»: «brief summary»(cross-repository form, the issue lives indevonfw/homebrew-IDEasy)In Progressand assigned to youChecklist for tool commandlets
Not applicable — no commandlet is added.
Precondition to be aware of when merging
The
waitUntil=publishedchange is required for the Homebrew jobs (the formula must not bepublished before the URLs it references resolve), but it also changes release timing for everyone:
mvn deploynow blocks until Maven Central reports the deployment as published instead of returningat validation. Publication typically takes on the order of 20 minutes, bounded here by
waitMaxTime=3600; if Central does not publish within that window the release fails loudly insteadof producing release notes pointing at URLs that do not resolve yet.
Merge order: devonfw/homebrew-IDEasy#8 must be merged first — this workflow checks that
repository out and runs
render-formula.shandwait-for-central.shfrom it.