Public Access
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad1a129159 | ||
|
|
e240c0cf26 |
No files matched your search
+48
-24
@@ -1221,27 +1221,55 @@ jobs:
|
||||
fi
|
||||
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
|
||||
# uploaded. An APK is one file the client is told about by a manifest this repository writes; a
|
||||
# Velopack release is a set of files plus an index whose format is Velopack's own. Writing that
|
||||
# index by hand would be reimplementing the tool that is already here.
|
||||
# curl, like the android job above, and no longer `vpk upload gitea`. vpk's Gitea client is a
|
||||
# generated SDK that cannot read the forge's answer to "create a release" since its upgrade to
|
||||
# 28.0.0: the release is created and the client gets null back, so both 1.2.0 and 1.2.161 threw a
|
||||
# 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
|
||||
# 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
|
||||
# against a release carrying no android manifest.
|
||||
dotnet vpk upload gitea \
|
||||
--skip-updates \
|
||||
--repoUrl "$FORGE/$REPO" \
|
||||
--token "$TOKEN" \
|
||||
--outputDir "$RUNNER_TEMP/nightly-releases" \
|
||||
--channel win-nightly \
|
||||
--tag "$TAG" \
|
||||
--releaseName "Nightly desktop $VERSION" \
|
||||
--targetCommitish "$GITHUB_SHA" \
|
||||
--pre \
|
||||
--publish
|
||||
releases="$RUNNER_TEMP/nightly-releases"
|
||||
|
||||
created="$(curl -fsS -X POST -H "$auth" -H 'Content-Type: application/json' \
|
||||
-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."}' \
|
||||
"$TAG" "$GITHUB_SHA" "$VERSION" "$GITHUB_SHA")" \
|
||||
"$api/releases")"
|
||||
|
||||
draft="$(printf '%s' "$created" | release_id)"
|
||||
if [ -z "$draft" ]; then
|
||||
echo "Gitea accepted the release call and returned no id:" >&2
|
||||
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
|
||||
# release, uploaded nothing, and reported success for every upload it never made. A nightly
|
||||
@@ -1260,20 +1288,16 @@ jobs:
|
||||
fi
|
||||
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,
|
||||
# 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
|
||||
# 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
|
||||
# recreates this release, so an RPM uploaded first would be attached to something 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.
|
||||
# It has to happen here, after the Windows upload, and not in a step before it. This step
|
||||
# deletes and recreates the release, so an RPM uploaded first would be attached to something
|
||||
# that no longer exists by the time the job ends — silently, because the delete succeeds.
|
||||
release="$(printf '%s' "$published" | release_id)"
|
||||
if [ -z "$release" ]; then
|
||||
echo "The release was published and its id could not be read back:" >&2
|
||||
|
||||
@@ -15,28 +15,39 @@ public sealed class ProbedDeviceKeyStoreTests
|
||||
{
|
||||
private static CancellationToken Token => TestContext.Current.CancellationToken;
|
||||
|
||||
/// <remarks>
|
||||
/// "Off the caller's thread" is proved by blocking, not by comparing thread ids. The probe waits for a
|
||||
/// release the test only gives once construction has returned, so a probe run on the thread that
|
||||
/// constructed the store could never be released and times out instead. Thread ids proved nothing: the
|
||||
/// test itself runs on a pool thread, and that same thread is free to pick up the queued probe the
|
||||
/// moment the test awaits, which is what failed on CI with the code doing exactly the right thing.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task TheChoiceIsMadeOnce_OffTheCallersThread()
|
||||
{
|
||||
var asking = Environment.CurrentManagedThreadId;
|
||||
var probes = 0;
|
||||
var probedOn = 0;
|
||||
var releasedInTime = false;
|
||||
|
||||
using var release = new ManualResetEventSlim();
|
||||
var inner = Substitute.For<IDeviceKeyStore>();
|
||||
|
||||
var store = new ProbedDeviceKeyStore(() =>
|
||||
{
|
||||
Interlocked.Increment(ref probes);
|
||||
probedOn = Environment.CurrentManagedThreadId;
|
||||
releasedInTime = release.Wait(TimeSpan.FromSeconds(10));
|
||||
return inner;
|
||||
});
|
||||
|
||||
(await store.IsAvailableAsync(Token)).ShouldBeTrue();
|
||||
var available = store.IsAvailableAsync(Token);
|
||||
available.IsCompleted.ShouldBeFalse("nothing has released the probe yet");
|
||||
release.Set();
|
||||
|
||||
(await available).ShouldBeTrue();
|
||||
(await store.IsAvailableAsync(Token)).ShouldBeTrue();
|
||||
await store.TryLoadAsync(Token);
|
||||
|
||||
releasedInTime.ShouldBeTrue("the probe ran on the thread that asked, so nothing could release it");
|
||||
probes.ShouldBe(1);
|
||||
probedOn.ShouldNotBe(asking);
|
||||
|
||||
// Availability is the choice, not a second probe through the store it chose.
|
||||
await inner.DidNotReceive().IsAvailableAsync(Arg.Any<CancellationToken>());
|
||||
|
||||
Reference in new issue
Block a user