From 03061f2f755ffbc957c91ad37b633a1189e7feaf Mon Sep 17 00:00:00 2001 From: magdev Date: Sat, 2 May 2026 19:50:42 +0200 Subject: [PATCH] Phase 4a sub-commit 3: Linux release CI on v* tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .gitea/workflows/release.yml builds the example's AppImage on every v* tag push and uploads it to a Gitea Release together with a signed SHA256SUMS: - Same PHP / Qt / FrankenPHP setup as the quality job (cached). - Reuses the AppImage recipe via `make appimage` (FRANKENPHP env points at the runner's installed binary; APPIMAGE_EXTRACT_AND_RUN=1 to avoid FUSE inside CI). - sha256sum → SHA256SUMS. - When a GPG_KEY secret is present, imports it and emits SHA256SUMS.asc (--detach-sign --armor). Skipped silently if secrets aren't configured — CI red-lines for real failures, not for missing operational secrets. - Creates the Release via the Gitea API (POST /repos/{repo}/releases) and uploads AppImage + SHA256SUMS + SHA256SUMS.asc. Workflow exists from this commit onward even before a Gitea runner is provisioned; it'll just fail at the runner-needed steps if no runner picks it up. Required Gitea secrets (configurable when ready): - GITEA_TOKEN — repo-scoped token, write:repository - GPG_KEY — ASCII-armoured private key (optional) - GPG_PASSPHRASE — the key's passphrase (optional) Sub-commit 4 will append a zsync + appcast (latest.json) step here for auto-update. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitea/workflows/release.yml | 121 +++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 .gitea/workflows/release.yml diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..efbe95f --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,121 @@ +name: Release + +on: + push: + tags: + - 'v*' + +jobs: + linux: + name: Linux AppImage + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # need tag history for release notes + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: curl, json, mbstring + tools: composer:v2 + coverage: none + + - name: Install bundle dependencies + working-directory: framework/php + run: composer install --no-interaction --prefer-dist + + - name: Setup Qt 6 + uses: jurplel/install-qt-action@v4 + with: + version: '6.5.*' + modules: 'qtquickcontrols2' + cache: true + + - name: Install FrankenPHP + run: | + curl -fsSL -o /usr/local/bin/frankenphp \ + https://github.com/php/frankenphp/releases/download/v1.12.2/frankenphp-linux-x86_64 + chmod +x /usr/local/bin/frankenphp + + - name: Build the todo example + working-directory: examples/todo + run: | + make install + make build + + - name: Build AppImage + working-directory: examples/todo + env: + # The AppImage tooling can't always FUSE-mount inside CI; use + # extract-and-run for linuxdeploy + manual appimagetool. + APPIMAGE_EXTRACT_AND_RUN: '1' + FRANKENPHP: /usr/local/bin/frankenphp + run: make appimage + + - name: Compute SHA256SUMS + working-directory: examples/todo/build + run: | + sha256sum Todo-x86_64.AppImage > SHA256SUMS + cat SHA256SUMS + + - name: Import GPG signing key + if: ${{ env.GPG_KEY != '' }} + env: + GPG_KEY: ${{ secrets.GPG_KEY }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + run: | + echo "$GPG_KEY" | gpg --batch --import + # Default key id from the imported keyring (first secret key). + KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec/ {print $5; exit}') + echo "GPG_KEYID=$KEYID" >> "$GITHUB_ENV" + + - name: Sign SHA256SUMS + if: ${{ env.GPG_KEYID != '' }} + working-directory: examples/todo/build + env: + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + run: | + gpg --batch --pinentry-mode loopback \ + --passphrase "$GPG_PASSPHRASE" \ + --local-user "$GPG_KEYID" \ + --detach-sign --armor \ + -o SHA256SUMS.asc \ + SHA256SUMS + + - name: Create Gitea Release and upload artefacts + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + REPO: ${{ github.repository }} + TAG: ${{ github.ref_name }} + working-directory: examples/todo/build + run: | + set -euo pipefail + api="${GITHUB_SERVER_URL}/api/v1" + + # Create the release (or get the existing one for this tag) + release_json=$(curl -fsSL -X POST "$api/repos/$REPO/releases" \ + -H "Authorization: token $GITEA_TOKEN" \ + -H 'Content-Type: application/json' \ + -d "$(jq -n --arg tag "$TAG" --arg name "$TAG" \ + '{tag_name:$tag,name:$name,draft:false,prerelease:false}')" \ + || curl -fsSL "$api/repos/$REPO/releases/tags/$TAG" \ + -H "Authorization: token $GITEA_TOKEN") + rid=$(echo "$release_json" | jq -r .id) + echo "Release id: $rid" + + upload() { + local f="$1" + echo " uploading $f" + curl -fsSL -X POST \ + "$api/repos/$REPO/releases/$rid/assets?name=$(basename "$f")" \ + -H "Authorization: token $GITEA_TOKEN" \ + -H 'Content-Type: application/octet-stream' \ + --data-binary "@$f" + } + upload Todo-x86_64.AppImage + upload SHA256SUMS + [ -f SHA256SUMS.asc ] && upload SHA256SUMS.asc || true