gh_workflow/
generate.rs

1//! This module provides functionality to customize generation of the GitHub
2//! Actions workflow files.
3
4use std::path::PathBuf;
5use std::process::Command;
6
7use derive_setters::Setters;
8
9use crate::error::{Error, Result};
10use crate::Workflow;
11
12#[derive(Setters, Clone)]
13#[setters(strip_option, into)]
14pub struct Generate {
15    workflow: Workflow,
16    name: String,
17}
18
19impl Generate {
20    pub fn new(workflow: Workflow) -> Self {
21        Self { workflow, name: "ci.yml".to_string() }
22    }
23
24    fn check_file(&self, path: &PathBuf, content: &str) -> Result<()> {
25        if let Ok(prev) = std::fs::read_to_string(path) {
26            if content != prev {
27                Err(Error::OutdatedWorkflow)
28            } else {
29                Ok(())
30            }
31        } else {
32            Err(Error::MissingWorkflowFile(path.clone()))
33        }
34    }
35
36    pub fn generate(&self) -> Result<()> {
37        let comment = include_str!("./comment.yml");
38
39        let root_dir = String::from_utf8(
40            Command::new("git")
41                .args(["rev-parse", "--show-toplevel"])
42                .output()?
43                .stdout,
44        )?;
45
46        let path = PathBuf::from(root_dir.trim())
47            .join(".github")
48            .join("workflows")
49            .join(self.name.as_str());
50
51        let content = format!("{}\n{}", comment, self.workflow.to_string()?);
52
53        let result = self.check_file(&path, &content);
54
55        if std::env::var("CI").is_ok() {
56            result
57        } else {
58            match result {
59                Ok(()) => {
60                    println!("Workflow file is up-to-date: {}", path.display());
61                    Ok(())
62                }
63                Err(Error::OutdatedWorkflow) => {
64                    std::fs::write(path.clone(), content)?;
65                    println!("Updated workflow file: {}", path.display());
66                    Ok(())
67                }
68                Err(Error::MissingWorkflowFile(path)) => {
69                    std::fs::create_dir_all(path.parent().ok_or(Error::IO(
70                        std::io::Error::other("Invalid parent dir(s) path"),
71                    ))?)?;
72                    std::fs::write(path.clone(), content)?;
73                    println!("Generated workflow file: {}", path.display());
74                    Ok(())
75                }
76                Err(e) => Err(e),
77            }
78        }
79    }
80}