Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: GitLab VendorBehavior #8300

Merged
merged 13 commits into from
Jun 18, 2024
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/turborepo-ci/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ license = "MIT"
workspace = true

[dependencies]
chrono = { workspace = true }
tracing = { workspace = true }

[dev-dependencies]
Expand Down
5 changes: 4 additions & 1 deletion crates/turborepo-ci/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ mod vendors;
use std::{env, sync::OnceLock};

use crate::vendors::get_vendors;
pub use crate::{vendor_behavior::VendorBehavior, vendors::Vendor};
pub use crate::{
vendor_behavior::{GroupPrefixFn, VendorBehavior},
vendors::Vendor,
};

static IS_CI: OnceLock<bool> = OnceLock::new();
static VENDOR: OnceLock<Option<&'static Vendor>> = OnceLock::new();
Expand Down
23 changes: 16 additions & 7 deletions crates/turborepo-ci/src/vendor_behavior.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
type GroupPrefixFn = fn(group_name: &str) -> String;
use std::sync::Arc;

use chrono::{DateTime, Utc};

pub type GroupPrefixFn = Arc<dyn Fn(DateTime<Utc>) -> String + Send + Sync>;
type GroupPrefixFnFactory = fn(group_name: String) -> GroupPrefixFn;

#[derive(Clone, Debug, PartialEq)]
pub struct VendorBehavior {
pub group_prefix: GroupPrefixFn,
pub group_suffix: GroupPrefixFn,
pub error_group_prefix: Option<GroupPrefixFn>,
pub error_group_suffix: Option<GroupPrefixFn>,
pub group_prefix: GroupPrefixFnFactory,
pub group_suffix: GroupPrefixFnFactory,
pub error_group_prefix: Option<GroupPrefixFnFactory>,
pub error_group_suffix: Option<GroupPrefixFnFactory>,
}

