/** * Resolve the WeChat Mini Program upload version. * * WeChat requires x.y.z with each segment in 0..999. * Server and miniapp versions are independent on purpose. * * Priority: * 1. MINIAPP_VERSION_OVERRIDE — full manual version (rare / release pinning) * 2. MINIAPP_BUILD_NUMBER — auto version from CI run number * 3. package.json version — local / fallback */ const fs = require("node:fs"); const path = require("node:path"); function readPackageVersion(projectPath) { const packageJson = JSON.parse( fs.readFileSync(path.join(projectPath, "package.json"), "utf8"), ); if (!packageJson.version) { throw new Error("package.json version is missing."); } return String(packageJson.version); } function parseSemverParts(version) { const parts = String(version) .trim() .split(".") .map((part) => Number.parseInt(part, 10)); if ( parts.length < 1 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 999) ) { throw new Error( `Invalid version "${version}". WeChat requires x.y.z with each segment 0-999.`, ); } return { major: parts[0] ?? 0, minor: parts[1] ?? 0, patch: parts[2] ?? 0, }; } /** * Encode a monotonic CI build number into WeChat x.y.z. * Keeps package.json major.minor as the baseline; build number maps to patch. * Examples (base 1.1.0): build 45 → 1.1.45, build 999 → 1.1.999 * (patch wraps every 1000 builds; bump package.json minor before that) */ function versionFromBuildNumber(major, minor, buildNumber) { if (!Number.isInteger(buildNumber) || buildNumber < 1) { throw new Error("MINIAPP_BUILD_NUMBER must be a positive integer."); } if (!Number.isInteger(major) || major < 0 || major > 999) { throw new Error("package.json major version must be an integer 0-999."); } if (!Number.isInteger(minor) || minor < 0 || minor > 999) { throw new Error("package.json minor version must be an integer 0-999."); } const patch = buildNumber % 1000; return `${major}.${minor}.${patch}`; } /** @param {Record} [env] */ function resolveVersion(projectPath, env = process.env) { const override = (env.MINIAPP_VERSION_OVERRIDE || "").trim(); if (override) { parseSemverParts(override); return override; } const packageVersion = readPackageVersion(projectPath); const { major, minor } = parseSemverParts(packageVersion); const buildRaw = (env.MINIAPP_BUILD_NUMBER || "").trim(); if (buildRaw) { const buildNumber = Number.parseInt(buildRaw, 10); return versionFromBuildNumber(major, minor, buildNumber); } // Legacy fixed override — prefer not to use; keeps version stuck across uploads. const legacy = (env.MINIAPP_VERSION || "").trim(); if (legacy) { parseSemverParts(legacy); return legacy; } return packageVersion; } module.exports = { parseSemverParts, resolveVersion, versionFromBuildNumber, };