Публикация ночных сборок

Запуск пользователями “ночных” сборок — отличный способ получить быструю обратную связь о текущей деятельности по разработке. Одним из основных способов получения такой обратной связи является максимальное упрощение установки ночных сборок и их обновление. Инструменты F-Droid теперь позволяют автоматизировать весь этот процесс для приложений, настроенных на GitLab CI.

Ночные репозитории F-Droid построены поверх стандартного хранилища ключей Android ~/.android/debug.keystore, которое автоматически генерируется инструментами Android. Этот ключ подписи используется для подписи ночных сборок, а также индекса репозитория. Это предназначено для простоты настройки и управления, но это не обеспечивает тот же уровень безопасности, что и стандартный репозиторий F-Droid!

Поскольку речь идет о сглаживании процесса разработки, также имеет смысл повторно использовать разделяемый debug.keyystore среди вашей команды. Таким образом, все отладочные сборки будут взаимозаменяемы. Это значительно облегчает отладку некоторых проблем, так как вы можете сохранить состояние приложения при установке собственных отладочных сборок, например, для добавления протоколирования.

Автоматические коды версий

С ночными сборками обычная логика установки versionCode в git для каждого релиза больше не имеет смысла. Для того чтобы Android рассматривал каждую новую сборку как возможное обновление, versionCode должен увеличиваться, но это не имеет смысла для фиксации в git каждый раз. Поэтому должна быть какая-то автоматическая логика для установки versionCode:

  • временная метка в секундах (date +%s) всегда будет увеличиваться
  • инкрементирование versionCode последнего выпуска (например, 104030034, 104030035, 104030036)
  • git commit count (git rev-list --first-parent --count HEAD) дает некоторые подсказки о том, в каком месте кода была сделана сборка

Для многих приложений наибольший смысл будет иметь некая комбинация. Для F-Droid у нас есть переменная DB_VERSION для внутренней базы данных. Мы занимаемся только обновлением базы данных, но никогда не понижением. Поэтому это должна быть самая важная часть versionCode. Любая сборка с DB_VERSION = 77 не должна быть обновлена любой сборкой с DB_VERSION = 75. Затем второстепенной частью является счетчик коммитов, так что он выглядит как (7502543, 7502544, 7702601 и т.д.). с DB_VERSION в качестве первых двух цифр, затем счетчик коммитов с добавлением 0 в качестве последних 5 цифр.

Настройка GitLab CI

Это предполагает, что приложение уже настроено с помощью .gitlab-ci.yml и сборки выполняются на GitLab CI. Это также работает для форков основного проекта с .gitlab-ci-yml.

  1. Запустите fdroid nightly --show-secret-var в локальном git-репо, которое настраивается, например fdroid/fdroidclient. Это выведет открытый ключ SSH. Использование --show-secret-var заставит его вывести текст base 64 для вставки в секретную переменную DEBUG_KEYSTORE. Осторожно! Этот текст - весь debug.keystore, поэтому защищайте его соответствующим образом!

  2. Создайте новый “проект” GitLab, добавив к его названию -nightly. Например, https://gitlab.com/fdroid/fdroidclient становится https://gitlab.com/fdroid/fdroidclient-nightly, а https://gitlab.com/eighthave/fdroidclient становится https://gitlab.com/eighthave/fdroidclient-nightly

  3. В этом новом проекте добавьте открытый ключ SSH, полученный из debug.keystore, в качестве ключа развертывания в настройках репозитория, например, https://gitlab.com/eighthave/fdroidclient-nightly/settings/repository

  4. В CI/CD Settings собираемого проекта вставьте это в секретную переменную GitLab CI под названием DEBUG_KEYSTORE, например, https://gitlab.com/eighthave/fdroidclient/settings/ci_cd

  5. Затем на этой же странице в разделе Protected настройте ветку master так, чтобы ограничить возможность утечки debug.keystore. Если master не может быть принудительно вытолкнут, то любые попытки получить хранимые секреты навсегда записываются в историю git. Без такой защиты кто-то, имеющий доступ к push, может подтолкнуть коммит в ветке, чтобы распечатать секреты, а затем удалить этот коммит, чтобы скрыть свои действия.

  6. Добавьте этап deploy в ваш .gitlab-ci.yml, который создает только сборку для публикации в nightly, а затем запускает fdroid nightly. Например:

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

Реальный пример использования gitlab-ci см. в fdroidclient: * https://gitlab.com/fdroid/fdroidclient-nightly * https://gitlab.com/fdroid/fdroidclient/blob/master/.gitlab-ci.yml

Настройка 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. Запустите fdroid nightly --show-secret-var в локальном git-репо, которое настраивается, например fdroid/fdroidclient. Это выведет открытый ключ SSH. Использование --show-secret-var заставит его вывести текст base 64 для вставки в секретную переменную DEBUG_KEYSTORE. Осторожно! Этот текст - весь debug.keystore, поэтому защищайте его соответствующим образом!

  2. Создайте новый “проект” GitHub, добавив к его названию -nightly. Например, https://github.com/f-droid/fdroidclient становится https://github.com/f-droid/fdroidclient-nightly, а https://github.com/eighthave/fdroidclient становится https://github.com/eighthave/fdroidclient-nightly

  3. В этом новом проекте добавьте открытый ключ SSH, полученный из вашего debug.keystore, в качестве ключа развертывания в настройках безопасности, например, https://github.com/eighthave/fdroidclient-nightly/settings/keys

  4. В Настройках собираемого проекта в разделе «Secrets» найдите «Actions». Вставьте всю строку вывода DEBUG_KEYSTORE в новый секрет репозитория с названием DEBUG_KEYSTORE, например https://gitlab.com/eighthave/fdroidclient/settings/secrets/actions.

  5. Добавьте в ваш .github/workflows/ этап nightly , который создает только сборку для публикации в nightly, а затем запускает fdroid nightly. Например:

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=${{ secrets.DEBUG_KEYSTORE }}
          fdroid nightly --archive-older 10

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

Настройка для GitHub и Travis CI

  1. Создайте новый debug.keystore для каждого приложения, поскольку GitHub позволяет использовать ключ развертывания только для одного репозитория. Храните этот файл в безопасности, поскольку он является ключом подписи для вашей ночной сборки.
    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. Установите ключ развертывания GitHub для https://github.com/zom/zom-android-nightly, перейдя по адресу https://github.com/zom/zom-android-nightly/settings/keys.
    Публичный SSH-ключ распечатывается при выполнении:
    fdroid nightly --keystore im.zom.messenger-debug.keystore
    
  3. установите флажок Разрешить доступ на запись (Allow write access) в настройках GitHub Deploy Key
  4. Чтобы вывести содержимое секретной переменной, используйте --show-secret-var. Осторожно! Этот текст - весь debug.keystore, поэтому защищайте его соответствующим образом! Это выводит текст в формате base64 для вставки в “переменную окружения” Travis CI в https://travis-ci.org/zom/Zom-Android/settings. Вызовите переменную DEBUG_KEYSTORE и убедитесь, что “Display value in build log” - OFF.
    fdroid nightly --keystore im.zom.messenger-debug.keystore --show-secret-var
    

А вот простой пример того, как добавить fdroidserver в настройку Travis CI, чтобы заставить его развернуть APK после успешного тестирования:

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

Пример из реального мира см. в 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