Skip to content

#2224: publish the Homebrew formula as part of the release - #2223

Open
maybeec wants to merge 4 commits into
devonfw:mainfrom
maybeec:feature/homebrew-primary-distribution
Open

#2224: publish the Homebrew formula as part of the release#2223
maybeec wants to merge 4 commits into
devonfw:mainfrom
maybeec:feature/homebrew-primary-distribution

Conversation

@maybeec

@maybeec maybeec commented Jul 28, 2026

Copy link
Copy Markdown
Member

This PR fixes #2224

Homebrew users are stuck on 2026.04.002: brew upgrade ideasy reports "already installed" because
the tap has not been updated since May. The tap's own polling automation opened five pull requests
that all carry empty sha256 fields and that nobody merges. That is fixed on the tap side in
devonfw/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.config was parsed independently in
    three places, and it is rewritten twice during the run (to the release version, then to the next
    snapshot). The same number was called next_version in build-natives and current_version in
    the release step, and anything reading the file afterwards resolves a different version depending
    on when it runs. A new resolve-version job publishes release_version and snapshot_version as
    job 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-plugin defaults to
    waitUntil=validated, so mvn deploy returns as soon as Central has validated the bundle. In the
    2026.07.002 run the GitHub release — whose notes link directly to repo1.maven.org — was created
    seven seconds after validation, well before those URLs resolved. The deploy profile now sets
    autoPublish + waitUntil=published with waitMaxTime=3600.

  • Drop the dead OSSRH configuration. The deploy profile configured
    nexus-staging-maven-plugin against s01.oss.sonatype.org, which was retired on 2025-06-30. The
    release log confirms it is vestigial: the actual publishing is done by central-publishing:0.8.0
    inherited from com.devonfw:maven-parent. It is replaced by an explicit central-publishing
    configuration, keeping publishingServerId=repository so the existing
    SONATYPE_USERNAME/SONATYPE_PASSWORD credentials from .mvn/settings.xml continue to apply.

  • Publish the formula from the release. Three new jobs after release:

    • await-central — waits until all four archives are served by repo1 and verifies the
      checksums match the artifacts that were just deployed.
    • verify-homebrew — renders the formula and runs brew audit --strict --online,
      brew install and brew test on macos-latest and macos-15-intel.
    • publish-homebrew — pushes the formula to the tap, only after verification passed, so the tap
      is never left broken.

    Checksums are computed from the archives in cli/target/ that were just deployed — the exact bytes
    Central will serve — so nothing is downloaded to build the formula.

  • Add the missing linux-arm64 download to the release notes. The assembly
    (cli/src/main/assembly/release-linux-arm64.xml) has been built and deployed for a while but was
    listed nowhere.

The tap is checked out with ACTION_PUSH_TOKEN, the same secret already used to push to
devonfw/ide-urls in update-urls.yml and update-cve.yml. If its scope does not cover
devonfw/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 by
the next release. What can be checked before that:

  1. Review the job graph: resolve-versionbuild-nativesreleaseawait-central
    verify-homebrewpublish-homebrew. No job re-derives the version.
  2. mvn -N -Pdeploy validate passes with the new publishing plugin configuration.
  3. In #4: publish the formula synchronously from the IDEasy release homebrew-IDEasy#8, ./wait-for-central.sh 2026.07.002 verifies against the real
    2026.07.002 artifacts, and render-formula.sh rejects the empty-version and empty-checksum
    inputs that produced the stale bot PRs.
  4. At the next release, publish-homebrew must push the new version to the tap, and
    brew update && brew upgrade ideasy must upgrade.

Checklist for this PR

  • When running mvn clean test locally all tests pass and build is successful (no production code touched; mvn -N -Pdeploy validate verified the POM change)
  • PR title is of the form #«issue-id»: «brief summary» (cross-repository form, the issue lives in devonfw/homebrew-IDEasy)
  • PR top-level comment summarizes what has been done and contains link to addressed issue(s)
  • PR and issue(s) have suitable labels
  • Issue is set to In Progress and assigned to you
  • You followed all coding conventions
  • You have added the issue implemented by your PR in CHANGELOG.adoc
  • You have formulated clear instructions on how to test your contribution under "Testing instructions"

Checklist for tool commandlets

Not applicable — no commandlet is added.


Precondition to be aware of when merging

