11 releases

0.1.0 May 17, 2024
0.0.8 Jan 13, 2023
0.0.7 Oct 18, 2022
0.0.5 May 16, 2022
0.0.1 Sep 26, 2021

#227 in Build Utils

Download history 7/week @ 2024-07-20 35/week @ 2024-07-27 35/week @ 2024-09-21 2/week @ 2024-09-28 86/week @ 2024-10-12 2/week @ 2024-10-19 10/week @ 2024-10-26

98 downloads per month

MIT/Apache

79KB
2K SLoC

gitlab-runner-rs

A crate to help build custom gitlab runner implementations.

Implementing a custom runner

The overall idea is that this crate handles all interaction with the gitlab server and drives the executions while the the runner implementation focus on how to handle jobs from gitlab.

As the focus for an implementer of a custom runner is to implement the async JobHandler trait, which gets calle during job executation. An absolute minimal runner can be implement as such:

use gitlab_runner::{outputln, GitlabLayer, RunnerBuilder, JobHandler, JobResult, Phase};
use tracing_subscriber::prelude::*;
use std::path::PathBuf;

#[derive(Debug)]
struct Run {}

#[async_trait::async_trait]
impl JobHandler for Run {
      async fn step(&mut self, script: &[String], phase: Phase) -> JobResult {
          outputln!("Running script for phase {:?}", phase);
          for s in script {
            outputln!("Step: {}", s);
          }
          Ok(())
      }
}

#[tokio::main]
async fn main() {
    let (layer, jobs) = GitlabLayer::new();

    // By default show logs from my_runner and warnings, the gitlab_runner::gitlab::job span which
    // sets the gitlab.job field is always enabled regardless of the over all log level.
    let env = std::env::var("RUNNER_LOG").unwrap_or_else(|_| "my_runner=info,warn".to_string());
    let envfilter = tracing_subscriber::EnvFilter::builder()
        .parse(&env)
        .unwrap_or_else(|_| panic!("Failed to parse RUNNER_LOG env var: {env}"))
        .add_directive("gitlab_runner::gitlab::job=error".parse().unwrap());

    tracing_subscriber::Registry::default()
        .with(
            tracing_subscriber::fmt::Layer::new()
               .pretty()
               .with_filter(envfilter),
        )
        .with(layer)
        .init();
    let mut runner = RunnerBuilder::new(
        "https://gitlab.example.com".try_into().expect("failed to parse url"),
        "runner token",
        "/tmp",
        jobs
    )
    .build()
    .await;
    runner.run(move | _job | async move { Ok(Run{}) }, 16).await.unwrap();
}

When setting up the tracing subscriber only per-layer filtering should be used, to ensure logs intended for gitlab don't get filtered out. For other logging outputs the gitlab_runner::gitlab::job target should always be enabled to get the gitlab.job field which contains the gitlab job id.

Gitlab runner creation

This crate does not support creating new runners on the GitLab server. This can be done using the runner creation API, or manually in the GitLab runner management web interface. Make sure to follow the runner creation with an authentication token workflow, as the registration token workflow is deprecated.

One key parameter provided when creating the runner is run_untagged=false (or leaving the Run untagged jobs box unchecked in the web interface), which will make the runner only pickup jobs which matches its tags. This is important to prevent the runner from picking up "normal" jobs which it will not be able to process.

When the runner is created GitLab provides an authentication token starting with glrt-. This token should be provided to the runner for its GitLab connection.

The token can be verified using a curl command like:

curl --request POST "https://GITLAB_URL/api/v4/runners/verify"  \
  --form "token=AUTHENTICATION_TOKEN"

This step is optional.

Dependencies

~16–30MB
~461K SLoC