ci(snap): build from shared Linux payload

This commit is contained in:
Hakan Seven 2026-08-16 08:16:09 +03:00
commit 2d9b828b87
3 changed files with 113 additions and 192 deletions

View file

@ -43,6 +43,17 @@ jobs:
rsvg-convert -w 256 -h 256 assets/logo.svg \
-o AppDir/usr/share/icons/hicolor/256x256/apps/io.github.HakanSeven12.OpenCadStudio.png
- name: Pack shared Linux payload
run: tar -C AppDir -czf linux-payload.tar.gz usr
- name: Upload shared Linux payload
uses: actions/upload-artifact@v4
with:
name: linux-payload
path: linux-payload.tar.gz
if-no-files-found: error
retention-days: 7
- name: Download linuxdeploy
run: |
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
@ -68,6 +79,75 @@ jobs:
mv OpenCADStudio.AppImage "$ASSET"
gh release upload ${{ github.ref_name }} "$ASSET" --clobber --repo ${{ github.repository }}
build-snap:
needs: build-appimage
runs-on: ubuntu-22.04
timeout-minutes: 75
concurrency:
group: snap
cancel-in-progress: false
permissions:
actions: read
contents: write
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download shared Linux payload
uses: actions/download-artifact@v4
with:
name: linux-payload
path: .
- name: Set package version
env:
EVENT_NAME: ${{ github.event_name }}
REF_NAME: ${{ github.ref_name }}
run: |
if [ "$EVENT_NAME" = "release" ]; then
VERSION="${REF_NAME#v}"
if [ "v$VERSION" != "$REF_NAME" ]; then
echo "::error::Release tag must be vX.Y.Z"
exit 1
fi
else
VERSION="$(sed -n 's/^version = "\([0-9][0-9.]*\)"/\1/p' Cargo.toml | head -1)"
fi
if ! printf '%s' "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Invalid package version: $VERSION"
exit 1
fi
sed -i "s/^version: .*/version: '$VERSION'/" snap/snapcraft.yaml
- name: Build snap
id: snapcraft
uses: snapcore/action-build@v1
- name: Upload snap to release
if: github.event_name == 'release'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SNAP: ${{ steps.snapcraft.outputs.snap }}
run: gh release upload "${{ github.ref_name }}" "$SNAP" --clobber
- name: Upload snap as workflow artifact
if: github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v4
with:
name: open-cad-studio-snap
path: ${{ steps.snapcraft.outputs.snap }}
if-no-files-found: error
- name: Publish snap to edge
if: github.event_name == 'release' && env.SNAPCRAFT_STORE_CREDENTIALS != ''
uses: snapcore/action-publish@v1
with:
snap: ${{ steps.snapcraft.outputs.snap }}
release: edge
build-windows:
runs-on: windows-latest
permissions:

View file

