534 lines
17 KiB
YAML
534 lines
17 KiB
YAML
include:
|
|
- project: 'agarroux/publish-github'
|
|
ref: master
|
|
file: '/jobs/release.gitlab-ci.yml'
|
|
|
|
- project: 'translations/generator'
|
|
ref: master
|
|
file: '/jobs/sync-crowdin.gitlab-ci.yml'
|
|
|
|
- project: 'translations/generator'
|
|
ref: master
|
|
file: '/jobs/commit-locales.gitlab-ci.yml'
|
|
|
|
- local: '/ci/templates-shared/appetize-integration.yml'
|
|
|
|
- local: '/ci/templates/git.gitlab-ci.yml'
|
|
|
|
- local: '/ci/templates/base-job.gitlab-ci.yml'
|
|
|
|
- local: '/ci/templates/tools.gitlab-ci.yml'
|
|
|
|
- project: 'proton/devops/atlas-deploy'
|
|
ref: main
|
|
file: '/scenarios/pipeline-env.yml'
|
|
|
|
default:
|
|
image: ${CI_REGISTRY}/android/shared/docker-android/oci:v2.0.0
|
|
tags:
|
|
- shared-small
|
|
|
|
workflow:
|
|
rules:
|
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
variables:
|
|
# deploy to Atlas with prep job
|
|
ATLAS_DEPLOY_ENV: "true"
|
|
ATLAS_DEPLOY_PREP: "true"
|
|
- if: $CI_COMMIT_REF_NAME =~ /^release/
|
|
- if: $CI_COMMIT_REF_NAME == 'main'
|
|
|
|
stages:
|
|
- prepare
|
|
- bot
|
|
- deploy
|
|
- build
|
|
- test
|
|
- firebase
|
|
- publish
|
|
- review
|
|
- cleanup
|
|
|
|
variables:
|
|
# Use fastzip to improve cache times
|
|
FF_USE_FASTZIP: "true"
|
|
# Output upload and download progress every 5 seconds
|
|
TRANSFER_METER_FREQUENCY: "5s"
|
|
# Use no compression for artifacts
|
|
ARTIFACT_COMPRESSION_LEVEL: "fastest"
|
|
# Use low compression for caches
|
|
CACHE_COMPRESSION_LEVEL: "fast"
|
|
|
|
## pre stage #######################################################################################
|
|
prepare-environment:
|
|
tags:
|
|
- shared-small
|
|
extends: .script-job
|
|
stage: prepare
|
|
when: always
|
|
image: $CI_REGISTRY/proton/devops/atlas-cli
|
|
variables:
|
|
NAMESERVICE_URL: "https://nameservice.$ATLAS_BASE_DOMAIN/api/env"
|
|
REQUEST_DATA: "--header 'Content-Type:application/x-www-form-urlencoded' --data app=${CI_PROJECT_PATH} --data branch=${CI_COMMIT_REF_SLUG} --data tag=${CI_COMMIT_REF_SLUG}"
|
|
SENSITIVE_DIR: "test/quark/src/main/resources/sensitive"
|
|
script:
|
|
- echo PROXY_TOKEN="$(curl -o - https://proxy.$ATLAS_BASE_DOMAIN/token/get)" >> local.properties
|
|
- echo HOST="$DYNAMIC_DOMAIN" >> local.properties
|
|
- mkdir -p $SENSITIVE_DIR
|
|
- cat $TEST_USERS > $SENSITIVE_DIR/users.json
|
|
- cat $TEST_USERS_VPN_USERNAME > $SENSITIVE_DIR/users-vpn-username.json
|
|
- cat $TEST_INTERNAL_API_V4 > $SENSITIVE_DIR/internal_apis.json
|
|
rules:
|
|
- if: $ATLAS_DEPLOY_ENV == "true"
|
|
artifacts:
|
|
paths:
|
|
- $SENSITIVE_DIR
|
|
- local.properties
|
|
expire_in: never
|
|
|
|
detekt-analyze:
|
|
extends: .gradle-job
|
|
stage: prepare
|
|
when: always
|
|
interruptible: true
|
|
script:
|
|
- ./gradlew multiModuleDetekt
|
|
artifacts:
|
|
expire_in: 1 month
|
|
reports:
|
|
codequality: config/detekt/reports/mergedReport.json
|
|
|
|
## bot stage #######################################################################################
|
|
i18n-sync-crowdin:
|
|
extends: .i18n-sync-crowdin-common
|
|
variables:
|
|
I18N_SYNC_CROWDIN_PROJECT: 'android-core'
|
|
I18N_SYNC_BRANCH: 'main'
|
|
I18N_FILTER_OUT_ITEMS: 'coreexample'
|
|
|
|
i18n-commit-locales:
|
|
extends: .i18n-commit-locales-shared
|
|
variables:
|
|
I18N_COMMIT_CROWDIN_PROJECT: 'android-core'
|
|
I18N_COMMIT_BRANCH_PUSH: 'main'
|
|
I18N_COMMIT_BRANCH_ALLOWED: 'main'
|
|
|
|
grafana-commit-dashboards:
|
|
extends: .gradle-job
|
|
stage: prepare
|
|
allow_failure: true
|
|
before_script:
|
|
- source /load-env.sh
|
|
script:
|
|
- ./ci/script/pushDashboards.sh
|
|
rules:
|
|
- if: $DASHBOARDS_SCHEDULES_FILTER == "commit-dashboards"
|
|
|
|
## build stage #####################################################################################
|
|
assemble:
|
|
extends: .gradle-job
|
|
stage: build
|
|
needs:
|
|
- detekt-analyze
|
|
- job: prepare-environment
|
|
artifacts: true
|
|
interruptible: true
|
|
variables:
|
|
# Build the base apk
|
|
CORE_APP: :coreexample:assembleLocalPropertiesDebug
|
|
# Build UI tests for CoreExample
|
|
CORE_APP_TESTS: :coreexample:assembleLocalPropertiesDebugAndroidTest
|
|
# Mock variant and mock UI tests
|
|
CORE_APP_MOCK: :coreexample:assembleMockDebug :coreexample:assembleMockDebugAndroidTest
|
|
# Hilt tests
|
|
HILT_TESTS: :coreexample:coreexample-hilt-tests:assembleLocalPropertiesDebug
|
|
# Build androidTest apks for several projects
|
|
CORE_LIBS_TESTS: :user:user-data:assembleDebugAndroidTest :key:key-data:assembleDebugAndroidTest :crypto:crypto-android:assembleDebugAndroidTest :key-transparency:key-transparency-data:assembleDebugAndroidTest
|
|
script:
|
|
- ./gradlew $CORE_APP $CORE_APP_MOCK $CORE_APP_TESTS $CORE_LIBS_TESTS $HILT_TESTS
|
|
artifacts:
|
|
paths:
|
|
- coreexample/build/outputs/
|
|
- coreexample/hilt-tests/build/outputs/apk/
|
|
- user/data/build/outputs/apk/
|
|
- key/data/build/outputs/apk/
|
|
- crypto/android/build/outputs/apk/
|
|
- key-transparency/data/build/outputs/apk/
|
|
|
|
assemble:configurator:
|
|
extends: .gradle-job
|
|
stage: build
|
|
needs: [ ]
|
|
when: manual
|
|
allow_failure: true
|
|
interruptible: true
|
|
script:
|
|
- ./gradlew :configuration:configuration-configurator:assembleDebug
|
|
artifacts:
|
|
paths:
|
|
- configuration/configurator/build/outputs/apk/
|
|
|
|
## test stage ######################################################################################
|
|
unit-tests-and-coverage-report:
|
|
extends: .gradle-job
|
|
needs:
|
|
- assemble
|
|
stage: test
|
|
script:
|
|
- ./gradlew -Pci --console=plain :coreexample:testDevDebugUnitTest coberturaXmlReport globalLineCoverage :coverage:koverHtmlReport -x :coverage:jacocoToCobertura
|
|
- ./gradlew -Pci --console=plain koverVerify
|
|
- ./gradlew -Pci --console=plain verifyPaparazziDebug
|
|
coverage: /TotalLineCoverage.*?(\d{1,3}\.\d{0,2})%/
|
|
interruptible: true
|
|
artifacts:
|
|
when: always
|
|
expire_in: 1 week
|
|
paths:
|
|
- '**/build/reports/kover/cobertura*.xml'
|
|
- './coverage/build/reports/kover/html/'
|
|
reports:
|
|
junit: ./**/test-results/*/TEST-*.xml
|
|
coverage_report:
|
|
coverage_format: cobertura
|
|
path: '**/build/reports/kover/cobertura*.xml'
|
|
|
|
start-review:
|
|
needs:
|
|
- assemble
|
|
before_script:
|
|
- source /load-env.sh
|
|
- export REVIEW_APP_ARTIFACT_PATH="coreexample/build/outputs/apk/localProperties/debug/coreexample-localProperties-debug.apk"
|
|
extends: .startReview
|
|
stage: test
|
|
rules:
|
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
|
|
binary-compatibility-check:
|
|
extends: .gradle-job
|
|
stage: test
|
|
interruptible: true
|
|
needs:
|
|
- assemble
|
|
script:
|
|
- ./gradlew apiCheck
|
|
|
|
.client-integration-tests:
|
|
stage: test
|
|
inherit:
|
|
variables: false
|
|
variables:
|
|
CORE_COMMIT_SHA: $CI_COMMIT_SHA
|
|
ORG_GRADLE_PROJECT_useCoreGitSubmodule: "true"
|
|
|
|
calendar-integration-tests:
|
|
extends: .client-integration-tests
|
|
when: manual
|
|
variables:
|
|
CALENDAR_INTEGRATION_REF: develop
|
|
trigger:
|
|
project: android/calendar/proton-calendar-android
|
|
branch: $CALENDAR_INTEGRATION_REF
|
|
|
|
mail-v6-integration-tests:
|
|
extends: .client-integration-tests
|
|
when: manual
|
|
variables:
|
|
MAIL_V6_INTEGRATION_REF: master
|
|
trigger:
|
|
project: android/mail/proton-mail
|
|
branch: $MAIL_V6_INTEGRATION_REF
|
|
|
|
mail-v5-integration-tests:
|
|
extends: .client-integration-tests
|
|
when: manual
|
|
variables:
|
|
MAIL_INTEGRATION_REF: develop
|
|
trigger:
|
|
project: android/mail/proton-mail-android
|
|
branch: $MAIL_INTEGRATION_REF
|
|
|
|
vpn-integration-tests:
|
|
extends: .client-integration-tests
|
|
when: manual
|
|
variables:
|
|
VPN_INTEGRATION_REF: development
|
|
trigger:
|
|
project: ProtonVPN/android/android-app-new
|
|
branch: $VPN_INTEGRATION_REF
|
|
|
|
drive-integration-tests:
|
|
extends: .client-integration-tests
|
|
when: manual
|
|
variables:
|
|
DRIVE_INTEGRATION_REF: develop
|
|
trigger:
|
|
project: android/drive/proton-drive
|
|
branch: $DRIVE_INTEGRATION_REF
|
|
|
|
pass-integration-tests:
|
|
extends: .client-integration-tests
|
|
when: manual
|
|
variables:
|
|
PASS_INTEGRATION_REF: main
|
|
trigger:
|
|
project: android/pass/ProtonPass
|
|
branch: $PASS_INTEGRATION_REF
|
|
|
|
## firebase stage ##################################################################################
|
|
.firebase-tests-common:
|
|
stage: firebase
|
|
when: always
|
|
variables:
|
|
APP_APK: "coreexample/build/outputs/apk/localProperties/debug/coreexample-localProperties-debug.apk"
|
|
TEST_APK: "coreexample/build/outputs/apk/androidTest/localProperties/debug/coreexample-localProperties-debug-androidTest.apk"
|
|
RESULTS_DIR: "${CI_COMMIT_REF_SLUG}/${CI_COMMIT_SHORT_SHA}/${CI_JOB_NAME}"
|
|
DEVICE_MODEL: "Pixel2,version=28"
|
|
DEVICE_MODEL_RESULTS_DIR: "Pixel2-28-en-portrait"
|
|
EXTRA_OPTIONS: ""
|
|
FLAKY_TEST_RERUN: "0"
|
|
tags:
|
|
- shared-medium
|
|
allow_failure: false
|
|
script:
|
|
- gcloud config set project $CLOUD_PROJECT_ID_CORE
|
|
- gcloud auth activate-service-account --key-file $GOOGLE_SERVICE_ACCOUNT
|
|
- gcloud firebase test android run
|
|
--app ${APP_APK}
|
|
--test ${TEST_APK}
|
|
--device model=${DEVICE_MODEL}
|
|
--test-targets "$TEST_TARGET"
|
|
--timeout 30m
|
|
--results-dir=$RESULTS_DIR
|
|
--num-flaky-test-attempts=$FLAKY_TEST_RERUN
|
|
--environment-variables listener=me.proton.core.test.android.ToastingRunListener
|
|
--client-details=matrixLabel="$CI_JOB_NAME $CI_PIPELINE_URL"
|
|
${EXTRA_OPTIONS}
|
|
after_script:
|
|
- mkdir -p screenshots
|
|
- mkdir -p logs
|
|
- gsutil cp $FIREBASE_BUCKET_URL/$RESULTS_DIR/$DEVICE_MODEL_RESULTS_DIR/logcat logcat.txt
|
|
- gsutil cp $FIREBASE_BUCKET_URL/$RESULTS_DIR/$DEVICE_MODEL_RESULTS_DIR/video.mp4 video.mp4
|
|
- gsutil cp $FIREBASE_BUCKET_URL/$RESULTS_DIR/$DEVICE_MODEL_RESULTS_DIR/test_result_1.xml test_result_1.xml
|
|
- gsutil -m cp -r $FIREBASE_BUCKET_URL/$RESULTS_DIR/$DEVICE_MODEL_RESULTS_DIR/test_cases ./logs
|
|
- gsutil -m cp -r $FIREBASE_BUCKET_URL/$RESULTS_DIR/$DEVICE_MODEL_RESULTS_DIR/artifacts/sdcard/screenshots ./screenshots 2> /dev/null || true
|
|
- python3 coreexample/ci/process_report.py test_result_1.xml test_result.xml
|
|
needs:
|
|
- assemble
|
|
- deploy:review
|
|
artifacts:
|
|
when: always
|
|
reports:
|
|
junit: test_result.xml
|
|
paths:
|
|
- test_result.xml
|
|
- screenshots
|
|
- logcat.txt
|
|
- video.mp4
|
|
- logs
|
|
rules:
|
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
|
|
uitest:signup:
|
|
allow_failure: true
|
|
variables:
|
|
TEST_TARGET: "package me.proton.core.test.android.uitests.tests.medium.auth.signup"
|
|
extends: .firebase-tests-common
|
|
|
|
uitest:login-and-hv:
|
|
allow_failure: true
|
|
variables:
|
|
TEST_TARGET: "package me.proton.core.test.android.uitests.tests.medium.auth.login,package me.proton.core.test.android.uitests.tests.medium.humanverification"
|
|
extends: .firebase-tests-common
|
|
|
|
uitest:plans-and-payments:
|
|
allow_failure: true
|
|
variables:
|
|
TEST_TARGET: "package me.proton.core.test.android.uitests.tests.medium.plans,package me.proton.core.test.android.uitests.tests.medium.payments"
|
|
extends: .firebase-tests-common
|
|
|
|
uitest:usersettings:
|
|
allow_failure: true
|
|
variables:
|
|
TEST_TARGET: "package me.proton.core.test.android.uitests.tests.medium.usersettings"
|
|
extends: .firebase-tests-common
|
|
|
|
uitest:mocked-tests:
|
|
variables:
|
|
APP_APK: "coreexample/build/outputs/apk/mock/debug/coreexample-mock-debug.apk"
|
|
TEST_APK: "coreexample/build/outputs/apk/androidTest/mock/debug/coreexample-mock-debug-androidTest.apk"
|
|
TEST_TARGET: "package me.proton.core.test.android.mockuitests"
|
|
FLAKY_TEST_RERUN: "1"
|
|
DEVICE_MODEL: "Pixel2.arm,version=28"
|
|
DEVICE_MODEL_RESULTS_DIR: "Pixel2.arm-28-en-portrait"
|
|
EXTRA_OPTIONS: "--use-orchestrator --environment-variables clearPackageData=true"
|
|
extends: .firebase-tests-common
|
|
|
|
uitest:hilt-tests:
|
|
allow_failure: true
|
|
variables:
|
|
TEST_APK: "coreexample/hilt-tests/build/outputs/apk/localProperties/debug/coreexample-hilt-tests-localProperties-debug.apk"
|
|
TEST_TARGET: "package me.proton.android.core.coreexample.hilttests"
|
|
DEVICE_MODEL: "Pixel2.arm,version=28"
|
|
DEVICE_MODEL_RESULTS_DIR: "Pixel2.arm-28-en-portrait"
|
|
EXTRA_OPTIONS: "--use-orchestrator --environment-variables clearPackageData=true"
|
|
extends: .firebase-tests-common
|
|
|
|
androidTest:user-data:
|
|
variables:
|
|
TEST_APK: "user/data/build/outputs/apk/androidTest/debug/user-data-debug-androidTest.apk"
|
|
TEST_TARGET: "package me.proton.core.user.data"
|
|
extends: .firebase-tests-common
|
|
|
|
androidTest:key-data:
|
|
variables:
|
|
TEST_APK: "key/data/build/outputs/apk/androidTest/debug/key-data-debug-androidTest.apk"
|
|
TEST_TARGET: "package me.proton.core.key.domain" # Domain entities are Android Tested in data
|
|
extends: .firebase-tests-common
|
|
|
|
androidTest:crypto-android:
|
|
variables:
|
|
TEST_APK: "crypto/android/build/outputs/apk/androidTest/debug/crypto-android-debug-androidTest.apk"
|
|
TEST_TARGET: "package me.proton.core.crypto.android"
|
|
extends: .firebase-tests-common
|
|
|
|
androidTest:key-transparency-data:
|
|
variables:
|
|
TEST_APK: "key-transparency/data/build/outputs/apk/androidTest/debug/key-transparency-data-debug-androidTest.apk"
|
|
TEST_TARGET: "package me.proton.core.keytransparency.data"
|
|
DEVICE_MODEL: "Pixel2.arm,version=28"
|
|
DEVICE_MODEL_RESULTS_DIR: "Pixel2.arm-28-en-portrait"
|
|
extends: .firebase-tests-common
|
|
|
|
androidTest:coreexample-migration:
|
|
variables:
|
|
TEST_TARGET: "package me.proton.core.test.android.dbtests"
|
|
extends: .firebase-tests-common
|
|
|
|
## publish stage ###################################################################################
|
|
|
|
pages:
|
|
extends: .script-job
|
|
needs:
|
|
- unit-tests-and-coverage-report
|
|
stage: publish
|
|
script:
|
|
- mkdir -p ./public/coverage
|
|
- mv ./coverage/build/reports/kover/html/* ./public/coverage
|
|
artifacts:
|
|
paths:
|
|
- public
|
|
rules:
|
|
- if: $CI_COMMIT_BRANCH == 'main'
|
|
|
|
trigger-new-libs-release:
|
|
extends: .script-job
|
|
stage: publish
|
|
when: manual
|
|
resource_group: release/libs
|
|
tags:
|
|
- shared-small
|
|
variables:
|
|
NEXT_VERSION: '' # If empty, the version will be automatically calculated.
|
|
before_script:
|
|
- source /load-env.sh
|
|
- !reference [.download-tools, script]
|
|
script:
|
|
- ./ci/script/prepareRelease.sh
|
|
rules:
|
|
- if: $CI_COMMIT_BRANCH == 'main'
|
|
|
|
release-publish-github:
|
|
stage: publish
|
|
tags:
|
|
- shared-small
|
|
variables:
|
|
RELEASE_SYNC_PUBLIC_URL: git@github.com:ProtonMail/protoncore_android.git
|
|
RELEASE_SYNC_TO_BRANCH: 'main'
|
|
RELEASE_SYNC_FROM_BRANCH: 'main'
|
|
extends: .release-sync-commit-shared
|
|
|
|
publish-libs:
|
|
extends: .gradle-job
|
|
stage: publish
|
|
resource_group: release/libs
|
|
variables:
|
|
ORG_GRADLE_PROJECT_mavenCentralUsername: $MAVEN_USER
|
|
ORG_GRADLE_PROJECT_mavenCentralPassword: $MAVEN_PASSWORD
|
|
ORG_GRADLE_PROJECT_signingInMemoryKey: $MAVEN_SIGNING_KEY
|
|
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: $MAVEN_SIGNING_KEY_PASSWORD
|
|
ORG_GRADLE_PROJECT_androidDevChannelWebhook: $ANDROID_DEVS_CHANNEL_WEBHOOK
|
|
script:
|
|
- ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository
|
|
- ./gradlew notifyNewRelease
|
|
rules:
|
|
- if: $CI_COMMIT_BRANCH =~ /^release\/libs\/.*/ # stable release with notification
|
|
|
|
tag-libs-release:
|
|
extends: .gradle-job
|
|
stage: publish
|
|
resource_group: release/libs
|
|
needs:
|
|
- job: publish-libs
|
|
rules:
|
|
- if: $CI_COMMIT_BRANCH =~ /^release\/libs\/.*/
|
|
before_script:
|
|
- !reference [ .git, before_script ]
|
|
script:
|
|
- ./gradlew tagRelease
|
|
|
|
publish-gradle-plugins:
|
|
extends: .gradle-job
|
|
stage: publish
|
|
variables:
|
|
ORG_GRADLE_PROJECT_mavenCentralUsername: $MAVEN_USER
|
|
ORG_GRADLE_PROJECT_mavenCentralPassword: $MAVEN_PASSWORD
|
|
ORG_GRADLE_PROJECT_signingInMemoryKey: $MAVEN_SIGNING_KEY
|
|
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: $MAVEN_SIGNING_KEY_PASSWORD
|
|
script:
|
|
- ./gradlew -p plugins publishToSonatype closeAndReleaseSonatypeStagingRepository
|
|
rules:
|
|
- if: $CI_COMMIT_BRANCH =~ /^release\/gradle-plugins\/.*/ # stable release with notification
|
|
|
|
tag-gradle-plugins-release:
|
|
extends: .gradle-job
|
|
stage: publish
|
|
needs:
|
|
- job: publish-gradle-plugins
|
|
before_script:
|
|
- !reference [ .git, before_script ]
|
|
script:
|
|
- ./gradlew -p plugins tagRelease
|
|
rules:
|
|
- if: $CI_COMMIT_BRANCH =~ /^release\/gradle-plugins\/.*/
|
|
|
|
## review stage ######################################################################################
|
|
danger-review:
|
|
tags:
|
|
- shared-medium
|
|
extends: .ruby-job
|
|
stage: review
|
|
when: always
|
|
needs:
|
|
- unit-tests-and-coverage-report
|
|
script:
|
|
- !reference [.download-tools, script]
|
|
- bundle exec danger --fail-on-errors=false
|
|
allow_failure: true
|
|
variables:
|
|
DANGER_GITLAB_API_TOKEN: $DANGER_GITLAB_API_TOKEN
|
|
DANGER_COBERTURA_GIT_URL: https://${GIT_CI_USERNAME}:${PRIVATE_TOKEN_GITLAB_API_PROTON_CI}@${CI_SERVER_HOST}/proton/devops/quality/danger-cobertura.git
|
|
DANGER_RANDOM_REVIEWERS_GIT_URL: https://${GIT_CI_USERNAME}:${PRIVATE_TOKEN_GITLAB_API_PROTON_CI}@${CI_SERVER_HOST}/proton/devops/quality/danger-random-reviewers.git
|
|
interruptible: true
|
|
rules:
|
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
|
|
# .startReview requires 'stopReview' job. See GitLab merged YAML.
|
|
stopReview:
|
|
extends: .stopReview
|
|
stage: cleanup
|
|
rules:
|
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
when: manual
|
|
allow_failure: true
|