- Workflows
- Failed Delivery
- Deliver a new release by triggering the CI
- Services
- Fastlane
- Determining the next version
- Environment variables
- Hints and quirks
Several workflows exist for different purposes:
Workflow | Schedule/Trigger | Checks | native delivery | web delivery | Version bump | Move release notes |
---|---|---|---|---|---|---|
commit | commits of PRs | ✔️ | ❌ | ❌ | ❌ | ❌ |
commit_main | commits on main | ❌ | browserstack | webnext | ❌ | ❌ |
delivery | Monday (04:00), script | ✔️ | beta | beta | ✔️ | ✔️ |
native_promotion | Monday (02:00), script | ❌ | promotion | ❌ | ❌ | ❌ |
web_promotion | Monday (02:00), script | ❌ | ❌ | promotion | ❌ | ❌ |
native_beta_delivery | script | ✔️ | beta | ❌ | ✔️ | ❌ |
native_production_delivery | script | ✔️ | production | ❌ | ✔️ | ❌ |
web_beta_delivery | script | ✔️ | ❌ | beta | ✔️ | ❌ |
web_production_delivery | script | ✔️ | ❌ | production | ✔️ | ❌ |
e2e_tests | commits on main | ❌ | ❌ | ❌ | ❌ | ❌ |
Steps executed if Checks is checked ✔️:
- Linting
- Prettier formatting
- TypeScript checks
- Unit testing with jest
- Building the app
- E2E tests
Steps executed if Version bump is checked ✔️:
- Bump version: Bump the version(s) and create a tag and release on github
Sometimes it happens that one or multiple steps of our scheduled CI delivery workflow fails. In that case,
you should not use the Restart Workflow from Start
(as this will lead to just another failure since the version number
was bumped before but not in the state of the failed delivery workflow such that it attempts to create the same releases again).
If the reason for a delivery to fail was just a transient error that was fixed in the meantime and doesn't require a code change
(e.g. network error, API down, problems in the stores), you can use the Restart Workflow from Failed
and in the best case the workflow should finish now.
In all other cases you can decide if there is an important change that should be delivered asap and can't wait another week. Examples are important bug fixes or big new features that should be released on multiple platforms in the same time. In that case you can trigger a delivery. It is possible to either just execute web_beta_delivery or native_beta_delivery or just run the whole delivery workflow again. If that is not the case, just waiting one week is also fine.
Normally the scheduled deliveries (see workflows) should be frequent enough for most purposes.
If you still have to deliver a new reason for example for an urgent bug fix or because of a failed CI delivery, the easiest way to deliver a new build to production or beta is to trigger the corresponding CircleCI workflows native_beta_delivery, native_production_delivery, web_beta_delivery and web_production_delivery:
- Get a CircleCI Personal API Token.
- Trigger a delivery using the tool trigger-pipeline:
cd tools && yarn trigger-pipeline trigger <workflow-type> --api-token <api-token>
deliverino
is a GitHub App and can be accessed and installed here. This bot bumps the version of the app when a new release is delivered.
A private key in PEM format grants access to the bot. If the deliverino
is installed for a specific repository then it has access to create commits there.
deliverino
has the role of an Administrator. This is important when setting up Protected branches in GitHub. You have to disable "Include Administrators", else deliverino
is not allowed to directly commit to the protected branch.
You can visit the management website for the Play Store here. The Google Play Console is the product by Google for managing the App Store presence.
The Play Store has the concept of tracks to manage released versions of the app. The beta track is for public tests. Tests can be added via their Google E-Mail or by signing up at play.google.com/apps/testing/tuerantuer.app.integreat.
The CI/CD pipeline uploads and overwrites metadata during the delivery step. You can read more about managing metadata for Android here.
You can visit the management website for the Play Store here. App Store Connect is the product by Apple for managing the App Store presence.
For delivery an account without 2FA is required.
The scheduled_native_production_workflow makes the builds directly available to TestFlights "App Store Connect Users". Those should not be confused with "External Tests" which require an approval by apple. Therefore, we currently only use "App Store Connect Users" as testers.
In order to add someone as "App Store Connect User" you have to add the Apple Account to App Store Connect and to TestFlight. This is a two-step process.
The CI/CD pipeline uploads and overwrites metadata during the delivery step. You can read more about managing metadata for iOS here.
Authentication happens by setting the APP_STORE_CONNECT_API_KEY_CONTENT
environment variable as documented above. For more information visit the documentation here.
We are using BrowserStack to run our E2E tests on real iOS and Android devices. The general documentation about E2E tests and BrowserStack for native development can be found here.
Fastlane is a task-runner for triggering build relevant tasks. It offers integration with XCode and the Android SDK for building and delivering the app.
- Install Ruby >= 2.6.5
- The preferred and tested way is to use the Ruby Version Manager (RVM).
- If using RVM you have to run:
rvm use ruby-2.6.5
.
- Make sure
ruby --version
reports the correct version. - Run
bundle install --path vendor/bundle
in the project root AND in./android/
AND in./ios/
. - Run
bundle exec fastlane --version
.
Hint: You can run export FASTLANE_SKIP_UPDATE_CHECK=true
to skip the changelog output.
Lanes for Android live in ../native/android/fastlane and for iOS in ../native/ios/fastlane. Shared lanes are in ../native/fastlane.
An overview about FL lanes is available in several documents:
- General - Responsible for delivering and uploading artifacts.
- Android - Responsible for setting up the signing keys and building the Android app.
- iOS - Responsible for setting up the certificates and building the iOS app.
Fastlane is used to setup certificates and keystores. The detailed steps of the CI/CD pipeline are the same as those when manually building the app. Therefore, you can follow the documentation for Manual Builds to set up certificates for iOS and keystores for android.
The next version of the app must be determined programmatically. The tool next-version can be used. More information on the version naming schema used can be found here.
Variable | Description | Where do I get it from? | Example | Reference |
---|---|---|---|---|
BROWSERSTACK_ACCESS_KEY | Access Key for BrowserStack | Password Manager | DEADBEEF | Appium REST API |
BROWSERSTACK_USERNAME | Username for BrowserStack | Password Manager | 123546 | Appium REST API |
DELIVERINO_PRIVATE_KEY | Base64 encoded PEM private key | Password Manager | Deliverino Settings | Deliverino |
SENTRY_AUTH_TOKEN | Auth Token from Sentry for uploading sourcemaps and artifacts | Generate this in your Sentry account with the scope project:releases |
deadbeef | Sentry Authentication |
MM_WEBHOOK | URL which can be used to send notifications to our mattermost. Keep this private! | Mattermost server settings | https://chat.tuerantuer.org/hooks/... | Mattermost Documentation |
Variable | Description | Where do I get it from? | Example | Reference |
---|---|---|---|---|
GOOGLE_SERVICE_ACCOUNT_JSON | JSON for authentication in the Google Play Console as Release Manager. This should expire after two years. | Password Manager | {...} | Service Account Docu |
CREDENTIALS_GIT_REPOSITORY_URL | Git remote URL to the credentials repository which contains the Java Keystore | Ask the team about this secret repository | git@github.com:User/credentials.git | - |
CREDENTIALS_DIRECTORY_PATH | Path where the credentials Git repository cloned to automatically by FL | The developer can choose this freely | /home/circleci/credentials | - |
CREDENTIALS_KEYSTORE_PATH | Path to the OpenSSL AES256-CBC encrypted Java Keystore file | - | /home/circleci/credentials/.enc | Look for the openssl enc command in the Android Fastlane file for more information |
KEYSTORE_PATH | Path to the decrypted Java Keystore file | - | /home/circleci/keystore.jks | - |
CREDENTIALS_KEYSTORE_PASSWORD | Password for decrypting the keystore using OpenSSL | password | - | |
KEYSTORE_KEY_ALIAS | Alias of the key within the Java Keystore | You should look in the JKS file using keytool -list -v -keystore <jks> |
my-key | - |
KEYSTORE_KEY_PASSWORD | Password of the key within the Java Keystore | Password Manager | 123456 | - |
KEYSTORE_PASSWORD | Password of the JKS which can contain multiple keys | Password Manager | 123456 | - |
Variable | Description | Where do I get it from? | Example | Reference |
---|---|---|---|---|
APP_STORE_CONNECT_API_KEY_ID | Key ID for App Store Connect API | Password Manager | D83848D23 | app_store_connect_api_key |
APP_STORE_CONNECT_API_ISSUER_ID | Issuer ID for App Store Connect API | Password Manager | 227b0bbf-ada8-458c-9d62-3d8022b7d07f | app_store_connect_api_key |
APP_STORE_CONNECT_API_KEY_CONTENT | Key content for App Store Connect API | Password Manager | -----BEGIN EC PRIVATE KEY-----\nfewfawefawfe\n-----END EC PRIVATE KEY----- | app_store_connect_api_key |
MATCH_PASSWORD | Password for accessing the certificates for the iOS app using Fastlane Match | Password Manager | 123456 | Using a Git Repo |
You can control which jobs should be skipped through environment variables.
Set the variable SKIP_JOB_deliver_aschaffenburg_ios
to "aschaffenburg"
to skip the job with the name deliver_aschaffenburg_ios
.
You can also set it to "malte|aschaffenburg"
in order to match multiple build configs or to "all"
to match all build configs.
Environment variables can be set in the Project Settings of CircleCI.
Note: Some jobs like bump_version
run only once for multiple build configs. Therefore, it does not make sense to set SKIP_JOB_bump_version
to something other than "all"
.
Note: Most of the time job names contain the build config name as well, therefore setting e.g. the environment variable SKIP_JOB_deliver_ios
won't work.
There is no obvious way for an application to know how many cores it has available in a CircleCI docker container. The usual ways of getting the CPU count reports the CPU count of the host. This causes out-of-memory issues as the host has a lot of cores.
Therefore, all tools must set the worker limit to $TOTAL_CPUS
. Set this variable in the .circleci/config.yml
.