The waitUntil=published change is required for the Homebrew jobs (the formula must not be
published before the URLs it references resolve), but it also changes release timing for everyone:
mvn deploy now blocks until Maven Central reports the deployment as published instead of returning
at 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 instead
of 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.sh and wait-for-central.sh from it.

…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.
@coveralls

coveralls commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 30393724658

Coverage decreased (-0.008%) to 72.585%

Details

  • Coverage decreased (-0.008%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 1 coverage regression across 1 file.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

1 previously-covered line in 1 file lost coverage.

File Lines Losing Coverage Coverage
com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java 1 78.33%

Coverage Stats

Coverage Status
Relevant Lines: 16997
Covered Lines: 12864
Line Coverage: 75.68%
Relevant Branches: 7603
Covered Branches: 4992
Branch Coverage: 65.66%
Branches in Coverage %: Yes
Coverage Strength: 3.21 hits per line

💛 - Coveralls

@maybeec

maybeec commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

Note for the reviewer: what has and has not been executed

verify-homebrew runs brew audit --strict --online plus a real brew install and brew test — a
stricter gate than the tap's own CI, which only checks tap syntax. It has never executed, because
these jobs only run during a release. The same is true for await-central and publish-homebrew.

What has been verified:

  • #4: publish the formula synchronously from the IDEasy release homebrew-IDEasy#8 is green on ubuntu-latest, macos-latest and macos-15-intel,
    including the check that the formula is in sync with its template.
  • wait-for-central.sh was run against the real 2026.07.002 artifacts. The three checksums it
    computed match exactly what the old (broken) auto-update workflow computed on 2026-07-26, and it
    produced the linux-arm64 checksum that has never been part of the formula.
  • render-formula.sh rejects every failure mode behind the stale bot PRs: empty checksum, empty
    version, wrong argument count, uppercase hex.
  • mvn -N -Pdeploy validate passes with the central-publishing configuration.

If you want the release-side path exercised before the next release, the Publish formula
workflow on the tap (workflow_dispatch) runs the same render → verify → publish sequence, sourcing
the checksums from Maven Central instead of from freshly built artifacts. Note that it pushes to the
tap's main, so it is only worth running once devonfw/homebrew-IDEasy#8 is merged.

One deviation worth knowing about

The formula was intended to reference repo1.maven.org directly. Homebrew does not allow it:
FormulaAudit/Urls requires the https://search.maven.org/remotecontent?filepath=... form, and
neither override route is available — a tap level .rubocop.yml is not picked up, and inline
# rubocop:disable directives are rejected by Style/DisableCopsWithinSourceCodeDirective. The
required form was verified to return 301 to repo1.maven.org and to serve byte-identical content.
wait-for-central.sh therefore still checks availability against canonical repo1.maven.org, while
the formula uses the redirecting form that brew audit demands.

@maybeec maybeec moved this from 🆕 New to Team Review in IDEasy board Jul 28, 2026
@maybeec
maybeec requested review from MarvMa, hohwille and laim2003 July 28, 2026 14:19
@maybeec maybeec added release related to release commandlet and releases of IDEasy macOS specific for Apple MacOS workflow GitHub actions (CI,CD,update urls/CVEs) internal Nothing to be added to CHANGELOG, only internal story labels Jul 28, 2026

@hohwille hohwille left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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

Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated
Comment on lines +214 to +294
# 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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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: inherit

Why 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: @main cannot resolve until
    #4: publish the formula synchronously from the IDEasy release homebrew-IDEasy#8 is merged.
  • @main pins 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.

Comment thread CHANGELOG.adoc Outdated
Comment thread pom.xml
@github-project-automation github-project-automation Bot moved this from Team Review to 👀 In review in IDEasy board Jul 28, 2026
@hohwille hohwille added this to the release:2026.08.001 milestone Jul 28, 2026
@hohwille hohwille changed the title devonfw/homebrew-IDEasy#4: publish the Homebrew formula as part of the release #2224: publish the Homebrew formula as part of the release Jul 28, 2026
maybeec and others added 3 commits July 28, 2026 21:20
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal Nothing to be added to CHANGELOG, only internal story macOS specific for Apple MacOS release related to release commandlet and releases of IDEasy workflow GitHub actions (CI,CD,update urls/CVEs)

Projects

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

Brew upgrade ideasy not working

3 participants