@ -1,169 +0,0 @@
name: Build Snap Package
on:
# workflow_run only works if this workflow file lives on the DEFAULT branch.
# Triggered as soon as "Release" finishes (which itself triggers on
# `release: published` + workflow_dispatch, not on every push to main).
workflow_run:
workflows: ["Release"]
types: [completed]
workflow_dispatch:
inputs:
version:
description: 'Existing release tag to build against (test)'
required: true
default: 'v0.9.0'
# Minimal default; the build-snap job raises this to `contents: write` itself,
# because it attaches the snap as a release asset.
permissions:
contents: read
# One global group, and deliberately NOT cancel-in-progress: two releases in
# quick succession would both publish to the Snap Store's `stable` channel, and
# a Snap release cannot be retracted.
concurrency:
group: snap
cancel-in-progress: false
jobs:
build-snap:
timeout-minutes: 75
runs-on: ubuntu-22.04
# `types: [completed]` also fires when the release workflow FAILED or was
# cancelled; without this gate a failed release would still build a snap.
# No extra head_branch guard is needed here: "Release" only triggers on
# `release: published` + workflow_dispatch, never on an ordinary push to
# main, so there is no spurious-trigger scenario.
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
permissions:
contents: write
env:
# Job-level so the gated publish step can reference it from `if:`.
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
steps:
- uses: actions/checkout@v5
with:
# On workflow_run, checkout defaults to the DEFAULT BRANCH rather than
# the tag/commit the release workflow built — wrong, because
# snap/snapcraft.yaml must come from the built commit. Hence the
# explicit head_sha of that workflow; for workflow_dispatch (no
# workflow_run event) it falls back to github.ref, i.e. the branch the
# manual dispatch was started from.
ref: ${{ github.event.workflow_run.head_sha || github.ref }}
- name: Get version
id: get-version
env:
# Untrusted input goes through env, NEVER directly as ${} in the shell.
# Do not set GITHUB_* names here: they are reserved and already present.
EVENT_NAME: ${{ github.event_name }}
DISPATCH_VERSION: ${{ github.event.inputs.version }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
VERSION="$DISPATCH_VERSION"
elif [ "$EVENT_NAME" = "workflow_run" ]; then
# For a `release`-triggered workflow_run, head_branch is not
# guaranteed to be the tag name (it can be the default branch), so
# fall back to looking up the latest published release instead of
# trusting head_branch.
if printf '%s' "$HEAD_BRANCH" | grep -qE '^v[0-9]'; then
VERSION="$HEAD_BRANCH"
else
VERSION="$(gh release list --exclude-drafts --limit 1 --json tagName --jq '.[0].tagName // empty')"
fi
else
VERSION=""
fi
if [ -z "$VERSION" ]; then
echo "::error::Could not determine version (event=$EVENT_NAME, head_branch=$HEAD_BRANCH)"
exit 1
fi
# `version` and `version_number` are fed into a `sed` REPLACEMENT
# PATTERN below, and a dispatch input is free text — a '/' or '&' would
# rewrite that pattern, and a newline would write a second line into
# $GITHUB_OUTPUT (output injection). Whitelist: the `case` covers the
# entire value (including newlines), the regex then checks structure.
case "$VERSION" in
*[!v0-9.]*)
echo "::error::Version contains characters other than 'v', digits and dots." >&2
exit 1
;;
esac
if ! printf '%s' "$VERSION" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Version '$VERSION' is not of the form vX.Y.Z." >&2
exit 1
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "version_number=${VERSION#v}" >> "$GITHUB_OUTPUT"
# We do NOT rebuild the Rust app: the snap repackages the AppImage from the
# published GitHub release (--appimage-extract rather than dpkg-deb -x,
# since this project does not produce a .deb).
- name: Wait for release AppImage and download it
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.get-version.outputs.version }}
run: |
echo "Waiting for AppImage asset of release $VERSION..."
found=""
for i in $(seq 1 10); do
if gh release view "$VERSION" --json assets --jq '.assets[].name' 2>/dev/null | grep -q '\.AppImage$'; then
found=1
echo "AppImage asset found"
break
fi
echo "no AppImage asset yet... (attempt $i/10)"
sleep 15
done
if [ -z "$found" ]; then
echo "::error::AppImage asset for $VERSION did not appear in time"
exit 1
fi
gh release download "$VERSION" -p '*.AppImage' --clobber --dir .
appimage=$(ls *.AppImage | head -1)
cp "$appimage" open-cad-studio.AppImage
echo "Using $appimage -> open-cad-studio.AppImage"
- name: Set version in snapcraft.yaml
env:
VERSION_NUMBER: ${{ steps.get-version.outputs.version_number }}
run: |
sed -i "s/^version: .*/version: '$VERSION_NUMBER'/" snap/snapcraft.yaml
grep '^version:' snap/snapcraft.yaml
- name: Build snap
uses: snapcore/action-build@v1
id: snapcraft
# Real release (via workflow_run): attach the snap as a release asset.
- name: Upload snap to GitHub release
if: github.event_name == 'workflow_run'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.get-version.outputs.version }}
SNAP: ${{ steps.snapcraft.outputs.snap }}
run: |
gh release upload "$VERSION" "$SNAP" --clobber
# Manual test run: snap as a CI artifact only, do NOT touch the release.
- name: Upload snap as workflow artifact
if: github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v4
with:
name: open-cad-studio-snap
path: ${{ steps.snapcraft.outputs.snap }}
if-no-files-found: error
# Publishing live to the Snap Store: only on a real release, and only once
# the store credentials secret exists (an owner step) — and only once the
# name `open-cad-studio` has been registered on snapcraft.io.
- name: Publish to Snap Store
if: github.event_name == 'workflow_run' && env.SNAPCRAFT_STORE_CREDENTIALS != ''
uses: snapcore/action-publish@v1
with:
snap: ${{ steps.snapcraft.outputs.snap }}
release: stable