feat(gitea): attach build artifacts to Gitea releases
Android Release / Build signed release APK (push) Successful in 37m54s
Android Release / Build signed release APK (push) Successful in 37m54s
The Android release workflow now creates or updates a Gitea release and attaches the APK and its SHA256 to it. A GITEA_TOKEN with releases: write is required for uploads. The README now documents the Gitea release flow and the required permissions. - Enforces that releases run only on a tag and matches the app version. - Replaces or updates release assets to match tag names. - Requires GITEA_TOKEN with releases: write for uploads.
This commit is contained in:
@@ -11,6 +11,9 @@ jobs:
|
|||||||
name: Build signed release APK
|
name: Build signed release APK
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
|
permissions:
|
||||||
|
code: read
|
||||||
|
releases: write
|
||||||
env:
|
env:
|
||||||
ANDROID_COMPILE_SDK: "36"
|
ANDROID_COMPILE_SDK: "36"
|
||||||
ANDROID_BUILD_TOOLS: "36.0.0"
|
ANDROID_BUILD_TOOLS: "36.0.0"
|
||||||
@@ -19,6 +22,7 @@ jobs:
|
|||||||
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||||||
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
||||||
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
||||||
|
GITEA_RELEASE_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository
|
- name: Check out repository
|
||||||
@@ -64,8 +68,11 @@ jobs:
|
|||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
- name: Check release tag and app version
|
- name: Check release tag and app version
|
||||||
if: gitea.ref_type == 'tag'
|
|
||||||
run: |
|
run: |
|
||||||
|
if [ "${GITHUB_REF_TYPE}" != "tag" ]; then
|
||||||
|
echo "Release builds must run on a tag such as v0.1.0." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
APP_VERSION="$(node -p "require('./src-tauri/tauri.conf.json').version")"
|
APP_VERSION="$(node -p "require('./src-tauri/tauri.conf.json').version")"
|
||||||
if [ "${GITHUB_REF_NAME}" != "v${APP_VERSION}" ]; then
|
if [ "${GITHUB_REF_NAME}" != "v${APP_VERSION}" ]; then
|
||||||
echo "Tag ${GITHUB_REF_NAME} does not match app version v${APP_VERSION}." >&2
|
echo "Tag ${GITHUB_REF_NAME} does not match app version v${APP_VERSION}." >&2
|
||||||
@@ -78,7 +85,8 @@ jobs:
|
|||||||
ANDROID_KEYSTORE_BASE64 \
|
ANDROID_KEYSTORE_BASE64 \
|
||||||
ANDROID_KEYSTORE_PASSWORD \
|
ANDROID_KEYSTORE_PASSWORD \
|
||||||
ANDROID_KEY_ALIAS \
|
ANDROID_KEY_ALIAS \
|
||||||
ANDROID_KEY_PASSWORD
|
ANDROID_KEY_PASSWORD \
|
||||||
|
GITEA_RELEASE_TOKEN
|
||||||
do
|
do
|
||||||
if [ -z "${!SECRET_NAME:-}" ]; then
|
if [ -z "${!SECRET_NAME:-}" ]; then
|
||||||
echo "Missing Gitea Actions secret: ${SECRET_NAME}" >&2
|
echo "Missing Gitea Actions secret: ${SECRET_NAME}" >&2
|
||||||
@@ -118,11 +126,73 @@ jobs:
|
|||||||
rm "${ALIGNED_APK}"
|
rm "${ALIGNED_APK}"
|
||||||
(cd "${RELEASE_DIRECTORY}" && sha256sum WallpaperFlow-release.apk > WallpaperFlow-release.apk.sha256)
|
(cd "${RELEASE_DIRECTORY}" && sha256sum WallpaperFlow-release.apk > WallpaperFlow-release.apk.sha256)
|
||||||
|
|
||||||
- name: Upload release APK
|
- name: Attach APK to Gitea release
|
||||||
uses: actions/upload-artifact@v3
|
run: |
|
||||||
with:
|
API_ROOT="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}"
|
||||||
name: WallpaperFlow-${{ gitea.ref_name }}-android
|
RELEASE_JSON="${RUNNER_TEMP}/wallpaperflow-release.json"
|
||||||
path: |
|
CREATE_JSON="${RUNNER_TEMP}/wallpaperflow-create-release.json"
|
||||||
release/WallpaperFlow-release.apk
|
ASSETS_JSON="${RUNNER_TEMP}/wallpaperflow-release-assets.json"
|
||||||
|
|
||||||
|
STATUS="$(curl --silent --show-error \
|
||||||
|
--output "${RELEASE_JSON}" \
|
||||||
|
--write-out '%{http_code}' \
|
||||||
|
--header "Authorization: token ${GITEA_RELEASE_TOKEN}" \
|
||||||
|
"${API_ROOT}/releases/tags/${GITHUB_REF_NAME}")"
|
||||||
|
|
||||||
|
if [ "${STATUS}" = "404" ]; then
|
||||||
|
node -e '
|
||||||
|
process.stdout.write(JSON.stringify({
|
||||||
|
tag_name: process.env.GITHUB_REF_NAME,
|
||||||
|
name: `WallpaperFlow ${process.env.GITHUB_REF_NAME}`,
|
||||||
|
body: "Automatisch erstelltes Android-Release.",
|
||||||
|
draft: false,
|
||||||
|
prerelease: false
|
||||||
|
}))
|
||||||
|
' > "${CREATE_JSON}"
|
||||||
|
curl --fail --silent --show-error \
|
||||||
|
--request POST \
|
||||||
|
--header "Authorization: token ${GITEA_RELEASE_TOKEN}" \
|
||||||
|
--header "Content-Type: application/json" \
|
||||||
|
--data-binary "@${CREATE_JSON}" \
|
||||||
|
--output "${RELEASE_JSON}" \
|
||||||
|
"${API_ROOT}/releases"
|
||||||
|
elif [ "${STATUS}" != "200" ]; then
|
||||||
|
echo "Could not read Gitea release for ${GITHUB_REF_NAME} (HTTP ${STATUS})." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RELEASE_ID="$(node -e '
|
||||||
|
const release = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
|
||||||
|
if (!release.id) process.exit(1);
|
||||||
|
process.stdout.write(String(release.id));
|
||||||
|
' "${RELEASE_JSON}")"
|
||||||
|
|
||||||
|
curl --fail --silent --show-error \
|
||||||
|
--header "Authorization: token ${GITEA_RELEASE_TOKEN}" \
|
||||||
|
--output "${ASSETS_JSON}" \
|
||||||
|
"${API_ROOT}/releases/${RELEASE_ID}/assets"
|
||||||
|
|
||||||
|
for FILE in \
|
||||||
|
release/WallpaperFlow-release.apk \
|
||||||
release/WallpaperFlow-release.apk.sha256
|
release/WallpaperFlow-release.apk.sha256
|
||||||
if-no-files-found: error
|
do
|
||||||
|
ASSET_NAME="$(basename "${FILE}")"
|
||||||
|
ASSET_ID="$(ASSET_NAME="${ASSET_NAME}" node -e '
|
||||||
|
const assets = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
|
||||||
|
const asset = assets.find(item => item.name === process.env.ASSET_NAME);
|
||||||
|
if (asset) process.stdout.write(String(asset.id));
|
||||||
|
' "${ASSETS_JSON}")"
|
||||||
|
|
||||||
|
if [ -n "${ASSET_ID}" ]; then
|
||||||
|
curl --fail --silent --show-error \
|
||||||
|
--request DELETE \
|
||||||
|
--header "Authorization: token ${GITEA_RELEASE_TOKEN}" \
|
||||||
|
"${API_ROOT}/releases/${RELEASE_ID}/assets/${ASSET_ID}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl --fail --silent --show-error \
|
||||||
|
--request POST \
|
||||||
|
--header "Authorization: token ${GITEA_RELEASE_TOKEN}" \
|
||||||
|
--form "attachment=@${FILE}" \
|
||||||
|
"${API_ROOT}/releases/${RELEASE_ID}/assets" >/dev/null
|
||||||
|
done
|
||||||
|
|||||||
@@ -68,10 +68,17 @@ Den Keystore-Inhalt für das Secret erzeugt man unter Linux mit:
|
|||||||
base64 -w 0 /sicherer/pfad/wallpaperflow-release.jks
|
base64 -w 0 /sicherer/pfad/wallpaperflow-release.jks
|
||||||
```
|
```
|
||||||
|
|
||||||
Nach erfolgreichem Lauf stehen `WallpaperFlow-release.apk` und die zugehörige
|
Nach erfolgreichem Lauf erstellt die Pipeline ein Gitea-Release für den Tag
|
||||||
SHA-256-Prüfsumme als Artefakt des Workflows bereit. Der Keystore darf nicht in
|
beziehungsweise verwendet ein bereits vorhandenes Release. Die Dateien
|
||||||
das Repository eingecheckt werden und muss dauerhaft gesichert bleiben, da
|
`WallpaperFlow-release.apk` und `WallpaperFlow-release.apk.sha256` werden direkt
|
||||||
spätere Updates mit demselben Schlüssel signiert werden müssen.
|
an dieses Release angehängt. Bei einem erneuten Lauf für denselben Tag werden
|
||||||
|
vorhandene Anhänge mit diesen Namen ersetzt. Dafür muss der integrierte
|
||||||
|
`GITEA_TOKEN` Schreibzugriff auf Releases besitzen; die Pipeline fordert die
|
||||||
|
Berechtigung `releases: write` selbst an.
|
||||||
|
|
||||||
|
Der Keystore darf nicht in das Repository eingecheckt werden und muss dauerhaft
|
||||||
|
gesichert bleiben, da spätere Updates mit demselben Schlüssel signiert werden
|
||||||
|
müssen.
|
||||||
|
|
||||||
Voraussetzung ist ein aktiver Gitea-Actions-Runner mit dem Label
|
Voraussetzung ist ein aktiver Gitea-Actions-Runner mit dem Label
|
||||||
`ubuntu-latest`, Netzwerkzugriff auf npm, Rust und die Android-SDK-Server sowie
|
`ubuntu-latest`, Netzwerkzugriff auf npm, Rust und die Android-SDK-Server sowie
|
||||||
|
|||||||
Reference in New Issue
Block a user