Nightly Builds veröffentlichen

Anwender, die „Nightly Builds“ (Beta-Versionen) verwenden, stellen ein großartige Möglichkeit dar, umgehend Rückmeldung zu laufenden Entwicklungsarbeiten zu erhalten. Ein entscheidender Punkt, auf diese Art Feedback zu bekommen, ist dabei, es den Leuten so einfach wie möglich zu machen, die Nightly Builds zu installieren und auf dem neuesten Stand zu halten. Mit den F-Droid-Tools können Sie nun diesen gesamten Prozess für Anwendungen, die auf GitLab CI eingerichtet sind, automatisieren.

Die F-Droid Nightly Repos bauen auf den serienmäßigen ~/.android/debug.keystore in Android auf, den die Android Tools automatisch generieren. Dieser Signierschlüssel wird zur Signierung der Nightly Builds wie auch des Repo-Index verwendet. Das soll einfach einzurichten und zu verwalten sein, bietet aber nicht die gleiche Sicherheit wie ein F-Droid-Standardrepo!

Da es darum geht, den Entwicklungsprozess zu erleichtern, ist es außerdem sinnvoll, einen gemeinsamen debug.keystore in Ihrem Team wiederzuverwenden. Auf diese Weise sind alle Debug-Builds austauschbar. Dies erleichtert die Fehlersuche bei bestimmten Problemen erheblich, da Sie den App-Status beibehalten können, wenn Sie Ihre eigenen Debug-Builds installieren, z. B. um eine Ereignisprotokollierung hinzuzufügen.

Automatische Versionscodes

Bei Nightly Builds macht die normale Logik der Festlegung des versionCode in git für jedes Release keinen Sinn mehr. Damit Android jeden neuen Build als mögliches Update behandeln kann, muss der versionCode erhöht werden, aber es ist sinnlos, jedes Mal auf git zu committen. Es muss also eine automatische Logik für die Festlegung des versionCode geben, wie:

  • die ständige Erhöhung eines sekundengenauen Zeitstempels (Datum +%s)
  • ein Inkrementieren des versionCode der letzten Version (z.B. 104030034, 104030035, 104030036)
  • der Git-Commit-Zähler (git rev-list --first-parent --count HEAD) gibt Hinweise, woher im Code der Build stammt

Für viele Apps werden irgendwelche Kombinationen davon am sinnvollsten sein. Für F-Droid haben wir eine Variable DB_VERSION für die interne Datenbank. Wir bearbeiten nur ein Upgrading der Datenbank, niemals ein Downgrading. Das muss also der wichtigste Teil des Versionscodes sein. Kein Build mit DB_VERSION = 77darf durch einen Build mit DB_VERSION = 75 aktualisiert werden. Der untergeordnete Teil ist dann der Commit-Zähler, also sieht er folgendermaßen aus (7502543, 7502544, 7702601, usw.) mit DB_VERSION als den ersten beiden Ziffern, gefolgt von einem mit Nullen aufgefüllten, fünfstelligen Commit-Zähler.

GitLab CI konfigurieren

Voraussetzung dafür ist, dass die App bereits mit .gitlab-ci.yml eingerichtet ist und Builds auf GitLab CI laufen. Dies funktioniert auch für Forks des Hauptprojekts, das die .gitlab-ci-yml enthält.

  1. Starten Sie fdroid nightly --show-secret-var im lokalen Git-Repo, das gerade eingerichtet wird, z. B. fdroid/fdroidclient. Es wird der SSH Public Key ausgegeben. Mit --show-secret-var wird der base-64-Text ausgegeben, der in die geheime Variable DEBUG_KEYSTORE eingefügt werden soll. Vorsicht! Dieser Text ist der gesamte debug.keystore, also schützen Sie ihn entsprechend!

  2. Erstellen Sie ein neues GitLab-„Projekt“, indem Sie -nightly an den Namen anhängen. Zum Beispiel wird https://gitlab.com/fdroid/fdroidclient zu https://gitlab.com/fdroid/fdroidclient-nightly und https://gitlab.com/eighthave/fdroidclient zu https://gitlab.com/eighthave/fdroidclient-nightly

  3. Fügen Sie in diesem neuen Projekt den von Ihrem debug.keystore abgeleiteten SSH Public Key als Deploy Key in Ihre Repository-Einstellungen ein, z. B. https://gitlab.com/eighthave/fdroidclient-nightly/settings/repository

  4. In den CI/CD-Einstellungen des zu erstellenden Projekts fügen Sie diese in die GitLab CI-Secret Variable DEBUG_KEYSTORE ein, z.B. https://gitlab.com/eighthave/fdroidclient/settings/ci_cd

  5. Richten Sie dann auf der gleichen Seite im geschützten Bereich Ihren master-Zweig ein, um die Wahrscheinlichkeit eines debug.keystore-Leaks zu begrenzen. Wenn kein „force push“ für master möglich ist, werden alle Versuche, die gespeicherten Geheimnisse zu erhalten, permanent in die Git-Historie geschrieben. Ohne diesen Schutz könnte jemand mit Push-Zugriff einen Commit in einem Zweig pushen, um die Geheimnisse auszulesen, und dann diesen Commit wieder entfernen, um seine Aktionen zu verheimlichen.

  6. Ergänzen Sie eine deploy Stufe in Ihrer .gitlab-ci.yml, die nur den Build erzeugt, der für die Nightly-Veröffentlichung bestimmt ist und dann fdroid nightly ausführt. Zum Beispiel:

