The previous Windows quick-install one-liner used `Invoke-WebRequest -OutFile
(Join-Path $env:TEMP 'install-qwen.bat'); & (Join-Path …)`. When pasted into a
narrow terminal, line wrap could land on `-OutFile`, orphaning the parameter
from its value and producing the "missing argument for OutFile" failure
followed by a "file not found" when the second `&` ran. PowerShell's line
continuation rules cannot resolve this for parameter-name-at-EOL.
Add `install-qwen.ps1` as a thin hosted entrypoint that downloads
`install-qwen.bat` into TEMP, runs it, and cleans up. Documented one-liner
becomes the standard pattern used by bun, uv, scoop, deno, pnpm:
powershell -ExecutionPolicy Bypass -c "irm <url>/install-qwen.ps1 | iex"
The `.bat` remains the source of truth for installer behavior; `.ps1` is just
the modern hosted entrypoint. Version pinning via `$env:QWEN_INSTALL_VERSION`
flows through unchanged. Stored with `*.ps1 -text` so CRLF survives both
GitHub raw and OSS uploads, matching the existing `.bat` handling.
- Add standalone archive installer (bat/sh) that downloads platform binaries
from GitHub/Aliyun without requiring Node.js or npm on the target machine
- Add fork-friendly release-test workflow for manual GitHub Release creation
covering all 5 platforms (darwin-arm64/x64, linux-arm64/x64, win-x64)
- Add OSS upload/mirror tools for staging and release distribution
- Update .gitignore to exclude generated build artifacts (release-staging/,
hosted-staging/)
- Fix Windows PowerShell test command in copy-release-to-latest tool
Three small refinements from the second review pass:
- normalizeHttpsBaseUrl rejects everything except https, since real release
URLs are always HTTPS. Accepting http previously would let an operator
silently target a stale or attacker-controlled mirror.
- Drop EXPECTED_RELEASE_ASSET_NAMES from the public exports; it was only
used internally for the verification log line.
- Rename the test helper standaloneChecksumContent to
placeholderChecksumContent and document that the hashes in its output are
placeholders — the remote verifier does not download archives or compare
hashes, it only validates that SHA256SUMS lists the expected names and
that each archive URL is reachable.
The non-https rejection test now also covers `http://` in addition to the
existing `file://` case.
Adds `npm run verify:installation-release` and wires it into the release
workflow after `Build Standalone Archives`, so a broken release directory
fails CI before publishing.
Local mode (`--dir PATH`) checks:
- All five `qwen-code-{platform}.{ext}` standalone archives exist.
- `SHA256SUMS` covers exactly those five — missing or unexpected entries fail.
- Each archive's actual SHA256 matches its `SHA256SUMS` entry.
Remote mode (`--base-url URL`) checks:
- `SHA256SUMS` is downloadable, parseable, and contains exactly the expected
archive entries.
- Each archive URL is reachable via HEAD, with a 1-byte ranged GET fallback
for hosts that disable HEAD.
Hosted installer scripts (`install-qwen.sh` / `install-qwen.bat`) are
intentionally out of scope here — they are served from the hosted endpoint
prepared by `package:hosted-installation` (PR #3853), not from the GitHub
Release surface this verifier targets.
- Replace the loose `latest` fragment check with per-format regex patterns
in HOSTED_INSTALLER_DEFAULT_VERSION_PATTERNS so an unrelated occurrence
of `latest` (comment, help text) cannot satisfy the staging guard. The
patterns still tolerate whitespace variation, only the default-version
assignment itself must be intact.
- Add a "Hosted endpoint status" callout in INSTALLATION_GUIDE.md before
the curl examples. The documented `--version` flow does not work against
the OSS URL today because it currently serves the legacy NVM-based
installer; the callout points users at a local checkout until the next
release sync.
- Tests: drop `latest` from the fragments equality assertion, add positive
and negative regex coverage, add a failure-path case for sources whose
default version is not `latest`, and pin the new guide markers so the
callout cannot silently disappear.
Three CI failures and a few review followups in one pass.
- ensureMinimalDist places its dist/ backup beside dist/ instead of
under os.tmpdir(). On Windows GitHub runners the workspace lives on
D: while os.tmpdir() is on C:, so renameSync raised EXDEV for every
test that needed to swap dist/ in.
- create-standalone-package.js and the matching test fixture build
win-x64 zips with [IO.Compression.ZipFile]::CreateFromDirectory.
Compress-Archive emits backslash entry names that the .bat
installer's path-traversal guard then rejected, so every freshly
built archive failed the standalone install path on Windows.
- :ValidateArchiveContents normalizes entry separators to '/' before
checking for '..', absolute paths, and drive prefixes - archives
from any Windows zip tool still install while real traversal
entries remain rejected.
- createWindowsTraversalStandaloneArchive runs PowerShell via -File
instead of a single -Command line; the joined-with-'; ' form had a
function definition the runner's PowerShell refused to parse.
Drive-by review followups:
- replaceRequired uses replaceAll so a future duplicate placeholder
cannot silently keep the trailing copy as 'latest'.
- :ValidateOptions runs the unsafe-character check on SOURCE
alongside the other variables.
- build-installation-assets.js drops a dead INSTALLATION_ASSETS
re-export; consumers already import from release-asset-config.js.
- .gitignore covers the new sibling .qwen-dist-backup-* directory.
- sh: reject CR/LF in archive entry names before the literal `..` glob so
a `..\r` entry cannot bypass path validation.
- bat: prefer Tls12+Tls13 in PowerShell helpers, fall back to Tls12 alone
on older .NET Framework where the Tls13 enum is missing.
- bat: document the implicit `:ValidateOptions` dependency next to the
qwen.cmd wrapper writer so loosening the validator stays a conscious
choice.
- build-standalone-release: surface the `xz-utils` host requirement for
Linux Node downloads in `--help`.
- release-script-utils: support `--key=value` form in `parseCliArgs`.
- tests: cover the new CRLF message, TLS string, and `--key=value` parsing;
register process-level signal/exit handlers in `ensureMinimalDist` so a
crashed test still restores `dist/`.
Move four duplicated utility functions (getArgs, readJson,
validateVersion, isExpectedMissingGitHubRelease) from the three
get-release-version.js scripts into a shared module at
scripts/lib/release-helpers.js so that changes only need to happen
in one place.
Also fixes a pre-existing bug in getArgs where argument values
containing '=' were silently truncated (e.g. --msg=a=b produced
{msg:'a'} instead of {msg:'a=b'}).
Closes#3795🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
Co-authored-by: jinye.djy <jinye.djy@alibaba-inc.com>
* feat(sdk-python): add pypi release workflow
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): build cli before smoke test
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): tighten release conflict handling
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): harden python release workflow
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): tighten stable release guards
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): harden prerelease publish flow
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): reuse release branches on rerun
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): resume incomplete releases
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(release): tighten missing-release checks
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): resume stable release reruns
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): tighten release recovery guards
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(sdk-python): cover release version edge cases
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): address release workflow review feedback
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* refactor(sdk-python): address review feedback on release version script
- Remove unreachable `if (type === 'stable')` branch in bumpVersion();
the stable path was dead code since getVersion() throws for all
stable conflicts before calling bumpVersion(). Move nightly conflict
throw to the call site for symmetry.
- Rename getNextPatchBaseVersion → getNextBaseVersion to reflect that
the function can return a prerelease base without incrementing patch.
- Add test for preview+nightly coexistence where nightly base is higher.
🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
* fix(sdk-python): address remaining review feedback on release workflow
- Fix failure-issue gate to read github.event.inputs.dry_run directly
instead of steps.vars.outputs.is_dry_run (which is empty when early
steps fail). Add --repo flag for gh issue create when checkout failed.
- Add diagnostic state table to failure-issue body (RELEASE_TAG,
PACKAGE_VERSION, PUBLISH_CHANNEL, RESUME_EXISTING_RELEASE, etc.)
- Fix release-notes error swallow: only silence release not found /
Not Found / HTTP 404, emit :⚠️: for other gh release view errors.
- Improve validateVersion error messages to use human-readable format
keys (X.Y.Z, X.Y.Z-preview.N) matching TS sibling convention.
- Filter fully-yanked versions in getAllVersionsFromPyPI.
- Add console.error log when stable is derived from nightly.
- Add bash regex guard for inputs.version to prevent shell injection.
- Use per-release-type concurrency groups (nightly/preview/stable).
- Add jq null-guard checks for all 6 field extractions.
- Remove misleading --follow-tags from git push (lightweight tags).
🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
* fix(sdk-python): rename misleading test description
The test asserts that preview/nightly releases return empty
previousReleaseTag, but the name said "same-channel previous
release tags" which implied non-empty values.
🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
* fix(sdk-python): address unresolved review comments on release workflow
- Remove -z check in extract_field() that blocked preview/nightly releases
(previousReleaseTag is legitimately empty for non-stable releases)
- Use static environment.url since step outputs aren't available at job startup
- Use skip-existing for resumed PyPI publish to fill in missing artifacts
- Add AbortSignal.timeout(30s) to PyPI fetch to prevent indefinite hangs
- Add downgrade guard for stable_version_override
- Use GHA :⚠️: annotation instead of console.error for visibility
- Separate yanked/non-yanked version lists so conflict detection includes
yanked versions (PyPI still reserves those slots)
- Filter current release from previousReleaseTag to avoid self-reference on resume
- Add tests for yanked conflict detection, downgrade guard, and resume previousReleaseTag
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(sdk-python): address final review round on release version script
- Fix getNextBaseVersion() first-release skip: use pyproject.toml version
directly when PyPI has no stable versions instead of unconditionally
incrementing
- Fix getNextBaseVersion() off-by-one: change > to >= so equal prerelease
base continues the existing line instead of incrementing patch
- Add :⚠️: annotation when preview auto-bumps due to orphan git
tags (tag exists without PyPI version or GitHub release)
- Add set -euo pipefail to 5 workflow steps missing it: release_branch,
persist_source, Create GitHub release, Delete prerelease branch, Create
issue on failure
- Fix 2 existing tests affected by first-release change, add 4 new tests
🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
* fix(sdk-python): use stderr for GHA warning annotations to avoid corrupting JSON stdout
console.log writes to stdout, which gets captured by VERSION_JSON=$(node ...)
in the workflow and corrupts the JSON output for jq. Switch to console.error
so :⚠️: annotations go to stderr (GHA recognizes workflow commands on
both streams). Also add set -euo pipefail to the "Get the version" step for
consistency with other workflow steps.
🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
---------
Co-authored-by: jinye.djy <jinye.djy@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>