XuqmGroup-RNSDK/packages/update/scripts/release-identity.mjs

67 行
2.1 KiB
JavaScript

import { createHash } from 'node:crypto'
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import path from 'node:path'
const MAX_ANDROID_VERSION_CODE = 2_100_000_000
function readPreviousVersionCode(cacheFile) {
try {
return Number(JSON.parse(readFileSync(cacheFile, 'utf8')).versionCode) || 0
} catch {
return 0
}
}
/**
* 为同一 versionName 的连续测试包生成可安装的新构建身份。
*
* 本地缓存只负责同一工作区内的单调递增;CI 若需要跨工作区全局唯一,必须通过
* XUQM_VERSION_CODE 注入流水线唯一编号。
*/
export function createAndroidReleaseIdentity({
projectRoot,
environment = process.env,
now = Date.now(),
entropy = `${process.pid}:${Math.random()}`,
}) {
const cacheFile = path.join(projectRoot, '.xuqm-cache', 'release-build.json')
const previousVersionCode = readPreviousVersionCode(cacheFile)
const requestedText = environment.XUQM_VERSION_CODE
const requested = requestedText === undefined ? undefined : Number(requestedText)
if (
requestedText !== undefined &&
(!Number.isInteger(requested) || requested <= 0 || requested > MAX_ANDROID_VERSION_CODE)
) {
throw new Error(
`XUQM_VERSION_CODE must be an integer between 1 and ${MAX_ANDROID_VERSION_CODE}`,
)
}
const epochSeconds = Math.floor(now / 1_000)
const versionCode = requested ?? Math.max(epochSeconds, previousVersionCode + 1)
if (versionCode > MAX_ANDROID_VERSION_CODE) {
throw new Error('Generated Android versionCode exceeds limit')
}
const buildId =
environment.XUQM_BUILD_ID ??
createHash('sha256').update(`${versionCode}:${now}:${entropy}`).digest('hex').slice(0, 32)
if (!/^[A-Za-z0-9._-]{1,128}$/.test(buildId)) {
throw new Error('XUQM_BUILD_ID must contain only letters, numbers, dot, underscore or hyphen')
}
mkdirSync(path.dirname(cacheFile), { recursive: true })
writeFileSync(
cacheFile,
`${JSON.stringify(
{
versionCode,
buildId,
generatedAt: new Date(now).toISOString(),
},
null,
2,
)}\n`,
)
return { versionCode, buildId }
}