feat(installer): add hosted install release alias

This commit is contained in:
yiliang114 2026-05-05 19:57:54 +08:00
parent 668c006941
commit a205e6ccdc
4 changed files with 33 additions and 1 deletions

View file

@ -34,13 +34,27 @@ GitHub releases publish these standalone archives:
- `qwen-code-linux-arm64.tar.gz`
- `qwen-code-linux-x64.tar.gz`
- `qwen-code-win-x64.zip`
- `install`
- `install-qwen.sh`
- `install-qwen.bat`
- `SHA256SUMS`
Release packaging copies these from the source-tracking installer scripts:
`install` and `install-qwen.sh` come from `install-qwen-with-source.sh`, while
`install-qwen.bat` comes from `install-qwen-with-source.bat`.
The installer scripts are published as release assets so version-specific
install entrypoints can be distributed alongside the standalone archives after
that release is created:
that release is created. The extensionless `install` asset is the Unix installer
alias for future hosted endpoints such as `https://qwen-code.ai/install`; it is
identical to `install-qwen.sh` and can be used interchangeably on Unix systems.
Use `install-qwen.bat` on Windows. That hosted endpoint is not available yet;
until it is live, use a concrete release version in the direct GitHub release
URL and replace `vX.Y.Z` with the actual release tag:
```bash
curl -fsSL https://github.com/QwenLM/qwen-code/releases/download/vX.Y.Z/install | bash
```
```bash
curl -fsSL https://github.com/QwenLM/qwen-code/releases/download/vX.Y.Z/install-qwen.sh | bash

View file

@ -13,6 +13,12 @@ const INSTALLATION_ASSETS = [
output: 'install-qwen.sh',
mode: 0o755,
},
// Hosted endpoint alias for install-qwen.sh; keep byte-for-byte identical.
{
sourcePath: ['scripts', 'installation', 'install-qwen-with-source.sh'],
output: 'install',
mode: 0o755,
},
{
sourcePath: ['scripts', 'installation', 'install-qwen-with-source.bat'],
output: 'install-qwen.bat',

View file

@ -274,6 +274,7 @@ describe('standalone release packaging', () => {
expect(releaseAssetConfig).toContain('Copyright 2025 Qwen Team');
expect(releaseAssetConfig).toContain('INSTALLATION_ASSETS');
expect(releaseAssetConfig).toContain('install-qwen-with-source.sh');
expect(releaseAssetConfig).toContain("output: 'install'");
expect(releaseAssetConfig).toContain('install-qwen.sh');
expect(releaseAssetConfig).toContain('install-qwen-with-source.bat');
expect(releaseAssetConfig).toContain('install-qwen.bat');
@ -324,12 +325,15 @@ describe('standalone release packaging', () => {
expect(INSTALLATION_ASSET_NAMES).toEqual([
'install-qwen.sh',
'install',
'install-qwen.bat',
]);
expect(isStandaloneArchiveName('qwen-code-linux-x64.tar.gz')).toBe(true);
expect(isStandaloneArchiveName('qwen-code-win-x64.zip')).toBe(true);
expect(isStandaloneArchiveName('install-qwen.sh')).toBe(false);
expect(isInstallationAssetName('install')).toBe(true);
expect(isInstallationAssetName('install-qwen.sh')).toBe(true);
expect(isReleaseChecksumAsset('install')).toBe(true);
expect(isReleaseChecksumAsset('install-qwen.bat')).toBe(true);
});
@ -393,20 +397,25 @@ describe('standalone release packaging', () => {
await buildInstallationAssets(tmpDir);
const installSh = path.join(tmpDir, 'install-qwen.sh');
const install = path.join(tmpDir, 'install');
const installBat = path.join(tmpDir, 'install-qwen.bat');
const checksums = readScript(path.join(tmpDir, 'SHA256SUMS'));
expect(readScript(installSh)).toBe(
readScript('scripts/installation/install-qwen-with-source.sh'),
);
// The hosted endpoint alias must remain byte-for-byte equivalent.
expect(readScript(install)).toBe(readScript(installSh));
expect(readScript(installBat)).toBe(
readScript('scripts/installation/install-qwen-with-source.bat'),
);
expect(checksums).toContain('qwen-code-linux-x64.tar.gz');
expect(checksums).toMatch(/\sinstall\n/);
expect(checksums).toContain('install-qwen.sh');
expect(checksums).toContain('install-qwen.bat');
if (process.platform !== 'win32') {
expect(lstatSync(installSh).mode & 0o111).not.toBe(0);
expect(lstatSync(install).mode & 0o111).not.toBe(0);
}
writeFileSync(installSh, 'tampered');
@ -637,6 +646,7 @@ describe('standalone release packaging', () => {
expect(workflow).not.toContain('verify_node_checksum()');
expect(workflow).not.toContain('download_node()');
expect(workflow).toContain('dist/standalone/qwen-code-*');
expect(workflow).toContain('dist/standalone/install \\');
expect(workflow).toContain('dist/standalone/install-qwen.sh');
expect(workflow).toContain('dist/standalone/install-qwen.bat');
expect(workflow).toContain('dist/standalone/SHA256SUMS');
@ -653,6 +663,7 @@ describe('standalone release packaging', () => {
const guide = readScript('scripts/installation/INSTALLATION_GUIDE.md');
expect(guide).toContain('Optional Native Modules');
expect(guide).toContain('https://qwen-code.ai/install');
expect(guide).toContain('node-pty');
expect(guide).toContain('clipboard');
});