#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Target {
GitHubActions,
}
#[derive(Debug, Clone)]
pub struct Generator {
target: Target,
clippy: bool,
fmt: bool,
msrv: Option<String>,
}
impl Default for Generator {
fn default() -> Self {
Self::new()
}
}
impl Generator {
pub fn new() -> Self {
Self {
target: Target::GitHubActions,
clippy: false,
fmt: false,
msrv: None,
}
}
pub fn target(mut self, target: Target) -> Self {
self.target = target;
self
}
pub fn with_clippy(mut self) -> Self {
self.clippy = true;
self
}
pub fn with_fmt(mut self) -> Self {
self.fmt = true;
self
}
pub fn with_msrv(mut self, version: impl Into<String>) -> Self {
self.msrv = Some(version.into());
self
}
pub fn target_kind(&self) -> Target {
self.target
}
pub fn generate(&self) -> String {
match self.target {
Target::GitHubActions => self.render_github_actions(),
}
}
fn render_github_actions(&self) -> String {
let mut out = String::new();
out.push_str("name: CI\n\n");
out.push_str(
"on:\n push:\n branches: [main]\n pull_request:\n branches: [main]\n\n",
);
out.push_str("env:\n CARGO_TERM_COLOR: always\n\n");
out.push_str("jobs:\n");
out.push_str(" test:\n runs-on: ubuntu-latest\n steps:\n");
out.push_str(" - uses: actions/checkout@v5\n");
out.push_str(" - uses: dtolnay/rust-toolchain@stable\n");
out.push_str(" - run: cargo test --all-features\n");
if self.clippy {
out.push_str(" clippy:\n runs-on: ubuntu-latest\n steps:\n");
out.push_str(" - uses: actions/checkout@v5\n");
out.push_str(
" - uses: dtolnay/rust-toolchain@stable\n with:\n components: clippy\n",
);
out.push_str(" - run: cargo clippy --all-targets -- -D warnings\n");
}
if self.fmt {
out.push_str(" fmt:\n runs-on: ubuntu-latest\n steps:\n");
out.push_str(" - uses: actions/checkout@v5\n");
out.push_str(
" - uses: dtolnay/rust-toolchain@stable\n with:\n components: rustfmt\n",
);
out.push_str(" - run: cargo fmt --all -- --check\n");
}
if let Some(msrv) = &self.msrv {
out.push_str(" msrv:\n runs-on: ubuntu-latest\n steps:\n");
out.push_str(" - uses: actions/checkout@v5\n");
out.push_str(&format!(" - uses: dtolnay/rust-toolchain@{msrv}\n"));
out.push_str(" - run: cargo build --all-features\n");
}
out
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_generates_a_test_job() {
let yaml = Generator::new().generate();
assert!(yaml.contains("jobs:"));
assert!(yaml.contains("test:"));
assert!(yaml.contains("actions/checkout@v5"));
}
#[test]
fn clippy_job_added_when_requested() {
let yaml = Generator::new().with_clippy().generate();
assert!(yaml.contains("clippy:"));
}
#[test]
fn fmt_job_added_when_requested() {
let yaml = Generator::new().with_fmt().generate();
assert!(yaml.contains("fmt:"));
}
#[test]
fn msrv_job_uses_pinned_toolchain() {
let yaml = Generator::new().with_msrv("1.85").generate();
assert!(yaml.contains("rust-toolchain@1.85"));
}
}