Skip to content

Add a windows package job to the release workflow - #7987

Open
denusklo wants to merge 1 commit into
coder:mainfrom
denusklo:windows-release-job
Open

Add a windows package job to the release workflow#7987
denusklo wants to merge 1 commit into
coder:mainfrom
denusklo:windows-release-job

Conversation

@denusklo

@denusklo denusklo commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Windows is the one platform code-server has no build for, so tode, and
anything else that wants a server on that machine, has nowhere to get one.
This adds a third job beside package-linux and package-macos that produces a
windows-x64 tarball the same way they produce theirs: on that platform's own
runner, with the native modules compiled there, uploaded to the same draft
release.

Most of it is the macos job with a different runner. What follows is every
place windows needed something else, and why.

The default shell is set to bash for the job rather than on each step, since
windows is the one runner whose default is not bash.

Git rewrites line endings on checkout on windows. That turns every shell
script the build is made of into one bash cannot read, and every name in
patches/series into one with a stray return on the end.

OS is answered up front. ci/lib.sh works the system out only when OS is empty,
and windows sets OS to Windows_NT for every process, so the detection never
runs and every question the build asks about the system gets Windows_NT
instead -- which launchers to fix up, what the archive is called. The check for
an existing value is what makes answering it up front the intended way; a
fix inside ci/lib.sh is possible but belongs in its own change.

quilt has no windows build, so the patches are applied with git. They are
ordinary -p1 diffs against the repository root and go on in the order series
names them. Worth knowing for anyone who prefers the symmetry: msys2 packages
quilt, and this job already installs one package from it, so quilt push -a
here is plausible. It is untried on a runner, so it is not what this does.

npm hands every script it runs to cmd, which cannot run the shell scripts this
repository is built out of, so npm_config_script_shell points it at the same
bash the steps use.

jq is handed a process substitution when the build merges json, which bash
presents as a file under /dev/fd. The jq on this image is a windows program
and cannot open those: it reads the second input as nothing and the merge
fails silently. The shim copies those arguments to real files.

signtool has to be findable. Stamping version details into the native binaries
clears any signature first and asks signtool whether there is one, which only
reads and removes -- no certificate, nothing signed.

rsync exists in the MSYS2 already on the image but not on the path, and it is
reached through a forwarder rather than by putting msys2's /usr/bin in front.
Measured, because the obvious way fails strangely: npm on the path is a shell
script whose shebang reads /usr/bin/env bash, so with msys2 first it is msys2's
bash that runs it, and crossing into a second msys runtime does not carry the
environment -- 93 variables arrived as 7, PATH rebuilt from msys2's defaults.
npm then saw no script-shell and fell back to cmd, and KEEP_MODULES was dropped
by the same crossing, which would have produced a release tree with no
node_modules and no node beside it and said nothing about it.

The archive step asserts it has GNU tar. Of the two on this image only git
bash's can rename the tree's top directory as it archives; the windows bsdtar
is built without substitution support and refuses -s outright. They are
interchangeable everywhere except in exactly this, so it is checked rather
than assumed.

This depends on the windows arms of the build scripts being correct. Without
those fixes the release step fails on a missing node, and with them this job
has produced a tarball that unpacks and runs: the server serves, the extension
host starts, and a terminal in the workbench round-trips a command.

Two things deliberately left out. There is no node-gyp header cache, which
existed while this was being brought up and only saved downloads. And
npm run test:native is not here, because it has not been run on windows; it
would be a small addition once the job exists to run it in.

Windows is the one platform code-server has no build for, so `tode`, and
anything else that wants a server on that machine, has nowhere to get one.
This adds a third job beside package-linux and package-macos that produces a
windows-x64 tarball the same way they produce theirs: on that platform's own
runner, with the native modules compiled there, uploaded to the same draft
release.

Most of it is the macos job with a different runner. What follows is every
place windows needed something else, and why.

The default shell is set to bash for the job rather than on each step, since
windows is the one runner whose default is not bash.

Git rewrites line endings on checkout on windows. That turns every shell
script the build is made of into one bash cannot read, and every name in
patches/series into one with a stray return on the end.

OS is answered up front. ci/lib.sh works the system out only when OS is empty,
and windows sets OS to Windows_NT for every process, so the detection never
runs and every question the build asks about the system gets Windows_NT
instead -- which launchers to fix up, what the archive is called. The check for
an existing value is what makes answering it up front the intended way; a
fix inside ci/lib.sh is possible but belongs in its own change.

quilt has no windows build, so the patches are applied with git. They are
ordinary -p1 diffs against the repository root and go on in the order series
names them. Worth knowing for anyone who prefers the symmetry: msys2 packages
quilt, and this job already installs one package from it, so `quilt push -a`
here is plausible. It is untried on a runner, so it is not what this does.

npm hands every script it runs to cmd, which cannot run the shell scripts this
repository is built out of, so npm_config_script_shell points it at the same
bash the steps use.

jq is handed a process substitution when the build merges json, which bash
presents as a file under /dev/fd. The jq on this image is a windows program
and cannot open those: it reads the second input as nothing and the merge
fails silently. The shim copies those arguments to real files.

signtool has to be findable. Stamping version details into the native binaries
clears any signature first and asks signtool whether there is one, which only
reads and removes -- no certificate, nothing signed.

rsync exists in the MSYS2 already on the image but not on the path, and it is
reached through a forwarder rather than by putting msys2's /usr/bin in front.
Measured, because the obvious way fails strangely: npm on the path is a shell
script whose shebang reads /usr/bin/env bash, so with msys2 first it is msys2's
bash that runs it, and crossing into a second msys runtime does not carry the
environment -- 93 variables arrived as 7, PATH rebuilt from msys2's defaults.
npm then saw no script-shell and fell back to cmd, and KEEP_MODULES was dropped
by the same crossing, which would have produced a release tree with no
node_modules and no node beside it and said nothing about it.

The archive step asserts it has GNU tar. Of the two on this image only git
bash's can rename the tree's top directory as it archives; the windows bsdtar
is built without substitution support and refuses -s outright. They are
interchangeable everywhere except in exactly this, so it is checked rather
than assumed.

This depends on the windows arms of the build scripts being correct. Without
those fixes the release step fails on a missing node, and with them this job
has produced a tarball that unpacks and runs: the server serves, the extension
host starts, and a terminal in the workbench round-trips a command.

Two things deliberately left out. There is no node-gyp header cache, which
existed while this was being brought up and only saved downloads. And
npm run test:native is not here, because it has not been run on windows; it
would be a small addition once the job exists to run it in.
@denusklo
denusklo requested a review from a team as a code owner September 5, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant