diff --git a/.gitea/workflows/build-test-apk.yml b/.gitea/workflows/build-test-apk.yml index 64c4ee6d..944ac182 100644 --- a/.gitea/workflows/build-test-apk.yml +++ b/.gitea/workflows/build-test-apk.yml @@ -15,6 +15,11 @@ name: '📱 Test APK' # Both variants install as com.dtourolle.jellytau.debug ("JellyTau Debug"), # side by side with a real install and with their own data directory. Neither # needs the release signing key. +# +# Getting the APK to somebody else: Gitea artifacts need an account with read +# access to download, so `publish: true` also attaches the APK to a pre-release +# whose assets are a plain public URL. That is the only way an outside tester +# gets the file without being given an account. on: workflow_dispatch: @@ -41,6 +46,11 @@ on: - aarch64 - armv7 - x86_64 + publish: + description: 'Also publish as a pre-release, for testers with no Gitea account' + required: false + default: false + type: boolean concurrency: # One test build at a time; a newer dispatch supersedes an in-flight one. @@ -171,6 +181,83 @@ jobs: ls -lah dist/test-apk/ + # Deliberately NOT tagged `v*`: that pattern triggers build-release.yml, + # which would run the whole three-platform release matrix and publish a + # real release off a feature branch. The tag here is derived from the + # branch name and carries no version, so nothing else reacts to it. + # + # This also cannot reach existing users. The desktop updater reads a + # static latest.json from the `updater` branch, not the release list, so a + # pre-release published here is invisible to anyone without the link. + - name: Publish as a pre-release + if: ${{ inputs.publish }} + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + AUTO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -e + command -v jq >/dev/null || { echo "❌ jq is required on the runner"; exit 1; } + API="${GITHUB_SERVER_URL}/api/v1" + REPO="${GITHUB_REPOSITORY}" + TOKEN="${GITEA_TOKEN:-$AUTO_TOKEN}" + BRANCH="${GITHUB_REF#refs/heads/}" + TAG="test-$(echo "$BRANCH" | tr '/' '-')" + + # printf, not a heredoc: inside a YAML block scalar every line is + # indented, and a heredoc terminator has to sit at column 0. + BODY=$(printf '%s\n' \ + "Test build of \`$BRANCH\` at \`${GITHUB_SHA::8}\` — **not a release**." \ + "" \ + "Installs as **JellyTau Debug** (\`com.dtourolle.jellytau.debug\`), alongside a" \ + "normal install and with its own separate data. Uninstalling it does not touch" \ + "the real app." \ + "" \ + "Variant: \`${{ inputs.variant }}\` ¡ ABI: \`${{ inputs.abi }}\`" \ + "" \ + "Android will warn about installing from an unknown source; that is expected" \ + "for a build signed with a debug key rather than the store key.") + + PAYLOAD=$(jq -n \ + --arg tag "$TAG" \ + --arg name "Test build: $BRANCH" \ + --arg body "$BODY" \ + --arg target "$GITHUB_SHA" \ + '{tag_name:$tag, target_commitish:$target, name:$name, body:$body, draft:false, prerelease:true}') + + HTTP=$(curl -sS -o resp.json -w '%{http_code}' -X POST "$API/repos/$REPO/releases" \ + -H "Authorization: token $TOKEN" -H "Content-Type: application/json" -d "$PAYLOAD") + + if [ "$HTTP" = "201" ]; then + RELEASE_ID=$(jq -r '.id' resp.json) + elif [ "$HTTP" = "409" ]; then + # Re-dispatching for the same branch replaces the previous APK rather + # than accumulating one release per attempt. + echo "â„šī¸ Pre-release $TAG exists; reusing it" + RELEASE_ID=$(curl -fsS "$API/repos/$REPO/releases/tags/$TAG" \ + -H "Authorization: token $TOKEN" | jq -r '.id') + for id in $(curl -fsS "$API/repos/$REPO/releases/$RELEASE_ID/assets" \ + -H "Authorization: token $TOKEN" | jq -r '.[].id'); do + curl -fsS -X DELETE "$API/repos/$REPO/releases/$RELEASE_ID/assets/$id" \ + -H "Authorization: token $TOKEN" >/dev/null + done + else + echo "❌ Failed to create pre-release (HTTP $HTTP):"; cat resp.json; exit 1 + fi + + for f in dist/test-apk/*.apk; do + echo "âŦ†ī¸ $(basename "$f")" + curl -fsS -X POST \ + "$API/repos/$REPO/releases/$RELEASE_ID/assets?name=$(basename "$f")" \ + -H "Authorization: token $TOKEN" -F "attachment=@$f" >/dev/null + done + + { + echo "" + echo "**Published:** ${GITHUB_SERVER_URL}/${REPO}/releases/tag/${TAG}" + echo "" + echo "Public link — no Gitea account needed. Delete the release when testing is done." + } >> "$GITHUB_STEP_SUMMARY" + - name: Upload APK uses: actions/upload-artifact@v3 with: diff --git a/src-tauri/android/README_ANDROID_BUILD.md b/src-tauri/android/README_ANDROID_BUILD.md index 2680009a..ef23ed81 100644 --- a/src-tauri/android/README_ANDROID_BUILD.md +++ b/src-tauri/android/README_ANDROID_BUILD.md @@ -110,6 +110,25 @@ two other projects, so building on every feature-branch commit would starve them. The APK lands as the `jellytau-test-apk` artifact (7-day retention), named for the branch and short SHA, with its size and SHA256 in the run summary. +#### Sending a build to an outside tester + +Gitea **artifacts require an account** with read access to download, so an +artifact is no use to someone outside the project. Tick **`publish`** on the +dispatch and the APK is also attached to a **pre-release**, whose assets are a +plain public URL on a public repo — no account, no MR, no merge to `master`. + +Two things make that safe to do from a feature branch: + +- The tag is `test-`, **not** `v*`. Only `v*` triggers + `build-release.yml`, so nothing else reacts to it. +- It cannot reach existing users. The desktop updater reads a static + `latest.json` from the `updater` branch, not the release list, so a + pre-release published this way is invisible to anyone without the link. + +Re-dispatching for the same branch replaces the APK on the existing +pre-release rather than piling up one release per attempt. Delete the release +when testing is over. + ### Key Files Player-related Kotlin files: