gh_workflow_tailcall/
workflow.rsuse ctx::Context;
use derive_setters::Setters;
use generate::Generate;
use gh_workflow::error::Result;
use gh_workflow::{Workflow as GHWorkflow, *};
use heck::ToTitleCase;
use release_plz::{Command, Release};
use toolchain::Toolchain;
#[derive(Debug, Clone, Setters)]
pub struct Workflow {
pub auto_release: bool,
pub name: String,
pub benchmarks: bool,
pub auto_fix: bool,
}
impl Default for Workflow {
fn default() -> Self {
Self {
auto_release: false,
name: "ci".into(),
benchmarks: false,
auto_fix: false,
}
}
}
impl Workflow {
pub fn generate(self) -> Result<()> {
self.to_ci_workflow().generate()?;
Generate::new(self.to_autofix_workflow())
.name("autofix.yml")
.generate()?;
Ok(())
}
fn to_autofix_workflow(&self) -> GHWorkflow {
GHWorkflow::new("autofix.ci")
.add_env(self.workflow_flags())
.on(self.workflow_event())
.add_job("lint", self.lint_job(true))
}
fn to_ci_workflow(&self) -> GHWorkflow {
GHWorkflow::new(self.name.clone())
.add_env(self.workflow_flags())
.on(self.workflow_event())
.add_job("build", self.test_job())
.add_job("lint", self.lint_job(false))
.add_job_when(
self.auto_release,
"release",
self.release_job(Command::Release),
)
.add_job_when(
self.auto_release,
"release-pr",
self.release_job(Command::ReleasePR),
)
}
fn release_job(&self, cmd: Command) -> Job {
Job::new(cmd.to_string().to_title_case())
.concurrency(
Concurrency::new(Expression::new("release-${{github.ref}}"))
.cancel_in_progress(false),
)
.cond(self.workflow_cond())
.add_needs(self.test_job())
.add_needs(self.lint_job(false))
.add_env(Env::github())
.add_env(Env::new(
"CARGO_REGISTRY_TOKEN",
"${{ secrets.CARGO_REGISTRY_TOKEN }}",
))
.permissions(self.write_permissions())
.add_step(Step::checkout())
.add_step(Release::default().command(cmd))
}
fn lint_job(&self, auto_fix: bool) -> Job {
let job = if auto_fix {
Job::new("Lint Fix").concurrency(
Concurrency::new(Expression::new("autofix-${{github.ref}}"))
.cancel_in_progress(false),
)
} else {
Job::new("Lint")
};
job.permissions(Permissions::default().contents(Level::Read))
.add_step(Step::checkout())
.add_step(Toolchain::default().add_nightly().add_clippy().add_fmt())
.add_step(
Cargo::new("fmt")
.name("Cargo Fmt")
.nightly()
.add_args("--all")
.add_args_when(!auto_fix, "--check"),
)
.add_step(
Cargo::new("clippy")
.name("Cargo Clippy")
.nightly()
.add_args_when(auto_fix, "--fix")
.add_args_when(auto_fix, "--allow-dirty")
.add_args("--all-features --workspace -- -D warnings"),
)
.add_step_when(
auto_fix,
Step::uses(
"autofix-ci",
"action",
"ff86a557419858bb967097bfc916833f5647fa8c",
),
)
}
fn test_job(&self) -> Job {
Job::new("Build and Test")
.permissions(Permissions::default().contents(Level::Read))
.add_step(Step::checkout())
.add_step(Toolchain::default().add_stable())
.add_step(
Cargo::new("test")
.args("--all-features --workspace")
.name("Cargo Test"),
)
.add_step_when(
self.benchmarks,
Cargo::new("bench").args("--workspace").name("Cargo Bench"),
)
}
fn write_permissions(&self) -> Permissions {
Permissions::default()
.pull_requests(Level::Write)
.packages(Level::Write)
.contents(Level::Write)
}
fn workflow_cond(&self) -> Context<bool> {
let is_main = Context::github().ref_().eq("refs/heads/main".into());
let is_push = Context::github().event_name().eq("push".into());
is_main.and(is_push)
}
fn workflow_event(&self) -> Event {
Event::default()
.push(Push::default().add_branch("main"))
.pull_request(
PullRequest::default()
.add_type(PullRequestType::Opened)
.add_type(PullRequestType::Synchronize)
.add_type(PullRequestType::Reopened)
.add_branch("main"),
)
}
fn workflow_flags(&self) -> RustFlags {
RustFlags::deny("warnings")
}
}