Skip to main content

silver_platter/
checks.rs

1//! Check if the package should be uploaded
2use breezyshim::tree::WorkingTree;
3use breezyshim::RevisionId;
4use std::collections::HashMap;
5use std::error::Error;
6use std::fmt;
7use std::process::Command;
8
9#[derive(Debug, PartialEq)]
10/// The pre check failed
11pub struct PreCheckFailed;
12
13impl fmt::Display for PreCheckFailed {
14    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15        write!(f, "Pre-check failed")
16    }
17}
18
19impl Error for PreCheckFailed {}
20
21/// Run check to see if the package should be uploaded
22pub fn run_pre_check(tree: &dyn WorkingTree, script: &str) -> Result<(), PreCheckFailed> {
23    let path = tree.abspath(std::path::Path::new("")).unwrap();
24    let status = Command::new("sh")
25        .arg("-c")
26        .arg(script)
27        .current_dir(path)
28        .status();
29
30    match status {
31        Ok(status) => {
32            if status.code().unwrap() != 0 {
33                Err(PreCheckFailed)
34            } else {
35                Ok(())
36            }
37        }
38        Err(_) => Err(PreCheckFailed),
39    }
40}
41
42#[derive(Debug, PartialEq)]
43/// The post check failed
44pub struct PostCheckFailed;
45
46impl fmt::Display for PostCheckFailed {
47    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48        write!(f, "Post-check failed")
49    }
50}
51
52impl Error for PostCheckFailed {}
53
54/// Post-build check if the package should be uploaded
55pub fn run_post_check(
56    tree: &dyn WorkingTree,
57    script: &str,
58    since_revid: &RevisionId,
59) -> Result<(), PostCheckFailed> {
60    let mut env_vars = HashMap::new();
61    env_vars.insert("SINCE_REVID", since_revid.to_string());
62    let path = tree.abspath(std::path::Path::new("")).unwrap();
63
64    let status = Command::new("sh")
65        .arg("-c")
66        .arg(script)
67        .current_dir(path)
68        .envs(&env_vars)
69        .status();
70
71    match status {
72        Ok(status) => {
73            if status.code().unwrap() != 0 {
74                Err(PostCheckFailed)
75            } else {
76                Ok(())
77            }
78        }
79        Err(_) => Err(PostCheckFailed),
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use breezyshim::controldir::ControlDirFormat;
87    use breezyshim::prelude::{Branch, MutableTree};
88    use breezyshim::testing::TestEnv;
89    use serial_test::serial;
90    use std::error::Error as StdError;
91    use std::path::Path;
92    use tempfile::tempdir;
93
94    #[test]
95    fn test_pre_check_failed_display() {
96        let error = PreCheckFailed;
97        assert_eq!(format!("{}", error), "Pre-check failed");
98
99        // Test Error trait implementation
100        let error: Box<dyn StdError> = Box::new(PreCheckFailed);
101        assert_eq!(error.to_string(), "Pre-check failed");
102    }
103
104    #[test]
105    fn test_post_check_failed_display() {
106        let error = PostCheckFailed;
107        assert_eq!(format!("{}", error), "Post-check failed");
108
109        // Test Error trait implementation
110        let error: Box<dyn StdError> = Box::new(PostCheckFailed);
111        assert_eq!(error.to_string(), "Post-check failed");
112    }
113
114    #[test]
115    fn test_run_pre_check_success() {
116        let td = tempdir().unwrap();
117        let wt = breezyshim::controldir::create_standalone_workingtree(
118            td.path(),
119            &ControlDirFormat::default(),
120        )
121        .unwrap();
122
123        // Run a successful script
124        let result = run_pre_check(&wt, "exit 0");
125        assert!(result.is_ok());
126    }
127
128    #[test]
129    fn test_run_pre_check_failure() {
130        let td = tempdir().unwrap();
131        let wt = breezyshim::controldir::create_standalone_workingtree(
132            td.path(),
133            &ControlDirFormat::default(),
134        )
135        .unwrap();
136
137        // Run a failing script
138        let result = run_pre_check(&wt, "exit 1");
139        assert!(result.is_err());
140        assert_eq!(result.err().unwrap(), PreCheckFailed);
141    }
142
143    #[test]
144    fn test_run_pre_check_nonexistent_command() {
145        let td = tempdir().unwrap();
146        let wt = breezyshim::controldir::create_standalone_workingtree(
147            td.path(),
148            &ControlDirFormat::default(),
149        )
150        .unwrap();
151
152        // Run a nonexistent command
153        let result = run_pre_check(&wt, "nonexistent_command_12345");
154        assert!(result.is_err());
155        assert_eq!(result.err().unwrap(), PreCheckFailed);
156    }
157
158    #[test]
159    fn test_run_pre_check_with_file_creation() {
160        let td = tempdir().unwrap();
161        let wt = breezyshim::controldir::create_standalone_workingtree(
162            td.path(),
163            &ControlDirFormat::default(),
164        )
165        .unwrap();
166
167        // Create a test file and check if it exists
168        let script = "touch test_file.txt && test -f test_file.txt";
169        let result = run_pre_check(&wt, script);
170        assert!(result.is_ok());
171
172        // Verify the file was created in the working tree
173        let file_path = Path::new("test_file.txt");
174        let absolute_path = wt.abspath(file_path).unwrap();
175        assert!(absolute_path.exists());
176    }
177
178    #[test]
179    fn test_run_pre_check_with_multiple_commands() {
180        let td = tempdir().unwrap();
181        let wt = breezyshim::controldir::create_standalone_workingtree(
182            td.path(),
183            &ControlDirFormat::default(),
184        )
185        .unwrap();
186
187        // Run multiple commands in a script
188        let script = "mkdir -p test_dir && cd test_dir && touch test_file.txt && cd .. && test -f test_dir/test_file.txt";
189        let result = run_pre_check(&wt, script);
190        assert!(result.is_ok());
191
192        // Verify the directory and file were created
193        let dir_path = Path::new("test_dir");
194        let file_path = Path::new("test_dir/test_file.txt");
195        let absolute_dir_path = wt.abspath(dir_path).unwrap();
196        let absolute_file_path = wt.abspath(file_path).unwrap();
197        assert!(absolute_dir_path.exists());
198        assert!(absolute_file_path.exists());
199    }
200
201    #[test]
202    fn test_run_post_check_success() {
203        let td = tempdir().unwrap();
204        let wt = breezyshim::controldir::create_standalone_workingtree(
205            td.path(),
206            &ControlDirFormat::default(),
207        )
208        .unwrap();
209
210        let revid = wt.branch().last_revision();
211
212        // Run a successful script
213        let result = run_post_check(&wt, "exit 0", &revid);
214        assert!(result.is_ok());
215    }
216
217    #[test]
218    fn test_run_post_check_failure() {
219        let td = tempdir().unwrap();
220        let wt = breezyshim::controldir::create_standalone_workingtree(
221            td.path(),
222            &ControlDirFormat::default(),
223        )
224        .unwrap();
225
226        let revid = wt.branch().last_revision();
227
228        // Run a failing script
229        let result = run_post_check(&wt, "exit 1", &revid);
230        assert!(result.is_err());
231        assert_eq!(result.err().unwrap(), PostCheckFailed);
232    }
233
234    #[test]
235    fn test_run_post_check_environment() {
236        let td = tempdir().unwrap();
237        let wt = breezyshim::controldir::create_standalone_workingtree(
238            td.path(),
239            &ControlDirFormat::default(),
240        )
241        .unwrap();
242
243        let revid = wt.branch().last_revision();
244
245        // Verify that SINCE_REVID environment variable contains the revision ID
246        let result = run_post_check(&wt, "test \"$SINCE_REVID\" = \"null:\"", &revid);
247        assert!(result.is_ok());
248    }
249
250    #[test]
251    #[serial]
252    fn test_run_post_check_with_file_operations() {
253        let _test_env = TestEnv::new();
254        let td = tempdir().unwrap();
255        let wt = breezyshim::controldir::create_standalone_workingtree(
256            td.path(),
257            &ControlDirFormat::default(),
258        )
259        .unwrap();
260
261        // Make an initial commit
262        std::fs::write(
263            wt.abspath(Path::new("initial.txt")).unwrap(),
264            "initial content",
265        )
266        .unwrap();
267        wt.add(&[Path::new("initial.txt")]).unwrap();
268        let revid = wt
269            .build_commit()
270            .message("Initial commit")
271            .allow_pointless(true)
272            .commit()
273            .unwrap();
274
275        // Create a post-check script that creates a file with the revision ID
276        let script = "echo $SINCE_REVID > revid.txt && test -f revid.txt";
277        let result = run_post_check(&wt, script, &revid);
278        assert!(result.is_ok());
279
280        // Verify the file was created and contains the revision ID
281        let file_path = wt.abspath(Path::new("revid.txt")).unwrap();
282        assert!(file_path.exists());
283        let content = std::fs::read_to_string(file_path).unwrap();
284        assert_eq!(content.trim(), revid.to_string());
285    }
286
287    #[test]
288    fn test_run_post_check_nonexistent_command() {
289        let td = tempdir().unwrap();
290        let wt = breezyshim::controldir::create_standalone_workingtree(
291            td.path(),
292            &ControlDirFormat::default(),
293        )
294        .unwrap();
295
296        let revid = wt.branch().last_revision();
297
298        // Run a nonexistent command
299        let result = run_post_check(&wt, "nonexistent_command_12345", &revid);
300        assert!(result.is_err());
301        assert_eq!(result.err().unwrap(), PostCheckFailed);
302    }
303}