Slide 1

Slide 1 text

PIPELINE ANDROID Automatizando da sua máquina até a loja

Slide 2

Slide 2 text

/_rafaeltoledo /rafaeltoledo

Slide 3

Slide 3 text

POR QUE AUTOMATIZAR É IMPORTANTE? 3

Slide 4

Slide 4 text

4 Ow, instala pra mim aí?

Slide 5

Slide 5 text

Ow, instala pra mim aí? 5 Ow, instala pra mim aí? Ow, instala pra mim aí? Ow, instala pra mim aí? Ow, instala pra mim aí? Ow, instala pra mim aí?

Slide 6

Slide 6 text

6

Slide 7

Slide 7 text

7 Qual o caminho do nosso código? ?

Slide 8

Slide 8 text

8 Qual o caminho do nosso código? Ow, instala pra mim aí?

Slide 9

Slide 9 text

9 Qual o caminho do nosso código? ?

Slide 10

Slide 10 text

Por que eu preciso disso? ● Integração de código ● Todo mundo na mesma página ● Execução de testes e validação contínua ● Cobertura de código e outras métricas ● Releases frequentes 10

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Jenkins Concourse Soluções on-premise

Slide 14

Slide 14 text

14 Script

Slide 15

Slide 15 text

15 Script Shell Script

Slide 16

Slide 16 text

16 Script

Slide 17

Slide 17 text

17 Script Python

Slide 18

Slide 18 text

PLANEJANDO O PIPELINE 18

Slide 19

Slide 19 text

19 Pipeline

Slide 20

Slide 20 text

20 Onde fazer o build?

Slide 21

Slide 21 text

E como ficam os meus segredos nesse bolo todo? 21

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

Como guardar os segredos do meu repositório? ● Variáveis de Ambiente ● Arquivos pequenos podem ser codificados em Base64 ● Arquivos maiores podem estar criptografados no repositório - e a chave como variável de ambiente ● Ou podem estar em outro serviço (Google Drive, Dropbox) e serem baixados via API 23

Slide 24

Slide 24 text

Pipeline ● Importante granularizar para isolar os pontos de erro ● Dividir em blocos (passos) maiores, para diferentes cenários 24

Slide 25

Slide 25 text

25 Pipeline Lint e testes de JVM Pull Requests

Slide 26

Slide 26 text

26 Pipeline Lint e testes de JVM Pull Requests

Slide 27

Slide 27 text

27 Pipeline Lint e testes de JVM Pull Requests Testes instrumentados Check de Segurança Integração na master

Slide 28

Slide 28 text

28 Pipeline Firebase Test Lab Lint e testes de JVM Pull Requests Testes instrumentados Check de Segurança Integração na master

Slide 29

Slide 29 text

29 Pipeline Lint e testes de JVM Pull Requests Testes instrumentados Check de Segurança Integração na master Upload Google Play App Center Upload de Build Este passo pode, Inclusive, ser manual

Slide 30

Slide 30 text

VAMOS COLOCAR A MÃO NA MASSA?

Slide 31

Slide 31 text

31 Variáveis de Ambiente no CI

Slide 32

Slide 32 text

workflows: version: 2 build_and_test: jobs: - build - test_instrumented: requires: - build - google_play_upload: requires: - test_instrumented

Slide 33

Slide 33 text

references: workspace: &workspace ~/recipes-android

Slide 34

Slide 34 text

config_android: &config_android working_directory: *workspace docker: - image: circleci/android:api-28-alpha environment: TERM: dumb JAVA_TOOL_OPTIONS: "-Xmx1g" GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=2 -Dkotlin.incremental=false" CIRCLE_JDK_VERSION: oraclejdk8

Slide 35

Slide 35 text

config_gcloud: &config_gcloud working_directory: *workspace docker: - image: google/cloud-sdk:latest environment: TERM: dumb

Slide 36

Slide 36 text

cache_key: &cache_key key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}

Slide 37

Slide 37 text

restore_cache: &restore_cache restore_cache: <<: *cache_key save_cache: &save_cache save_cache: <<: *cache_key paths: - ~/.gradle/caches - ~/.gradle/wrapper

Slide 38

Slide 38 text

