name: Release # Builds the Docker image, the Windows installers (NSIS + portable) and the Linux # AppImage, then publishes all of it: the image goes to the Gitea container # registry as `latest` + the tag, the installers are attached to a Gitea release # for that tag. Flatpak is intentionally not built here — flatpak-builder's # sandbox (bwrap) needs working user namespaces, which a containerized Actions # runner is not guaranteed to have; it stays a local-only step via # scripts/publish.ps1. # # There is no Windows runner in this setup, so the "win" target (NSIS + portable) # is cross-built on the Linux runner via Wine, the same path # scripts/build-release.ps1 uses for -UseWsl. Unsigned either way. # # Requires two Actions secrets on this repo (Settings > Actions > Secrets), a # token with package read/write *and* repository write (write:repository) scope: # GITEA_USER - registry/API username # GITEA_TOKEN - registry/API token on: push: tags: - '*' workflow_dispatch: inputs: tag: description: 'Tag to publish (e.g. v1.2.3)' required: true type: string env: IMAGE: git.azuze.fr/kawa/motionity jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # full tag history, for the changelog compare link - name: Resolve tag id: vars env: EVENT_NAME: ${{ github.event_name }} DISPATCH_TAG: ${{ inputs.tag }} REF_TAG: ${{ github.ref_name }} run: | if [ "$EVENT_NAME" = "workflow_dispatch" ]; then echo "tag=$DISPATCH_TAG" >> "$GITHUB_OUTPUT" else echo "tag=$REF_TAG" >> "$GITHUB_OUTPUT" fi - uses: actions/setup-node@v4 with: node-version: '22' - name: Install build tools (jq, Wine for the NSIS uninstaller) run: | sudo dpkg --add-architecture i386 sudo apt-get update sudo apt-get install -y jq wine - name: Ensure PowerShell run: command -v pwsh >/dev/null || sudo snap install powershell --classic - name: Build Windows installers + Linux AppImage shell: pwsh env: TAG: ${{ steps.vars.outputs.tag }} run: ./scripts/build-release.ps1 -Targets win,linux-appimage -Tag $env:TAG - name: Log in to git.azuze.fr uses: docker/login-action@v3 with: registry: git.azuze.fr username: ${{ secrets.GITEA_USER }} password: ${{ secrets.GITEA_TOKEN }} - uses: docker/setup-buildx-action@v3 - name: Build and push image uses: docker/build-push-action@v6 with: context: . push: true tags: | ${{ env.IMAGE }}:latest ${{ env.IMAGE }}:${{ steps.vars.outputs.tag }} - name: Publish Gitea release env: TAG: ${{ steps.vars.outputs.tag }} GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} SERVER_URL: ${{ github.server_url }} REPO_PATH: ${{ github.repository }} run: | set -euo pipefail api="$SERVER_URL/api/v1/repos/$REPO_PATH/releases" auth=(-H "Authorization: token $GITEA_TOKEN") prev_tag=$(git tag --sort=-v:refname | grep -A1 -x -F "$TAG" | tail -n1) if [ "$prev_tag" = "$TAG" ]; then prev_tag=""; fi if [ -n "$prev_tag" ]; then body="**Full Changelog**: $SERVER_URL/$REPO_PATH/compare/$prev_tag...$TAG" else body="**Full Changelog**: first release" fi echo "changelog: $body" status=$(curl -s -o /tmp/release.json -w '%{http_code}' "${auth[@]}" "$api/tags/$TAG") if [ "$status" = "200" ]; then release_id=$(jq -r '.id' /tmp/release.json) echo "reusing release $TAG (id $release_id)" elif [ "$status" = "404" ]; then echo "creating release $TAG" payload=$(jq -n --arg tag "$TAG" --arg name "Motionity $TAG" --arg body "$body" \ '{tag_name:$tag, name:$name, body:$body, draft:false}') status=$(curl -s -o /tmp/release.json -w '%{http_code}' -X POST "${auth[@]}" \ -H "Content-Type: application/json" -d "$payload" "$api") [ "$status" = "201" ] || { echo "release creation failed ($status):"; cat /tmp/release.json; exit 1; } release_id=$(jq -r '.id' /tmp/release.json) else echo "unexpected status $status fetching release:"; cat /tmp/release.json; exit 1 fi # Keep the changelog link authoritative even when reusing an existing # release (a manual re-run after a later tag was pushed). curl -sf -X PATCH "${auth[@]}" -H "Content-Type: application/json" \ -d "$(jq -n --arg body "$body" '{body:$body}')" \ "$api/$release_id" -o /dev/null for f in "dist/motionity-$TAG-win-x64-setup.exe" \ "dist/motionity-$TAG-win-x64-portable.exe" \ "dist/motionity-$TAG-linux-x86_64.AppImage" \ "dist/SHA256SUMS.txt"; do [ -f "$f" ] || { echo "expected artifact missing: $f" >&2; exit 1; } name=$(basename "$f") existing_id=$(jq -r --arg n "$name" '.assets[]? | select(.name==$n) | .id' /tmp/release.json) if [ -n "$existing_id" ]; then echo "replacing attachment $name (asset $existing_id)" curl -sf -X DELETE "${auth[@]}" "$api/$release_id/assets/$existing_id" -o /dev/null else echo "adding attachment $name" fi encoded=$(jq -rn --arg n "$name" '$n|@uri') curl -sf "${auth[@]}" -F "attachment=@$f" "$api/$release_id/assets?name=$encoded" -o /dev/null done echo "release: $SERVER_URL/$REPO_PATH/releases/tag/$TAG"