Augmenter CI sur github pour Android en une journée

salut!

Avec l'avènement de Github Actions, il a pris l'initiative et intégré un CI / CD simple (mais assez efficace) dans notre petit projet Flowwow live, déjà vieux de 2 ans .

Pourquoi?



Peut-être qu'il y a des développeurs qui ne font pas d'erreurs, mais ici, je ne suis pas l'un d'eux, donc de temps en temps, mais de si petits éclats de crash se produisent et vous devez publier de toute urgence une nouvelle version avec modification ou restauration de la version précédente. Mais ces heures-jours dans lesquelles les utilisateurs tombent sur des plantages d'applications ne restent pas sans traces à la fois chez les clients et dans l'humeur d'un développeur responsable.

Comment minimiser la fakapy sur la production, je le dirai ci-dessous.

Pourquoi ai-je personnellement un tel fakap?

  1. Extrait de code non sécurisé
  2. Ils ont apporté une bibliothèque et ça plante de façon situationnelle
  3. Mise à jour d'une bibliothèque (généralement analytique) vers une version instable

Avec 1 point, révision de code, tests unitaires, analyse de code statique, tests d'interface utilisateur, tests manuels nous aideront.

Avec 2-3 points - uniquement des tests d'interface utilisateur et des tests manuels.

Il ne reste plus qu'à automatiser cela. À ce stade, le choix s'est porté sur les actions Github alors apparues , l'avantage et le code du projet sont sur Github. Je dois dire tout de suite, pour un compte github gratuit, il y a 2000 minutes d'action gratuites par mois.

Où commencer?


Il est plein d'exemples prêts à l'emploi pour différents langages et cadres. Cette chose est configurée via le fichier de configuration YAML , qui se trouve dans le référentiel du projet.



Exemple minimal pour Android:

name: Android CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: Build with Gradle
        run: ./gradlew assembleDebug

Description: pour chaque push, une tâche est lancée sur n'importe quelle branche de la machine virtuelle github avec ubuntu OS. Étapes de la tâche: vérifiez notre code, configurez jdk, exécutez les tâches gradle pour l'assemblage.

En cas de passage infructueux d'une étape, nous verrons une telle image



là où vous pourrez voir les logs.

Il est pratique qu'avec Pull Request nous montrons immédiatement que notre séquence de test a échoué.



Et si vous avez l'intégration de github avec Slack, alors c'est aussi



Maintenant, point par point


1. Tests unitaires

Vous avez écrit des tests unitaires en utilisant junit, mockito, etc.

Vos tests sont maintenant inclus dans la séquence de test en ajoutant la tâche gradle appropriée.

- name: Run some unit tests
  run: ./gradlew testStageDebugUnitTest

2. Analyse de code statique

Vous pouvez utiliser des linters simples ( detekt - pour kotlin, pmd - pour java).
Ou une option plus compliquée est le sonarqube .

Dans le cas de linters simples (par exemple, nous avons à la fois java et kotlin):

task("checkAll") {
    group "Verify"
    description "Runs all static checks on the build"
    dependsOn "pmd", "detekt"
}

- name: Run some unit tests
  run: ./gradlew checkAll

en cas de sonarqube - en savoir plus sur le réglage - ici

- uses: actions/checkout@v1
- name: SonarCloud Scan
   run: ./gradlew jacocoUnitTestReport sonarqube -Dsonar.login=${{ secrets.SONAR_TOKEN }} --stacktrace
   env:
     GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Link to SonarCloud Report
   run: echo "https://sonarcloud.io/dashboard?id=.."

3. Tests d'interface utilisateur

L'écriture d'un test d'interface utilisateur est le fruit de votre imagination, mon approche est un test de «fumée» qui imite les actions standard de l'utilisateur dans l'application - connectez-vous, sélectionnez un produit, passez une commande, suivez la commande. Vous pouvez utiliser UIAutomator, Espresso, Kaspresso.

Il existe également 2 options pour le lancement ici - un émulateur sur une machine virtuelle github ou des services cloud tels que le Firebase Test Lab.
Pour utiliser l'émulateur dans github, il existe des implémentations prêtes à l'emploi: une et deux .

Dans le cas du Firebase Test Lab, vous devez travailler avec Google Cloud Platform via la gcloud CLI

- name: prepare gcloud
  uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
  with:
    version: latest
    service_account_email:  ${{ secrets.SA_EMAIL }}
    service_account_key: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
- name: gcloud Set up project
  run: |
    gcloud config set project ${{ secrets.PROJECT_ID }}
- name: Assemble apks for smoke test
  run: ./gradlew Smoke
- name: Run tests in test lab
  run: |
     gcloud firebase test android run \
       --app app/build/outputs/apk/production/debug/app.apk \
       --test app/build/outputs/apk/androidTest/production/debug/appTest.apk \
       --device model=Nexus6P,version=25,orientation=portrait,locale=en_US \
       --device model=athene,version=23,orientation=portrait,locale=en_US \
       --device model=sailfish,version=26,orientation=portrait,locale=en_US

Pour que cela fonctionne, vous devez créer un projet dans Firebase, créer un compte de service avec des droits d'administrateur dans Google Cloud Console et télécharger la clé json reçue sur base64 dans github secrets pour autorisation dans gcloud .

La configuration générale dans mon cas ressemblait à ceci. La tâche est déclenchée par l'événement PR dans le maître

name: Android CI

on:
  pull_request:
    branches:
      - 'master'

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v1
      - name: set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: Run static checks
        run: ./gradlew checkAll
      - name: Run some unit tests
        run: ./gradlew testStageDebugUnitTest

      - name: prepare gcloud
        uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
        with:
          version: latest
          service_account_email:  ${{ secrets.SA_EMAIL }}
          service_account_key: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
      - name: gcloud Set up project
        run: |
          gcloud config set project ${{ secrets.PROJECT_ID }}
      - name: Assemble apks for smoke test
        run: ./gradlew Smoke
      - name: Run tests in test lab
        run: |
          gcloud firebase test android run \
            --app app/build/outputs/apk/production/debug/app.apk \
            --test app/build/outputs/apk/androidTest/production/debug/appTest.apk \
            --device model=Nexus6P,version=25,orientation=portrait,locale=en_US \
            --device model=athene,version=23,orientation=portrait,locale=en_US \
            --device model=sailfish,version=26,orientation=portrait,locale=en_US

Cela semble simple. L'efficacité dépend des tests écrits et des règles d'analyse de code sélectionnées. Vous pouvez écrire plusieurs tâches indépendantes (travail) pour les exécuter en parallèle. Dans mon cas, tout se passe séquentiellement. Le processus de vérification prend environ 15 minutes sur notre projet (machine virtuelle github 2-core CPU, 7 Go de RAM, 14 Go de SSD), mais ce n'est pas vraiment critique, tant que vous le "codez" avec vos yeux, les résultats de ces tests arrivent également.

Les tests d'interface utilisateur aident le plus - il arrive que lors de leur passage, l'analyse se bloque après la mise à jour de la bibliothèque et vous comprenez simplement que vous ne devez pas la mettre à jour.

Grâce à gcloud, vous pouvez également fournir des versions à Firebase App Distribution, les publier sur Google Play, etc.

De nombreux exemples utiles peuvent être vus ici et ici .
J'espère que cet article sera utile à quelqu'un. Bonne chance et moins de plantages en production!

All Articles