Public Access
Copy the checkout into the container, because a socket is not a shared filesystem
The container started and could not see the repository: MSBUILD : error MSB1009: Project file does not exist. Switch: src/DodoSSH.Client.Android/DodoSSH.Client.Android.csproj `-v "$PWD:/build"` cannot work here. This runner is itself a container holding the host's Docker socket, so the workspace path it reports — /root/.cache/act/<hash>/… — exists in the runner and not on the daemon's host, which is where Docker resolves a bind source. It finds nothing, creates an empty directory, and mounts that. Nothing about the failure says so. Nothing earlier in this workflow would have caught it either, and that is the part worth keeping: the image job's `docker build` sends its context over the API and Testcontainers mounts nothing, so neither of the two places this repository already used Docker proves a bind mount would work. I read a working daemon as a shared filesystem, and they are not the same claim. `docker cp` goes over the same API and so does not care where the daemon lives. In with the whole checkout, .git included, since MinVer and the versionCode both read it — the repository is well under a megabyte packed. Out with the staged package. The NuGet cache becomes a named volume for the same reason: it lives on the daemon and needs no path either side has to agree on. The two container steps collapse into one, since with a copy in and a copy out there is nothing to be gained by paying for both twice, and scripts/ci-android.sh is now what runs inside — a file that can be read and executed on its own rather than a heredoc inside a workflow. Exercised locally against a real clone, every step as the job runs it: create, cp in, start --attach, cp out, parse the manifest on the outside. package: name='dev.dodotech.dodossh.nightly' versionCode='196' versionName='0.0.0-alpha.0.129' The second run took 2m25s against the first run's 8m, which is the named volume doing its job.
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Everything the android CI job does inside the toolchain image, which is everything that needs a
|
||||
# glibc host. See build/android-build.Dockerfile for why there is an image at all, and
|
||||
# docs/platform-flags.md for the three rounds of CI that established it.
|
||||
#
|
||||
# It runs against a copy of the checkout at /build, put there with `docker cp` rather than a bind
|
||||
# mount — see the job for why — so it may read .git and it may write anywhere. What it leaves in
|
||||
# artifacts/android-nightly is what the job copies back out and publishes.
|
||||
#
|
||||
# Nothing here holds a secret. The key this signs with is committed to this repository in the open and
|
||||
# is meant to be; the token that publishes the result never enters this container.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
project=src/DodoSSH.Client.Android/DodoSSH.Client.Android.csproj
|
||||
staged=artifacts/android-nightly
|
||||
|
||||
# Aapt2ToolPath takes the directory and aapt2 itself is inside it. Both come from the Android SDK in
|
||||
# this image rather than from the copy inside the workload pack: both work here, and using the SDK's
|
||||
# makes the build and the versionName read below the same binary, so the manifest the feed publishes
|
||||
# is read by the thing that wrote it.
|
||||
build_tools="$ANDROID_HOME/build-tools/$ANDROID_BUILD_TOOLS"
|
||||
|
||||
echo "==> restore"
|
||||
# Locked mode, the same gate the solution restore gives every other project. This head is not in
|
||||
# DodoSSH.slnx — it needs a workload the other jobs have no reason to install — so this is the only
|
||||
# place its lock file is ever checked. It has silently gone stale before.
|
||||
dotnet restore "$project" --locked-mode
|
||||
|
||||
echo "==> build"
|
||||
dotnet build "$project" \
|
||||
--no-restore --configuration Release \
|
||||
"-p:Aapt2ToolPath=$build_tools"
|
||||
|
||||
echo "==> package the nightly"
|
||||
# Packaging rather than only compiling, because the two failures this head is most exposed to are both
|
||||
# link-time: a native library with no android ABI, and a managed assembly that resolves for net10.0 but
|
||||
# has nothing to dex. Neither shows up in a compile.
|
||||
#
|
||||
# versionCode is the commit count: monotonic by construction, and nobody has to remember anything. It
|
||||
# is not a version and is never displayed. versionName carries MinVer's full answer including the
|
||||
# prerelease height, which is what tells two nightlies apart.
|
||||
#
|
||||
# No RuntimeIdentifier, where this once pinned android-arm64. That produced the smallest possible build
|
||||
# check and the least installable artefact — an arm64-only APK will not run on an x86_64 emulator,
|
||||
# which is what most people testing a nightly actually have.
|
||||
code="$(git rev-list --count HEAD)"
|
||||
|
||||
dotnet build "$project" \
|
||||
--no-restore --configuration Release \
|
||||
-t:SignAndroidPackage \
|
||||
-p:DodoChannel=nightly \
|
||||
-p:DodoNightlyVersionCode="$code" \
|
||||
"-p:Aapt2ToolPath=$build_tools"
|
||||
|
||||
apk="$(find src/DodoSSH.Client.Android/bin/Release -name '*-Signed.apk' | head -1)"
|
||||
if [ -z "$apk" ]; then
|
||||
echo "The package step produced no signed APK." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read back out of the APK rather than recomputed, so what the feed advertises is what the bytes say.
|
||||
# A versionName derived a second time in shell is a second implementation of the csproj's target, and
|
||||
# the two would drift on the first change to either.
|
||||
badging="$("$build_tools/aapt2" dump badging "$apk")"
|
||||
name="$(printf '%s' "$badging" | sed -n "s/.*versionName='\([^']*\)'.*/\1/p" | head -1)"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo "aapt2 reported no versionName for $apk." >&2
|
||||
printf '%s\n' "$badging" | head -3 >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$staged"
|
||||
cp "$apk" "$staged/DodoSSH-nightly-$name.apk"
|
||||
|
||||
# The channel manifest, which is what the client reads and the whole reason the feed is machine-
|
||||
# readable at all. versionCode is the comparison — it is the number Android itself uses to accept or
|
||||
# refuse an install, so comparing anything else would let the client offer an update the platform then
|
||||
# rejects. versionName is for the person reading the banner.
|
||||
printf '{"versionCode":%s,"versionName":"%s","apk":"DodoSSH-nightly-%s.apk"}' \
|
||||
"$code" "$name" "$name" > "$staged/android-nightly.json"
|
||||
|
||||
printf '%s\n' "$badging" | head -1
|
||||
ls -la "$staged"
|
||||
Reference in New Issue
Block a user