Skip to content

Instantly share code, notes, and snippets.

@LukeMathWalker
Last active August 22, 2024 04:24
Show Gist options
  • Save LukeMathWalker/d98fa8d0fc5394b347adf734ef0e85ec to your computer and use it in GitHub Desktop.
Save LukeMathWalker/d98fa8d0fc5394b347adf734ef0e85ec to your computer and use it in GitHub Desktop.
GitLab CI - Rust setup
image: "rust:latest"
default:
before_script:
- rustc --version
- cargo --version
stages:
- test
test-code:
stage: test
script:
- cargo test
- cargo install cargo-tarpaulin
- cargo tarpaulin --ignore-tests
lint-code:
stage: test
script:
- rustup component add clippy
- cargo clippy -- -D warnings
format-code:
stage: test
script:
- rustup component add rustfmt
- cargo fmt -- --check
audit-code:
stage: test
script:
- cargo install cargo-audit
- cargo audit
@w3irdrobot
Copy link

This could, and probably should, be broken into separate steps instead of everything being done in a single step. At least attempt to parallelize things that could be done at the same time.

@LukeMathWalker
Copy link
Author

If anybody who knows GitLab CI wants to pitch in with a more optimised setup I am happy to edit the gist 😁

@devonh
Copy link

devonh commented Feb 6, 2021

Hey! To parallelize things you could update this to something like the following:

image: "rust:latest"

default:
  before_script:
    - rustc --version 
    - cargo --version

stages:
  - test

test-code:
  stage: test
  script:
    - cargo test
    - cargo install cargo-tarpaulin
    - cargo tarpaulin --ignore-tests

lint-code:
  stage: test
  script:
    - rustup component add rustfmt
    - cargo fmt -- --check
    - rustup component add clippy
    - cargo clippy -- -D warnings

audit-code:
  stage: test
  script:
    - cargo install cargo-audit
    - cargo audit

@LukeMathWalker
Copy link
Author

Thanks - updated @devonh!

@Valmirius
Copy link

What else needs to be added to the Gitlab version to account for SQLX's compile time checks?

@wynro
Copy link

wynro commented Jan 1, 2022

To consider coverage in Merge Requests, the test-code job should be:

test-code:
  stage: test
  artifacts:
    when: always
    reports:
      cobertura: "cobertura.xml"
  coverage: '/\d+\.\d+% coverage, /'
  script:
    - cargo test
    - cargo install cargo-tarpaulin
    - cargo tarpaulin --ignore-tests --out Xml

image can be moved under the default part, to allow individual jobs to use different images (for example, if you want to compile in different Rust versions), leaving it like this:

default:
  image: rust:latest
  before_script:
    - rustc --version
    - cargo --version

To add caching, you can use the following on top of the file:

cache:
  paths:
    - target/

I don't know if Rust requires to cache any other directory, but you can easily add any other directory under the paths piece (or exclude directories if it may be a problem)

@Arevjensen
Copy link

Ran into:

$ cargo test
Compiling zero2prod v0.1.0 (/builds/SniffleEU/zero2prod)
error: linker clang not found = note: No such file or directory (os error 2)
error: could not compile zero2prod due to previous error
Cleaning up project directory and file based variables 00:01
ERROR: Job failed: exit code 1

In the test-code block.
As I've never tried gitlab CI before my workaround is crude, but changing from:

test-code:
  stage: test  
  script:  
    - cargo test
    - cargo install cargo-tarpaulin
    - cargo tarpaulin --ignore-tests

to

test-code:
  stage: test  
  script:  
    - apt update  
    - apt install lld clang -y
    - cargo test
    - cargo install cargo-tarpaulin
    - cargo tarpaulin --ignore-tests

Fixes the issue and runs the block

@Estus-Dev
Copy link

@Arevjensen Gitlab CI runs in a docker container, in this case, rust:latest as specified at the top of the file here. As you've discovered the rust container doesn't include lld or clang by default.

When doing it this way, you're installing these each and every time. I've gone ahead and bundled all the dependencies as of Chapter 1 into a single docker image.

If you'd like you can replace image: "rust-latest" with image: "aestusvitae/rust-ci:latest" and remove the installs (apt, cargo install, rustup component add) from your CI scripts, and CI runs should be noticeably quicker.

You can even build the image yourself if you're so inclined. (or if I fail to keep mine up to date) The Dockerfile is very simple.

@jstitch
Copy link

jstitch commented Jul 9, 2024

What else needs to be added to the Gitlab version to account for SQLX's compile time checks?

@Valmirius , you can use Gitlab CI services for the tests and coverage jobs:

tests:
  stage: test
  services:
    - postgres:14
  variables:
    POSTGRES_DB: newsletter
    POSTGRES_USER: postgres
    POSTGRES_PASSWORD: password
    POSTGRES_HOST: postgres
    POSTGRES_PORT: 5432
    DATABASE_URL: postgres://postgres:password@postgres:5432/newsletter
  script:
    - SKIP_DOCKER=true ./scripts/init_db.sh
    - cargo test

coverage:
  stage: test
  services:
    - postgres:14
  variables:
    POSTGRES_DB: newsletter
    POSTGRES_USER: postgres
    POSTGRES_PASSWORD: password
    POSTGRES_HOST: postgres
    POSTGRES_PORT: 5432
    DATABASE_URL: postgres://postgres:password@postgres:5432/newsletter
  script:
    - SKIP_DOCKER=true ./scripts/init_db.sh
    - cargo tarpaulin --ignore-tests

the way it works is that gitlab runner instantiates another container (the service), and you can make requests to it with a hostname the same as the service name. The variables section allows you to set whatever the service requires to work. At hub.docker.com for postgres image, you can find that you require those POSTGRES_ suffixed variables.

I added DATABASE_URL variable to override what the .env file has as default, you may recall that it uses localhost as hostname. For that t o work I needed to add the following line to tests/health_check.rs so that the configuration read from the yaml overrides the url string that gets built when configuration is read using yaml:

    let connection_string = configuration.database.connection_string();
+   let env_connection_string = std::env::var("DATABASE_URL").unwrap_or(connection_string);
    let mut connection = PgConnection::connect(&env_connection_string)

I know that config allows env variables to get this same effect, but haven't found how to make it work. This solution at least works for me currently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment