Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gitlab-runner-mock/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl GitlabRunnerMock {
};
let inner = Inner {
server: m,
runner_token: "fakerunnertoken".to_string(),
runner_token: "glrt-fakerunnertoken".to_string(),
jobs: Mutex::new(jobs),
update_interval: Mutex::new(3),
expected_metadata: Mutex::new(ExpectedMetadata::default()),
Expand Down
72 changes: 72 additions & 0 deletions gitlab-runner/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ where

const GITLAB_TRACE_UPDATE_INTERVAL: &str = "X-GitLab-Trace-Update-Interval";
const JOB_STATUS: &str = "Job-Status";
const SHORT_TOKEN_LENGTH: usize = 9;

#[derive(Debug, Default, Clone, Serialize)]
struct FeaturesInfo {
Expand Down Expand Up @@ -290,6 +291,28 @@ pub(crate) struct Client {
metadata: ClientMetadata,
}

// Reimplementation of gitlab-runners `ShortenToken` function.
// This returns a view into the token without the standard prefixes, and shortened to 9 characters.
// See: https://gitlab.com/gitlab-org/gitlab-runner/-/blob/654132dc91a40f80a4fd5bb290a18a13b7064aa0/helpers/shorten_token.go
fn shorten_token<T: AsRef<str> + ?Sized>(token: &T) -> &str {
let token = token.as_ref();

// Match and remove ^glrt-
let token = token.strip_prefix("glrt-").unwrap_or(token);

// Match and remove ^t[123]_
let token = token
.strip_prefix('t')
.and_then(|t| t.strip_prefix(|c| ('1'..='3').contains(&c)))
.and_then(|t| t.strip_prefix('_'))
.unwrap_or(token);

// Match and remove ^glrtr-
let token = token.strip_prefix("glrtr-").unwrap_or(token);

token.get(..SHORT_TOKEN_LENGTH).unwrap_or(token)
}

impl Client {
pub fn new(url: Url, token: String, system_id: String, metadata: ClientMetadata) -> Self {
Self {
Expand All @@ -301,6 +324,33 @@ impl Client {
}
}

pub fn get_app_version_line(&self) -> String {
format!(
"{} {} ({})",
self.metadata
.platform
Comment thread
ColinKinloch marked this conversation as resolved.
.as_deref()
.unwrap_or("unknown gitlab-runner-rs runner"),
self.metadata.version.as_deref().unwrap_or("?.?.?"),
self.metadata
.revision
.as_deref()
.unwrap_or("unknown revision")
)
}

/// Get the runners identifier as displayed in brackets on the gitlab frontend.
///
/// The value is the first 8 or 9 characters of the runners after stripping it's prefix,
/// it is alphanumeric and may include hyphens and underscores.
pub fn get_short_description(&self) -> &str {
shorten_token(&self.token)
}

pub fn system_id(&self) -> &str {
&self.system_id
}

pub async fn request_job(&self) -> Result<Option<JobResponse>, Error> {
let request = JobRequest {
token: &self.token,
Expand Down Expand Up @@ -539,6 +589,28 @@ mod test {
);
}

#[test]
fn short_description_test() {
for (token, expected) in [
// no prefix
("short", "short"),
("veryverylongtoken", "veryveryl"),
// partition prefix only
("t1_t9Wkyj-HGRkqQ-VWTGAr", "t9Wkyj-HG"),
("t2_t9Wkyj-HGRkqQ-VWTGAr", "t9Wkyj-HG"),
("t3_t9Wkyj-HGRkqQ-VWTGAr", "t9Wkyj-HG"),
("t4_t9Wkyj-HGRkqQ-VWTGAr", "t4_t9Wkyj"),
// glrt prefix, with and without partition prefix
("glrt-t9Wkyj-HGRkqQ-VWTGAr", "t9Wkyj-HG"),
("glrt-t1_t9Wkyj-HGRkqQ-VWTGAr", "t9Wkyj-HG"),
// glrtr prefix, with and without partition prefix, though the latter should never happen
("glrtr-t9Wkyj-HGRkqQ-VWTGAr", "t9Wkyj-HG"),
("glrtr-t1_t9Wkyj-HGRkqQ-VWTGAr", "t1_t9Wkyj"),
] {
assert_eq!(shorten_token(token), expected);
}
}

#[tokio::test]
async fn no_job() {
let mock = GitlabRunnerMock::start().await;
Expand Down
18 changes: 18 additions & 0 deletions gitlab-runner/src/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,24 @@ impl Job {
self.log.trace(data.as_ref());
}

/// Print the runner information to the gitlab log
pub(crate) fn output_runner_header(&self) {
outputln!("Running with {}", self.client.get_app_version_line());
let short_description = self.client.get_short_description();

if !short_description.is_empty() {
let name = self
.variable("CI_RUNNER_DESCRIPTION")
.map_or_else(|| "unnamed".to_string(), |v| format!("{v}"));
outputln!(
" on {} {}, system ID: {}",
name,
short_description,
self.client.system_id()
);
}
}

/// Get the variable matching the given key
pub fn variable(&self, key: &str) -> Option<Variable<'_>> {
self.response.variables.get(key).map(|v| Variable { v })
Expand Down
2 changes: 2 additions & 0 deletions gitlab-runner/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ where
U: UploadableFile + Send + 'static,
Ret: Future<Output = Result<J, ()>>,
{
job.output_runner_header();

if let Err(e) = tokio::fs::create_dir(&build_dir).await {
job.trace(format!("Failed to create build dir: {e}"));
return Err(());
Comment thread
ColinKinloch marked this conversation as resolved.
Expand Down
11 changes: 10 additions & 1 deletion gitlab-runner/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,16 @@ async fn job_log() {
assert!(got_job);
runner.wait_for_space(1).await;
assert_eq!(MockJobState::Success, job.state());
assert_eq!(b"aa\nbb\ncc\n", job.log().as_slice());

let log = job.log();

assert!(log.ends_with(b"aa\nbb\ncc\n"));

let header =
str::from_utf8(log.strip_suffix(b"aa\nbb\ncc\n").unwrap()).expect("Log wasn't utf8");

assert!(header.starts_with("Running with "));
assert!(header.contains("on Rust runner test fakerunne,"));
}
.with_subscriber(subscriber)
.await;
Expand Down
5 changes: 4 additions & 1 deletion gitlab-runner/tests/runhandler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@ async fn log_ping(job: &MockJob, control: &LoggerControl, mut patches: u32) -> u
patches += 1;

assert_eq!(job.log_patches(), patches);
assert_eq!(job.log_last(), Some(ping.as_bytes().to_vec()));
assert!(
job.log_last()
.is_some_and(|log| log.ends_with(ping.as_bytes()))
);

patches
}
Expand Down