Continuous Integration in an SFDX: experience report
I recently added Continuous Integration (CI) for the Graphvizforce-Lightning project. I thought I’d share what I learned in case it can help you if you decide to use SFDX and CI.
You can see the various parts:
I selected CircleCI for this project because it’s free for open source (OSS) projects and because Circle v2 uses Docker containers. I prefer Docker for CI because I can run all the steps on my local machine in an exact replica of the cloud CI environment.
My favourite Docker CI engine is Bitbucket Pipelines but, since it’s not free for open source, I chose CircleCI for this project.
Watch out for these items
Authentication: in SFDX CI, the only auth step is to the Dev Hub org. In this project, we use the sfdxurl flow, using a file created dynamically from a CI environment variable. Since CircleCI protects these values, this should be secure. There is another flow which is more secure and more complex to setup, that’s the JWT Flow which you may want to use if your hub is your production org. I’d suggest starting with sfdxurl for the initial implementation because it’s much easier to setup and, depending on your CI server, secure. There are a few blog posts on the interwebs describing how to setup the JWT flow.
DE Scratch org limits: if you are also doing OSS, then there are quite strict limits on using a free/Developer edition as the SFDX Hub org. The limits on production orgs are much higher but you should think about this in the context of the volume of commits/pushes in your environment.
Docker OS: I used Ubuntu as the base OS for this project because I copied it from the Lightning Testing Service (LTS) example. It makes quite a large image but I believe that an Alpine based image would also work if you want a smaller Docker image.
Docker and Chrome Headless: the debian Chrome install installs the latest Chrome version. If you build a new Docker image, it is essential that you use the latest Chrome driver to make this work in a headless environment. You can find the latest versions listed here. This took me quite a while to figure out.
LTS rollbacks: when running Apex tests, there is an automatic rollback of any changes made to the database. This is not true for LTS tests. Because we create a scratch org just for the CI run and then throw it away, this doesn’t really matter. Scratch orgs FTW! This shows why your dev/test orgs should be "Cattle not Pets"
Always CI Steps: in the same way as a try/finally code block ensures some steps are always run, CircleCI has an always
feature which you can use to clean up the scratch org. Adding || true
after the command will always return a zero exit code to ensure the CI run passes, even if the scratch org was never created.
CircleCI has another way of ensuring a zero exit code which is probably better but the technique I’m using will work in any CI service/bash shell.
Learnings
How many tests: using the junit reporting for all tests is really useful. It means you have a nice summary for each test run of how many tests were invoked and which is the slowest. This will be very useful for speeding up CI and this will, in turn, speed up all developers. That’s a valuable feedback loop and one of the many unspoken benefits of CI.
Apex test waits: using the junit reporting means you need to configure an explicit wait time for the Apex tests. This is not ideal because it will eventually be too short so requires manual maintenance. Hopefully the SFDX Apex plugin will improve on this in future so it doesn’t require a hardcoded wait.
Unreliable nodejs tests: some of the nodejs tests in this project write out .soql files as a side-effect of running a test. This intermittently fails and this reduces the value of the tests. I’ll keep looking for a solution on this one.
Nodejs versions: I have Nodejs v9 running on my laptop but the Docker image installs the latest v11.
This broke some calls to the fs
lib functions. It was an easy fix but it’s worth watching out for version mismatches for tests which you also run locally.
Summary
I hope this helps and gives you the confidence to start using CI as soon as possible. There are many benefits for developers, testers and general stability that come from CI and automation.
Most people won’t get to full Continuous Delivery (CD) but CI is much less work and provides instant value.
p.s. If you are curious about why we are using nodejs in a Lightning Component, I’ll blog about that soon.