2026-03-06 01:25:29 -06:00
|
|
|
/**
|
2026-04-24 17:50:44 -05:00
|
|
|
* Single source of truth: set "version" in package.json, then run:
|
2026-03-06 01:25:29 -06:00
|
|
|
* pnpm run version:sync
|
2026-04-24 17:50:44 -05:00
|
|
|
*
|
2026-04-24 18:10:40 -05:00
|
|
|
* Writes: meshchatx/__init__.py (__version__), meshchatx/src/version.py, pyproject.toml [project].version,
|
2026-04-24 17:50:44 -05:00
|
|
|
* meshchatx/src/backend/data/THIRD_PARTY_NOTICES.txt (reticulum-meshchatx line only),
|
2026-08-03 20:53:12 -05:00
|
|
|
* README + lang README "current version" lines, docs/en/platform-guides/raspberry-pi.md,
|
|
|
|
|
* meshchatx/src/frontend/public/meshchatx-docs/en/platform-guides/raspberry-pi.md,
|
2026-07-06 22:04:02 -05:00
|
|
|
* meshchatx/src/backend/data/licenses_backend.json (reticulum-meshchatx entry),
|
2026-06-21 17:04:44 -05:00
|
|
|
* android/app/build.gradle,
|
2026-08-14 15:38:01 -05:00
|
|
|
* electron/app-version.json,
|
2026-08-14 15:50:37 -05:00
|
|
|
* .github/ISSUE_TEMPLATE bug and feature version placeholders,
|
2026-07-24 05:40:54 -05:00
|
|
|
* pipx example, packaging/arch/PKGBUILD pkgver / printf fallback,
|
|
|
|
|
* then runs scripts/bake_build_meta.js (git commit / channel overlay).
|
2026-04-24 17:50:44 -05:00
|
|
|
*
|
2026-04-24 18:10:40 -05:00
|
|
|
* __version__ lives in meshchatx/__init__.py so Chaquopy/Android (which may not ship loose .py
|
|
|
|
|
* data files next to bytecode) always has a resolvable version. src/version.py stays for packaging and tools.
|
2026-04-24 17:50:44 -05:00
|
|
|
* The build script runs version:sync automatically.
|
2026-03-06 01:25:29 -06:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const fs = require("fs");
|
|
|
|
|
const path = require("path");
|
|
|
|
|
|
|
|
|
|
const root = path.resolve(__dirname, "..");
|
|
|
|
|
const pkgPath = path.join(root, "package.json");
|
|
|
|
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
|
|
|
const version = pkg.version;
|
|
|
|
|
if (!version || typeof version !== "string") {
|
2026-03-06 01:27:25 -06:00
|
|
|
console.error("package.json has no valid 'version' field");
|
|
|
|
|
process.exit(1);
|
2026-03-06 01:25:29 -06:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 17:50:44 -05:00
|
|
|
function writeIfChanged(absPath, content) {
|
|
|
|
|
const prev = fs.existsSync(absPath) ? fs.readFileSync(absPath, "utf8") : null;
|
|
|
|
|
if (prev !== content) {
|
|
|
|
|
fs.writeFileSync(absPath, content, "utf8");
|
|
|
|
|
console.log(`Updated ${path.relative(root, absPath)}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-25 16:30:28 -05:00
|
|
|
const versionPy = `"""Version string synced from package.json.
|
|
|
|
|
|
|
|
|
|
Do not edit by hand. Run: pnpm run version:sync
|
2026-03-06 01:25:29 -06:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
__version__ = "${version}"
|
|
|
|
|
`;
|
2026-04-24 17:50:44 -05:00
|
|
|
writeIfChanged(path.join(root, "meshchatx", "src", "version.py"), versionPy);
|
|
|
|
|
|
2026-04-24 18:10:40 -05:00
|
|
|
patchFile("meshchatx/__init__.py", (c) => c.replace(/^__version__\s*=\s*"[^"]*"\s*$/m, `__version__ = "${version}"`));
|
|
|
|
|
|
2026-04-24 17:50:44 -05:00
|
|
|
const pyprojectPath = path.join(root, "pyproject.toml");
|
|
|
|
|
let pyproject = fs.readFileSync(pyprojectPath, "utf8");
|
|
|
|
|
const pyprojectNext = pyproject.replace(/^version = "[^"]+"/m, `version = "${version}"`);
|
|
|
|
|
if (pyprojectNext !== pyproject) {
|
|
|
|
|
fs.writeFileSync(pyprojectPath, pyprojectNext, "utf8");
|
|
|
|
|
console.log(`Updated ${path.relative(root, pyprojectPath)}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const noticesPath = path.join(root, "meshchatx", "src", "backend", "data", "THIRD_PARTY_NOTICES.txt");
|
|
|
|
|
if (fs.existsSync(noticesPath)) {
|
|
|
|
|
let notices = fs.readFileSync(noticesPath, "utf8");
|
|
|
|
|
const noticesNext = notices.replace(/^reticulum-meshchatx .+$/m, `reticulum-meshchatx ${version}`);
|
|
|
|
|
if (noticesNext !== notices) {
|
|
|
|
|
fs.writeFileSync(noticesPath, noticesNext, "utf8");
|
|
|
|
|
console.log(`Updated ${path.relative(root, noticesPath)}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function patchFile(rel, fn) {
|
|
|
|
|
const abs = path.join(root, rel);
|
|
|
|
|
if (!fs.existsSync(abs)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const before = fs.readFileSync(abs, "utf8");
|
|
|
|
|
const after = fn(before);
|
|
|
|
|
if (after !== before) {
|
|
|
|
|
fs.writeFileSync(abs, after, "utf8");
|
|
|
|
|
console.log(`Updated ${rel}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
patchFile("README.md", (c) => c.replace(/(Current version in this repo is `)[^`]+(`)/, `$1${version}$2`));
|
|
|
|
|
|
|
|
|
|
patchFile("lang/README.de.md", (c) =>
|
2026-04-24 18:01:43 -05:00
|
|
|
c.replace(/(Aktuelle Version in diesem Repository: `)[^`]+(`)/, `$1${version}$2`)
|
2026-04-24 17:50:44 -05:00
|
|
|
);
|
2026-04-24 18:01:43 -05:00
|
|
|
patchFile("lang/README.it.md", (c) => c.replace(/(Versione attuale nel repository: `)[^`]+(`)/, `$1${version}$2`));
|
2026-04-24 17:50:44 -05:00
|
|
|
patchFile("lang/README.ja.md", (c) =>
|
2026-04-24 18:01:43 -05:00
|
|
|
c.replace(/(このリポジトリの現在のバージョンは `)[^`]+(` です。)/, `$1${version}$2`)
|
2026-04-24 17:50:44 -05:00
|
|
|
);
|
2026-04-24 18:01:43 -05:00
|
|
|
patchFile("lang/README.ru.md", (c) => c.replace(/(Текущая версия в репозитории: `)[^`]+(`)/, `$1${version}$2`));
|
2026-04-24 17:50:44 -05:00
|
|
|
patchFile("lang/README.zh.md", (c) => c.replace(/(本仓库当前版本: `)[^`]+(`)/, `$1${version}$2`));
|
|
|
|
|
|
2026-06-01 08:16:33 -05:00
|
|
|
function patchRaspberryPiDoc(c) {
|
2026-04-24 17:50:44 -05:00
|
|
|
let x = c;
|
|
|
|
|
x = x.replace(/\(\d+\.\d+\.\d+ or newer\)/, `(${version} or newer)`);
|
|
|
|
|
x = x.replace(/Direct example \(v\d+\.\d+\.\d+\):/, `Direct example (v${version}):`);
|
|
|
|
|
x = x.replace(
|
2026-06-01 08:16:33 -05:00
|
|
|
/releases\/download\/v\d+\.\d+\.\d+\/reticulum_meshchatx-\d+\.\d+\.\d+-py3-none-any\.whl/g,
|
2026-04-24 18:01:43 -05:00
|
|
|
`releases/download/v${version}/reticulum_meshchatx-${version}-py3-none-any.whl`
|
2026-04-24 17:50:44 -05:00
|
|
|
);
|
|
|
|
|
return x;
|
2026-06-01 08:16:33 -05:00
|
|
|
}
|
|
|
|
|
|
2026-08-03 20:53:12 -05:00
|
|
|
patchFile("docs/en/platform-guides/raspberry-pi.md", patchRaspberryPiDoc);
|
2026-08-12 20:28:15 -05:00
|
|
|
patchFile("meshchatx/src/frontend/public/meshchatx-docs/en/platform-guides/raspberry-pi.md", patchRaspberryPiDoc);
|
2026-07-06 22:04:02 -05:00
|
|
|
|
|
|
|
|
const licensesBackendPath = path.join(root, "meshchatx", "src", "backend", "data", "licenses_backend.json");
|
|
|
|
|
if (fs.existsSync(licensesBackendPath)) {
|
|
|
|
|
const licensesBackend = JSON.parse(fs.readFileSync(licensesBackendPath, "utf8"));
|
|
|
|
|
const meshchatEntry = licensesBackend.find((entry) => entry.name === "reticulum-meshchatx");
|
|
|
|
|
if (meshchatEntry && meshchatEntry.version !== version) {
|
|
|
|
|
meshchatEntry.version = version;
|
|
|
|
|
fs.writeFileSync(licensesBackendPath, `${JSON.stringify(licensesBackend, null, 4)}\n`, "utf8");
|
|
|
|
|
console.log(`Updated ${path.relative(root, licensesBackendPath)}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-06-01 08:16:33 -05:00
|
|
|
|
|
|
|
|
const versionParts = version.split(".").map((n) => Number.parseInt(n, 10));
|
|
|
|
|
if (versionParts.length === 3 && versionParts.every((n) => Number.isFinite(n))) {
|
|
|
|
|
const versionCode = versionParts[0] * 10000 + versionParts[1] * 1000 + versionParts[2];
|
|
|
|
|
patchFile("android/app/build.gradle", (c) => {
|
|
|
|
|
let x = c.replace(/versionCode \d+/, `versionCode ${versionCode}`);
|
|
|
|
|
x = x.replace(/versionName "[^"]+"/, `versionName "${version}"`);
|
|
|
|
|
return x;
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-04-24 17:50:44 -05:00
|
|
|
|
|
|
|
|
patchFile("packaging/arch/PKGBUILD", (c) => {
|
|
|
|
|
let x = c.replace(/^pkgver=\d+\.\d+\.\d+(.*)$/m, `pkgver=${version}$1`);
|
|
|
|
|
x = x.replace(/printf "\d+\.\d+\.\d+\.r%s\.%s"/, `printf "${version}.r%s.%s"`);
|
|
|
|
|
return x;
|
|
|
|
|
});
|
2026-03-06 01:25:29 -06:00
|
|
|
|
2026-07-06 22:04:02 -05:00
|
|
|
patchFile("packaging/arch/.SRCINFO", (c) =>
|
|
|
|
|
c.replace(/^(\tpkgver = )\d+\.\d+\.\d+(\.r\d+\.g[0-9a-f]+)$/m, `$1${version}$2`)
|
|
|
|
|
);
|
|
|
|
|
|
2026-04-24 17:50:44 -05:00
|
|
|
console.log(`Synced version ${version} from package.json`);
|
2026-07-24 05:40:54 -05:00
|
|
|
|
2026-08-14 15:38:01 -05:00
|
|
|
const appVersionPath = path.join(root, "electron", "app-version.json");
|
|
|
|
|
writeIfChanged(appVersionPath, `${JSON.stringify({ version }, null, 4)}\n`);
|
|
|
|
|
|
2026-08-14 15:50:37 -05:00
|
|
|
patchFile(".github/ISSUE_TEMPLATE/bug_report.yml", (c) => {
|
|
|
|
|
let x = c.replace(/placeholder: "\d+\.\d+\.\d+"/, `placeholder: "${version}"`);
|
|
|
|
|
x = x.replace(/\(for example \d+\.\d+\.\d+\)/, `(for example ${version})`);
|
|
|
|
|
return x;
|
|
|
|
|
});
|
|
|
|
|
patchFile(".github/ISSUE_TEMPLATE/feature_request.yml", (c) =>
|
|
|
|
|
c.replace(/placeholder: "\d+\.\d+\.\d+"/, `placeholder: "${version}"`)
|
|
|
|
|
);
|
|
|
|
|
|
2026-07-24 05:40:54 -05:00
|
|
|
try {
|
|
|
|
|
require("./bake_build_meta.js");
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.warn(`bake_build_meta skipped: ${err && err.message ? err.message : err}`);
|
|
|
|
|
}
|