CI: publish the desktop nightly with curl, since vpk's Gitea client cannot read the upgraded forge's replies
ci / build and test (push) Successful in 3m35s
ci / android head (push) Successful in 3m43s
ci / api image (push) Successful in 7s
ci / desktop nightly (push) Successful in 1m25s

Moving vpk to 1.2.161 was not enough: it got further and failed the same way, one frame later.
Both versions use a generated Gitea SDK that gets null back from 'create release' on the forge's
28.0.0, although the release is created, so the step threw before uploading anything and left an
empty draft behind on every push since 2 October.

The upload is now the android job's curl pattern. The release is created as a draft prerelease,
the three packages go up, then releases.win-nightly.json, which vpk pack already wrote and which is
exactly the index vpk upload would have generated, and only then is it published. The read-back
check, the RPM and the Linux manifest after it are unchanged.
This commit is contained in:
jaap-jan committed 2026-10-03 19:56:53 +02:00
1 parent e240c0cf26
commit ad1a129159
1 file changed
+48 -24
+48 -24
View File
@@ -1221,27 +1221,55 @@ jobs:
fi fi
curl -fsS -X DELETE -H "$auth" "$api/tags/$TAG" >/dev/null 2>&1 || true curl -fsS -X DELETE -H "$auth" "$api/tags/$TAG" >/dev/null 2>&1 || true
# vpk rather than curl, unlike the android job above, and the difference is what is being # curl, like the android job above, and no longer `vpk upload gitea`. vpk's Gitea client is a
# uploaded. An APK is one file the client is told about by a manifest this repository writes; a # generated SDK that cannot read the forge's answer to "create a release" since its upgrade to
# Velopack release is a set of files plus an index whose format is Velopack's own. Writing that # 28.0.0: the release is created and the client gets null back, so both 1.2.0 and 1.2.161 threw a
# index by hand would be reimplementing the tool that is already here. # NullReferenceException before uploading anything, leaving an empty draft behind on every push.
# Nothing here writes Velopack's index by hand: `vpk pack` already wrote releases.win-nightly.json
# beside the packages, and with no earlier release downloaded into that directory it is exactly
# the index `vpk upload` would have generated from it.
# #
# --pre is load-bearing twice over. It keeps this out of the release channel, which refuses # A draft first, published only once everything is on it, which is the order vpk used too: the
# client reads the index and then fetches what it names, and a published release missing a
# package is a few seconds in which every desktop is told to download something that is not
# there. The index goes up last for the same reason.
#
# prerelease is load-bearing twice over. It keeps this out of the release channel, which refuses
# prereleases — and it keeps it out of `releases/latest`, which is what the *phone's* release # prereleases — and it keeps it out of `releases/latest`, which is what the *phone's* release
# channel reads: a desktop nightly published as a stable release would become the newest release # channel reads: a desktop nightly published as a stable release would become the newest release
# in this repository and every phone on the release channel would start failing its update check # in this repository and every phone on the release channel would start failing its update check
# against a release carrying no android manifest. # against a release carrying no android manifest.
dotnet vpk upload gitea \ releases="$RUNNER_TEMP/nightly-releases"
--skip-updates \
--repoUrl "$FORGE/$REPO" \ created="$(curl -fsS -X POST -H "$auth" -H 'Content-Type: application/json' \
--token "$TOKEN" \ -d "$(printf '{"tag_name":"%s","target_commitish":"%s","name":"Nightly desktop %s","draft":true,"prerelease":true,"body":"Built from %s by CI. Installs beside the release build, never over it."}' \
--outputDir "$RUNNER_TEMP/nightly-releases" \ "$TAG" "$GITHUB_SHA" "$VERSION" "$GITHUB_SHA")" \
--channel win-nightly \ "$api/releases")"
--tag "$TAG" \
--releaseName "Nightly desktop $VERSION" \ draft="$(printf '%s' "$created" | release_id)"
--targetCommitish "$GITHUB_SHA" \ if [ -z "$draft" ]; then
--pre \ echo "Gitea accepted the release call and returned no id:" >&2
--publish printf '%s\n' "$created" >&2
exit 1
fi
for file in "$releases"/*-full.nupkg "$releases"/*-Portable.zip "$releases"/*-Setup.exe \
"$releases"/releases.win-nightly.json; do
if [ ! -f "$file" ]; then
echo "vpk pack did not leave $file behind:" >&2
ls -la "$releases" >&2
exit 1
fi
name="$(basename "$file")"
echo "Uploading $name ($(wc -c < "$file") bytes)"
curl -fsS -X POST -H "$auth" \
-F "attachment=@$file" \
"$api/releases/$draft/assets?name=$name" >/dev/null
done
curl -fsS -X PATCH -H "$auth" -H 'Content-Type: application/json' \
-d '{"draft":false}' \
"$api/releases/$draft" >/dev/null
# Asked for back rather than assumed, and the android job's history is why: it once created a # Asked for back rather than assumed, and the android job's history is why: it once created a
# release, uploaded nothing, and reported success for every upload it never made. A nightly # release, uploaded nothing, and reported success for every upload it never made. A nightly
@@ -1260,20 +1288,16 @@ jobs:
fi fi
done done
# ◆ THE RPM GOES ONTO THE RELEASE vpk JUST MADE, RATHER THAN ONTO ONE OF ITS OWN. # ◆ THE RPM GOES ONTO THE RELEASE JUST MADE, RATHER THAN ONTO ONE OF ITS OWN.
# #
# One rolling release carrying both heads, because they are one nightly: the same commit, # One rolling release carrying both heads, because they are one nightly: the same commit,
# the same version, and one page a person looks at to find out what is on main. A second tag # the same version, and one page a person looks at to find out what is on main. A second tag
# would double the delete-and-recreate dance this step already does, and would let the two # would double the delete-and-recreate dance this step already does, and would let the two
# drift apart on a run where one of them failed. # drift apart on a run where one of them failed.
# #
# It has to happen here, after `vpk upload`, and not in a step before it. vpk deletes and # It has to happen here, after the Windows upload, and not in a step before it. This step
# recreates this release, so an RPM uploaded first would be attached to something that no # deletes and recreates the release, so an RPM uploaded first would be attached to something
# longer exists by the time the job ends — silently, because the delete succeeds. # that no longer exists by the time the job ends — silently, because the delete succeeds.
#
# curl rather than vpk, unlike the assets above, for the reason the android job gives about
# its APK: this is one file the release simply carries. There is no index to write and no
# format that belongs to a tool.
release="$(printf '%s' "$published" | release_id)" release="$(printf '%s' "$published" | release_id)"
if [ -z "$release" ]; then if [ -z "$release" ]; then
echo "The release was published and its id could not be read back:" >&2 echo "The release was published and its id could not be read back:" >&2