Radish alpha
r
rad:z3qg5TKmN83afz2fj9z3fQjU8vaYE
Radicle CI adapter for native CI
Radicle
Git
feat: allow setting max duration of a CI run
Lars Wirzenius committed 2 years ago
commit 87f91e2474a36910228430bd4d5ce8700d86eab4
parent ddfedf5
3 files changed +43 -2
modified 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"))?,
        })
    }
modified 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)
    }
}
modified test-suite
@@ -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"]