From a44e1d2d4e558df8f50117810be545e0d94d8081 Mon Sep 17 00:00:00 2001 From: Niels Pardon Date: Mon, 6 Jul 2026 16:30:48 +0200 Subject: [PATCH 1/3] fix(ci): pin semantic-release tooling and restore v0.95.0 notes --- .releaserc.json | 65 ------------------- .releaserc.mjs | 148 ++++++++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 57 ++++++++++++++++ ci/release/dry_run.sh | 22 +++---- ci/release/run.sh | 18 ++--- 5 files changed, 223 insertions(+), 87 deletions(-) delete mode 100644 .releaserc.json create mode 100644 .releaserc.mjs diff --git a/.releaserc.json b/.releaserc.json deleted file mode 100644 index 5b6afd807..000000000 --- a/.releaserc.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "branches": [ - { "name": "+([0-9])?(.{+([0-9]),x}).x" }, - { "name": "main" }, - { "name": "next" }, - { "name": "next-major" }, - { "name": "beta", "prerelease": true }, - { "name": "alpha", "prerelease": true } - ], - "preset": "conventionalcommits", - "plugins": [ - "@semantic-release/release-notes-generator", - [ - "@semantic-release/commit-analyzer", - { - "releaseRules": [ - {"breaking": true, "release": "minor"} - ] - } - ], - [ - "@semantic-release/exec", - { - "verifyConditionsCmd": "ci/release/verify.sh", - "prepareCmd": "ci/release/prepare.sh ${nextRelease.version}", - "publishCmd": "ci/release/publish.sh" - } - ], - [ - "@semantic-release/changelog", - { - "changelogTitle": "Release Notes\n---", - "changelogFile": "CHANGELOG.md" - } - ], - [ - "@semantic-release/github", - { - "assets": [ - { - "path": "native/libs/isthmus-macOS-latest", - "name": "isthmus-macOS-${nextRelease.version}", - "label": "Isthmus Native Image - macOS" - }, - { - "path": "native/libs/isthmus-ubuntu-latest", - "name": "isthmus-ubuntu-${nextRelease.version}", - "label": "Isthmus Native Image - Linux" - } - ], - "successComment": false - } - ], - [ - "@semantic-release/git", - { - "assets": [ - "gradle.properties", - "CHANGELOG.md" - ], - "message": "chore(release): ${nextRelease.version}" - } - ] - ] -} diff --git a/.releaserc.mjs b/.releaserc.mjs new file mode 100644 index 000000000..65f87aefa --- /dev/null +++ b/.releaserc.mjs @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// semantic-release configuration. +// +// This is an ESM (.mjs) config rather than .releaserc.json because the +// release-notes-generator needs a `writerOpts.transform` function to strip git +// trailers (e.g. `Signed-off-by:`) that the conventional-commits parser folds +// into `BREAKING CHANGE` notes. JSON cannot carry functions. +// +// This config defaults to a dry run as a fail-safe: the publishing plugins +// (@semantic-release/github, @semantic-release/git) and the verify/publish exec +// commands are only included when RELEASE_DRY_RUN=false. ci/release/run.sh opts +// in to a real release that way; every other invocation stays harmless. + +import { createRequire } from "node:module"; +import { pathToFileURL } from "node:url"; + +const loadPreset = async () => { + try { + return (await import("conventional-changelog-conventionalcommits")).default; + } catch { + const require = createRequire(pathToFileURL(process.argv[1])); + const resolved = pathToFileURL( + require.resolve("conventional-changelog-conventionalcommits") + ).href; + return (await import(resolved)).default; + } +}; +const conventionalcommits = await loadPreset(); + +const TRAILER_KEYS = [ + "Signed-off-by", + "Co-authored-by", + "Co-developed-by", + "Reviewed-by", + "Acked-by", + "Tested-by", + "Reported-by", + "Suggested-by", + "Helped-by", + "Cc", +]; +const TRAILER = new RegExp(`^(?:${TRAILER_KEYS.join("|")}):\\s`, "i"); + +const stripTrailers = (text) => { + if (!text) { + return text; + } + + const lines = text.split("\n"); + while (lines.length) { + const last = lines[lines.length - 1].trim(); + if (last === "" || TRAILER.test(last)) { + lines.pop(); + } else { + break; + } + } + return lines.join("\n"); +}; + +const preset = await conventionalcommits(); +const presetTransform = preset.writer.transform; +const dryRun = process.env.RELEASE_DRY_RUN !== "false"; + +export default { + branches: [ + { name: "+([0-9])?(.{+([0-9]),x}).x" }, + { name: "main" }, + { name: "next" }, + { name: "next-major" }, + { name: "beta", prerelease: true }, + { name: "alpha", prerelease: true }, + ], + preset: "conventionalcommits", + dryRun, + plugins: [ + [ + "@semantic-release/release-notes-generator", + { + writerOpts: { + transform(commit, context) { + const out = presetTransform(commit, context); + if (out && Array.isArray(out.notes)) { + out.notes = out.notes.map((note) => ({ + ...note, + text: stripTrailers(note.text), + })); + } + return out; + }, + }, + }, + ], + [ + "@semantic-release/commit-analyzer", + { + releaseRules: [{ breaking: true, release: "minor" }], + }, + ], + [ + "@semantic-release/exec", + dryRun + ? {} + : { + verifyConditionsCmd: "ci/release/verify.sh", + prepareCmd: "ci/release/prepare.sh ${nextRelease.version}", + publishCmd: "ci/release/publish.sh", + }, + ], + [ + "@semantic-release/changelog", + { + changelogTitle: "Release Notes\n---", + changelogFile: "CHANGELOG.md", + }, + ], + ...(dryRun + ? [] + : [ + [ + "@semantic-release/github", + { + assets: [ + { + path: "native/libs/isthmus-macOS-latest", + name: "isthmus-macOS-${nextRelease.version}", + label: "Isthmus Native Image - macOS", + }, + { + path: "native/libs/isthmus-ubuntu-latest", + name: "isthmus-ubuntu-${nextRelease.version}", + label: "Isthmus Native Image - Linux", + }, + ], + successComment: false, + }, + ], + [ + "@semantic-release/git", + { + assets: ["gradle.properties", "CHANGELOG.md"], + message: "chore(release): ${nextRelease.version}", + }, + ], + ]), + ], +}; diff --git a/CHANGELOG.md b/CHANGELOG.md index d1e315091..7c6ec4ca1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,63 @@ Release Notes ## [0.95.0](https://github.com/substrait-io/substrait-java/compare/v0.94.0...v0.95.0) (2026-07-05) +### ⚠ BREAKING CHANGES + +* **core:** remove deprecated Time, Timestamp, TimestampTZ types and literals (#950) +* **deps:** Protobuf bindings are now generated using the v4 +protobuf libraries, released in March 2024. Ensure that dependent +projects also use the v4 protobuf-java libraries, and be aware of the +breaking changes within the protobuf-java APIs documented at +https://protobuf.dev/news/v26/#java-breaking-changes + +### Features + +* **core:** add Substrait dialect support ([#861](https://github.com/substrait-io/substrait-java/issues/861)) ([ff76c77](https://github.com/substrait-io/substrait-java/commit/ff76c771d37f644ee57c77c7db0eb061804126f5)) +* **core:** remove deprecated Time, Timestamp, TimestampTZ types and literals ([#950](https://github.com/substrait-io/substrait-java/issues/950)) ([71b940f](https://github.com/substrait-io/substrait-java/commit/71b940f94fcd711603d1cfbafb9a2002ea5fd0f5)) +* **isthmus:** map execution context variables to/from Calcite ([#976](https://github.com/substrait-io/substrait-java/issues/976)) ([08c2889](https://github.com/substrait-io/substrait-java/commit/08c2889e675bb51ef6b5d39b8c9ed1e3811a474b)) + +### Bug Fixes + +* **core:** add compiled output to javadocImmutable classpath ([#953](https://github.com/substrait-io/substrait-java/issues/953)) ([1d3ea51](https://github.com/substrait-io/substrait-java/commit/1d3ea51537ee6b3e944ae6db96d014ef15e37c41)) +* **core:** validate Plan.Root output name count ([#812](https://github.com/substrait-io/substrait-java/issues/812)) ([4bd6b69](https://github.com/substrait-io/substrait-java/commit/4bd6b69ce535098da82d1ae33d6e2cfd78c62e78)) +* **isthmus:** avoid NPE from dangling correlations left by partial decorrelation ([fbf2930](https://github.com/substrait-io/substrait-java/commit/fbf2930ce575a47a643940f3f5bcd89474dab3cc)) +* **isthmus:** handle LITERAL_AGG in aggregate conversion ([52a32ba](https://github.com/substrait-io/substrait-java/commit/52a32bad575da67031ddd4e44caddeef641b9ed5)) +* **isthmus:** use reachability-metadata.json for native image build ([#979](https://github.com/substrait-io/substrait-java/issues/979)) ([a1e48c6](https://github.com/substrait-io/substrait-java/commit/a1e48c6b4d38b5ec8750b1918263c35bc1a83dc0)) +* **isthmus:** use Substrait type system when building Calcite RelBuilder ([#973](https://github.com/substrait-io/substrait-java/issues/973)) ([b370df5](https://github.com/substrait-io/substrait-java/commit/b370df50b8f35e802be3e78d3e5f87303b2e7517)), closes [#954](https://github.com/substrait-io/substrait-java/issues/954) [#955](https://github.com/substrait-io/substrait-java/issues/955) + +### Build System + +* **deps:** update protobuf from v3 to v4 ([#962](https://github.com/substrait-io/substrait-java/issues/962)) ([1516209](https://github.com/substrait-io/substrait-java/commit/1516209dd1c6801082a4a04649b5da79af4e0a1b)) + +### ⚠ BREAKING CHANGES + +* **core:** remove deprecated Time, Timestamp, TimestampTZ types and literals (#950) +* **deps:** Protobuf bindings are now generated using the v4 +protobuf libraries, released in March 2024. Ensure that dependent +projects also use the v4 protobuf-java libraries, and be aware of the +breaking changes within the protobuf-java APIs documented at +https://protobuf.dev/news/v26/#java-breaking-changes + +### Features + +* **core:** add Substrait dialect support ([#861](https://github.com/substrait-io/substrait-java/issues/861)) ([ff76c77](https://github.com/substrait-io/substrait-java/commit/ff76c771d37f644ee57c77c7db0eb061804126f5)) +* **core:** remove deprecated Time, Timestamp, TimestampTZ types and literals ([#950](https://github.com/substrait-io/substrait-java/issues/950)) ([71b940f](https://github.com/substrait-io/substrait-java/commit/71b940f94fcd711603d1cfbafb9a2002ea5fd0f5)) +* **isthmus:** map execution context variables to/from Calcite ([#976](https://github.com/substrait-io/substrait-java/issues/976)) ([08c2889](https://github.com/substrait-io/substrait-java/commit/08c2889e675bb51ef6b5d39b8c9ed1e3811a474b)) + +### Bug Fixes + +* **core:** add compiled output to javadocImmutable classpath ([#953](https://github.com/substrait-io/substrait-java/issues/953)) ([1d3ea51](https://github.com/substrait-io/substrait-java/commit/1d3ea51537ee6b3e944ae6db96d014ef15e37c41)) +* **core:** validate Plan.Root output name count ([#812](https://github.com/substrait-io/substrait-java/issues/812)) ([4bd6b69](https://github.com/substrait-io/substrait-java/commit/4bd6b69ce535098da82d1ae33d6e2cfd78c62e78)) +* **isthmus:** avoid NPE from dangling correlations left by partial decorrelation ([fbf2930](https://github.com/substrait-io/substrait-java/commit/fbf2930ce575a47a643940f3f5bcd89474dab3cc)) +* **isthmus:** handle LITERAL_AGG in aggregate conversion ([52a32ba](https://github.com/substrait-io/substrait-java/commit/52a32bad575da67031ddd4e44caddeef641b9ed5)) +* **isthmus:** use reachability-metadata.json for native image build ([#979](https://github.com/substrait-io/substrait-java/issues/979)) ([a1e48c6](https://github.com/substrait-io/substrait-java/commit/a1e48c6b4d38b5ec8750b1918263c35bc1a83dc0)) +* **isthmus:** use Substrait type system when building Calcite RelBuilder ([#973](https://github.com/substrait-io/substrait-java/issues/973)) ([b370df5](https://github.com/substrait-io/substrait-java/commit/b370df50b8f35e802be3e78d3e5f87303b2e7517)), closes [#954](https://github.com/substrait-io/substrait-java/issues/954) [#955](https://github.com/substrait-io/substrait-java/issues/955) + +### Build System + +* **deps:** update protobuf from v3 to v4 ([#962](https://github.com/substrait-io/substrait-java/issues/962)) ([1516209](https://github.com/substrait-io/substrait-java/commit/1516209dd1c6801082a4a04649b5da79af4e0a1b)) + + ## [0.94.0](https://github.com/substrait-io/substrait-java/compare/v0.93.0...v0.94.0) (2026-06-21) ### Features diff --git a/ci/release/dry_run.sh b/ci/release/dry_run.sh index 238c57b25..84c17e7ee 100755 --- a/ci/release/dry_run.sh +++ b/ci/release/dry_run.sh @@ -21,23 +21,19 @@ trap cleanup EXIT ERR cd "$worktree" || exit 1 export GITHUB_REF="$branch" +export RELEASE_DRY_RUN=true npx --yes \ - -p semantic-release \ - -p "@semantic-release/commit-analyzer" \ - -p "@semantic-release/release-notes-generator" \ - -p "@semantic-release/changelog" \ - -p "@semantic-release/exec" \ - -p "@semantic-release/git" \ - -p "conventional-changelog-conventionalcommits" \ + -p "semantic-release@25.0.5" \ + -p "@semantic-release/commit-analyzer@13.0.1" \ + -p "@semantic-release/release-notes-generator@14.1.1" \ + -p "@semantic-release/changelog@7.0.0-beta.1" \ + -p "@semantic-release/github@12.0.8" \ + -p "@semantic-release/exec@7.1.0" \ + -p "@semantic-release/git@10.0.1" \ + -p "conventional-changelog-conventionalcommits@9.3.1" \ semantic-release \ --ci false \ --dry-run \ - --preset conventionalcommits \ - --plugins \ - --analyze-commits "@semantic-release/commit-analyzer" \ - --generate-notes "@semantic-release/release-notes-generator" \ - --verify-conditions "@semantic-release/changelog,@semantic-release/exec,@semantic-release/git" \ - --prepare "@semantic-release/changelog,@semantic-release/exec" \ --branches "$branch" \ --repository-url "file://$PWD" diff --git a/ci/release/run.sh b/ci/release/run.sh index 438e00c77..5319b2e93 100755 --- a/ci/release/run.sh +++ b/ci/release/run.sh @@ -3,13 +3,13 @@ set -euo pipefail -npx --yes \ - -p semantic-release \ - -p "@semantic-release/commit-analyzer" \ - -p "@semantic-release/release-notes-generator" \ - -p "@semantic-release/changelog" \ - -p "@semantic-release/github" \ - -p "@semantic-release/exec" \ - -p "@semantic-release/git" \ - -p "conventional-changelog-conventionalcommits" \ +RELEASE_DRY_RUN=false npx --yes \ + -p "semantic-release@25.0.5" \ + -p "@semantic-release/commit-analyzer@13.0.1" \ + -p "@semantic-release/release-notes-generator@14.1.1" \ + -p "@semantic-release/changelog@7.0.0-beta.1" \ + -p "@semantic-release/github@12.0.8" \ + -p "@semantic-release/exec@7.1.0" \ + -p "@semantic-release/git@10.0.1" \ + -p "conventional-changelog-conventionalcommits@9.3.1" \ semantic-release --ci From e5c53daa5289358aae5c606b23a860beae36a603 Mon Sep 17 00:00:00 2001 From: Niels Pardon Date: Fri, 10 Jul 2026 18:00:01 +0200 Subject: [PATCH 2/3] fix(ci): pin changelog plugin to stable 6.0.3 and document release config Address review feedback on the semantic-release config: - pin @semantic-release/changelog to the stable 6.0.3 (latest, peer semantic-release >=18.0.0) instead of 7.0.0-beta.1; there is no functional reason for the prerelease. Validated with a dry run. - restore the explanatory comments that were dropped when the config was ported from the spec repo: why the preset import needs the npx temp-node_modules fallback, and why the publishing plugins are omitted via RELEASE_DRY_RUN rather than guarded by --dry-run (semantic-release still runs verifyConditions in dry-run mode, so @semantic-release/github would fail without a token). Corrected the dry-run description, which wrongly claimed dry-run skips only tag and push. --- .releaserc.mjs | 26 ++++++++++++++++++++++++-- ci/release/dry_run.sh | 2 +- ci/release/run.sh | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/.releaserc.mjs b/.releaserc.mjs index 65f87aefa..625d54bbc 100644 --- a/.releaserc.mjs +++ b/.releaserc.mjs @@ -8,13 +8,28 @@ // into `BREAKING CHANGE` notes. JSON cannot carry functions. // // This config defaults to a dry run as a fail-safe: the publishing plugins -// (@semantic-release/github, @semantic-release/git) and the verify/publish exec +// (@semantic-release/github, @semantic-release/git) and the exec verify/publish // commands are only included when RELEASE_DRY_RUN=false. ci/release/run.sh opts -// in to a real release that way; every other invocation stays harmless. +// in to a real release that way; every other invocation -- including a typo'd or +// forgotten env var -- stays harmless. +// +// The env var is needed on top of --dry-run because --dry-run alone is not +// enough: semantic-release still runs every plugin's verifyConditions step in +// dry-run mode (it skips only prepare, publish, addChannel, success and fail). +// @semantic-release/github's verifyConditions fails without a GITHUB_TOKEN, so +// the side-effecting plugins must be omitted entirely, not merely guarded by +// --dry-run, to allow a credential-free dry run. import { createRequire } from "node:module"; import { pathToFileURL } from "node:url"; +// Load the conventionalcommits preset. The release scripts run semantic-release +// via `npx -p ...`, which installs the preset alongside semantic-release in a +// temporary node_modules. A bare `import` here would resolve relative to this +// config file's directory (the repo, which has no node_modules) and fail, so +// fall back to resolving the preset relative to the running semantic-release +// binary (process.argv[1]). The plain import still covers local dev where the +// preset is installed alongside the project. const loadPreset = async () => { try { return (await import("conventional-changelog-conventionalcommits")).default; @@ -28,6 +43,7 @@ const loadPreset = async () => { }; const conventionalcommits = await loadPreset(); +// Git trailers that should never appear in the changelog or release notes. const TRAILER_KEYS = [ "Signed-off-by", "Co-authored-by", @@ -42,6 +58,10 @@ const TRAILER_KEYS = [ ]; const TRAILER = new RegExp(`^(?:${TRAILER_KEYS.join("|")}):\\s`, "i"); +// The conventional-commits parser ends a BREAKING CHANGE note only at a +// recognized reference (closes #..., fixes #...) or another note keyword, not +// at a git trailer -- so a trailing `Signed-off-by:` gets absorbed into the +// note text. Strip such trailing trailer lines. const stripTrailers = (text) => { if (!text) { return text; @@ -78,6 +98,8 @@ export default { [ "@semantic-release/release-notes-generator", { + // Only `transform` is overridden; the generator merges this over the + // preset's writer options, so templates/grouping/sorting are kept. writerOpts: { transform(commit, context) { const out = presetTransform(commit, context); diff --git a/ci/release/dry_run.sh b/ci/release/dry_run.sh index 84c17e7ee..c0482335b 100755 --- a/ci/release/dry_run.sh +++ b/ci/release/dry_run.sh @@ -27,7 +27,7 @@ npx --yes \ -p "semantic-release@25.0.5" \ -p "@semantic-release/commit-analyzer@13.0.1" \ -p "@semantic-release/release-notes-generator@14.1.1" \ - -p "@semantic-release/changelog@7.0.0-beta.1" \ + -p "@semantic-release/changelog@6.0.3" \ -p "@semantic-release/github@12.0.8" \ -p "@semantic-release/exec@7.1.0" \ -p "@semantic-release/git@10.0.1" \ diff --git a/ci/release/run.sh b/ci/release/run.sh index 5319b2e93..bc1b35bf4 100755 --- a/ci/release/run.sh +++ b/ci/release/run.sh @@ -7,7 +7,7 @@ RELEASE_DRY_RUN=false npx --yes \ -p "semantic-release@25.0.5" \ -p "@semantic-release/commit-analyzer@13.0.1" \ -p "@semantic-release/release-notes-generator@14.1.1" \ - -p "@semantic-release/changelog@7.0.0-beta.1" \ + -p "@semantic-release/changelog@6.0.3" \ -p "@semantic-release/github@12.0.8" \ -p "@semantic-release/exec@7.1.0" \ -p "@semantic-release/git@10.0.1" \ From 376db89f0a38bb2abdfd0b72b05ea750ad0d6c7e Mon Sep 17 00:00:00 2001 From: Niels Pardon Date: Fri, 17 Jul 2026 10:39:34 +0200 Subject: [PATCH 3/3] fix(ci): strip Mentored-by trailer from release notes Add the Mentored-by git trailer to the strip list so it does not leak into changelog or release notes. It is one of the standard trailers documented in git's SubmittingPatches and was the only canonical one missing from the list. --- .releaserc.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/.releaserc.mjs b/.releaserc.mjs index 625d54bbc..e7b931124 100644 --- a/.releaserc.mjs +++ b/.releaserc.mjs @@ -54,6 +54,7 @@ const TRAILER_KEYS = [ "Reported-by", "Suggested-by", "Helped-by", + "Mentored-by", "Cc", ]; const TRAILER = new RegExp(`^(?:${TRAILER_KEYS.join("|")}):\\s`, "i");