ci: add Forgejo release workflow
Some checks failed
Forgejo Release Builder / release (push) Failing after 5s
Some checks failed
Forgejo Release Builder / release (push) Failing after 5s
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
9c110ee46a
commit
d51aaa39b9
2 changed files with 328 additions and 0 deletions
250
.forgejo/workflows/build_release.yml
Executable file
250
.forgejo/workflows/build_release.yml
Executable file
|
|
@ -0,0 +1,250 @@
|
|||
name: Forgejo Release Builder
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: forgejo-release
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
|
||||
- name: Write google-services.json
|
||||
uses: DamianReeves/write-file-action@6929a9a6d1807689191dcc8bbe62b54d70a32b42 # v1.3
|
||||
with:
|
||||
path: app/google-services.json
|
||||
contents: ${{ secrets.GOOGLE_SERVICES_JSON }}
|
||||
write-mode: overwrite
|
||||
|
||||
- name: Write client_secrets.json
|
||||
uses: DamianReeves/write-file-action@6929a9a6d1807689191dcc8bbe62b54d70a32b42 # v1.3
|
||||
with:
|
||||
path: app/src/main/assets/client_secrets.json
|
||||
contents: ${{ secrets.GOOGLE_CLIENT_SECRETS_JSON }}
|
||||
write-mode: overwrite
|
||||
|
||||
- name: Prepare release metadata
|
||||
id: prepare
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
version_tag="${GITHUB_REF_NAME:-${GITHUB_REF#refs/tags/}}"
|
||||
previous_tag="$(git tag --list 'v*' --sort=-version:refname | grep -Fxv "$version_tag" | head -n 1 || true)"
|
||||
|
||||
echo "VERSION_TAG=$version_tag" >> "$GITHUB_OUTPUT"
|
||||
echo "PREV_TAG_NAME=$previous_tag" >> "$GITHUB_OUTPUT"
|
||||
|
||||
if [ -n "$previous_tag" ]; then
|
||||
commit_logs="$(git log --pretty=format:'- %s (@%an)' "${previous_tag}..HEAD")"
|
||||
else
|
||||
commit_logs='- Initial release'
|
||||
fi
|
||||
|
||||
{
|
||||
echo 'COMMIT_LOGS<<EOF'
|
||||
printf '%s\n' "$commit_logs"
|
||||
echo 'EOF'
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5
|
||||
|
||||
- name: Check code format
|
||||
run: ./gradlew spotlessCheck
|
||||
|
||||
- name: Build app
|
||||
run: ./gradlew assembleRelease -Pinclude-telemetry -Penable-updater
|
||||
|
||||
- name: Run unit tests
|
||||
run: ./gradlew testReleaseUnitTest
|
||||
|
||||
- name: Sign APK
|
||||
uses: r0adkll/sign-android-release@f30bdd30588842ac76044ecdbd4b6d0e3e813478
|
||||
with:
|
||||
releaseDirectory: app/build/outputs/apk/release
|
||||
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
|
||||
alias: ${{ secrets.ALIAS }}
|
||||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
|
||||
keyPassword: ${{ secrets.KEY_PASSWORD }}
|
||||
env:
|
||||
BUILD_TOOLS_VERSION: '35.0.1'
|
||||
|
||||
- name: Rename release artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
version_tag="${{ steps.prepare.outputs.VERSION_TAG }}"
|
||||
|
||||
mv app/build/outputs/apk/release/app-universal-release-unsigned-signed.apk "Komikku-${version_tag}.apk"
|
||||
mv app/build/outputs/apk/release/app-arm64-v8a-release-unsigned-signed.apk "Komikku-arm64-v8a-${version_tag}.apk"
|
||||
mv app/build/outputs/apk/release/app-armeabi-v7a-release-unsigned-signed.apk "Komikku-armeabi-v7a-${version_tag}.apk"
|
||||
mv app/build/outputs/apk/release/app-x86-release-unsigned-signed.apk "Komikku-x86-${version_tag}.apk"
|
||||
mv app/build/outputs/apk/release/app-x86_64-release-unsigned-signed.apk "Komikku-x86_64-${version_tag}.apk"
|
||||
|
||||
zip -qr "Komikku-mapping-${version_tag}.zip" app/build/outputs/mapping/release
|
||||
|
||||
- name: Create or update release
|
||||
id: release
|
||||
shell: bash
|
||||
env:
|
||||
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERSION_TAG: ${{ steps.prepare.outputs.VERSION_TAG }}
|
||||
PREV_TAG_NAME: ${{ steps.prepare.outputs.PREV_TAG_NAME }}
|
||||
COMMIT_LOGS: ${{ steps.prepare.outputs.COMMIT_LOGS }}
|
||||
REPO_URL: ${{ github.server_url }}/${{ github.repository }}
|
||||
REPOSITORY_NAME: ${{ github.repository }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
api_base="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases"
|
||||
payload_file="$(mktemp)"
|
||||
response_file="$(mktemp)"
|
||||
|
||||
python3 - <<'PY' > "$payload_file"
|
||||
import json
|
||||
import os
|
||||
import textwrap
|
||||
|
||||
version_tag = os.environ["VERSION_TAG"]
|
||||
previous_tag = os.environ.get("PREV_TAG_NAME", "").strip()
|
||||
commit_logs = os.environ.get("COMMIT_LOGS", "").strip() or "- Initial release"
|
||||
repo_url = os.environ["REPO_URL"]
|
||||
repository_name = os.environ["REPOSITORY_NAME"]
|
||||
|
||||
if previous_tag:
|
||||
full_changelog = (
|
||||
f"**Full Changelog**: "
|
||||
f"[{repository_name}@{previous_tag}...{version_tag}]"
|
||||
f"({repo_url}/compare/{previous_tag}...{version_tag})"
|
||||
)
|
||||
else:
|
||||
full_changelog = ""
|
||||
|
||||
body = textwrap.dedent(
|
||||
f"""\
|
||||
#### What's Changed
|
||||
##### New
|
||||
|
||||
##### Improve
|
||||
|
||||
##### Fix
|
||||
|
||||
{commit_logs}
|
||||
|
||||
##### Based on
|
||||
|
||||
{full_changelog}
|
||||
|
||||
<!-->
|
||||
> [!TIP]
|
||||
>
|
||||
> ### If you are unsure which version to download then go with `Komikku-{version_tag}.apk`
|
||||
""",
|
||||
)
|
||||
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"tag_name": version_tag,
|
||||
"name": f"Komikku {version_tag}",
|
||||
"body": body,
|
||||
"draft": True,
|
||||
"prerelease": False,
|
||||
},
|
||||
),
|
||||
)
|
||||
PY
|
||||
|
||||
status="$(curl -sS -o "$response_file" -w '%{http_code}' \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
"${api_base}/tags/${VERSION_TAG}")"
|
||||
|
||||
if [ "$status" = "200" ]; then
|
||||
release_id="$(python3 -c 'import json, sys; print(json.load(sys.stdin)["id"])' < "$response_file")"
|
||||
curl -fsS \
|
||||
-X PATCH \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data @"$payload_file" \
|
||||
"${api_base}/${release_id}" \
|
||||
> "$response_file"
|
||||
elif [ "$status" = "404" ]; then
|
||||
curl -fsS \
|
||||
-X POST \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data @"$payload_file" \
|
||||
"${api_base}" \
|
||||
> "$response_file"
|
||||
release_id="$(python3 -c 'import json, sys; print(json.load(sys.stdin)["id"])' < "$response_file")"
|
||||
else
|
||||
cat "$response_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "RELEASE_ID=$release_id" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload release assets
|
||||
shell: bash
|
||||
env:
|
||||
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_ID: ${{ steps.release.outputs.RELEASE_ID }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
release_api="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}"
|
||||
assets_file="$(mktemp)"
|
||||
|
||||
curl -fsS \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
"${release_api}/assets" \
|
||||
> "$assets_file"
|
||||
|
||||
for file in Komikku-*.apk Komikku-mapping-*.zip; do
|
||||
[ -e "$file" ] || continue
|
||||
|
||||
asset_name="$(basename "$file")"
|
||||
asset_id="$(
|
||||
python3 -c 'import json, sys; assets = json.load(open(sys.argv[1], encoding="utf-8")); name = sys.argv[2]; print(next((str(asset["id"]) for asset in assets if asset.get("name") == name), ""))' \
|
||||
"$assets_file" \
|
||||
"$asset_name"
|
||||
)"
|
||||
|
||||
if [ -n "$asset_id" ]; then
|
||||
curl -fsS \
|
||||
-X DELETE \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
"${release_api}/assets/${asset_id}" \
|
||||
> /dev/null
|
||||
fi
|
||||
|
||||
encoded_name="$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1]))' "$asset_name")"
|
||||
|
||||
curl -fsS \
|
||||
-X POST \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
-H 'Content-Type: application/octet-stream' \
|
||||
--data-binary @"$file" \
|
||||
"${release_api}/assets?name=${encoded_name}" \
|
||||
> /dev/null
|
||||
done
|
||||
78
docs/forgejo-release-runner.md
Executable file
78
docs/forgejo-release-runner.md
Executable file
|
|
@ -0,0 +1,78 @@
|
|||
# Forgejo release runner
|
||||
|
||||
This repository now includes a Forgejo-native release workflow at `.forgejo/workflows/build_release.yml`.
|
||||
|
||||
## What it does
|
||||
|
||||
- Triggers on tags matching `v*`
|
||||
- Builds the release APKs
|
||||
- Signs the APKs
|
||||
- Creates or updates a draft release through the Forgejo API
|
||||
- Uploads the APKs and a zipped ProGuard mapping as release assets
|
||||
|
||||
The workflow intentionally avoids GitHub-only artifact and release actions so it can run on Forgejo with a self-hosted runner.
|
||||
|
||||
## Required repository secrets
|
||||
|
||||
Set these secrets in the Forgejo repository settings:
|
||||
|
||||
- `GOOGLE_SERVICES_JSON`
|
||||
- `GOOGLE_CLIENT_SECRETS_JSON`
|
||||
- `SIGNING_KEY`
|
||||
- `ALIAS`
|
||||
- `KEY_STORE_PASSWORD`
|
||||
- `KEY_PASSWORD`
|
||||
|
||||
`secrets.GITHUB_TOKEN` is used as the Forgejo-provided built-in token for the release API calls.
|
||||
|
||||
## Runner label
|
||||
|
||||
The workflow uses:
|
||||
|
||||
```yaml
|
||||
runs-on: forgejo-release
|
||||
```
|
||||
|
||||
Register a runner with a matching label. Host mode is the simplest option for Android builds:
|
||||
|
||||
```sh
|
||||
forgejo-runner register \
|
||||
--instance https://192.168.1.155:3030 \
|
||||
--token <registration-token> \
|
||||
--name komikku-release \
|
||||
--labels "forgejo-release:host"
|
||||
```
|
||||
|
||||
## Runner prerequisites
|
||||
|
||||
Install these on the runner host before enabling the workflow:
|
||||
|
||||
- Git
|
||||
- curl
|
||||
- zip
|
||||
- Python 3
|
||||
- JDK 17
|
||||
- Android SDK command-line tools
|
||||
- Android platform `android-35`
|
||||
- Android build-tools `35.0.1`
|
||||
|
||||
Recommended environment variables on the runner host:
|
||||
|
||||
```sh
|
||||
export ANDROID_HOME=/opt/android-sdk
|
||||
export ANDROID_SDK_ROOT=/opt/android-sdk
|
||||
export PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH"
|
||||
```
|
||||
|
||||
## Suggested setup flow
|
||||
|
||||
1. Enable Actions on the Forgejo instance and repository.
|
||||
2. Register the `forgejo-release` runner.
|
||||
3. Add the required repository secrets.
|
||||
4. Push a test tag such as `v0.0.0-forgejo.1`.
|
||||
5. Open the draft release in Forgejo and verify the uploaded APKs.
|
||||
|
||||
## Notes
|
||||
|
||||
- The existing GitHub workflows under `.github/workflows/` remain unchanged.
|
||||
- The Forgejo release notes are generated from git history, so they do not depend on the GitHub compare API.
|
||||
Loading…
Reference in a new issue