Rust + Diesel + GitLab + CI
The folks over at GitLab give away some free compute power to allow users to have CI builds of their project. It is very straightforward to get Rust projects to build within a CI environment. This post is going to take that build process one small step further, we’re going to build a Rust project that uses the Diesel ORM. This adds a step of complexity since to compile a Diesel project you need to have a postgresql database accessible if you’re using the infer_schema!()
macro.
Note: diesel has instructions for using diesel print-schema
instead of using infer_schema!()
in version 1.3.x. It has been proposed to move away from . A redditor commented that infer_schema!()
, but that issues was closed because infer_schema!()
is still usefulinfer_schema!()
has been deprecated in diesel 1.3.
The Following assumes you already have rust installed, if not see the awesome project rustup.
First The Very Basics
Create an example project in GitLab then create the rust project using cargo
.
cargo new hello_ci
Within that project directory create the CI rule file named .gitlab-ci.yml
with the following:
# Use Rust docker image, see: https://hub.docker.com/_/rust/
image: rust:latest
# Defines stages which are to be executed
stages:
- build
# Run `cargo build` for the project with stable Rust
run-build:
stage: build
image: rust:latest
script:
- rustc --version && cargo --version
- cargo build --release --jobs 1
Make sure to add the file to your git project, and push to GitLab.
git add .gitlab-ci.yml
git commit -am "Adding CI file"
git push
Once the project has been pushed, GitLab will kick off a build automatically. See the example screenshots, and note, to see the CI features in GitLab, expand the CI / CD
menu on the left panel and select Pipeliles
or Jobs
. And don’t worry, if something goes wrong, GitLab will kindly email you.
Adding in a Little Diesel
Now that the trivial case is completed, let’s take a look at adding in Diesel to the project. Let’s use the diesel getting_started_1 project as an example.
In order to build a project that uses Diesel (and uses infer_schema!()
) we need to have a postgresql database accessible. You could use the standard Rust Docker image and then install/configure postgresql then configure postgres to trust local connection, then create the bare DB with psql and then build your project, but that’s, like, kind of a pain. I know this process because I went down that rat-hole first. Fortunately there’s a more elegent solution, GitLab’s services with Postgres.
You just need to configure the GitLab postgres service for your project with the following snippet in your .gitlab-ci.yml
file.
services:
- postgres:latest
variables:
POSTGRES_DB: diesel_example_db_1
POSTGRES_USER: runner
POSTGRES_PASSWORD: ""
The POSTGRES_DB
is the name of the database and POSTGRES_USER
is the name of the database user … makes sense. runner
appears to be the standard POSTGRES_USER
, however it can be anything. In general, these can be anything as long as your consistent with your DATABASE_URL
variable further down in the build section of your .gitlab-ci.yml
file.
You’re also going to need diesel_cli
installed into your build container. That can be added to the container using the before_script
section of the CI config file.
before_script:
- cargo install diesel_cli
Putting it all together the whole .gitlab-ci.yml
# Use Rust docker image, see: https://hub.docker.com/_/rust/
image: rust:latest
# postgres ci: https://docs.gitlab.com/ee/ci/services/postgres.html
services:
- postgres:latest
variables:
POSTGRES_DB: diesel_example_db_1
POSTGRES_USER: runner
POSTGRES_PASSWORD: ""
before_script:
- cargo install diesel_cli
# Defines stages which are to be executed
stages:
- build
# Run `cargo test` for the project with stable Rust
run-build:
when: manual
stage: build
image: rust:latest
variables:
DATABASE_URL: "postgres://runner@postgres/diesel_example_db_1"
script:
# - diesel migration run
- rustc --version && cargo --version
- cargo build --release --verbose --jobs 1
Note that I have defined when: manual
which means you need to manual start the Pipeline in the UI instead of having it kicked off as part of the push. I usually set my CI builds to manual since GitLab is giving this compute time away for free, I don’t want to be an abuser of the service, see GitLab issue 23366. note: a reddit commenter pointed out the linked bug is more about too many artifacts instead of actually compute usage. And that there are limitations to the free CI service where a user is allotted a certain number of CI minutes, 2000 for a free plan.
Related and Recommended Reading
I got some nice tidbits from the following post.
http://blog.wjlr.org.uk/2016/08/16/fast-rust-gitlab-ci.html
This post will also teach you how to improve build times on GitLab’s CI.
My Example project that is configured to use GitLab’s CI,
https://gitlab.com/noyez_examples/diesel_rs_example_1/
The Reddit thread has some great comments, specifically one about using your own runner