deploy_nightly:
  stage: deploy
  only:
    - master
  script:
    - ./gradlew assembleDebug
    - pip3 install fdroidserver
    - export PATH=~/.local/bin:$PATH
    - fdroid nightly

Für ein reales Beispiel mit gitlab-ci siehe fdroidclient: * https://gitlab.com/fdroid/fdroidclient-nightly * https://gitlab.com/fdroid/fdroidclient/blob/master/.gitlab-ci.yml

Configuring for GitHub Actions

GitHub and GitHub Actions are both proprietary platforms that are widely used to develop free software. Since F-Droid does not promote proprietary software, there is no official support for GitHub Actions. All of the F-Droid tooling is free software, so contributors have made a GitHub Action based on the F-Droid tools.

  1. Starten Sie fdroid nightly --show-secret-var im lokalen Git-Repo, das gerade eingerichtet wird, z. B. fdroid/fdroidclient. Es wird der SSH Public Key ausgegeben. Mit --show-secret-var wird der base-64-Text ausgegeben, der in die geheime Variable DEBUG_KEYSTORE eingefügt werden soll. Vorsicht! Dieser Text ist der gesamte debug.keystore, also schützen Sie ihn entsprechend!

  2. Create a new GitHub “project” by appending -nightly to the name. For example, https://github.com/f-droid/fdroidclient becomes https://github.com/f-droid/fdroidclient-nightly and https://github.com/eighthave/fdroidclient becomes https://github.com/eighthave/fdroidclient-nightly

  3. In that new project, add the SSH Public Key derived from your debug.keystore as a Deploy Key in your Security settings, e.g. https://github.com/eighthave/fdroidclient-nightly/settings/keys

  4. In the Settings of the project being built, find “Actions” under “Secrets” in the “Security” section. Paste the whole DEBUG_KEYSTORE output line into a new repository secret called DEBUG_KEYSTORE, e.g. https://github.com/eighthave/fdroidclient/settings/secrets/actions.

  5. Add a nightly stage to your .github/workflows/ that produces only the build to publish to the nightly, then runs fdroid nightly. For example:

name: Publish nightly build

on:
  push:
    branches:
      - main

jobs:
  nightly:
    name: Publish nightly build
    runs-on: ubuntu-latest
    environment: nightly
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Gradle Wrapper Validation
        uses: gradle/wrapper-validation-action@v1
      - name: Set up JDK 11
        uses: actions/setup-java@v2
        with:
          distribution: 'adopt'
          java-version: 11
      - name: Build
        run: |
          # use timestamp as Version Code
          export versionCode=$(date '+%s')
          sed -i "s,^\(\s*versionCode\)  *[0-9].*,\1 $versionCode," app/build.gradle
          ./gradlew assembleDebug
      - name: fdroid nightly
        run: |
          sudo add-apt-repository ppa:fdroid/fdroidserver
          sudo apt-get update
          sudo apt-get install apksigner fdroidserver --no-install-recommends
          export DEBUG_KEYSTORE=$
          fdroid nightly --archive-older 10

There is an alternate approach based on Docker maintained by @wardvl: wardvl/f-droid-nightly-action

Konfiguration für GitHub und Travis CI

  1. Erzeugen Sie einen neuen debug.keystore für jede App, da GitHub nur die Verwendung eines Deploy-Schlüssels pro Repo zulässt. Bewahren Sie diese Datei sicher auf, da sie der Signierschlüssel für Ihr Nightly Build ist.
    keytool -genkey -v -keystore im.zom.messenger-debug.keystore \
      -keyalg RSA -keysize 2048 -validity 10000 \
      -alias androiddebugkey -storepass android -keypass android \
      -dname "CN=Android Debug,O=Android,C=US"
    
  2. Legen Sie in GitHub einen Deploy-Schlüssel für https://github.com/zom/zom-android-nightly fest, indem Sie zu https://github.com/zom/zom-android-nightly/settings/keysgehen. Der öffentliche SSH-Schlüssel wird ausgedruckt über:
    fdroid nightly --keystore im.zom.messenger-debug.keystore
    
  3. markieren Sie Allow write access in den GitHub-Einstellungen für Deploy-Schlüssel
  4. Um den Inhalt der Geheimvariable auszudrucken, verwenden Sie --show-secret-var. Vorsicht! Dieser Text ist der gesamte debug.keystore, schützen Sie ihn also entsprechend! Es wird so base64-Text ausgedruckt, der in einer Travis CI “Environment Variable” in https://travis-ci.org/zom/Zom-Android/settingseingefügt werden soll. Rufen Sie die Variable DEBUG_KEYSTORE auf und vergewissern Sie sich, dass “Display value in build log” auf OFF steht.
    fdroid nightly --keystore im.zom.messenger-debug.keystore --show-secret-var
    

Und hier ein einfaches Beispiel, wie Sie fdroidserver zu Ihrem Travis CI-Setup hinzufügen können, damit er nach einem erfolgreichen Test das APK bereitstellt:

sudo: required
language: android

addons:
  apt:
    sources:
      - sourceline: 'ppa:fdroid/fdroidserver'
    packages:
      - fdroidserver
      - openssh-client

android:
  components:
    - tools
    - platform-tools
    - build-tools-26.0.2
    - android-25
  licenses:
    - 'android-sdk-license-.+'

script:
  - ./gradlew test

after_success:
  - fdroid nightly -v

Ein Beispiel aus der Praxis finden Sie unter Zom: * https://github.com/zom/Zom-Android-nightly * https://github.com/zom/Zom-Android/blob/master/.travis.yml * https://travis-ci.org/zom/Zom-Android