diff --git a/.github/scripts/bump-jdbc-plugin-version.mjs b/.github/scripts/bump-jdbc-plugin-version.mjs new file mode 100644 index 000000000..dea4e4bad --- /dev/null +++ b/.github/scripts/bump-jdbc-plugin-version.mjs @@ -0,0 +1,88 @@ +#!/usr/bin/env node +import { execFileSync } from "node:child_process"; +import { readFileSync, writeFileSync } from "node:fs"; + +const POM_PATH = "plugins/jdbc/pom.xml"; +const MANIFEST_PATH = "plugins/jdbc/manifest.json"; + +function firstProjectVersion(pomXml) { + const match = pomXml.match(/([^<]+)<\/version>/); + return match?.[1]?.trim() ?? ""; +} + +function manifestVersion(manifestJson) { + return JSON.parse(manifestJson).version ?? ""; +} + +function bumpPatchVersion(version) { + const match = version.match(/^(\d+)\.(\d+)\.(\d+)(.*)$/); + if (!match) { + throw new Error(`JDBC plugin version '${version}' is not a patchable semver version.`); + } + return `${match[1]}.${match[2]}.${Number(match[3]) + 1}${match[4]}`; +} + +function isReleaseBumpRelevantJdbcPluginChange(file) { + if (file.startsWith("plugins/jdbc/src/") || file.startsWith("plugins/jdbc/bin/")) return true; + if (!file.startsWith("plugins/jdbc/")) return false; + if (file.startsWith("plugins/jdbc/dist/") || file.startsWith("plugins/jdbc/target/")) return false; + if (file === "plugins/jdbc/README.md" || file === "plugins/jdbc/package.sh") return false; + if (file === POM_PATH || file === MANIFEST_PATH) return false; + return true; +} + +function updatePomVersion(pomXml, version) { + return pomXml.replace(/()([^<]+)(<\/version>)/, `$1${version}$3`); +} + +function updateManifestVersion(manifestJson, version) { + const manifest = JSON.parse(manifestJson); + manifest.version = version; + return `${JSON.stringify(manifest, null, 2)}\n`; +} + +export function evaluateJdbcPluginReleaseBump({ changedFiles, pomXml, manifestJson }) { + const pomVersion = firstProjectVersion(pomXml); + const currentManifestVersion = manifestVersion(manifestJson); + if (pomVersion !== currentManifestVersion) { + throw new Error(`JDBC plugin version mismatch: pom.xml is ${pomVersion} but manifest.json is ${currentManifestVersion}.`); + } + + const shouldBump = changedFiles.some(isReleaseBumpRelevantJdbcPluginChange); + const newVersion = shouldBump ? bumpPatchVersion(pomVersion) : pomVersion; + return { + changed: shouldBump, + oldVersion: pomVersion, + newVersion, + pomXml: shouldBump ? updatePomVersion(pomXml, newVersion) : pomXml, + manifestJson: shouldBump ? updateManifestVersion(manifestJson, newVersion) : manifestJson, + }; +} + +function git(args) { + return execFileSync("git", args, { encoding: "utf8" }).trim(); +} + +function main() { + const [baseRef = "HEAD~1", headRef = "HEAD", ...flags] = process.argv.slice(2); + const write = flags.includes("--write"); + const changedFiles = git(["diff", "--name-only", baseRef, headRef]).split("\n").filter(Boolean); + const result = evaluateJdbcPluginReleaseBump({ + changedFiles, + pomXml: readFileSync(POM_PATH, "utf8"), + manifestJson: readFileSync(MANIFEST_PATH, "utf8"), + }); + + if (write && result.changed) { + writeFileSync(POM_PATH, result.pomXml); + writeFileSync(MANIFEST_PATH, result.manifestJson); + } + + console.log(`changed=${result.changed}`); + console.log(`old_version=${result.oldVersion}`); + console.log(`new_version=${result.newVersion}`); +} + +if (import.meta.url === `file://${process.argv[1]}`) { + main(); +} diff --git a/.github/scripts/check-jdbc-plugin-version.mjs b/.github/scripts/check-jdbc-plugin-version.mjs index 8e3d098e3..266930d5e 100644 --- a/.github/scripts/check-jdbc-plugin-version.mjs +++ b/.github/scripts/check-jdbc-plugin-version.mjs @@ -13,17 +13,7 @@ function manifestVersion(manifestJson) { return JSON.parse(manifestJson).version ?? ""; } -function isRelevantJdbcPluginChange(file) { - if (!file.startsWith("plugins/jdbc/")) return false; - if (file.startsWith("plugins/jdbc/dist/") || file.startsWith("plugins/jdbc/target/")) return false; - if (file === "plugins/jdbc/README.md" || file === "plugins/jdbc/package.sh") return false; - return true; -} - export function evaluateJdbcPluginVersionChange({ - changedFiles, - basePomVersion, - baseManifestVersion, headPomVersion, headManifestVersion, }) { @@ -32,14 +22,6 @@ export function evaluateJdbcPluginVersionChange({ errors.push(`JDBC plugin version mismatch: pom.xml is ${headPomVersion} but manifest.json is ${headManifestVersion}.`); return errors; } - - const baseVersion = basePomVersion || baseManifestVersion; - const relevantChanged = changedFiles.some(isRelevantJdbcPluginChange); - if (relevantChanged && headPomVersion === baseVersion) { - errors.push( - `JDBC plugin files changed, but the plugin version is still ${headPomVersion}. Bump plugins/jdbc/pom.xml and plugins/jdbc/manifest.json.`, - ); - } return errors; } @@ -52,16 +34,10 @@ function readFileAt(ref, path) { } function main() { - const [baseRef = "HEAD~1", headRef = "HEAD"] = process.argv.slice(2); - const changedFiles = git(["diff", "--name-only", baseRef, headRef]).split("\n").filter(Boolean); - const basePomVersion = firstProjectVersion(readFileAt(baseRef, POM_PATH)); - const baseManifestVersion = manifestVersion(readFileAt(baseRef, MANIFEST_PATH)); + const [, headRef = "HEAD"] = process.argv.slice(2); const headPomVersion = firstProjectVersion(readFileAt(headRef, POM_PATH)); const headManifestVersion = manifestVersion(readFileAt(headRef, MANIFEST_PATH)); const errors = evaluateJdbcPluginVersionChange({ - changedFiles, - basePomVersion, - baseManifestVersion, headPomVersion, headManifestVersion, }); diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index afddbf172..652acdec9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,6 +9,47 @@ permissions: contents: write jobs: + bump-jdbc-plugin-version: + runs-on: ubuntu-latest + outputs: + changed: ${{ steps.bump.outputs.changed }} + old_version: ${{ steps.bump.outputs.old_version }} + new_version: ${{ steps.bump.outputs.new_version }} + prev_tag: ${{ steps.prev-tag.outputs.prev_tag }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Find previous release tag + id: prev-tag + shell: bash + run: | + PREV_TAG=$(git tag --sort=-creatordate | grep '^v' | sed -n '2p') + if [ -z "$PREV_TAG" ]; then + PREV_TAG=$(git rev-list --max-parents=0 HEAD) + fi + echo "prev_tag=${PREV_TAG}" >> "$GITHUB_OUTPUT" + echo "Comparing ${PREV_TAG}..HEAD" + + - name: Detect JDBC plugin changes and bump version + id: bump + shell: bash + run: | + BUMP_OUTPUT="$(node .github/scripts/bump-jdbc-plugin-version.mjs "${{ steps.prev-tag.outputs.prev_tag }}" HEAD --write)" + echo "$BUMP_OUTPUT" + echo "$BUMP_OUTPUT" >> "$GITHUB_OUTPUT" + + - name: Commit JDBC plugin version bump + if: steps.bump.outputs.changed == 'true' + shell: bash + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add plugins/jdbc/pom.xml plugins/jdbc/manifest.json + git commit -m "chore(jdbc): bump plugin version [skip ci]" + git push origin HEAD:main + build: strategy: fail-fast: false @@ -161,10 +202,12 @@ jobs: gh release upload "${env:GITHUB_REF_NAME}" $zipName --repo "${env:GITHUB_REPOSITORY}" --clobber jdbc-plugin: - needs: build + needs: [build, bump-jdbc-plugin-version] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Setup Java uses: actions/setup-java@v4 @@ -173,6 +216,10 @@ jobs: java-version: '17' cache: maven + - name: Apply automatic JDBC plugin version bump + shell: bash + run: node .github/scripts/bump-jdbc-plugin-version.mjs "${{ needs.bump-jdbc-plugin-version.outputs.prev_tag }}" HEAD --write + - name: Read JDBC plugin version id: jdbc-plugin shell: bash diff --git a/packages/app-tests/jdbcPluginRelease.test.ts b/packages/app-tests/jdbcPluginRelease.test.ts index 9fd8bec0d..6f362c1d1 100644 --- a/packages/app-tests/jdbcPluginRelease.test.ts +++ b/packages/app-tests/jdbcPluginRelease.test.ts @@ -1,8 +1,9 @@ import { strict as assert } from "node:assert"; import test from "node:test"; +import { evaluateJdbcPluginReleaseBump } from "../../.github/scripts/bump-jdbc-plugin-version.mjs"; import { evaluateJdbcPluginVersionChange } from "../../.github/scripts/check-jdbc-plugin-version.mjs"; -test("requires a JDBC plugin version bump when runtime files change", () => { +test("allows JDBC plugin runtime changes without a manual version bump before release", () => { assert.deepEqual( evaluateJdbcPluginVersionChange({ changedFiles: ["plugins/jdbc/src/main/java/app/dbx/jdbc/DbxJdbcPlugin.java"], @@ -11,7 +12,7 @@ test("requires a JDBC plugin version bump when runtime files change", () => { headPomVersion: "0.1.1", headManifestVersion: "0.1.1", }), - ["JDBC plugin files changed, but the plugin version is still 0.1.1. Bump plugins/jdbc/pom.xml and plugins/jdbc/manifest.json."], + [], ); }); @@ -53,3 +54,41 @@ test("requires JDBC plugin pom and manifest versions to match", () => { ["JDBC plugin version mismatch: pom.xml is 0.1.2 but manifest.json is 0.1.1."], ); }); + +test("auto bumps JDBC plugin patch version when runtime files changed for release", () => { + const result = evaluateJdbcPluginReleaseBump({ + changedFiles: ["plugins/jdbc/src/main/java/app/dbx/jdbc/DbxJdbcPlugin.java"], + pomXml: "0.1.9", + manifestJson: '{ "version": "0.1.9" }', + }); + + assert.equal(result.changed, true); + assert.equal(result.oldVersion, "0.1.9"); + assert.equal(result.newVersion, "0.1.10"); + assert.match(result.pomXml, /0\.1\.10<\/version>/); + assert.match(result.manifestJson, /"version": "0\.1\.10"/); +}); + +test("does not auto bump JDBC plugin version for release packaging-only changes", () => { + const result = evaluateJdbcPluginReleaseBump({ + changedFiles: ["plugins/jdbc/README.md", "plugins/jdbc/package.sh"], + pomXml: "0.1.9", + manifestJson: '{ "version": "0.1.9" }', + }); + + assert.equal(result.changed, false); + assert.equal(result.oldVersion, "0.1.9"); + assert.equal(result.newVersion, "0.1.9"); +}); + +test("auto bump refuses mismatched JDBC plugin source versions", () => { + assert.throws( + () => + evaluateJdbcPluginReleaseBump({ + changedFiles: ["plugins/jdbc/src/main/java/app/dbx/jdbc/DbxJdbcPlugin.java"], + pomXml: "0.1.9", + manifestJson: '{ "version": "0.1.8" }', + }), + /JDBC plugin version mismatch/, + ); +});