
CI/CD || Circle CI || React Native Android ( only )
There always comes a time for a company where they feel the need to automate not only their tests, but also the builds, and CI/CD, which is a nightmare for all the developers, soon becoming a reality.
The problem with CI/CD pipelines is that, one can not debug it, you have to wait for the entire pipeline process to finish to determine what and where went wrong 😢.
Something which we developers practise on daily basis and which is always missed in almost all the documentations is modularity.
Just like in all our code bases, CI/CD could be partially debugged by making the jobs and their subsequent steps modular. Another step we need to keep in mind directly comes from the best practices of the coding world “Implement caching from the start, else you will die making it come true”.
NOTE: Circle CI, doesn't offer macOS machine in its free plan and also doesn’t provide parallel execution of its jobs.
Fist we start with making alias so as to minimise the block to its required logic and moving other outside.
aliases:
- &restore-yarn-cache
name: Restore cached root node_modules
key: yarn-cache-{{ checksum "yarn.lock" }}
- &save-yarn-cache
name: Save node_modules to cache
key: yarn-cache-{{ checksum "yarn.lock" }}
paths:
- node_modules/*
I generally use yarn in my project hence I am caching the yarn.lock file, if you use npm, you can cache package-lock.json file instead.To do so, you just have to replace the yarn.lock file in the above code block with package-lock.json and you will be good to go.Note: What circleCI does for caching is that it stores a custom cache based key for the file you wish to cache and upload it to there server, at the time you store the cache and hence for every subsequent builds, it uses the cached file to prevent the same activity again and hence subsequent builds becomes relatively faster.
*/
We now define the jobs, which we will refer in “workflows” later.
We now define the jobs, which we will refer in “workflows” later. Though one can directly define the jobs in the workflows, but the main agenda to of defining them separately is to keep the config minimal and modular, because it tends to get bigger with time and hence it becomes hard to manage and debug.
jobs:
android:
docker:
- image: reactnativecommunity/react-native-android/*
Here "android" is the job name, which uses "docker" image as an executor base.Note: One can also cache the docker images used in the pipeline in circle ci, but this feature is not supported in the base plan.
To know more about caching a docker image refer docs.Now we define the steps of job*//*
Writing steps though is most straight forward task of all but it also needs a very thorough clarity of what one wish to achieve with the job
*/steps:/*
checkout -> this steps ensure that you are the root directory of your project.
*/ - checkout/*
restore_cache: *restore-yarn-cache -> Notice here we used the alias we defined above, what it does ( as it name suggest ) looks for a cache of the dependencies and restores them if available.
*/ - restore_cache: *restore-yarn-cache
- run:
name: yarn install
command: yarn install/*
Followed by this we ran another job with name "yarn install" here we basically install the dependencies again, to be precise, install if not found in node_modules, which got restored by the restore cache step we did earlier.
This works in the same manner as the yarn or npm install command works on our local machines.
*/ - save_cache: *save-yarn-cache/*
Notice here we used the save cache alias we defined above, this basically updates the cache of the yarn.lock file if it was changed from the previous version of it.
*/ - run:
name: env file
command: ENVFILE=.env.development
- run:
name: jetify
command: npx jetify/*
Followed by that we attached the "env" file as per the requirement to the build phase so as to get the environment variables set, similarly I ran jetify for AndroidX based dependencies in the project.
*/ - run:
name: react bundle
command: npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle/*
In the above step we created the development bundle for the react native application, followed to which we created our debug apk.Note: We never push keystore.properties files to version control and hence here I am maintaining an example version of the same which I later copied on the fly.
*/ - run:
name: android build
command: |
cd android
cp keystore.properties.example keystore.properties
chmod +x gradlew && ./gradlew assembleDebug/*If your team is using some OTA Update methods like codepush you can set up there respective commands in the package.json file and run the from here, like this - run:
name: OTA Update Alpha
command: yarn ota_update_alpha_command_from_packageJSON_script
*/
Finally, all we need now is to setup the workflow and call the above defined job from it.
workflows:
version: 2
build_and_test:
jobs:
- android/*
We define a workflow called "build_and_test", it is just a name, you can call as it anything.Important thing is the following
Here, we called a job called android which we defined above, and hence the job is called and if we did all right, we will have a successful execution of your pipeline.
*/