persist_to_workspace: &persist_to_workspace persist_to_workspace: root: . paths: - ftl-tests - build - app/build - distribution - fastlane - changelog.txt - Gemfile

Slide 39

Slide 39 text

attach_workspace: &attach_workspace attach_workspace: at: *workspace

Slide 40

Slide 40 text

PARTE I - BUILD E TESTES 40

Slide 41

Slide 41 text

jobs: build: <<: *config_android steps: - checkout - *restore_cache

Slide 42

Slide 42 text

- run: name: Accept licenses command: yes | sdkmanager --licenses || true - run: name: Decrypt release key command: openssl aes-256-cbc -d -in distribution/release.keystore-cipher -out distribution/release.keystore -md sha256 -k $CIPHER_DECRYPT_KEY

Slide 43

Slide 43 text

- run: name: Setup Firebase JSON configuration file command: echo $FIREBASE_CONFIG_JSON | base64 -di > app/google-services.json - run: name: Run Linters command: ./gradlew check detekt --stacktrace

Slide 44

Slide 44 text

- run: name: Build command: ./gradlew assemble bundleRelease assembleAndroidTest --stacktrace

Slide 45

Slide 45 text

- store_test_results: path: app/build/test-results - store_artifacts: path: app/build/reports destination: reports - store_artifacts: path: app/build/outputs/apk destination: apks

Slide 46

Slide 46 text

- *save_cache - *persist_to_workspace

Slide 47

Slide 47 text

PARTE II - FIREBASE TEST LAB 47

Slide 48

Slide 48 text

5 execuções / dia em devices 10 execuções / dia em emuladores

Slide 49

Slide 49 text

test_instrumented: <<: *config_gcloud steps: - *attach_workspace

Slide 50

Slide 50 text

- run: name: Setup Google Cloud auth command: ftl-tests/setup.sh

Slide 51

Slide 51 text

- run: name: Setup Google Cloud auth command: ftl-tests/setup.sh

Slide 52

Slide 52 text

#!/bin/sh if [ "$GCLOUD_SERVICE_KEY" = "" ]; then echo "GCLOUD_SERVICE_KEY env variable is empty. Exiting." exit 1 fi # Export to secrets file echo $GCLOUD_SERVICE_KEY | base64 -di > client-secret.json # Set project ID gcloud config set project lowcarb-6eaa7

Slide 53

Slide 53 text

... # Auth account gcloud auth activate-service-account [email protected] --key-file client-secret.json # Delete secret rm client-secret.json

Slide 54

Slide 54 text

- run: name: Run tests on Firebase Test Lab command: ftl-tests/run-tests.sh

Slide 55

Slide 55 text

#!/bin/sh # Run tests on test lab gcloud firebase test android run \ --type instrumentation \ --app app/build/outputs/apk/debug/app-debug.apk \ --test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \ --device model=Nexus6P,version=27,locale=en_US,orientation=portrait \ --timeout 30m \ --results-bucket cloud-test-lowcarb-6eaa7 \ --no-record-video \ --no-performance-metrics

Slide 56

Slide 56 text

- run: name: Download results command: ftl-tests/download-results.sh firebase_test_results when: always

Slide 57

Slide 57 text

#!/bin/sh TEST_DIR=$1 # Create directory for results mkdir "$TEST_DIR" # Pull down test results gsutil -m cp -r -U "`gsutil ls gs://cloud-test-lowcarb-6eaa7 | tail -1`*" "$TEST_DIR"

Slide 58

Slide 58 text

- store_artifacts: path: firebase_test_results - store_test_results: path: firebase_test_results

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

PARTE III - GOOGLE PLAY 60

Slide 61

Slide 61 text

https://docs.fastlane.tools/getting-started/android/setup/ 61

Slide 62

Slide 62 text

lane :beta do gradle(task: 'assemble', build_type: 'Release') upload_to_play_store(track: 'beta') slack(message: 'Successfully distributed a new beta build') end

Slide 63

Slide 63 text

https://docs.fastlane.tools/getting-started/android/screenshots 63

Slide 64

Slide 64 text

google_play_upload: <<: *config_android steps: - *attach_workspace

Slide 65

Slide 65 text

