Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
94 lines
3.5 KiB
TypeScript
94 lines
3.5 KiB
TypeScript
/**
|
|
* Generates src/generated/versionInfo.json with the project's current version,
|
|
* git tag/describe info, and the last commit's metadata. Consumed by the admin
|
|
* VersionOverlay via GET /api/version (the file is read at runtime so a fresh
|
|
* post-bump regeneration rsync'd to the server shows up without a rebuild).
|
|
*
|
|
* Git metadata resolution order (first non-empty wins):
|
|
* 1. Environment variables — explicit overrides for CI systems that inject
|
|
* metadata as env vars:
|
|
* GIT_TAG, GIT_DESCRIBE, GIT_COMMIT_HASH, GIT_COMMIT_DATE, GIT_COMMIT_SUBJECT
|
|
* 2. SOURCE_COMMIT — the commit SHA Coolify injects as a build arg when
|
|
* "Include Source Commit in Build" is enabled (application settings →
|
|
* Advanced). Coolify strips `.git` from the build context, so `git` is
|
|
* unavailable there. Only the SHA is provided — tags, date, and subject
|
|
* have no Coolify equivalent and stay null in that case.
|
|
* 3. `git` from the project root — the local-dev path (and any build context
|
|
* that still contains .git, e.g. a local `docker build`).
|
|
*
|
|
* Gracefully no-ops on missing git metadata (no .git, no tags, no env) so the
|
|
* JSON always exists with whatever fields are resolvable.
|
|
*/
|
|
import { execSync } from "node:child_process";
|
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
const projectRoot = path.resolve(here, "..", "..");
|
|
|
|
function git(args: string): string | null {
|
|
try {
|
|
const out = execSync(`git ${args}`, { cwd: projectRoot, encoding: "utf8" });
|
|
const trimmed = out.trim();
|
|
return trimmed.length > 0 ? trimmed : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function envVar(name: string): string | null {
|
|
const value = process.env[name];
|
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
}
|
|
|
|
function shortCommit(sha: string): string {
|
|
return sha.length > 7 ? sha.slice(0, 7) : sha;
|
|
}
|
|
|
|
function readPackageVersion(): string | null {
|
|
try {
|
|
const pkg = JSON.parse(readFileSync(path.join(projectRoot, "package.json"), "utf8"));
|
|
return typeof pkg?.version === "string" && pkg.version.length > 0 ? pkg.version : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function main(): void {
|
|
const version = readPackageVersion();
|
|
const tag = envVar("GIT_TAG") ?? git("describe --tags --always --abbrev=0");
|
|
const gitDescribe = envVar("GIT_DESCRIBE") ?? git("describe --tags --always --abbrev=7");
|
|
const rawCommit = envVar("GIT_COMMIT_HASH") ?? envVar("SOURCE_COMMIT");
|
|
const commitHash = rawCommit ? shortCommit(rawCommit) : git("rev-parse --short HEAD");
|
|
const commitDate = envVar("GIT_COMMIT_DATE") ?? git("log -1 --format=%cI");
|
|
const commitSubject = envVar("GIT_COMMIT_SUBJECT") ?? git("log -1 --format=%s");
|
|
const buildTime = new Date().toISOString();
|
|
|
|
const info = {
|
|
version,
|
|
tag,
|
|
gitDescribe,
|
|
commitHash,
|
|
commitDate,
|
|
commitSubject,
|
|
lastUpdated: commitDate ?? buildTime,
|
|
commitMessage: commitSubject,
|
|
buildTime,
|
|
};
|
|
|
|
const outDir = path.join(projectRoot, "src", "generated");
|
|
if (!existsSync(outDir)) {
|
|
mkdirSync(outDir, { recursive: true });
|
|
}
|
|
writeFileSync(
|
|
path.join(outDir, "versionInfo.json"),
|
|
`${JSON.stringify(info, null, 2)}\n`,
|
|
"utf8",
|
|
);
|
|
|
|
const label = gitDescribe ?? tag ?? version ?? "unknown";
|
|
console.log(`[version-info] wrote src/generated/versionInfo.json (${label})`);
|
|
}
|
|
|
|
main();
|