213 lines
7.2 KiB
JavaScript
213 lines
7.2 KiB
JavaScript
#!/usr/bin/env node
|
|
import { execFileSync } from "node:child_process";
|
|
import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
|
const VERSIONS_PATH = "agents/versions.json";
|
|
|
|
function bumpPatchVersion(version) {
|
|
const match = /^(\d+)\.(\d+)\.(\d+)(.*)$/.exec(version);
|
|
if (!match) {
|
|
throw new Error(`Agent version '${version}' is not a patchable semver version.`);
|
|
}
|
|
return `${match[1]}.${match[2]}.${Number(match[3]) + 1}${match[4]}`;
|
|
}
|
|
|
|
function pathChanged(changedFiles, pathPrefix) {
|
|
const normalized = pathPrefix.endsWith("/") ? pathPrefix : `${pathPrefix}/`;
|
|
return changedFiles.some((file) => file === pathPrefix || file.startsWith(normalized));
|
|
}
|
|
|
|
function isCommonRuntimeChange(file) {
|
|
return file === "agents/common/build.gradle" || file.startsWith("agents/common/src/main/");
|
|
}
|
|
|
|
function parseLegacyStandaloneProjects(buildGradle) {
|
|
const match = /legacyStandaloneProjects\s*=\s*\[([^\]]*)\]/m.exec(buildGradle);
|
|
if (!match) return new Set();
|
|
|
|
return new Set(
|
|
[...match[1].matchAll(/['"]([^'"]+)['"]/g)]
|
|
.map((entry) => entry[1])
|
|
.filter(Boolean),
|
|
);
|
|
}
|
|
|
|
function fileContainsCommonDependency(path, moduleExists, readModuleFile) {
|
|
if (!moduleExists(path)) return false;
|
|
const source = readModuleFile(path);
|
|
return /project\(\s*['"]:common['"]\s*\)/.test(source);
|
|
}
|
|
|
|
function resolveAgentModule(moduleName, { legacyStandaloneModules, moduleExists, readModuleFile }) {
|
|
let checkDir = null;
|
|
if (moduleName === "oracle" && moduleExists("agents/drivers/oracle-go")) {
|
|
checkDir = "drivers/oracle-go";
|
|
} else if (moduleExists(`agents/drivers/${moduleName}`)) {
|
|
checkDir = `drivers/${moduleName}`;
|
|
} else if (moduleExists(`agents/${moduleName}`) || moduleName === "common") {
|
|
checkDir = moduleName;
|
|
}
|
|
|
|
if (!checkDir) return null;
|
|
|
|
const modulePath = `agents/${checkDir}`;
|
|
const buildGradlePath = `${modulePath}/build.gradle`;
|
|
const hasBuildGradle = moduleExists(buildGradlePath);
|
|
const explicitlyDependsOnCommon = fileContainsCommonDependency(buildGradlePath, moduleExists, readModuleFile);
|
|
|
|
return {
|
|
checkDir,
|
|
modulePath,
|
|
commonDependent: hasBuildGradle && (explicitlyDependsOnCommon || !legacyStandaloneModules.has(moduleName)),
|
|
};
|
|
}
|
|
|
|
export function evaluateAgentVersionBump({
|
|
versions,
|
|
prevVersions = versions,
|
|
changedFiles,
|
|
legacyStandaloneModules = new Set(),
|
|
moduleExists = existsSync,
|
|
readModuleFile = (path) => readFileSync(path, "utf8"),
|
|
skipBump = false,
|
|
manualVersionsChanged = changedFiles.includes(VERSIONS_PATH),
|
|
}) {
|
|
const nextVersions = { ...versions };
|
|
const logs = [];
|
|
let changed = false;
|
|
|
|
if (manualVersionsChanged && !skipBump) {
|
|
logs.push("Manual agents/versions.json changes detected; preserving manually changed module versions and auto-bumping the rest.");
|
|
}
|
|
|
|
if (skipBump) {
|
|
logs.push("Skipping automatic module version bump for migrated first release; versions.json was carried over from dbx-agents.");
|
|
return { changed, versions: nextVersions, prevVersions, logs };
|
|
}
|
|
|
|
const commonChanged = changedFiles.some(isCommonRuntimeChange);
|
|
if (commonChanged) {
|
|
logs.push("Common agent runtime changes detected; common-triggered bumps are limited to modules that package agents/common.");
|
|
}
|
|
|
|
for (const moduleName of Object.keys(versions)) {
|
|
const module = resolveAgentModule(moduleName, { legacyStandaloneModules, moduleExists, readModuleFile });
|
|
if (!module) continue;
|
|
|
|
const moduleChanged = pathChanged(changedFiles, module.modulePath);
|
|
// Only modules that package agents/common need installer-visible updates
|
|
// for shared Java runtime changes; native and standalone agents do not.
|
|
const commonAffectsModule = commonChanged && module.commonDependent;
|
|
const oldVersion = nextVersions[moduleName] ?? "0.1.0";
|
|
const prevVersion = prevVersions[moduleName] ?? "";
|
|
const manuallyVersioned = manualVersionsChanged && (!prevVersion || prevVersion !== oldVersion);
|
|
|
|
if (!moduleChanged && !commonAffectsModule) {
|
|
logs.push(` ${moduleName}: no changes`);
|
|
} else if (manuallyVersioned) {
|
|
if (!prevVersion) {
|
|
logs.push(` ${moduleName}: CHANGED, new module version kept at ${oldVersion}`);
|
|
} else {
|
|
logs.push(` ${moduleName}: CHANGED, manual version ${prevVersion} -> ${oldVersion}`);
|
|
}
|
|
} else {
|
|
const newVersion = bumpPatchVersion(oldVersion);
|
|
nextVersions[moduleName] = newVersion;
|
|
changed = true;
|
|
logs.push(` ${moduleName}: CHANGED`);
|
|
logs.push(` ${moduleName}: ${oldVersion} -> ${newVersion}`);
|
|
}
|
|
}
|
|
|
|
return { changed, versions: nextVersions, prevVersions, logs };
|
|
}
|
|
|
|
function git(args) {
|
|
return execFileSync("git", args, { encoding: "utf8" }).trim();
|
|
}
|
|
|
|
function parseArgs(argv) {
|
|
const options = {
|
|
migratedFirstRelease: false,
|
|
prevTag: "",
|
|
prevVersionsFile: "",
|
|
skipBump: false,
|
|
write: false,
|
|
};
|
|
|
|
for (let index = 0; index < argv.length; index += 1) {
|
|
const arg = argv[index];
|
|
if (arg === "--write") {
|
|
options.write = true;
|
|
} else if (arg === "--skip-bump") {
|
|
options.skipBump = true;
|
|
} else if (arg === "--prev-tag") {
|
|
options.prevTag = argv[++index] ?? "";
|
|
} else if (arg === "--prev-versions-file") {
|
|
options.prevVersionsFile = argv[++index] ?? "";
|
|
} else if (arg === "--migrated-first-release") {
|
|
options.migratedFirstRelease = (argv[++index] ?? "") === "true";
|
|
} else {
|
|
throw new Error(`Unexpected argument: ${arg}`);
|
|
}
|
|
}
|
|
|
|
if (!options.prevTag) {
|
|
throw new Error("--prev-tag is required.");
|
|
}
|
|
return options;
|
|
}
|
|
|
|
function outputStepValues(result, prevTag, migratedFirstRelease) {
|
|
const outputPath = process.env.GITHUB_OUTPUT;
|
|
if (!outputPath) return;
|
|
|
|
appendFileSync(
|
|
outputPath,
|
|
[
|
|
`versions=${JSON.stringify(result.versions)}`,
|
|
`prev_versions=${JSON.stringify(result.prevVersions)}`,
|
|
`prev_tag=${prevTag}`,
|
|
`migrated_first_release=${migratedFirstRelease}`,
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
}
|
|
|
|
function main() {
|
|
const options = parseArgs(process.argv.slice(2));
|
|
const versions = JSON.parse(readFileSync(VERSIONS_PATH, "utf8"));
|
|
const legacyStandaloneModules = parseLegacyStandaloneProjects(readFileSync("agents/build.gradle", "utf8"));
|
|
const changedFiles = options.skipBump ? [] : git(["diff", "--name-only", `${options.prevTag}..HEAD`]).split("\n").filter(Boolean);
|
|
const manualVersionsChanged = changedFiles.includes(VERSIONS_PATH);
|
|
const prevVersions = options.prevVersionsFile
|
|
? JSON.parse(readFileSync(options.prevVersionsFile, "utf8"))
|
|
: manualVersionsChanged
|
|
? JSON.parse(git(["show", `${options.prevTag}:${VERSIONS_PATH}`]))
|
|
: versions;
|
|
|
|
const result = evaluateAgentVersionBump({
|
|
versions,
|
|
prevVersions,
|
|
changedFiles,
|
|
legacyStandaloneModules,
|
|
skipBump: options.skipBump,
|
|
manualVersionsChanged,
|
|
});
|
|
|
|
for (const line of result.logs) {
|
|
console.log(line);
|
|
}
|
|
|
|
const versionsJson = `${JSON.stringify(result.versions, null, 2)}\n`;
|
|
if (options.write) {
|
|
writeFileSync(VERSIONS_PATH, versionsJson);
|
|
}
|
|
console.log(versionsJson);
|
|
outputStepValues(result, options.prevTag, options.migratedFirstRelease);
|
|
}
|
|
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
main();
|
|
}
|