mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-19 07:54:38 +00:00
feat(installer): restore hosted PowerShell entrypoint
This commit is contained in:
parent
fedcbae1c9
commit
af64da874f
4 changed files with 80 additions and 13 deletions
|
|
@ -27,6 +27,10 @@ const HOSTED_INSTALLATION_ASSETS = [
|
|||
output: 'install-qwen.bat',
|
||||
lineEndings: 'crlf',
|
||||
},
|
||||
{
|
||||
sourcePath: ['scripts', 'installation', 'install-qwen.ps1'],
|
||||
output: 'install-qwen.ps1',
|
||||
},
|
||||
];
|
||||
const HOSTED_INSTALLATION_ASSET_NAMES = HOSTED_INSTALLATION_ASSETS.map(
|
||||
({ output }) => output,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ are only required when the installer falls back to npm or when
|
|||
## Installation Scripts
|
||||
|
||||
- Linux/macOS: `install-qwen.sh`
|
||||
- Windows: `install-qwen.bat`
|
||||
- Windows: `install-qwen.ps1`
|
||||
|
||||
## Release Artifacts
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ GitHub releases publish these standalone archives:
|
|||
- `SHA256SUMS`
|
||||
|
||||
The installer scripts (`install-qwen.sh`,
|
||||
`install-qwen.bat`) are not republished per release. They are
|
||||
`install-qwen.ps1`) are not republished per release. They are
|
||||
served from a hosted installation endpoint and accept `--version` to pin a
|
||||
specific standalone release. This keeps the public install command on a stable
|
||||
hosted entrypoint while still allowing version pinning, rather than using
|
||||
|
|
@ -58,16 +58,15 @@ curl -fsSL https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/in
|
|||
```
|
||||
|
||||
```cmd
|
||||
powershell -Command "Invoke-WebRequest 'https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen.bat' -OutFile (Join-Path $env:TEMP 'install-qwen.bat'); & (Join-Path $env:TEMP 'install-qwen.bat')"
|
||||
powershell -ExecutionPolicy Bypass -c "irm https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen.ps1 | iex"
|
||||
```
|
||||
|
||||
To pin a release with the hosted Windows entrypoint, download `install-qwen.bat`
|
||||
and pass `--version`:
|
||||
To pin a release with the hosted Windows entrypoint, set
|
||||
`QWEN_INSTALL_VERSION` before invoking `install-qwen.ps1`:
|
||||
|
||||
```powershell
|
||||
$installer = Join-Path $env:TEMP 'install-qwen.bat'
|
||||
Invoke-WebRequest 'https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen.bat' -OutFile $installer
|
||||
& $installer --version vX.Y.Z
|
||||
$env:QWEN_INSTALL_VERSION = 'vX.Y.Z'
|
||||
irm https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen.ps1 | iex
|
||||
```
|
||||
|
||||
`QWEN_INSTALL_VERSION` is the equivalent environment variable when arguments
|
||||
|
|
@ -76,7 +75,9 @@ cannot be passed through.
|
|||
Hosted installer assets are staged separately from GitHub Release archives:
|
||||
|
||||
- `install-qwen.sh` is the Linux/macOS hosted entrypoint.
|
||||
- `install-qwen.bat` is the Windows hosted entrypoint (also runnable directly).
|
||||
- `install-qwen.ps1` is the Windows hosted entrypoint for `irm | iex`.
|
||||
- `install-qwen.bat` is the Windows installer implementation used by
|
||||
`install-qwen.ps1` and can also be downloaded and run directly.
|
||||
|
||||
Build them with:
|
||||
|
||||
|
|
@ -84,9 +85,11 @@ Build them with:
|
|||
npm run package:hosted-installation -- --out-dir dist/installation
|
||||
```
|
||||
|
||||
The staged `install-qwen.sh` and `install-qwen.bat` files map to the fixed
|
||||
The staged `install-qwen.sh`, `install-qwen.ps1`, and `install-qwen.bat` files
|
||||
map to the fixed
|
||||
hosted URLs shown above. Upload their contents byte-for-byte to
|
||||
`installation/install-qwen.sh` and `installation/install-qwen.bat`; the staging
|
||||
`installation/install-qwen.sh`, `installation/install-qwen.ps1`, and
|
||||
`installation/install-qwen.bat`; the staging
|
||||
command also writes `SHA256SUMS` for upload verification. The hosted installers
|
||||
intentionally default to `latest`; use `--version` or `QWEN_INSTALL_VERSION` to
|
||||
pin a standalone release. OSS/CDN upload automation is still a follow-up release
|
||||
|
|
|
|||
37
scripts/installation/install-qwen.ps1
Normal file
37
scripts/installation/install-qwen.ps1
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Qwen Code Windows hosted PowerShell entrypoint.
|
||||
# Pairs with install-qwen.bat: this shim downloads the .bat into TEMP and runs
|
||||
# it, so the documented one-liner can use the standard irm | iex pattern.
|
||||
#
|
||||
# Usage:
|
||||
# powershell -ExecutionPolicy Bypass -c "irm https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen.ps1 | iex"
|
||||
#
|
||||
# To pin a specific release, set $env:QWEN_INSTALL_VERSION before invoking,
|
||||
# e.g. $env:QWEN_INSTALL_VERSION = 'vX.Y.Z'. This is equivalent to passing
|
||||
# --version vX.Y.Z to install-qwen.bat directly.
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$qwenInstallerUrl = 'https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen.bat'
|
||||
$qwenInstallerPath = Join-Path $env:TEMP 'install-qwen.bat'
|
||||
|
||||
try {
|
||||
Invoke-WebRequest -Uri $qwenInstallerUrl `
|
||||
-OutFile $qwenInstallerPath `
|
||||
-UseBasicParsing `
|
||||
-MaximumRedirection 10
|
||||
} catch {
|
||||
Write-Error "Failed to download Qwen Code installer from ${qwenInstallerUrl}: $($_.Exception.Message)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$qwenInstallerExitCode = 0
|
||||
try {
|
||||
& $qwenInstallerPath @args
|
||||
$qwenInstallerExitCode = $LASTEXITCODE
|
||||
} finally {
|
||||
Remove-Item -Path $qwenInstallerPath -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
if ($qwenInstallerExitCode -ne 0) {
|
||||
exit $qwenInstallerExitCode
|
||||
}
|
||||
|
|
@ -264,6 +264,7 @@ describe('standalone release packaging', () => {
|
|||
expect(hostedInstallScript).toContain('HOSTED_INSTALLATION_ASSETS');
|
||||
expect(hostedInstallScript).toContain("output: 'install-qwen.sh'");
|
||||
expect(hostedInstallScript).toContain("output: 'install-qwen.bat'");
|
||||
expect(hostedInstallScript).toContain("output: 'install-qwen.ps1'");
|
||||
expect(hostedInstallScript).not.toContain("output: 'install'");
|
||||
|
||||
const releaseVerifyScript = readScript(
|
||||
|
|
@ -409,6 +410,15 @@ describe('standalone release packaging', () => {
|
|||
);
|
||||
expect(installBatchSource).toContain('"%~1"=="--version"');
|
||||
expect(installBatchSource).toContain('--version requires a value');
|
||||
|
||||
const installPowerShellSource = readScript(
|
||||
'scripts/installation/install-qwen.ps1',
|
||||
);
|
||||
expect(installPowerShellSource).toContain('install-qwen.bat');
|
||||
expect(installPowerShellSource).toContain('Invoke-WebRequest');
|
||||
expect(installPowerShellSource).toContain('QWEN_INSTALL_VERSION');
|
||||
expect(installPowerShellSource).toContain('--version vX.Y.Z');
|
||||
expect(installPowerShellSource).toContain('@args');
|
||||
});
|
||||
|
||||
it('stages hosted installation assets with checksums', async () => {
|
||||
|
|
@ -425,12 +435,14 @@ describe('standalone release packaging', () => {
|
|||
|
||||
const installSh = path.join(tmpDir, 'install-qwen.sh');
|
||||
const installBat = path.join(tmpDir, 'install-qwen.bat');
|
||||
const installPs1 = path.join(tmpDir, 'install-qwen.ps1');
|
||||
const checksums = readScript(path.join(tmpDir, 'SHA256SUMS'));
|
||||
const checksumLines = checksums.trim().split('\n');
|
||||
|
||||
expect(HOSTED_INSTALLATION_ASSET_NAMES).toEqual([
|
||||
'install-qwen.sh',
|
||||
'install-qwen.bat',
|
||||
'install-qwen.ps1',
|
||||
]);
|
||||
expect(HOSTED_INSTALLATION_ASSETS.map(({ output }) => output)).toEqual(
|
||||
HOSTED_INSTALLATION_ASSET_NAMES,
|
||||
|
|
@ -444,14 +456,18 @@ describe('standalone release packaging', () => {
|
|||
'\r\n',
|
||||
),
|
||||
);
|
||||
expect(readScript(installPs1)).toBe(
|
||||
readScript('scripts/installation/install-qwen.ps1'),
|
||||
);
|
||||
expect(existsSync(path.join(tmpDir, 'install'))).toBe(false);
|
||||
expect(existsSync(path.join(tmpDir, 'install-qwen.ps1'))).toBe(false);
|
||||
expect(checksumLines.map((line) => line.split(' ')[1])).toEqual([
|
||||
'install-qwen.bat',
|
||||
'install-qwen.ps1',
|
||||
'install-qwen.sh',
|
||||
]);
|
||||
expect(checksums).toMatch(/^[0-9a-f]{64} {2}install-qwen\.sh$/m);
|
||||
expect(checksums).toMatch(/^[0-9a-f]{64} {2}install-qwen\.bat$/m);
|
||||
expect(checksums).toMatch(/^[0-9a-f]{64} {2}install-qwen\.ps1$/m);
|
||||
if (process.platform !== 'win32') {
|
||||
expect(lstatSync(installSh).mode & 0o111).not.toBe(0);
|
||||
}
|
||||
|
|
@ -485,6 +501,10 @@ describe('standalone release packaging', () => {
|
|||
path.join(sourceDir, 'install-qwen.bat'),
|
||||
'@echo off\r\nset "VERSION=latest"\r\n',
|
||||
);
|
||||
writeFileSync(
|
||||
path.join(sourceDir, 'install-qwen.ps1'),
|
||||
"# --version vX.Y.Z\n$env:QWEN_INSTALL_VERSION = 'latest'\n",
|
||||
);
|
||||
|
||||
await expect(
|
||||
buildHostedInstallationAssets(tmpDir, { root: tmpRoot }),
|
||||
|
|
@ -598,7 +618,7 @@ describe('standalone release packaging', () => {
|
|||
]);
|
||||
}
|
||||
for (const [url] of fetchedUrls) {
|
||||
expect(url).not.toMatch(/install-qwen\.(sh|bat)$/);
|
||||
expect(url).not.toMatch(/install-qwen\.(sh|bat|ps1)$/);
|
||||
expect(url).not.toMatch(/\/install$/);
|
||||
}
|
||||
});
|
||||
|
|
@ -831,6 +851,7 @@ describe('standalone release packaging', () => {
|
|||
expect(workflow).not.toContain('package:installation-assets');
|
||||
expect(workflow).not.toContain('install-qwen.sh');
|
||||
expect(workflow).not.toContain('install-qwen.bat');
|
||||
expect(workflow).not.toContain('install-qwen.ps1');
|
||||
expect(workflow).not.toContain('verify_node_checksum()');
|
||||
expect(workflow).not.toContain('download_node()');
|
||||
expect(workflow).toContain('dist/standalone/qwen-code-*.tar.gz');
|
||||
|
|
@ -855,6 +876,8 @@ describe('standalone release packaging', () => {
|
|||
expect(guide).toContain('package:hosted-installation');
|
||||
expect(guide).toContain('installation/install-qwen.sh');
|
||||
expect(guide).toContain('installation/install-qwen.bat');
|
||||
expect(guide).toContain('installation/install-qwen.ps1');
|
||||
expect(guide).toContain('irm https://qwen-code-assets');
|
||||
expect(guide).toContain('release operators must sync these staged files');
|
||||
expect(guide).toContain('Hosted endpoint status');
|
||||
expect(guide).toContain('legacy NVM-based installer');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue