Docker nightly images are pushed as crystallang/crystal:nightly to 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 crystallang/crystal:latest.

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 localhost:3306.

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.

Adding the 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:

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:

version:2dry:restore_shards_cache:&restore_shards_cache# Use {{ checksum "shard.yml" }} if developing a shard instead of an appkeys:-shards-cache-v1-{{ .Branch }}-{{ checksum "shard.lock" }}-shards-cache-v1-{{ .Branch }}-shards-cache-v1save_shards_cache:&save_shards_cache# Use {{ checksum "shard.yml" }} if developing a shard instead of an appkey:shards-cache-v1-{{ .Branch }}-{{ checksum "shard.lock" }}paths:-./shards-cachewait_for_db:&wait_for_dbname:Wait for MySQLcommand:sleep 7jobs:test:docker:# Use crystallang/crystal:latest or specific crystallang/crystal:VERSION-image:crystallang/crystal:latestenvironment:SHARDS_CACHE_PATH:./shards-cache-image:mysql:5.7environment:MYSQL_DATABASE:'sample_app'MYSQL_ALLOW_EMPTY_PASSWORD:'yes'steps:-run:crystal --version-checkout-restore_cache:*restore_shards_cache-run:shards-save_cache:*save_shards_cache-run:*wait_for_db-run:crystal spectest-on-nightly:docker:-image:crystallang/crystal:nightlyenvironment:SHARDS_CACHE_PATH:./shards-cache-image:mysql:5.7environment:MYSQL_DATABASE:'sample_app'MYSQL_ALLOW_EMPTY_PASSWORD:'yes'steps:-run:crystal --version-checkout-restore_cache:*restore_shards_cache-run:shards-run:*wait_for_db-run:crystal specworkflows:version:2# Run tests on every single commitci:jobs:-test# Run tests every night using crystal nightlynightly:triggers:-schedule:cron:"02***"filters:branches:only:-masterjobs:-test-on-nightly

Docker nightly images are pushed as crystallang/crystal:nightly to 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 crystallang/crystal:latest.

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 localhost:3306.

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.

Adding the 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:

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:

version:2dry:restore_shards_cache:&restore_shards_cache# Use {{ checksum "shard.yml" }} if developing a shard instead of an appkeys:-shards-cache-v1-{{ .Branch }}-{{ checksum "shard.lock" }}-shards-cache-v1-{{ .Branch }}-shards-cache-v1save_shards_cache:&save_shards_cache# Use {{ checksum "shard.yml" }} if developing a shard instead of an appkey:shards-cache-v1-{{ .Branch }}-{{ checksum "shard.lock" }}paths:-./shards-cachewait_for_db:&wait_for_dbname:Wait for MySQLcommand:sleep 7jobs:test:docker:# Use crystallang/crystal:latest or specific crystallang/crystal:VERSION-image:crystallang/crystal:latestenvironment:SHARDS_CACHE_PATH:./shards-cache-image:mysql:5.7environment:MYSQL_DATABASE:'sample_app'MYSQL_ALLOW_EMPTY_PASSWORD:'yes'steps:-run:crystal --version-checkout-restore_cache:*restore_shards_cache-run:shards-save_cache:*save_shards_cache-run:*wait_for_db-run:crystal spectest-on-nightly:docker:-image:crystallang/crystal:nightlyenvironment:SHARDS_CACHE_PATH:./shards-cache-image:mysql:5.7environment:MYSQL_DATABASE:'sample_app'MYSQL_ALLOW_EMPTY_PASSWORD:'yes'steps:-run:crystal --version-checkout-restore_cache:*restore_shards_cache-run:shards-run:*wait_for_db-run:crystal specworkflows:version:2# Run tests on every single commitci:jobs:-test# Run tests every night using crystal nightlynightly:triggers:-schedule:cron:"02***"filters:branches:only:-masterjobs:-test-on-nightly