ci(jdbc): auto bump plugin releases

This commit is contained in:
t8y2 2026-05-18 21:01:39 +08:00
parent 244eb23287
commit df87ec994e
4 changed files with 178 additions and 28 deletions

View File

@ -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(/<project[\s\S]*?<version>([^<]+)<\/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(/(<project[\s\S]*?<version>)([^<]+)(<\/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();
}

View File

@ -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,
});

View File

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

View File

@ -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: "<project><version>0.1.9</version></project>",
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, /<version>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: "<project><version>0.1.9</version></project>",
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: "<project><version>0.1.9</version></project>",
manifestJson: '{ "version": "0.1.8" }',
}),
/JDBC plugin version mismatch/,
);
});