feat: release OpsXShell 2.1.1
This commit is contained in:
1 parent
a3dba0c6ed
commit
494ef6b9d0
37 files changed
+2039
-370
No files matched your search
@@ -0,0 +1,43 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs'
|
||||
import test from 'node:test'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { inspectVersions, setVersion } from './set-version.mjs'
|
||||
|
||||
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
||||
|
||||
test('build.sh is valid Bash and documents supported native targets', () => {
|
||||
const syntax = spawnSync('bash', ['-n', 'build.sh'], { cwd: root, encoding: 'utf8' })
|
||||
assert.equal(syntax.status, 0, syntax.stderr)
|
||||
|
||||
const help = spawnSync('bash', ['build.sh', '--help'], { cwd: root, encoding: 'utf8' })
|
||||
assert.equal(help.status, 0, help.stderr)
|
||||
assert.match(help.stdout, /mac-arm64/)
|
||||
assert.match(help.stdout, /win-x64/)
|
||||
assert.match(help.stdout, /不会创建或推送 Git tag/)
|
||||
})
|
||||
|
||||
test('release metadata versions stay synchronized', () => {
|
||||
const versions = Object.values(inspectVersions(root))
|
||||
assert.ok(versions.length > 0)
|
||||
assert.ok(
|
||||
versions.every((version) => version === versions[0]),
|
||||
JSON.stringify(versions)
|
||||
)
|
||||
})
|
||||
|
||||
test('version updater synchronizes every release metadata file', () => {
|
||||
const fixture = mkdtempSync(resolve(tmpdir(), 'opsxshell-version-'))
|
||||
mkdirSync(resolve(fixture, 'src-tauri'))
|
||||
writeFileSync(resolve(fixture, 'package.json'), '{"version":"2.1.0"}\n')
|
||||
writeFileSync(resolve(fixture, 'package-lock.json'), '{"version":"2.1.0","packages":{"":{"version":"2.1.0"}}}\n')
|
||||
writeFileSync(resolve(fixture, 'src-tauri/tauri.conf.json'), '{"version":"2.1.0"}\n')
|
||||
writeFileSync(resolve(fixture, 'src-tauri/Cargo.toml'), '[package]\nname = "opsxshell"\nversion = "2.1.0"\n')
|
||||
writeFileSync(resolve(fixture, 'src-tauri/Cargo.lock'), '[[package]]\nname = "opsxshell"\nversion = "2.1.0"\n')
|
||||
|
||||
const versions = setVersion(fixture, '2.1.7')
|
||||
assert.ok(Object.values(versions).every((version) => version === '2.1.7'))
|
||||
})
|
||||
@@ -0,0 +1,110 @@
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { dirname, join, resolve } from 'node:path'
|
||||
|
||||
const scriptPath = fileURLToPath(import.meta.url)
|
||||
const defaultRoot = resolve(dirname(scriptPath), '..')
|
||||
|
||||
function readJson(path) {
|
||||
return JSON.parse(readFileSync(path, 'utf8'))
|
||||
}
|
||||
|
||||
function writeJson(path, value) {
|
||||
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`)
|
||||
}
|
||||
|
||||
function packageVersion(content, packageName) {
|
||||
const escapedName = packageName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||
const match = content.match(new RegExp(`\\[\\[package\\]\\]\\nname = "${escapedName}"\\nversion = "([^"]+)"`))
|
||||
if (!match) throw new Error(`Cargo.lock 中缺少 package ${packageName}`)
|
||||
return match[1]
|
||||
}
|
||||
|
||||
function replaceRootCargoVersion(content, version) {
|
||||
const pattern = /(\[package\][\s\S]*?\nversion = ")[^"]+("\n)/
|
||||
if (!pattern.test(content)) throw new Error('Cargo.toml 中缺少根 package version')
|
||||
return content.replace(pattern, `$1${version}$2`)
|
||||
}
|
||||
|
||||
function replaceLockedPackageVersion(content, packageName, version) {
|
||||
const escapedName = packageName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||
const pattern = new RegExp(`(\\[\\[package\\]\\]\\nname = "${escapedName}"\\nversion = ")[^"]+("\\n)`)
|
||||
if (!pattern.test(content)) throw new Error(`Cargo.lock 中无法更新 package ${packageName}`)
|
||||
return content.replace(pattern, `$1${version}$2`)
|
||||
}
|
||||
|
||||
export function inspectVersions(root = defaultRoot) {
|
||||
const packageJson = readJson(join(root, 'package.json'))
|
||||
const packageLock = readJson(join(root, 'package-lock.json'))
|
||||
const tauriConfig = readJson(join(root, 'src-tauri/tauri.conf.json'))
|
||||
const cargoToml = readFileSync(join(root, 'src-tauri/Cargo.toml'), 'utf8')
|
||||
const cargoLock = readFileSync(join(root, 'src-tauri/Cargo.lock'), 'utf8')
|
||||
const cargoManifestVersion = cargoToml.match(/\[package\][\s\S]*?\nversion = "([^"]+)"/)?.[1]
|
||||
if (!cargoManifestVersion) throw new Error('Cargo.toml 中缺少根 package version')
|
||||
|
||||
return {
|
||||
packageJson: packageJson.version,
|
||||
packageLock: packageLock.version,
|
||||
packageLockRoot: packageLock.packages?.['']?.version,
|
||||
cargoToml: cargoManifestVersion,
|
||||
cargoLock: packageVersion(cargoLock, 'opsxshell'),
|
||||
tauriConfig: tauriConfig.version,
|
||||
}
|
||||
}
|
||||
|
||||
export function assertVersion(root, expected) {
|
||||
const versions = inspectVersions(root)
|
||||
const mismatches = Object.entries(versions).filter(([, version]) => version !== expected)
|
||||
if (mismatches.length > 0) {
|
||||
throw new Error(
|
||||
`版本不一致,期望 ${expected}:${mismatches.map(([file, version]) => `${file}=${version ?? 'missing'}`).join(', ')}`
|
||||
)
|
||||
}
|
||||
return versions
|
||||
}
|
||||
|
||||
export function setVersion(root, version) {
|
||||
const packageJsonPath = join(root, 'package.json')
|
||||
const packageLockPath = join(root, 'package-lock.json')
|
||||
const tauriConfigPath = join(root, 'src-tauri/tauri.conf.json')
|
||||
const cargoTomlPath = join(root, 'src-tauri/Cargo.toml')
|
||||
const cargoLockPath = join(root, 'src-tauri/Cargo.lock')
|
||||
|
||||
const packageJson = readJson(packageJsonPath)
|
||||
packageJson.version = version
|
||||
writeJson(packageJsonPath, packageJson)
|
||||
|
||||
const packageLock = readJson(packageLockPath)
|
||||
packageLock.version = version
|
||||
if (packageLock.packages?.['']) packageLock.packages[''].version = version
|
||||
writeJson(packageLockPath, packageLock)
|
||||
|
||||
const tauriConfig = readJson(tauriConfigPath)
|
||||
tauriConfig.version = version
|
||||
writeJson(tauriConfigPath, tauriConfig)
|
||||
|
||||
const cargoToml = readFileSync(cargoTomlPath, 'utf8')
|
||||
writeFileSync(cargoTomlPath, replaceRootCargoVersion(cargoToml, version))
|
||||
|
||||
const cargoLock = readFileSync(cargoLockPath, 'utf8')
|
||||
writeFileSync(cargoLockPath, replaceLockedPackageVersion(cargoLock, 'opsxshell', version))
|
||||
|
||||
return assertVersion(root, version)
|
||||
}
|
||||
|
||||
if (process.argv[1] && resolve(process.argv[1]) === scriptPath) {
|
||||
const args = process.argv.slice(2)
|
||||
const checking = args[0] === '--check'
|
||||
const version = checking ? args[1] : args[0]
|
||||
if (!version) {
|
||||
console.error('Usage: node scripts/set-version.mjs [--check] <version>')
|
||||
process.exit(2)
|
||||
}
|
||||
try {
|
||||
const result = checking ? assertVersion(defaultRoot, version) : setVersion(defaultRoot, version)
|
||||
console.log(`[version] ${checking ? 'verified' : 'updated'} ${version}: ${Object.keys(result).join(', ')}`)
|
||||
} catch (error) {
|
||||
console.error(`[version] ${error instanceof Error ? error.message : String(error)}`)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user