- run: name: Setup Google Play upload key command: | touch distribution/google-play-key.json echo "${GOOGLE_PLAY_UPLOAD_KEY}" >> "distribution/google-play-key.json"

Slide 66

Slide 66 text

- run: name: Setup Fastlane command: gem install fastlane - run: name: Install JSON parser command: sudo apt-get update && sudo apt-get install -y jq

Slide 67

Slide 67 text

- run: name: Prepare changelog command: | mkdir "fastlane/metadata/android/pt-BR/changelogs" && touch "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt" mv changelog.txt "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt"

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

- run: name: Prepare changelog command: | mkdir "fastlane/metadata/android/pt-BR/changelogs" && touch "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt" mv changelog.txt "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt"

Slide 70

Slide 70 text

- run: name: Prepare changelog command: | mkdir "fastlane/metadata/android/pt-BR/changelogs" && touch "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt" mv changelog.txt "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt"

Slide 71

Slide 71 text

- run: name: Prepare changelog command: | mkdir "fastlane/metadata/android/pt-BR/changelogs" && touch "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt" mv changelog.txt "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt"

Slide 72

Slide 72 text

[ { "outputType": { "type": "APK" }, "apkInfo": { "type": "MAIN", "splits": [], "versionCode": 262, "versionName": "0.0.1.00c2466", "enabled": true, "outputFile": "app-release.apk", "fullName": "release", "baseName": "release" }, "path": "app-release.apk", "properties": {} } ]

Slide 73

Slide 73 text

[ { "outputType": { "type": "APK" }, "apkInfo": { "type": "MAIN", "splits": [], "versionCode": 262, "versionName": "0.0.1.00c2466", "enabled": true, "outputFile": "app-release.apk", "fullName": "release", "baseName": "release" }, "path": "app-release.apk", "properties": {} } ]

Slide 74

Slide 74 text

- run: name: Prepare changelog command: | mkdir "fastlane/metadata/android/pt-BR/changelogs" && touch "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt" mv changelog.txt "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt"

Slide 75

Slide 75 text

- run: name: Prepare changelog command: | mkdir "fastlane/metadata/android/pt-BR/changelogs" && touch "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt" mv changelog.txt "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt"

Slide 76

Slide 76 text

- run: name: Prepare changelog command: | mkdir "fastlane/metadata/android/pt-BR/changelogs" && touch "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt" mv changelog.txt "fastlane/metadata/android/pt-BR/changelogs/$(cat app/build/outputs/apk/release/output.json | jq -r '.[0].apkInfo.versionCode').txt"

Slide 77

Slide 77 text

- run: name: Deploy to Google Play command: bundle exec fastlane deploy

Slide 78

Slide 78 text

platform :android do desc "Deploy a new version to the Google Play Internal track" lane :deploy do upload_to_play_store(track: 'internal', aab: 'app/build/outputs/bundle/release/app.aab', skip_upload_apk: true) end end

Slide 79

Slide 79 text

platform :android do desc "Deploy a new version to the Google Play Internal track" lane :deploy do upload_to_play_store(track: 'internal', aab: 'app/build/outputs/bundle/release/app.aab', skip_upload_apk: true) end end

Slide 80

Slide 80 text

https://developer.android.com/platform/technology/app-bundle/ 80

Slide 81

Slide 81 text

- run: name: Update Changelog command: bundle exec fastlane supply --skip_upload_apk true --skip_upload_aab true

Slide 82

Slide 82 text

VAMOS VER RODANDO?

Slide 83

Slide 83 text

Links CIRCLECI https://circleci.com JENKINS https://jenkins.io FIREBASE TEST LAB https://firebase.google.com/docs/test-lab/ SEGMENTIO ANALYTICS (SETUP CIRCLECI + FIREBASE) https://github.com/segmentio/analytics-android 83

Slide 84

Slide 84 text

Links GIST COM OS ARQUIVOS DE CONFIGURAÇÃO https://gist.github.com/rafaeltoledo/10b30e17c3e3096fea4572098194b16f 84

Slide 85

Slide 85 text

OBRIGADO Slides disponíveis em: speakerdeck.com/rafaeltoledo thoughtworks.com/pt/careers 85