I call an “external snap” (in contrast to “organic snap”) a snap that is build outside the repo of the app being snapped.
Currently I have this CI in place for a single-platform snap, but I plan to extend it to multiple platforms in the future.
Assumptions
CI workflows for external snaps make assumptions about the app maintainer’s practices. The assumptions I made about nushell aren’t too wild and likely compatible with many other apps:
- The maintainer of the app merges changes into the main branch.
- Once in a while, the maintainer tags a commit with a semver.
- No more than one tag per commit.
Pattern
- Current main goes into edge channel. This is run daily.
- If the commit is tagged with a semver, promote to beta.
- On my machine, I snap-install the beta channel.
- After using the beta channel for a while, promote to stable manually. Here I’m skipping the “candidate” channel because there isn’t anything else to gate the promotion to stable with.
CI steps
You can inspect the full workflow here. In the next section I’ll go over the steps & rationale.
Check versions
The current version is always obtained from tag. We assume the maintainer practices tagging. If no tag is present, we’d get the commit hash, which is totally fine for the edge channel:
CURRENT=$(git describe --tags --always)
To obtain the edge and beta version we need to use the store API:
JSON=$(curl -s -H "Snap-Device-Series: 16" "https://api.snapcraft.io/v2/snaps/info/nushell?fields=version&architecture=amd64")
EDGE=$(echo "$JSON" | jq -r '."channel-map"[] | select(.channel.track == "latest" and .channel.risk == "edge") | .version')
BETA=$(echo "$JSON" | jq -r '."channel-map"[] | select(.channel.track == "latest" and .channel.risk == "beta") | .version')
Promote from edge to beta
We want to promote from edge to beta when the version in edge differs from the version in beta, and also matches a semver string:
if [[ "$EDGE" =~ ^v?[0-9]+(\.[0-9]+){1,2}$ && "$EDGE" != "$BETA" ]]; then
echo "promote=yes" >> $GITHUB_OUTPUT
else
echo "promote=no" >> $GITHUB_OUTPUT
fi
Build snap
We want to build only if the current version differs from the version in edge:
if [[ "$CURRENT" != "$EDGE" ]]; then
echo "build=yes" >> $GITHUB_OUTPUT
else
echo "build=no" >> $GITHUB_OUTPUT
fi
Install snap (test)
Before publishing to edge, we want to make sure the snap installs ok.
Publish snap
As of writing, snap info nushell
reflects the above pattern:
- The version in edge is the commit object (hash + number of commits from last tag). In the example below, the snap was packed from a commit in main that was 36 commits ahead of the 0.98 version.
- The version in beta, candidate and stable are semver versions.
channels:
latest/stable: 0.98.0 2024-09-20 (4) 39MB classic
latest/candidate: 0.98.0 2024-09-20 (4) 39MB classic
latest/beta: 0.98.0 2024-09-20 (4) 39MB classic
latest/edge: 0.98.0-36-g8200831b0 2024-09-29 (5) 39MB classic
installed: 0.98.0 (4) 39MB classic