impl VendorBehavior {
pub fn new(prefix: GroupPrefixFn, suffix: GroupPrefixFn) -> Self {
pub fn new(prefix: GroupPrefixFnFactory, suffix: GroupPrefixFnFactory) -> Self {
Self {
group_prefix: prefix,
group_suffix: suffix,
Expand All @@ -18,7 +23,11 @@ impl VendorBehavior {
}
}

pub fn with_error(mut self, prefix: GroupPrefixFn, suffix: GroupPrefixFn) -> Self {
pub fn with_error(
mut self,
prefix: GroupPrefixFnFactory,
suffix: GroupPrefixFnFactory,
) -> Self {
self.error_group_prefix = Some(prefix);
self.error_group_suffix = Some(suffix);
self
Expand Down
59 changes: 47 additions & 12 deletions crates/turborepo-ci/src/vendors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::{collections::HashMap, fmt::Debug, sync::OnceLock};
use std::{
collections::HashMap,
fmt::Debug,
sync::{Arc, OnceLock},
};

use crate::vendor_behavior::VendorBehavior;

Expand Down Expand Up @@ -78,8 +82,8 @@
branch_env_var: None,
username_env_var: None,
behavior: Some(VendorBehavior::new(
|group_name| format!("##[group]{group_name}\r\n"),
|_| String::from("##[endgroup]\r\n"),
|group_name| Arc::new(move |_| format!("##[group]{group_name}\r\n")),
|_| Arc::new(|_| String::from("##[endgroup]\r\n")),
)),
},
Vendor {
Expand Down Expand Up @@ -268,12 +272,14 @@
username_env_var: Some("GITHUB_ACTOR"),
behavior: Some(
VendorBehavior::new(
|group_name| format!("::group::{group_name}\n"),
|_| String::from("::endgroup::\n"),
|group_name| Arc::new(move |_| format!("::group::{group_name}\n")),
|_| Arc::new(move |_| String::from("::endgroup::\n")),
)
.with_error(
|group_name| format!("\x1B[;31m{group_name}\x1B[;0m\n"),
|_| String::new(),
|group_name| {
Arc::new(move |_| format!("\x1B[;31m{group_name}\x1B[;0m\n"))
},
|_| Arc::new(|_| String::new()),
),
),
},
Expand All @@ -288,7 +294,26 @@
sha_env_var: None,
branch_env_var: None,
username_env_var: None,
behavior: None,
// https://docs.gitlab.com/ee/ci/jobs/#custom-collapsible-sections
behavior: Some(VendorBehavior::new(
|group_name| {
Arc::new(move |start_time| {
let timestamp = start_time.timestamp();
format!(
"\\e[0Ksection_start:{timestamp}:{group_name}\\r\\
e[0K{group_name}"
)
})
},
|group_name| {
Arc::new(move |end_time| {
let timestamp = end_time.timestamp();
String::from(format!(

Check failure on line 311 in crates/turborepo-ci/src/vendors.rs

View workflow job for this annotation

GitHub Actions / Turborepo rust clippy

useless conversion to the same type: `std::string::String`
"\\e[0Ksection_end:{timestamp}:{group_name}\\r\\e[0K"
))
chris-olszewski marked this conversation as resolved.
Show resolved Hide resolved
})
},
)),
},
Vendor {
name: "GoCD",
Expand Down Expand Up @@ -553,8 +578,16 @@
branch_env_var: None,
username_env_var: None,
behavior: Some(VendorBehavior::new(
|group_name| format!("##teamcity[blockOpened name='{group_name}']"),
|group_name| format!("##teamcity[blockClosed name='{group_name}']"),
|group_name| {
Arc::new(move |_| {
format!("##teamcity[blockOpened name='{group_name}']")
})
},
|group_name| {
Arc::new(move |_| {
format!("##teamcity[blockClosed name='{group_name}']")
})
},
)),
},
Vendor {
Expand All @@ -569,8 +602,10 @@
branch_env_var: None,
username_env_var: None,
behavior: Some(VendorBehavior::new(
|group_name| format!("travis_fold:start:{group_name}\r\n"),
|group_name| format!("travis_fold:end:{group_name}\r\n"),
|group_name| {
Arc::new(move |_| format!("travis_fold:start:{group_name}\r\n"))
},
|group_name| Arc::new(move |_| format!("travis_fold:end:{group_name}\r\n")),
)),
},
Vendor {
Expand Down
18 changes: 11 additions & 7 deletions crates/turborepo-lib/src/task_graph/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,15 +402,19 @@ impl<'a> Visitor<'a> {
} else {
format!("{}:{}", task_id.package(), task_id.task())
};
let (header, footer) = (
(vendor_behavior.group_prefix)(&group_name),
(vendor_behavior.group_suffix)(&group_name),
);
logger.with_header_footer(Some(header), Some(footer));

let header_factory = (vendor_behavior.group_prefix)(group_name.to_owned());
let footer_factory = (vendor_behavior.group_suffix)(group_name.to_owned());

logger.with_header_footer(Some(header_factory), Some(footer_factory));

let (error_header, error_footer) = (
vendor_behavior.error_group_prefix.map(|f| f(&group_name)),
vendor_behavior.error_group_suffix.map(|f| f(&group_name)),
vendor_behavior
.error_group_prefix
.map(|f| f(group_name.to_owned())),
vendor_behavior
.error_group_suffix
.map(|f| f(group_name.to_owned())),
);
logger.with_error_header_footer(error_header, error_footer);
}
Expand Down
2 changes: 2 additions & 0 deletions crates/turborepo-ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ workspace = true

[dependencies]
atty = { workspace = true }
chrono = { workspace = true }
console = { workspace = true }
crossterm = "0.27.0"
dialoguer = { workspace = true }
Expand All @@ -27,5 +28,6 @@ thiserror = { workspace = true }
tracing = { workspace = true }
tui-term = { workspace = true }
turbopath = { workspace = true }
turborepo-ci = { workspace = true }
turborepo-vt100 = { workspace = true }
winapi = "0.3.9"
42 changes: 30 additions & 12 deletions crates/turborepo-ui/src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::{
sync::{Arc, Mutex, RwLock},
};

use turborepo_ci::GroupPrefixFn;

/// OutputSink represent a sink for outputs that can be written to from multiple
/// threads through the use of Loggers.
pub struct OutputSink<W> {
Expand All @@ -28,8 +30,8 @@ pub struct OutputClient<W> {

#[derive(Default)]
struct Marginals {
header: Option<String>,
footer: Option<String>,
header: Option<GroupPrefixFn>,
footer: Option<GroupPrefixFn>,
}

pub struct OutputWriter<'a, W> {
Expand Down Expand Up @@ -95,11 +97,19 @@ impl<W: Write> OutputSink<W> {
}

impl<W: Write> OutputClient<W> {
pub fn with_header_footer(&mut self, header: Option<String>, footer: Option<String>) {
pub fn with_header_footer(
&mut self,
header: Option<GroupPrefixFn>,
footer: Option<GroupPrefixFn>,
) {
self.primary = Marginals { header, footer };
}

pub fn with_error_header_footer(&mut self, header: Option<String>, footer: Option<String>) {
pub fn with_error_header_footer(
&mut self,
header: Option<GroupPrefixFn>,
footer: Option<GroupPrefixFn>,
) {
self.error = Marginals { header, footer };
}

Expand Down Expand Up @@ -151,7 +161,8 @@ impl<W: Write> OutputClient<W> {
// to ensure that the bytes aren't interspersed.
let mut writers = writers.lock().expect("lock poisoned");
if let Some(prefix) = header {
writers.out.write_all(prefix.as_bytes())?;
let start_time = chrono::Utc::now();
writers.out.write_all(prefix(start_time).as_bytes())?;
}
for SinkBytes {
buffer,
Expand All @@ -165,7 +176,8 @@ impl<W: Write> OutputClient<W> {
writer.write_all(buffer)?;
}
if let Some(suffix) = footer {
writers.out.write_all(suffix.as_bytes())?;
let end_time = chrono::Utc::now();
writers.out.write_all(suffix(end_time).as_bytes())?;
}
}

Expand Down Expand Up @@ -381,13 +393,19 @@ mod test {
fn test_marginals() -> io::Result<()> {
let sink = OutputSink::new(Vec::new(), Vec::new());
let mut group1_logger = sink.logger(OutputClientBehavior::Grouped);
group1_logger
.with_header_footer(Some("good header\n".into()), Some("good footer\n".into()));
group1_logger
.with_error_header_footer(Some("bad header\n".into()), Some("bad footer\n".into()));
group1_logger.with_header_footer(
Some(Arc::new(|_| "good header\n".into())),
Some(Arc::new(|_| "good footer\n".into())),
);
group1_logger.with_error_header_footer(
Some(Arc::new(|_| "bad header\n".into())),
Some(Arc::new(|_| "bad footer\n".into())),
);
let mut group2_logger = sink.logger(OutputClientBehavior::Grouped);
group2_logger
.with_header_footer(Some("good header\n".into()), Some("good footer\n".into()));
group2_logger.with_header_footer(
Some(Arc::new(|_| "good header\n".into())),
Some(Arc::new(|_| "good footer\n".into())),
);

let mut group1_out = group1_logger.stdout();
let mut group2_out = group2_logger.stdout();
Expand Down
Loading