It’s been a while since we wrote Using CircleCI for your Crystal projects. Since then the following things happened:
- CircleCI 2.0 was announced and 1.0 is deprecated.
- Crystal build process is partially automated in CircleCI
- Docker nightly images are pushed as
crystallang/crystal:nightlyto Docker Hub
- Shards added a cache to avoid downloading from scratch dependencies
It’s time to review how to take advantage of the awesome features in CircleCI, to ensure your application or shard is up to date not only with the current Crystal release, but with the upcoming one. Doing this helps to detect early unwanted breaking changes in your dependences or, at least, be ready to release earlier.
As a case study, we will use a fake app that requires a database. The final example will cover a couple more of the basic needs and show a more realistic scenario.
Using Crystal latest release for builds
You probably use
$ shards to install dependencies of your application and
$ crystal spec to run specs.
In order to do that in CircleCI using the latest release of Crystal you need to create a
.circleci/config.yml with the following content.
It will show the specific compiler version used thanks to
crystal --version. And you can force a specific version using
crystallang/crystal:VERSION docker images instead of
Using a database server
In your development environment you either have a database server installed or use docker and have probably mapped the ports to your host. So either way, if you use MySQL you can access the service as
In CircleCI you can use multiple docker images and the ports of the additional images will be mapped to the first container. Pretty much as if the service would have been installed locally.
mysql:5.7 image with some environment configuration and giving it some time to start property should be enough. The resulting config is as follows:
dry key is not standard. It’s just a placeholder of values that will be used multiple times later or that helps reading the job’s steps. If prefered, you can inline their contents directly.
Reduce CI delays
CircleCI caches docker images in each host and it even provides some additional features to reduce downloading and building docker images. This greatly reduces the time spent in each build.
Another source of delay is downloading dependencies from scratch in every build. There are solutions to store some files on a build to be used on a subsequent ones.
Adding steps to save and restore the path used as
SHARDS_CACHE_PATH allows the build to run faster.
Notice how the cache key involves the checksum of the content of
shard.lock. If you are using this for a shard, there should be no
shard.lock file checked in and the
shard.yml should be used instead.
Checked code against Crystal nightly
Crystal keeps evolving and, while the ecosystem is still growing, some dependencies may or may not need to be updated on every release. Some shards don’t have constant commit activity and CI usually runs on every push and PRs. This leads to the possibility of not running specs while the compiler and the std libs are still evolving and might break.
We can mostly duplicate the definition of the
test job and execute it against
crystallang/crystal:nightly image and schedule that run every single UTC night. Maybe, since crystal nightly starts at UTC night, it would be good to wait a bit, either way running
crystal --version in build seems a good idea to do.
The shards cache can be used for nightly builds but there is no gain in saving it.
So a not so minimalistic CircleCI config for a real app with dependencies, shorter build times and regular checks with Crystal nightly releases could be as follows:
That’s it! Thanks CircleCI for all the great features!