CAMEL-23703: camel-launcher - JReleaser packaging and WinGet distribution#24915
Conversation
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 6 tested, 0 compile-only — current: 3 all testedMaveniverse Scalpel detected 6 affected modules (current approach: 3).
|
gnodet
left a comment
There was a problem hiding this comment.
Review Summary
This PR adds JReleaser-driven package distribution for the camel-launcher module, targeting five package managers (Homebrew, SDKMAN, WinGet, Scoop, and Chocolatey). The implementation is thorough and well-engineered, with exceptional attention to error handling, test coverage, and documentation of design decisions. The dual-wrapper approach (POSIX + Windows batch) with parity testing across both platforms is a notable strength.
What I Love
-
Exhaustive inline documentation -- the
jreleaser.ymlheader and the comments throughout both wrapper scripts read like a design document. Every decision is traced back to a confirmed JReleaser behavior, and the rationale for workarounds (the Homebrew AT naming convention, theEnv.template prefix vs-Dproperties, theJAVA_BINARYvsBINARYtype) is anchored to verifiable facts. Future maintainers will thank you for this. -
Defense-in-depth validation chain -- the scripts validate the channel, LTS line (against an allowlist with expiry-date gating), snapshot version rejection, artifact existence, and copy integrity before invoking JReleaser. The test-mode safety guards (
CAMEL_PACKAGE_TEST_MODE=truerequired forCAMEL_PACKAGE_TEST_VERSION) prevent accidental production skips. This level of rigor is uncommon in release tooling scripts. -
Test architecture -- the
PackagePlanTestuses nested@DisabledOnOs(WINDOWS)/@EnabledOnOs(WINDOWS)classes to exercise both wrappers on their native platform, withmvnstubs to isolate JReleaser invocation from the plan logic. The synthetic LTS fixture (supportEnds: "9999-12-31") decouples tests from real LTS calendar dates. The test that deliberately reads the realsupported-lts.ymlfor 4.22 catches accidental deletions. Thoughtful design.
Findings
Important
Scoop autoupdate hash URL may 404 (manifest.json.tpl, autoupdate.hash.url):
The Scoop manifest configures autoupdate hash verification as:
"hash": {
"url": "$url.sha512"
}I verified that Maven Central does not publish .sha512 sidecar files for camel-launcher-4.21.0-bin.zip (returns HTTP 404). Only .sha1 and .md5 are present. This means that when Scoop's checkver -u runs, it will fail to fetch the hash for the new version, breaking auto-update.
Options:
- Use
"url": "$url.sha1"(universally available on Maven Central) - Omit the
hashblock entirely (Scoop will download the artifact and compute the hash itself duringcheckver -u) - Verify that the 4.22.0 release process (via Sonatype Central Portal) will generate
.sha512sidecar files for classified artifacts -- if it will, this is fine for future releases but needs documentation noting it won't work for retroactive verification of pre-4.22 artifacts
Could you confirm which approach is correct here? The Sonatype Central Portal's SHA-512 requirement may apply differently to classified artifacts.
Suggestions
[Suggestion] formula_opt_bin is Homebrew private API (formula.rb.tpl, line in def install):
CAMEL_FALLBACK_JAVA: "#{formula_opt_bin("openjdk")}/java"Homebrew's Ruby API documentation marks formula_opt_bin as private API ("This method is part of a private API. This method may only be used in the Homebrew/brew repository"). While JReleaser's own default JAVA_BINARY template uses this same pattern (so it is a well-established convention), it could break without warning in a future Homebrew release.
The public-API equivalent would be:
CAMEL_FALLBACK_JAVA: "#{Formula["openjdk"].opt_bin}/java"This is not blocking since JReleaser uses this pattern widely and Homebrew has maintained the method for years, but worth being aware of.
[Nit] Unquoted $SNAPSHOT_PATTERN_ARG in camel-package.sh (line ~859):
$SNAPSHOT_PATTERN_ARG \The intentional word-splitting (empty string becomes no argument) is correct behavior, but ShellCheck will flag this. A brief comment like # shellcheck disable=SC2086 -- intentional: empty var must vanish would prevent future contributors from "fixing" it.
[Nit] WinGet manifest schema version (installer.yaml.tpl):
# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.9.0.schema.json
ManifestVersion: 1.9.0Declaring ManifestVersion: 1.9.0 is fine and forward-looking. Just noting it should be verified against what the winget-pkgs community repository currently accepts, since newer schema versions sometimes require fields that older winget validate versions do not enforce.
Critical
None -- nice work!
Questions
[Question] Network dependency in test-mode Homebrew formula patching (camel-package.sh, lines ~912-960):
The test-mode code downloads a known-good release from Maven Central to patch the generated formula. This is a clever approach that exercises a real brew install end-to-end. However, it introduces a hard network dependency -- if Maven Central is unreachable during CI, the packaging validation fails even though the packaging logic itself is correct.
Is this expected to run in CI, or only in manual pre-release validation? If CI, would it make sense to have a fallback (e.g., skip the patch with a warning when Maven Central is unreachable, since the formula content correctness is already validated by the non-network tests)?
Overall
This is a high-quality, well-documented piece of release engineering work. The attention to platform parity, error handling, and test isolation is impressive. The Scoop autoupdate hash URL is the one item I would want confirmed before merge. Everything else is solid and ready.
Claude Code on behalf of gnodet -- AI-generated review
gnodet
left a comment
There was a problem hiding this comment.
Re-review: CAMEL-23703 JReleaser package generation (14 new commits)
This re-review covers the 14 new commits added since the initial review. Every finding from the previous review has been addressed, and the new changes represent a significant improvement in both design and robustness.
What stands out in this iteration
Vote-digest candidate promotion (release-distro.sh + stage-winget-distro.sh): The three-layer verification chain — vote-email digest match, .sha512 self-consistency check, GPG signature verification — is a genuinely strong security design. The insight that the candidate number alone cannot distinguish the approved candidate from a superseded one (each RC carries its own self-consistent .sha512 and .asc) is non-obvious and the digest-based approach solves it cleanly. The test coverage in WingetDistroScriptsTest validates all three failure modes (tampered payload, wrong candidate, missing digest) with fully stubbed dependencies.
Shared assembly content (launcher-content.xml): Extracting the common archive content into a shared component descriptor and having both bin.xml and winget-bin.xml reference it is the right structural choice. The test bothArchivesShareOneContentDefinition ensures this invariant survives future refactoring — a detail that makes this more than just "clean code."
CI defense-in-depth for Maven non-deployment: The CI step that deploys to a throwaway local repo and then fails if any *-winget-bin.zip* file appears is an effective guard against accidental Maven attachment. Combined with attach=false in the assembly execution, this provides two independent layers of protection.
Batch wrapper removal: The removal of camel-package.bat was clean — no remaining references anywhere in the diff, and install.ps1 was properly updated to use camel.bat (architecture-neutral) instead of the native executables for the public archive.
Findings
See inline comments. No blocking issues found.
Scanner coverage
- shellcheck: ran on all
.shfiles. Findings on pre-existing code inrelease-distro.sh(unquoted variables,[ -o ]usage); the new code added by this PR uses proper quoting throughout. One informational note onstage-winget-distro.sh(SC2015:A && B || C) which is safe here sinceusageexits. - gitleaks: ran on all release scripts — no leaks found.
- semgrep, pmd, ast-grep: available but not run (no Java source files with sufficient complexity to warrant it for this review; the test files are well-structured).
Previous review items — status
| Previous finding | Status |
|---|---|
| Scoop autoupdate hash URL may 404 | Fixed — hash key removed from autoupdate block; Scoop computes SHA-256 itself. Test scoopAutoupdateComputesSha256RatherThanReusingTheSha1Sidecar enforces this. |
formula_opt_bin is Homebrew private API |
Acknowledged — still present (was a suggestion, not blocking). |
Claude Code on behalf of gnodet — AI-generated review
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
davsclaus
left a comment
There was a problem hiding this comment.
Claude Code on behalf of Claus Ibsen (davsclaus)
Nice work on this PR — the packaging infrastructure is thorough, well-tested, and security-conscious. A few observations:
Findings
Minor
-
Wildcard import in
PackagePlanTest.java—import java.util.*;will likely be expanded byimpsort:sort, generating an uncommitted change that fails CI. See inline comment. -
supported-lts.ymlonly lists 4.22 — the file only contains line"4.22". Since this drives package distribution (not security patches), this seems intentional, but worth confirming it's not an omission of 4.14/4.18.
Questions
- The
publishsubcommand incamel-package.shreturnsexit 2with "not yet implemented (Phase 5)". Is there a follow-up task tracked? - The
jreleaser.ymlnotes a "KNOWN GAP" about producing both unversioned and versioned Homebrew formulae from a single--channel stable --lts-line X.Yrun. Is a follow-up task filed? - The
jreleaser-plugin-version(1.25.0) is declared as a module-level property rather than centralized. Since<inherited>false</inherited>is set this works fine, but is that intentional?
Strengths
- Thorough test coverage: 31+ tests in
PackagePlanTest, plusWingetDistroScriptsTestwith stubbed svn/gpg/curl - Security-conscious:
attach=falseprevents WinGet ZIP from reaching Maven Central; vote-approved SHA-512 digest guards against promoting a superseded candidate - CI reproducibility gates (build twice, compare SHA-256) and deploy verification
- Clean assembly refactoring via shared
launcher-content.xmlwith test invariants enforcing it - Correct symlink resolution in
camel.cwith proper fallback - Upgrade guide and release guide updates present
This review covers project rules and conventions. It does not replace specialized review tools such as CodeRabbit, Sourcery, or SonarCloud.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
gnodet
left a comment
There was a problem hiding this comment.
New commit d6ea308 (make the repackaged launcher JAR reproducible) looks good — clean follow-up to the PE timestamp pinning.
What works well:
- Root cause is clearly explained in the commit message: the 2-arg
Repackager.repackageleaves last-modified null, which causes both wall-clock entry timestamps and insertion-orderBOOT-INF/libordering. Using the 3-arg overload withparseOutputTimestampfixes both at once. - Using
MavenArchiver.parseBuildOutputTimestampis the canonical Maven API — handles ISO-8601, epoch-seconds, single-char disable convention, andSOURCE_DATE_EPOCHfallback correctly. - Good defensive design:
parseOutputTimestampreturns null when reproducible output is not configured, preserving backward compatibility. - Thorough tests cover all four edge cases (ISO, epoch, unset/disabled, malformed).
- The
testInvalidOutputTimestampFailsLoudlytest documents an important invariant — a malformed value must fail rather than silently degrading to non-reproducible output. - Workflow enhancement (diffing
unzip -voutput) is a nice diagnostic improvement for distinguishing content changes from timestamp changes.
LGTM ✅
Claude Code on behalf of gnodet — AI-generated review
gnodet
left a comment
There was a problem hiding this comment.
New commit 422afeb (replace placeholder repackager tests with real ones) is a significant quality improvement — well done.
What's great:
- The old tests were all `assertTrue(true, "Placeholder test")` — now they create actual repackaged JARs and verify real invariants:
- Structure: BOOT-INF/classes, BOOT-INF/lib, root loader classes all present
- Manifest: Main-Class = JarLauncher, Start-Class = CamelLauncher (swapping these produces a silently broken JAR)
- Dependency filtering: compile-scope included, test-scope excluded, native exe excluded
- Reproducibility: two runs produce byte-identical output — the most important invariant given this PR's theme
- The `writeJar()` fixture uses fixed entry times (`FIXED_ENTRY_TIME`) so the test fixture itself can't introduce the non-determinism the reproducibility test is checking for — good attention to detail.
- The workflow fix (installing `camel-repackager-maven-plugin` before the launcher build) is a real correctness improvement — without it, changes to the plugin in the same PR would be silently ignored because Maven resolves the plugin from the snapshot repo.
- Enhanced diagnostic: on mismatch, now also unpacks the launcher JAR from both builds and diffs entries one level deeper.
- Using `protected` instead of `private` on mojo fields is the standard Maven plugin testing pattern.
LGTM ✅
Claude Code on behalf of gnodet — AI-generated review
…ackagers Add jreleaser.yml and camel-package.sh/.bat, driving Homebrew, SDKMAN, WinGet, Scoop, and Chocolatey distribution from a channel-plan + supported-LTS allowlist. Stages the website installer output (install.sh, install.ps1, release manifest) alongside the packages. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… findings - Remove stale supported-lts.yml "4.18" entry (package-manager LTS support starts at 4.22) - Add CAMEL_PACKAGE_TEST_SUPPORTED_LTS test override so LTS-expiry tests are decoupled from real production supportEnds dates (mirrors CAMEL_PACKAGE_TEST_VERSION), and cover the previously-untested "line found but expired" rejection branch - Fail loudly instead of silently succeeding when the LTS Homebrew-formula rename step finds zero generated .rb files (sh and bat) - Replace deprecated wmic date lookup in camel-package.bat with PowerShell, and hard-fail if the resolved date is empty/malformed instead of silently skipping the LTS expiry check - Correct jreleaser.yml NOTE and README.md docs that no longer matched shipped behavior (unpinned openjdk dependency, ARM64 Chocolatey handling, Windows camel.bat usage) - Gate the Homebrew test-mode formula patch (and the JReleaser snapshot-pattern override) on CAMEL_PACKAGE_TEST_VERSION in addition to CAMEL_PACKAGE_TEST_MODE, so a genuine release run can never silently repoint the generated formula at a different already-published version, and JReleaser keeps its own snapshot guard on real releases - camel-package.bat: fail loudly when `mvn evaluate` yields no project.version (reset the variable, then check errorlevel and empty), and when the formula rename `move` fails, matching the sh script's set -e behavior - Distinguish a missing/malformed supported-lts.yml from an unknown LTS line in both wrappers, with a dedicated test - Chocolatey/Scoop native-exe removal: use -ErrorAction Stop behind a Test-Path guard instead of -ErrorAction SilentlyContinue, so a failed removal fails loudly rather than leaving a stray exe shimmed on PATH - Scoop manifest checkver/autoupdate: point at Maven Central metadata and the real artifact name instead of unset JReleaser template placeholders - Note in camel-package.bat that the Homebrew test-mode patch is intentionally POSIX-only (Homebrew validation runs on macOS/Linux) - Soften "empirically confirmed"/version-pinned comments to reference the pinned JReleaser plugin version, and fix the openjdk-dependency rationale to reflect that formula.rb.tpl declares depends_on explicitly - Add tests covering the LTS Homebrew formula rename, the test-mode formula-patch gate, malformed LTS metadata, the documented 4.22 support window, and stronger assertions on the JReleaser goal/packager/snapshot-pattern invocation Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fold the standalone "Chocolatey ARM64" README section into the "Native bootstrap executables" paragraph, and drop the imprecise "native ARM64 support not available" / "works without emulation" wording. choco#1803 tracks per-architecture declaration in Chocolatey's packaging framework (so a package cannot ship and auto-select per-arch native exes the way WinGet does), not whether camel.bat runs on ARM64 (it does). Align the chocolateyinstall.ps1.tpl comment with the same precise wording. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
The include-camel-exe and build-native-exe profiles activate on the camel.exe.build property, and the release profile sets it in <properties>. Maven's property activator only reads user and system properties, so a profile that sets a property cannot activate profiles keyed on it. Verified with help:active-profiles: under -Prelease alone neither profile is active. A release therefore built no native Windows executables and no WinGet payload at all, so the staging step in the release guide could never find camel-launcher-<version>-winget-bin.zip. Pass -Dcamel.exe.build=true as a real user property via maven-release-plugin's <arguments>, and correct the two comments and the upgrade-guide sentence that claimed -Prelease was sufficient on its own. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Found by invoking jreleaser:config/prepare/package locally in dry-run, which nothing had done before: every test stubs mvn, so none of these were reachable by the existing suite. jreleaser.yml: the second project icon declared a url with no width or height. JReleaser rejects that, so jreleaser:config failed outright and camel-package.sh prepare died at its first JReleaser goal. Templates: JReleaser HTML-escapes double-brace placeholders, rewriting the "=" in the Homebrew redirector's "?filepath=" as "&apache#61;" and producing a URL brew cannot download. Render URLs with the triple-brace unescaped form. Only Homebrew was affected today, but the other packagers use the same form so a future query parameter cannot silently break them. Scoop: drop autoupdate.hash. Maven Central publishes only a SHA-1 sidecar for these artifacts (.sha256 and .sha512 both 404), so pointing autoupdate at one would downgrade future versions from the pinned SHA-256 to SHA-1. Without it Scoop downloads the artifact and computes SHA-256 itself. camel-package.sh: a value-taking option with no value hit `shift 2` with one argument left, which fails under `set -e` and killed the script with a bare exit 1 and no message. Report the usage error instead. Treat a missing Homebrew formula directory on the LTS path as an error rather than skipping the rename, which would otherwise ship JReleaser's kebab-cased filename. Delete the test-mode block that rewrote the generated formula's url, version and sha256: it supported a camel-validate.sh that was never written, nothing invoked it, and it put network fetches and sed rewriting of a release artifact into the release path. camel.c: fall back to the module path when symlink resolution fails, so a directly-invoked exe still finds camel.bat instead of failing outright. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every dist/dev candidate carries its own self-consistent .sha512 and .asc, so exporting rc3 when the vote approved rc4 passed both checks and silently promoted a superseded payload to dist/release. The candidate number cannot distinguish them; only the digest published with the vote can. release-distro.sh now takes the approved SHA-512 as a fourth argument, mandatory whenever a candidate number is given, and aborts if the exported ZIP does not match. The check runs before the sidecar and signature verification so the error names the real problem rather than sending the release manager after a signature that was never broken. stage-winget-distro.sh prints the digest for the vote email, and honours CAMEL_GPG_KEY for release managers holding more than one key (the equivalent of maven-gpg-plugin's gpg.keyname). The workflow's Maven-exclusion gate matched only the ZIP and its .sha1; match every sidecar so a leaked .asc or .md5 is caught too. WingetDistroScriptsTest now drives release-distro.sh against stubbed wget/svn/gpg rather than asserting on its source text, covering promotion of the approved candidate, a tampered payload, a superseded candidate, and a missing digest. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
bin.xml and winget-bin.xml were near-duplicates differing only by the tar.gz format and one fileSet. The two archives must deliver the same CLI, so a file added to one could silently go missing from the other. Move the shared dependencySet and fileSets into launcher-content.xml and reference it from both descriptors, leaving each with only its id, formats and, for WinGet, the native executables. Verified behaviour-preserving: the public archive's entry list is byte-identical before and after, and the WinGet archive differs from it by exactly bin/camel-x64.exe and bin/camel-arm64.exe. PackagePlanTest: replace assertions that matched substrings in pom.xml, jreleaser.yml, the assembly descriptors and a GitHub workflow with structural XML, YAML and JSON parsing, so reformatting cannot break a test while a real content change slips through. Includes resolve through the shared component, so they describe what each archive carries rather than which file declares it. Drop the assertion that compared two hardcoded dates, which could never fail, in favour of running the wrapper against every line the production allowlist advertises: that starts failing when an LTS line's support window lapses, which is the intended signal. Drop the test asserting the workflow file's contents and the one asserting the wrapper's shebang; CI running is the verification for the former, and fifteen execution tests cover the latter. Remove the agent planning and design documents committed under docs/, which is the Antora source tree and not a home for working notes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Codex <noreply@openai.com>
The PE format carries a mandatory TimeDateStamp, and lld fills it with the current wall-clock time unless told otherwise. Two identical builds therefore produced byte-different executables, and the difference propagated into the WinGet archive whose SHA-256 is published in the manifest and voted on during the release. Pass -Wl,--no-insert-timestamp to both cross-compiles. Also stash the first-build executables before the reproducibility check runs 'clean verify', so a future mismatch reports the differing byte offsets rather than a bare FAILED. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RepackageMojo called the two-argument Repackager.repackage, which leaves the last-modified time null. That null drives two separate mechanisms in Spring Boot's packager: every entry is stamped with the current wall-clock time, and BOOT-INF/lib falls back to a LinkedHashMap ordered by the dependency set's iteration order rather than a sorted TreeMap. Consecutive builds of the same source therefore produced different JARs, and the JAR is the payload of the WinGet archive whose SHA-256 is published in the manifest and voted on during the release. Pass the pinned project.build.outputTimestamp instead, read through maven-archiver's parseBuildOutputTimestamp so the ISO-8601 and epoch-second forms and the SOURCE_DATE_EPOCH fallback all behave as Maven documents them. The three-argument overload is @SInCE 4.0.0, so this only became available with the recent Spring Boot upgrade. Also extend the workflow's reproducibility diagnostic to diff the WinGet archive's entry listing, which distinguishes changed content from a changed timestamp. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RepackageMojoTest carried three tests that asserted assertTrue(true) with a comment describing what they would check one day. They could not fail, so they reported coverage over exactly the JAR structure this branch is changing. Drive the mojo over a staged source JAR instead and assert the properties that matter: application classes under BOOT-INF/classes, dependencies under BOOT-INF/lib, loader classes at the root, Main-Class pointing at the loader with Start-Class pointing at the application, and the scope filter holding at the packaged output rather than only at includeArtifact. Mojo fields become protected so the test can set them, matching how EndpointSchemaGeneratorMojoTest drives its mojo. Two findings worth recording. Spring Boot adds spring-boot-jarmode-tools to BOOT-INF/lib on its own, so the launcher ships it today; the test asserts around it rather than silently encoding it as intended. And testRepackagingIsReproducible still passes when the outputTimestamp fix is reverted: with a null time Spring Boot derives each nested library's entry time from that library's first entry, which the fixture pins, so the fixture cannot reproduce the real conditions. The reproducibility fix therefore remains unproven by unit test. Also make the workflow install camel-repackager-maven-plugin before the launcher build. It is outside the -pl list, so the job was resolving it from the Apache snapshot repository and never exercising the change, and extend the failure diagnostic to diff the launcher JAR's own entry listing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
bin.xml and winget-bin.xml were near-duplicates differing only by the tar.gz format and one fileSet. The two archives must deliver the same CLI, so a file added to one could silently go missing from the other. Move the shared dependencySet and fileSets into launcher-content.xml and reference it from both descriptors, leaving each with only its id, formats and, for WinGet, the native executables. Verified behaviour-preserving: the public archive's entry list is byte-identical before and after, and the WinGet archive differs from it by exactly bin/camel-x64.exe and bin/camel-arm64.exe. PackagePlanTest: replace assertions that matched substrings in pom.xml, jreleaser.yml, the assembly descriptors and a GitHub workflow with structural XML, YAML and JSON parsing, so reformatting cannot break a test while a real content change slips through. Includes resolve through the shared component, so they describe what each archive carries rather than which file declares it. Drop the assertion that compared two hardcoded dates, which could never fail, in favour of running the wrapper against every line the production allowlist advertises: that starts failing when an LTS line's support window lapses, which is the intended signal. Drop the test asserting the workflow file's contents and the one asserting the wrapper's shebang; CI running is the verification for the former, and fifteen execution tests cover the latter. Remove the agent planning and design documents committed under docs/, which is the Antora source tree and not a home for working notes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
422afeb to
cea612f
Compare
Batch mode (-B) avoids interactive-mode ANSI/progress noise in CI logs for the exe-build and installation steps that were missing it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The "Phase 5" references were tracked only in local notes, not on any public tracker, and read like a scheduled implementation phase rather than what they actually are: publish is blocked on the Apache Camel PMC deciding where each packager's artifacts should go (e.g. Homebrew to this project's own tap vs. homebrew-core). The Homebrew dual-formula gap is blocked on that same decision, not a separate follow-up. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Claude Code on behalf of Adriano Machado (ammachado) Replying to @davsclaus's review:
Pushed as two commits: batch-mode ( |
gnodet
left a comment
There was a problem hiding this comment.
New commit 1f0f9e17f602 reviewed — good cleanup. Replacing the opaque "Phase 5" references with the actual blocking reason (PMC publish-destination decision) makes the codebase much more readable for contributors who weren't part of the original planning.
Comment/documentation-only changes — prior approval still applies.
Claude Code on behalf of gnodet — AI-generated review
|
Status update on the pieces of CAMEL-23703:
Not yet started:
Claude Code on behalf of Adriano Machado (ammachado) |
|
LGTM |
Description
Adds JReleaser-driven package distribution for the
camel-launchermodule, generating installable packages for five package managers: Homebrew, SDKMAN, WinGet, Scoop, and Chocolatey.Packaging
jreleaser.ymlconfigures the distribution definitions, with custom templates undersrc/jreleaser/distributions/camel-cli/<packager>/.src/jreleaser/bin/camel-package.shis the single entry point, wrapping the JReleaser Maven plugin and mapping a release channel (stable/lts) onto a packager set, a Homebrew formula name, and the website manifests.<inherited>false</inherited>and bound to no lifecycle phase, so ordinary Camel builds neither prepare nor publish packages; only the wrapper invokes its goals.search.maven.org/remotecontentredirector required by Homebrew'sFormulaAudit::Urlsrubocop rather thanrepo1.maven.org. All template URLs render through Mustache's unescaped triple-brace form, because the escaping form rewrites the=in?filepath=as=and yields a URLbrewcannot download.license-maven-pluginexcludes cover the new.tpltemplates, whose extension has no comment-style mapping (and JSON has no comment syntax at all); each exclude is documented inline in the pom.camel-package.sh publishis intentionally unimplemented: it exits with an error rather than defaulting a destination, because which target each packager's artifacts should be pushed to (e.g. Homebrew's own tap vs.homebrew-core) is a decision for the Apache Camel PMC, not something the script should decide on its own. The Homebrew dual-formula gap noted injreleaser.ymlis blocked on that same decision.WinGet payload
WinGet's portable installer type creates a symlink named
camel.exe, which cannot be backed by a.bat.tooling/camel-execross-compiles two small native bootstraps that resolve that symlink, locatecamel.batbeside the target, and forward the command line. Scoop and Chocolatey need no such binary and enter throughcamel.bat.camel-launcher-<version>-winget-bin.zip. The public-bin.zip/-bin.tar.gzno longer carry them.attach=false, so Maven never installs or deploys it. It is released through the Apache distribution archive instead:etc/scripts/stage-winget-distro.shstages a signed, checksummed candidate underdist/devfor the vote, andetc/scripts/release-distro.shpromotes the approved bytes unchanged todist/release..sha512and.asc, so the candidate number alone cannot distinguish an approved candidate from a superseded one.camel-package.shdownloads the archived payload and refuses to proceed unless it is byte-identical to the local one.launcher-content.xml), so the WinGet package cannot silently diverge from the published archive.1.12.0, preventing JReleaser's embedded1.9.0templates from producing an invalid mixed-version manifest set.CI gates
The native-exe workflow builds twice from clean output directories and compares SHA-256 of both executables and the WinGet archive, then deploys the reactor to a throwaway repository and fails if the WinGet payload or any of its sidecars appears there. Reproducibility required pinning the PE
TimeDateStamp: it is a mandatory header field that lld fills with the current wall-clock time, so both cross-compiles pass-Wl,--no-insert-timestamp. Without it every build is byte-different and the archive SHA-256 published in the WinGet manifest cannot be independently regenerated by anyone verifying the release.The launcher JAR itself needed a separate reproducibility fix, since it is the payload inside that same archive.
RepackageMojocalled Spring Boot's two-argumentrepackage, which leaves the last-modified time null; Spring Boot's packager then stamps every entry with the current wall-clock time and falls back to an unorderedBOOT-INF/libinstead of a sorted one.RepackageMojonow passes through the pinnedproject.build.outputTimestamp.RepackageMojoTest's three placeholderassertTrue(true)cases were replaced with real assertions over the packaged JAR's structure (BOOT-INF/classes,BOOT-INF/lib, loader classes, manifest entries), though the reproducibility fix itself remains unproven by unit test since the fixture pins each library's first-entry time regardless of the fix.Verification
Beyond the unit tests,
jreleaser:config,jreleaser:prepareandjreleaser:packagewere run locally in dry-run for both channels and the generated output inspected: all three WinGet manifests at schema1.12.0, both installer architectures resolving from one archive and checksum, the Homebrew formula for the unversioned and versioned cases, and the Scoop and Chocolatey manifests. Assembly changes were checked by diffing the archive entry list before and after. The completePackagePlanTestclass passes with 31 tests and none skipped.Open questions for reviewers
apache.orghost and covered by its own vote? If not, the WinGet archive could collapse back into the public one and thedist/devstaging step would go away.cmd.exe?This is part 3 of the split of the original CAMEL-23703 unified Camel CLI packaging work (see #24682, #24754, #24665, #24664). It targets
apache/camelmainand does not depend on unmerged content from any other part of the split.Target
mainbranch)Tracking
Apache Camel coding standards and style
mvn clean install -DskipTestslocally from root folder and I have committed all auto-generated changes.AI-assisted contributions
Co-authored-bytrailers) and the PR description identifies the AI tool used.AI-assisted by Claude Code and Codex on behalf of Adriano Machado (ammachado).