Hi,
Recently I have been assigned to a new android project and I got the opportunity to integrate CI/CD to this project. I was first searched how to do this with bitbucket, because this project was planned to use bitbucket from the day 1. Even though there were many articles and blogs on how to do this I only found few on android integration. And those articles were 2 or 3 years old and/or not having a complete guide.
So I have to get my hands dirty :) and had to find a solution which works for my project. Here are the steps I had to do for CI/CD integration with bitbucket.
1. Create a repo in Bitbucket
2. Create a pipeline for the project (Bitbuckets' way to do CI/CD)
There is a selection item called "Pipelines" at the left side panel.
Select Java(Gradle) to generate bitbucket-pipelines.yml file. We are going to edit this file later.
3. Edit bitbucket-pipeline.yml file to test CI
First open bitbucket-pipeline.yml file in Android Studio or you can edit it online. But I prefer Android Studio because it makes alignments clear.
You need a docker image which contains latest build environment for android. Goto dockerhub and select appropriate one that have your environment requirement, In my case I selected mingc docker image because latest android SDK and Kotlin support.
Change the first line to get docker image
image: mingc/android-build-box:latest
Edit "pipelines" area to integrate CI as follows.
pipelines: default: - step: caches: - gradle script: - chmod +x gradlew - echo 'inside default branch. tests should run now.' - ./gradlew test branches: development: - step: caches: - gradle script: - echo 'development branch building. tests should run now.' - chmod +x gradlew - ./gradlew test
default tag means if you haven't declare any specific script for a branch, it will run default. As for above case the default script will run if we push a code to master branch or any other feature branch but it will not run if we push a code to development branch. Because there is a script to run if we push to development branch. As per above file gradle will execute unit test for development branch and for any branch that is not defined in the script.
Now I need to run some script when I create a PR (pull request) to master branch.
pull-requests: development: - step: caches: - gradle script: - echo 'PR Script running' # - ./gradlew assembleDebug
When PR is accepted the code change will merge to master branch. And that process will run default script since we didn't declare any script for master branch. So I will add a scrip to run when there is a change to master branch.
master: - step: caches: - gradle name: Test and build apk script: - echo 'master branch building.' - chmod +x gradlew - ./gradlew test - ./gradlew assembleRelease
This script is for create a release apk but we need to sign the apk in order to install on a device or distribute on Google play store. For this you need to change the app level gradle file and include keystore file which contains relevant keys.
Now create a keystore file and a keyAlias. Put this jks file on application root folder (where your app build.gradle file resides). Then change app build.gradle file as follows.
android { compileSdkVersion 28 defaultConfig { applicationId "****.****.****" minSdkVersion 19 targetSdkVersion 28 versionCode 1 versionName "1.0" } signingConfigs { release { // You need to specify either an absolute path or include the // keystore file in the same directory as the build.gradle file. storeFile file("**********.jks") storePassword "*********" keyAlias "*********" keyPassword "**********" v1SigningEnabled true v2SigningEnabled true } } buildTypes { release { signingConfig signingConfigs.release minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } }}
Now when there is a change in master branch it will run the test and create a release apk. You can't see the release apk in Bitbucket files. To see the apk you need to define an artifact. Add following code after script tag in master tag.
artifacts:
- app/release/app-release.apk
After master branch build you will see "Artifacts" tab next to "Build".
Currently this generated artifact will remain for 7 days. To save it permanently in "Downloads" you need to do some additional work. I'll describe them under CD since after saving this release apk we are going to send it to test users via Slack.
4. Edit bitbucket-pipeline.yml file to test CD
Following image shows the download area in Btbucket.
To write a file in this location you need "App password". Select your image at the bottom left and go to "Bitbucket settings". There you can create app password. Give it a name and enable repositories write permission. Save the generated password because we need it later.
Select Settings -> Repository variables
Add new variable. Name is BB_AUTH_STRING and value is YOUR_USERNAME:APP_PASSWORD (This is where we use our saved app password)
eg: mark_twein:7ax3848XYu93933
Then add the following line to master tag.
- curl -X POST "https://${BB_AUTH_STRING}@api.bitbucket.org/2.0/repositories/${BITBUCKET_REPO_OWNER}/${BITBUCKET_REPO_SLUG}/downloads" --form files=@"./app/build/outputs/apk/release/app-release.apk"
Here BITBUCKET_REPO_OWNER and BITBUCKET_REPO_SLUG default repository variables. Don't worry about that.
So the master tag will now look like below.
master: - step: caches: - gradle name: Test and build apk script: - echo 'master branch building.' - chmod +x gradlew - ./gradlew test - ./gradlew assembleRelease - curl -X POST "https://${BB_AUTH_STRING}@api.bitbucket.org/2.0/repositories/${BITBUCKET_REPO_OWNER}/${BITBUCKET_REPO_SLUG}/downloads" --form files=@"./app/build/outputs/apk/release/app-release.apk"
artifacts:
- app/release/app-release.apk
Now when you push a change to master branch you will find a release apk in the "Downloads" location.
5. Edit bitbucket-pipeline.yml file to send apk to a slack channel
Finally we are going to publish our apk to Slack channel.
For this first go to this link and when you are scrolling down you will see legacy token generator section. Create a token there and save it.
Then Create a new repository variable in Bitbucket. You may name this as "SLACK_TOKEN" and for the value put the generated token value.
Add the following code to master tag.
- curl -F file=@"./app/build/outputs/apk/release/app-release.apk" -F channels=your_channel_name -F token=${SLACK_TOKEN} https://slack.com/api/files.upload
put the channel name where you need to publish the apk.
Here is the final code.
master: - step: caches: - gradle name: Test and build apk script: - echo 'master branch building.' - chmod +x gradlew - ./gradlew test - ./gradlew assembleRelease - curl -X POST "https://${BB_AUTH_STRING}@api.bitbucket.org/2.0/repositories/${BITBUCKET_REPO_OWNER}/${BITBUCKET_REPO_SLUG}/downloads" --form files=@"./app/build/outputs/apk/release/app-release.apk" - curl -F file=@"./app/build/outputs/apk/release/app-release.apk" -F channels=your_channel_name -F token=${SLACK_TOKEN} https://slack.com/api/files.upload artifacts: - app/release/app-release.apk
Now when you push the code to development bran the tests will execute. Then you make a PR and your lead approves the PR and development branch merge into master branch. This executes test and make a app-release.apk and put it into downloads area in bitbucket. After that the generated apk will publish into the selected channel where test users can install that to their phones.
phew..... Now that's it from my side. I hope you can take something from this article. I will list some useful links below.
Happy Coding :)
Some useful links
https://proandroiddev.com/bitbucket-pipelines-android-6eeff631f2eb
https://confluence.atlassian.com/bitbucket/get-started-with-bitbucket-pipelines-792298921.html
https://github.com/kigen/bitbucket-pipelines-android
https://api.slack.com/custom-integrations/legacy-tokens
https://confluence.atlassian.com/bitbucket/deploy-build-artifacts-to-bitbucket-downloads-872124574.html
https://confluence.atlassian.com/bitbucket/variables-in-pipelines-794502608.html
This comment has been removed by a blog administrator.
ReplyDelete