Reworks the pipeline so a change is built once and a release is driven by the merge, not a manual tag push. - ci.yaml now runs on pull_request (one gate per PR) instead of every branch push, so there's no CI-on-push + CI-on-merge double run. A single `ci` job with a docs-only fast-path keeps the required "CI" check always reporting (docs/metadata-only PRs skip the Android build but still go green). - release.yaml triggers on push to main. A cheap `detect` job reads versionName from build.gradle; only when no tag for it exists does the `release` job run: tests on the merged commit, build + sign, publish to F-Droid, then create the vX.Y.Z tag + Gitea release via the API (target_commitish = the merged sha). The tag is now an OUTPUT of a successful release, not its trigger — a failure before publish leaves no tag, so re-running safely retries. No more separate tag-triggered run or duplicate ci job. - The committed versionName/versionCode are now the source of truth (pipeline pins versionCode from versionName); updated the build.gradle comment. - translations.yaml switched to pull_request (same path filter). - docs/RELEASING.md: release-by-merge flow, no manual git tag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
129 lines
4.7 KiB
YAML
129 lines
4.7 KiB
YAML
name: CI
|
|
|
|
# One gate per pull request. Branch pushes no longer trigger CI on their own,
|
|
# so a change is built once on its PR (covering feature -> release/* and
|
|
# release/* -> main) instead of once per push and again on the merge to main.
|
|
# The merge itself is handled by release.yaml, which only does heavy work when
|
|
# the merge actually cuts a release.
|
|
on:
|
|
pull_request:
|
|
|
|
# Cancel superseded runs for the same PR.
|
|
concurrency:
|
|
group: ci-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# Single job named `ci` so the required "CI" status check is always reported,
|
|
# even for docs-only PRs: those just skip the Android build and the job still
|
|
# succeeds (fast green check) instead of being filtered out and leaving the
|
|
# required check pending forever.
|
|
ci:
|
|
runs-on: docker
|
|
env:
|
|
ANDROID_HOME: /opt/android-sdk
|
|
ANDROID_SDK_ROOT: /opt/android-sdk
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
# Full history so the base..HEAD diff below has a merge-base.
|
|
fetch-depth: 0
|
|
|
|
# Decide whether anything that affects the app build changed. Docs,
|
|
# F-Droid metadata and the licence don't, so those PRs skip the SDK +
|
|
# Gradle work below but still report a green `ci`.
|
|
- name: Classify change scope
|
|
id: scope
|
|
run: |
|
|
set -e
|
|
BASE="${{ github.base_ref }}"
|
|
git fetch --no-tags --depth=1 origin "$BASE"
|
|
CHANGED=$(git diff --name-only "origin/$BASE...HEAD")
|
|
echo "Changed files:"; echo "$CHANGED"
|
|
if echo "$CHANGED" | grep -vE '(\.md$|^docs/|^fdroid-metadata/|^LICENSE$)' | grep -q .; then
|
|
echo "code=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "code=false" >> "$GITHUB_OUTPUT"
|
|
echo "Docs/metadata-only change — skipping the Android build."
|
|
fi
|
|
|
|
- name: Setup Java
|
|
if: steps.scope.outputs.code == 'true'
|
|
uses: actions/setup-java@v4
|
|
with:
|
|
distribution: 'zulu'
|
|
java-version: '17'
|
|
|
|
- name: Setup Android SDK
|
|
if: steps.scope.outputs.code == 'true'
|
|
uses: android-actions/setup-android@v3
|
|
with:
|
|
# Default ("tools platform-tools") drags in the Android Emulator
|
|
# (~300 MB) which the build never uses.
|
|
packages: ''
|
|
|
|
- name: Setup Android SDK cache
|
|
if: steps.scope.outputs.code == 'true'
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: /opt/android-sdk
|
|
key: ${{ runner.os }}-android-sdk-37-36.0.0
|
|
|
|
- name: Install Android SDK packages
|
|
if: steps.scope.outputs.code == 'true'
|
|
run: |
|
|
yes | sdkmanager --licenses >/dev/null || true
|
|
sdkmanager \
|
|
"platform-tools" \
|
|
"platforms;android-37.0" \
|
|
"build-tools;36.0.0"
|
|
|
|
- name: Setup Gradle cache
|
|
if: steps.scope.outputs.code == 'true'
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.gradle/caches
|
|
~/.gradle/wrapper
|
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'gradle/libs.versions.toml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-gradle-
|
|
|
|
- name: Grant execute permission for gradlew
|
|
if: steps.scope.outputs.code == 'true'
|
|
run: chmod +x ./gradlew
|
|
|
|
# No --no-daemon: the daemon lives only as long as this job container
|
|
# and lets the following steps skip JVM startup + reconfiguration.
|
|
- name: Lint (debug variant only)
|
|
if: steps.scope.outputs.code == 'true'
|
|
run: ./gradlew lintDebug
|
|
|
|
- name: Unit tests
|
|
if: steps.scope.outputs.code == 'true'
|
|
run: ./gradlew testDebugUnitTest
|
|
|
|
- name: Assemble debug APK
|
|
if: steps.scope.outputs.code == 'true'
|
|
run: ./gradlew assembleDebug
|
|
|
|
- name: Trivy filesystem scan
|
|
if: steps.scope.outputs.code == 'true'
|
|
run: |
|
|
set -e
|
|
SUDO=""
|
|
if command -v sudo >/dev/null 2>&1; then
|
|
SUDO="sudo"
|
|
fi
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
$SUDO apt-get update
|
|
$SUDO apt-get install -y wget apt-transport-https gnupg lsb-release
|
|
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | $SUDO tee /usr/share/keyrings/trivy.gpg > /dev/null
|
|
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | $SUDO tee /etc/apt/sources.list.d/trivy.list
|
|
$SUDO apt-get update
|
|
$SUDO apt-get install -y trivy
|
|
fi
|
|
trivy filesystem --severity HIGH,CRITICAL --exit-code 0 .
|
|
continue-on-error: true
|