mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-19 16:28:28 +00:00
fix(installer): pin versioned installer assets
This commit is contained in:
parent
bbaa8ffc75
commit
6534e6f971
3 changed files with 113 additions and 4 deletions
|
|
@ -26,6 +26,9 @@ if (isMainModule()) {
|
|||
} else {
|
||||
await buildInstallationAssets(
|
||||
path.resolve(args.outDir || path.join(rootDir, 'dist', 'standalone')),
|
||||
{
|
||||
version: args.version,
|
||||
},
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -39,7 +42,7 @@ function isMainModule() {
|
|||
}
|
||||
|
||||
async function buildInstallationAssets(outDir, options = {}) {
|
||||
const { assets = INSTALLATION_ASSETS, root = rootDir } = options;
|
||||
const { assets = INSTALLATION_ASSETS, root = rootDir, version } = options;
|
||||
fs.mkdirSync(outDir, { recursive: true });
|
||||
|
||||
for (const asset of assets) {
|
||||
|
|
@ -49,7 +52,11 @@ async function buildInstallationAssets(outDir, options = {}) {
|
|||
}
|
||||
|
||||
const destination = path.join(outDir, asset.output);
|
||||
fs.copyFileSync(source, destination);
|
||||
const contents = fs.readFileSync(source, 'utf8');
|
||||
fs.writeFileSync(
|
||||
destination,
|
||||
version ? stampInstallerVersion(contents, asset, version) : contents,
|
||||
);
|
||||
if (asset.mode !== undefined && process.platform !== 'win32') {
|
||||
fs.chmodSync(destination, asset.mode);
|
||||
}
|
||||
|
|
@ -59,6 +66,56 @@ async function buildInstallationAssets(outDir, options = {}) {
|
|||
await assertInstallationAssetChecksums(outDir, assets);
|
||||
}
|
||||
|
||||
function stampInstallerVersion(contents, asset, version) {
|
||||
validateReleaseVersion(version);
|
||||
|
||||
const sourceName = asset.sourcePath.at(-1);
|
||||
if (sourceName.endsWith('.sh')) {
|
||||
const stampedDefault = replaceRequired(
|
||||
contents,
|
||||
'VERSION="${QWEN_INSTALL_VERSION:-latest}"',
|
||||
`VERSION="\${QWEN_INSTALL_VERSION:-${version}}"`,
|
||||
asset.output,
|
||||
);
|
||||
return stampVersionHelpText(stampedDefault, asset.output, version);
|
||||
}
|
||||
|
||||
if (sourceName.endsWith('.bat')) {
|
||||
const stampedDefault = replaceRequired(
|
||||
contents,
|
||||
'set "VERSION=latest"',
|
||||
`set "VERSION=${version}"`,
|
||||
asset.output,
|
||||
);
|
||||
return stampVersionHelpText(stampedDefault, asset.output, version);
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
function replaceRequired(contents, search, replacement, output) {
|
||||
if (!contents.includes(search)) {
|
||||
fail(`Unable to stamp release version in ${output}`);
|
||||
}
|
||||
return contents.replace(search, replacement);
|
||||
}
|
||||
|
||||
function stampVersionHelpText(contents, output, version) {
|
||||
return replaceRequired(
|
||||
contents,
|
||||
'Standalone release version. Defaults to latest.',
|
||||
`Standalone release version. Defaults to ${version}.`,
|
||||
output,
|
||||
);
|
||||
}
|
||||
|
||||
function validateReleaseVersion(version) {
|
||||
if (/^v?[0-9]+\.[0-9]+\.[0-9]+([.-][A-Za-z0-9]+)*$/.test(version)) {
|
||||
return;
|
||||
}
|
||||
fail('--version must be a semver string');
|
||||
}
|
||||
|
||||
async function assertInstallationAssetChecksums(
|
||||
outDir,
|
||||
assets = INSTALLATION_ASSETS,
|
||||
|
|
@ -108,6 +165,7 @@ function parseArgs(argv) {
|
|||
const args = {
|
||||
help: false,
|
||||
outDir: undefined,
|
||||
version: undefined,
|
||||
};
|
||||
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
|
|
@ -121,6 +179,11 @@ function parseArgs(argv) {
|
|||
args.outDir = readOptionValue(argv, index, arg);
|
||||
index += 1;
|
||||
break;
|
||||
case '--version':
|
||||
args.version = readOptionValue(argv, index, arg);
|
||||
validateReleaseVersion(args.version);
|
||||
index += 1;
|
||||
break;
|
||||
default:
|
||||
fail(`Unknown option: ${arg}`);
|
||||
}
|
||||
|
|
@ -144,6 +207,8 @@ Usage:
|
|||
|
||||
Options:
|
||||
--out-dir PATH Output directory. Defaults to dist/standalone.
|
||||
--version VERSION
|
||||
Stamp release installers so their default version is VERSION.
|
||||
`);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -301,6 +301,7 @@ describe('standalone release packaging', () => {
|
|||
|
||||
expect(output).toContain('package:installation-assets');
|
||||
expect(output).toContain('--out-dir PATH');
|
||||
expect(output).toContain('--version VERSION');
|
||||
});
|
||||
|
||||
it('rejects invalid installation asset CLI arguments', () => {
|
||||
|
|
@ -312,6 +313,14 @@ describe('standalone release packaging', () => {
|
|||
['scripts/build-installation-assets.js', '--out-dir'],
|
||||
/--out-dir requires a value/,
|
||||
);
|
||||
expectCommandFailure(
|
||||
['scripts/build-installation-assets.js', '--version'],
|
||||
/--version requires a value/,
|
||||
);
|
||||
expectCommandFailure(
|
||||
['scripts/build-installation-assets.js', '--version', 'beta'],
|
||||
/--version must be a semver string/,
|
||||
);
|
||||
});
|
||||
|
||||
it('shares release asset classification helpers', async () => {
|
||||
|
|
@ -418,6 +427,37 @@ describe('standalone release packaging', () => {
|
|||
}
|
||||
});
|
||||
|
||||
it('stamps release versions into copied installation assets', async () => {
|
||||
const { assertInstallationAssetChecksums, buildInstallationAssets } =
|
||||
await import(installationAssetsScriptUrl);
|
||||
const tmpDir = mkdtempSync(path.join(tmpdir(), 'qwen-install-assets-'));
|
||||
|
||||
try {
|
||||
await buildInstallationAssets(tmpDir, { version: '0.16.0' });
|
||||
|
||||
const installSh = readScript(path.join(tmpDir, 'install-qwen.sh'));
|
||||
const installBat = readScript(path.join(tmpDir, 'install-qwen.bat'));
|
||||
|
||||
expect(installSh).toContain('VERSION="${QWEN_INSTALL_VERSION:-0.16.0}"');
|
||||
expect(installSh).toContain(
|
||||
'Standalone release version. Defaults to 0.16.0.',
|
||||
);
|
||||
expect(installSh).toContain('--version)');
|
||||
expect(installBat).toContain('set "VERSION=0.16.0"');
|
||||
expect(installBat).toContain(
|
||||
'Standalone release version. Defaults to 0.16.0.',
|
||||
);
|
||||
expect(installBat).toContain(
|
||||
'if defined QWEN_INSTALL_VERSION set "VERSION=!QWEN_INSTALL_VERSION!"',
|
||||
);
|
||||
await expect(
|
||||
assertInstallationAssetChecksums(tmpDir),
|
||||
).resolves.not.toThrow();
|
||||
} finally {
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('rejects missing installation asset sources', async () => {
|
||||
const { buildInstallationAssets } = await import(
|
||||
installationAssetsScriptUrl
|
||||
|
|
@ -633,7 +673,9 @@ describe('standalone release packaging', () => {
|
|||
const workflow = readScript('.github/workflows/release.yml');
|
||||
|
||||
expect(workflow).toContain('npm run package:standalone:release --');
|
||||
expect(workflow).toContain('npm run package:installation-assets --');
|
||||
expect(workflow).toContain(
|
||||
'npm run package:installation-assets -- --out-dir dist/standalone --version "${RELEASE_VERSION}"',
|
||||
);
|
||||
expect(workflow).not.toContain('verify_node_checksum()');
|
||||
expect(workflow).not.toContain('download_node()');
|
||||
expect(workflow).toContain('dist/standalone/qwen-code-*');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue