diff options
author | Lars Wirzenius <liw@liw.fi> | 2024-01-10 17:31:14 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2024-01-10 17:38:05 +0200 |
commit | 87f91e2474a36910228430bd4d5ce8700d86eab4 (patch) | |
tree | 1f14a02642a4d35661e621e25ea2be7a336cd538 | |
parent | ddfedf5985b4da1fa37178ad2162861c4fa711c3 (diff) | |
download | radicle-native-ci-87f91e2474a36910228430bd4d5ce8700d86eab4.tar.gz |
feat: allow setting max duration of a CI run
Signed-off-by: Lars Wirzenius <liw@liw.fi>
-rw-r--r-- | src/bin/radicle-native-ci.rs | 20 | ||||
-rw-r--r-- | src/config.rs | 10 | ||||
-rwxr-xr-x | test-suite | 15 |
3 files changed, 43 insertions, 2 deletions
diff --git a/src/bin/radicle-native-ci.rs b/src/bin/radicle-native-ci.rs index 0c3910c..016a4fb 100644 --- a/src/bin/radicle-native-ci.rs +++ b/src/bin/radicle-native-ci.rs @@ -111,6 +111,7 @@ fn fallible_main_inner( .src(&src) .log(logfile) .run_log(&run_log) + .timeout(config.timeout) .builder(builder) .build()?; let result = runner.run(); @@ -155,6 +156,7 @@ struct Runner<'a> { src: PathBuf, log: &'a mut LogFile, run_log: LogFile, + timeout: Option<usize>, builder: &'a mut RunInfoBuilder, } @@ -211,7 +213,16 @@ impl<'a> Runner<'a> { debug!("running CI in cloned repository"); self.log.writeln("run shell snippet in repository")?; let snippet = format!("set -xeuo pipefail\n{}", &runspec.shell); - runcmd(&mut self.run_log, &["bash", "-c", &snippet], &self.src)?; + if let Some(timeout) = self.timeout { + let timeout = format!("{}", timeout); + runcmd( + &mut self.run_log, + &["timeout", &timeout, "bash", "-c", &snippet], + &self.src, + )?; + } else { + runcmd(&mut self.run_log, &["bash", "-c", &snippet], &self.src)?; + } let result = RunResult::Success; @@ -237,6 +248,7 @@ struct RunnerBuilder<'a> { src: Option<PathBuf>, log: Option<&'a mut LogFile>, run_log: Option<PathBuf>, + timeout: Option<usize>, builder: Option<&'a mut RunInfoBuilder>, } @@ -276,6 +288,11 @@ impl<'a> RunnerBuilder<'a> { self } + fn timeout(mut self, timeout: Option<usize>) -> Self { + self.timeout = timeout; + self + } + fn builder(mut self, builder: &'a mut RunInfoBuilder) -> Self { self.builder = Some(builder); self @@ -292,6 +309,7 @@ impl<'a> RunnerBuilder<'a> { src: self.src.ok_or(NativeError::Unset("src"))?, log: self.log.ok_or(NativeError::Unset("log"))?, run_log, + timeout: self.timeout, builder: self.builder.ok_or(NativeError::Unset("builder"))?, }) } diff --git a/src/config.rs b/src/config.rs index e9642ab..68401c7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,6 +5,8 @@ use serde::Deserialize; use crate::logfile::{LogError, LogFile}; +const DEFAULT_TIMEOUT: usize = 3600; + /// Configuration file for `radicle-native-ci`. #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] @@ -15,6 +17,9 @@ pub struct Config { /// File where native CI should write a log. pub log: PathBuf, + + /// Optional maximum duration of a CI run. + pub timeout: Option<usize>, } impl Config { @@ -35,8 +40,11 @@ impl Config { pub fn read(filename: &Path) -> Result<Self, ConfigError> { let file = std::fs::File::open(filename) .map_err(|e| ConfigError::ReadConfig(filename.into(), e))?; - let config = serde_yaml::from_reader(&file) + let mut config: Self = serde_yaml::from_reader(&file) .map_err(|e| ConfigError::ParseConfig(filename.into(), e))?; + if config.timeout.is_none() { + config.timeout = Some(DEFAULT_TIMEOUT); + } Ok(config) } } @@ -207,6 +207,19 @@ class Suite: assert "shell" in stderr assert "string" in stderr + def test_command_takes_too_long(self): + git = self._create_git_repo("command-takes-too-long") + self._create_valid_native_yaml(git, "sleep 5") + rid, commit = self._get_repo_info(git) + trigger = Trigger(rid, commit) + ci = self._create_ci() + exit, resps, stderr = ci.run(trigger) + assert exit != 0 + assert len(resps) == 2 + self.assert_triggered(resps[0]) + self.assert_error(resps[1]) + assert "124" in stderr + class Git: def __init__(self, path): @@ -281,6 +294,7 @@ class Config: self.dict = { "state": os.path.join(tmp, "state"), "log": os.path.join(tmp, "node-log.txt"), + "timeout": 2, } def write(self): @@ -325,6 +339,7 @@ class NativeCI: "RADICLE_NATIVE_CI": self.config, "RADICLE_NATIVE_CI_LOG": "debug", } + self.timeout = 1 def without_config(self): del self.env["RADICLE_NATIVE_CI"] |