67 行
2.1 KiB
JavaScript
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 }
|
|
}
|