|
| 1 | +# Travis CI |
| 2 | + |
| 3 | +In this section we are going to use [Travis CI](https://travis-ci.org/) as our continuous-integration service. Travis CI is [mostly used](https://docs.travis-ci.com/user/tutorial/#more-than-running-tests) for building and running tests for projects hosted at GitHub. It supports [different programming laguages](https://docs.travis-ci.com/user/tutorial/#selecting-a-different-programming-language) and for our particular case, it supports the [Crystal language](https://docs.travis-ci.com/user/languages/crystal/). |
| 4 | + |
| 5 | +>**Note:**If you are new to continuous integration (or you want to refresh the basic concepts) we may start reading the [core concepts guide](https://docs.travis-ci.com/user/for-beginners/). |
| 6 | +
|
| 7 | +Now let's see some examples! |
| 8 | + |
| 9 | +## Build and run specs |
| 10 | + |
| 11 | +### Using `latest` and `nightly` |
| 12 | + |
| 13 | +A first (and very basic) Travis CI config file could be: |
| 14 | + |
| 15 | +```yaml |
| 16 | +# .travis.yml |
| 17 | +language: crystal |
| 18 | +``` |
| 19 | +
|
| 20 | +That's it! With this config file, Travis CI by default will run `crystal spec`. |
| 21 | +Now, we just need to go to Travis CI dashboard to [add the GitHub repository](https://docs.travis-ci.com/user/tutorial/#to-get-started-with-travis-ci). |
| 22 | + |
| 23 | +Let's see another example: |
| 24 | + |
| 25 | +```yaml |
| 26 | +# .travis.yml |
| 27 | +language: crystal |
| 28 | +
|
| 29 | +crystal: |
| 30 | + - latest |
| 31 | + - nightly |
| 32 | +
|
| 33 | +script: |
| 34 | + - crystal spec |
| 35 | + - crystal tool format --check |
| 36 | +``` |
| 37 | + |
| 38 | +With this configuration, Travis CI will run the tests using both Crystal `latest` and `nightly` releases on every push to a branch on your Github repository. |
| 39 | + |
| 40 | +**Note:** When [creating a Crystal project](../../using_the_compiler/#creating-a-crystal-project) using `crystal init`, Crystal creates a `.travis.yml` file for us. |
| 41 | + |
| 42 | +### Using a specific Crystal release |
| 43 | + |
| 44 | +Let's suppose we want to pin a specific Crystal release (maybe we want to make sure the shard compiles and works with that version) for example [Crystal 0.31.1](https://github.com/crystal-lang/crystal/releases/tag/0.31.1). |
| 45 | + |
| 46 | +Travis CI only provides _runners_ to `latest` and `nightly` releases directly and so, we need to install the requested Crystal release manually. For this we are going to use [Docker](https://www.docker.com/). |
| 47 | + |
| 48 | +First we need to add Docker as a service in `.travis.yml`, and then we can use `docker` commands in our build steps, like this: |
| 49 | + |
| 50 | +```yml |
| 51 | +# .travis.yml |
| 52 | +language: minimal |
| 53 | +
|
| 54 | +services: |
| 55 | + - docker |
| 56 | +
|
| 57 | +script: |
| 58 | + - docker run -v $PWD:/src -w /src crystallang/crystal:0.31.1 crystal spec |
| 59 | +``` |
| 60 | + |
| 61 | +**Note:** We may read about different (languages)[https://docs.travis-ci.com/user/languages/] supported by Travis CI, included [minimal](https://docs.travis-ci.com/user/languages/minimal-and-generic/). |
| 62 | + |
| 63 | +**Note:** A list with the different official [Crystal docker images](https://hub.docker.com/r/crystallang/crystal/tags) is available at [DockerHub](https://hub.docker.com/r/crystallang/crystal). |
| 64 | + |
| 65 | +### Using `latest`, `nightly` and a specific Crystal release all together! |
| 66 | + |
| 67 | +Supported _runners_ can be combined with Docker-based _runners_ using a [Build Matrix](https://docs.travis-ci.com/user/customizing-the-build#build-matrix). This will allow us to run tests against `latest` and `nightly` and pinned releases. |
| 68 | + |
| 69 | +Here is the example: |
| 70 | + |
| 71 | +```yaml |
| 72 | +# .travis.yml |
| 73 | +matrix: |
| 74 | + include: |
| 75 | + - language: crystal |
| 76 | + crystal: |
| 77 | + - latest |
| 78 | + script: |
| 79 | + - crystal spec |
| 80 | +
|
| 81 | + - language: crystal |
| 82 | + crystal: |
| 83 | + - nightly |
| 84 | + script: |
| 85 | + - crystal spec |
| 86 | +
|
| 87 | + - language: bash |
| 88 | + services: |
| 89 | + - docker |
| 90 | + script: |
| 91 | + - docker run -v $PWD:/src -w /src crystallang/crystal:0.31.1 crystal spec |
| 92 | +``` |
| 93 | + |
| 94 | +## Installing shards packages |
| 95 | + |
| 96 | +In native _runners_ (`language: crystal`), Travis CI already automatically installs shards dependencies using `shards install`. To improve build performance we may add [caching](#caching) on top of that. |
| 97 | + |
| 98 | +#### Using Docker |
| 99 | + |
| 100 | +In a Docker-based _runner_ we need to run `shards install` explicitly, like this: |
| 101 | + |
| 102 | +```yml |
| 103 | +# .travis.yml |
| 104 | +language: bash |
| 105 | +
|
| 106 | +services: |
| 107 | + - docker |
| 108 | +
|
| 109 | +script: |
| 110 | + - docker run -v $PWD:/src -w /src crystallang/crystal:0.31.1 shards install |
| 111 | + - docker run -v $PWD:/src -w /src crystallang/crystal:0.31.1 crystal spec |
| 112 | +``` |
| 113 | + |
| 114 | +**Note:** Since the shards will be installed in `./lib/` folder, it will be preserved for the second docker run command. |
| 115 | + |
| 116 | +## Installing binary dependencies |
| 117 | + |
| 118 | +Our application or maybe some shards may required libraries and packages. This binary dependencies may be installed using different methods. Here we are going to show an example using the [Apt](https://help.ubuntu.com/lts/serverguide/apt.html) command (since the Docker image we are using is based on Ubuntu) |
| 119 | + |
| 120 | +Here is a first example installing the `libsqlite3` development package using the [APT addon](https://docs.travis-ci.com/user/installing-dependencies/#installing-packages-with-the-apt-addon): |
| 121 | + |
| 122 | +```yaml |
| 123 | +# .travis.yml |
| 124 | +language: crystal |
| 125 | +crystal: |
| 126 | + - latest |
| 127 | +
|
| 128 | +before_install: |
| 129 | + - sudo apt-get -y install libsqlite3-dev |
| 130 | +
|
| 131 | +addons: |
| 132 | + apt: |
| 133 | + update: true |
| 134 | +
|
| 135 | +script: |
| 136 | + - crystal spec |
| 137 | +``` |
| 138 | + |
| 139 | +#### Using Docker |
| 140 | + |
| 141 | +We are going to build a new docker image based on [crystallang/crystal](https://hub.docker.com/r/crystallang/crystal/), and in this new image we will be installing the binary dependencies. |
| 142 | + |
| 143 | +To accomplish this we are going to use a [Dockerfile](https://docs.docker.com/engine/reference/builder/): |
| 144 | + |
| 145 | +```dockerfile |
| 146 | +# Dockerfile |
| 147 | +FROM crystallang/crystal:latest |
| 148 | +
|
| 149 | +# install binary dependencies: |
| 150 | +RUN apt-get update && apt-get install -y libsqlite3-dev |
| 151 | +``` |
| 152 | + |
| 153 | +And here is the Travis CI configuration file: |
| 154 | + |
| 155 | +```yml |
| 156 | +# .travis.yml |
| 157 | +language: bash |
| 158 | +
|
| 159 | +services: |
| 160 | + - docker |
| 161 | +
|
| 162 | +before_install: |
| 163 | + # build image using Dockerfile: |
| 164 | + - docker build -t testing . |
| 165 | +
|
| 166 | +script: |
| 167 | + # run specs in the container |
| 168 | + - docker run -v $PWD:/src -w /src testing crystal spec |
| 169 | +``` |
| 170 | + |
| 171 | +**Note:** Dockerfile arguments can be used to use the same Dockerfile for latest, nightly or a specific version. |
| 172 | + |
| 173 | +## Using services |
| 174 | + |
| 175 | +Travis CI may start [services](https://docs.travis-ci.com/user/database-setup/) as requested. |
| 176 | + |
| 177 | +For example, we can start a [MySQL](https://docs.travis-ci.com/user/database-setup/#mysql) database service by adding a `services:` section to our `.travis.yml`: |
| 178 | + |
| 179 | +```yaml |
| 180 | +# .travis.yml |
| 181 | +language: crystal |
| 182 | +crystal: |
| 183 | + - latest |
| 184 | +
|
| 185 | +services: |
| 186 | + - mysql |
| 187 | +
|
| 188 | +script: |
| 189 | + - crystal spec |
| 190 | +``` |
| 191 | + |
| 192 | +Here is the new test file for testing against the database: |
| 193 | + |
| 194 | +```crystal |
| 195 | +# spec/simple_db_spec.cr |
| 196 | +require "./spec_helper" |
| 197 | +require "mysql" |
| 198 | +
|
| 199 | +it "connects to the database" do |
| 200 | + DB.connect ENV["DATABASE_URL"] do |cnn| |
| 201 | + cnn.query_one("SELECT 'foo'", as: String).should eq "foo" |
| 202 | + end |
| 203 | +end |
| 204 | +``` |
| 205 | + |
| 206 | +When pushing this changes Travis CI will report the following error: `Unknown database 'test' (Exception)`, showing that we need to configure the MySQL service **and also setup the database**: |
| 207 | + |
| 208 | +```yaml |
| 209 | +# .travis.yml |
| 210 | +language: crystal |
| 211 | +crystal: |
| 212 | + - latest |
| 213 | +
|
| 214 | +env: |
| 215 | + global: |
| 216 | + - DATABASE_NAME=test |
| 217 | + - DATABASE_URL=mysql://root@localhost/$DATABASE_NAME |
| 218 | +
|
| 219 | +services: |
| 220 | + - mysql |
| 221 | +
|
| 222 | +before_install: |
| 223 | + - mysql -e "CREATE DATABASE IF NOT EXISTS $DATABASE_NAME;" |
| 224 | + - mysql -u root --password="" $DATABASE_NAME < db/schema.sql |
| 225 | +
|
| 226 | +script: |
| 227 | + - crystal spec |
| 228 | +``` |
| 229 | + |
| 230 | +We are [using a `schema.sql` script](https://andidittrich.de/2017/06/travisci-setup-mysql-tablesdata-before-running-tests.html) to create a more readable `.travis.yml`. The file `./db/schema.sql` looks like this: |
| 231 | + |
| 232 | +```sql |
| 233 | +-- schema.sql |
| 234 | +CREATE TABLE ... etc ... |
| 235 | +``` |
| 236 | + |
| 237 | +Pushing these changes will trigger Travis CI and the build should be successful! |
| 238 | + |
| 239 | +## Caching |
| 240 | + |
| 241 | +If we read Travis CI job log, we will find that every time the job runs, Travis CI needs to fetch the libraries needed to run the application: |
| 242 | + |
| 243 | +```log |
| 244 | +Fetching https://github.com/crystal-lang/crystal-mysql.git |
| 245 | +Fetching https://github.com/crystal-lang/crystal-db.git |
| 246 | +``` |
| 247 | + |
| 248 | +This takes time and, on the other hand, these libraries might not change as often as our application, so it looks like we may cache them and save time. |
| 249 | + |
| 250 | +Travis CI [uses caching](https://docs.travis-ci.com/user/caching/) to improve some parts of the building path. Here is the new configuration file **with cache enabled**: |
| 251 | + |
| 252 | +```yml |
| 253 | +# .travis.yml |
| 254 | +language: crystal |
| 255 | +crystal: |
| 256 | + - latest |
| 257 | +
|
| 258 | +cache: shards |
| 259 | +
|
| 260 | +script: |
| 261 | + - crystal spec |
| 262 | +``` |
| 263 | + |
| 264 | +Let's push these changes. Travis CI will run, and it will install dependencies, but then it will cache the shards cache folder which, usually, is `~/.cache/shards`. The following runs will use the cached dependencies. |
0 commit comments