Skip to content

Commit

Permalink
chore: update toolchain
Browse files Browse the repository at this point in the history
  • Loading branch information
tusharmath committed Nov 6, 2024
1 parent 369d3e2 commit 0e0b26d
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 58 deletions.
12 changes: 11 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
permissions:
contents: read
jobs:
rust:
stable:
name: Rust Job
runs-on: ubuntu-latest
steps:
Expand All @@ -25,6 +25,16 @@ jobs:
toolchain: stable
- name: Run Cargo Test
run: RUSTFLAGS="-Awarnings" cargo test --all-features --workspace
nightly:
name: Rust Job
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Rust Toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: nightly
- name: Check Formatting
run: cargo fmt -- --check
- name: Run Clippy
Expand Down
29 changes: 22 additions & 7 deletions workspace/gh-workflow-gen/build.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
use gh_workflow::toolchain::RustToolchain;
use gh_workflow::toolchain::Toolchain;
use gh_workflow::{Permissions, Workflow};

fn main() {
let toolchain = RustToolchain::default()
.workspace(true)
.fmt(true)
.clippy(true);
toolchain
.to_workflow()
let stable = Toolchain::stable().workspace(true).test(true);

let nightly = Toolchain::nightly().workspace(true).fmt(true).clippy(true);

Workflow::new("CI")
.permissions(Permissions::read())
.on(vec![
// TODO: enums
("push", vec![("branches", vec!["main"])]),
(
"pull_request",
vec![
("types", vec!["opened", "synchronize", "reopened"]),
("branches", vec!["main"]),
],
),
])
.add_job("stable", stable)
.unwrap()
.add_job("nightly", nightly)
.unwrap()
.write(format!(
"{}/../../.github/workflows/ci.yml",
Expand Down
100 changes: 57 additions & 43 deletions workspace/gh-workflow/src/toolchain.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,76 @@
//! A type-safe representation of the Rust toolchain.
use std::time::Duration;

use derive_setters::Setters;

use crate::error::Result;
use crate::workflow::*;

///
/// A type-safe representation of the Rust toolchain.
/// Instead of writing the github action for Rust by hand, we can use this
/// struct to generate the github action.
pub trait Version: ToString {}

#[derive(Default, Clone)]
pub enum Version {
#[default]
Stable,
Beta,
Nightly,
pub struct Stable;

impl Version for Stable {}
impl ToString for Stable {
fn to_string(&self) -> String {
"stable".to_string()
}
}

impl ToString for Version {
#[derive(Default, Clone)]
pub struct Nightly;

impl Version for Nightly {}
impl ToString for Nightly {
fn to_string(&self) -> String {
match self {
Version::Stable => "stable".to_string(),
Version::Beta => "beta".to_string(),
Version::Nightly => "nightly".to_string(),
}
"nightly".to_string()
}
}

#[derive(Setters, Default, Clone)]
#[setters(strip_option)]
pub struct RustToolchain {
#[derive(Setters, Clone)]
pub struct Toolchain<Version> {
version: Version,
fmt: bool,
clippy: bool,
timeout: Option<Duration>,
workspace: bool,
test: bool,
}

impl RustToolchain {
pub fn to_workflow(&self) -> Result<Workflow> {
impl<V: Version + Default> Toolchain<V> {
pub fn new(version: V) -> Self {
Toolchain {
version,
fmt: false,
clippy: false,
timeout: None,
workspace: false,
test: false,
}
}
}

impl Toolchain<Stable> {
pub fn stable() -> Self {
Toolchain::new(Stable)
}
}

impl Toolchain<Nightly> {
pub fn nightly() -> Self {
Toolchain::new(Nightly)
}
}

impl<V: Version> Into<Job> for Toolchain<V> {
fn into(self) -> Job {
let mut job = Job::new("Rust Job")
.runs_on("ubuntu-latest")
.add_step(Step::uses("actions", "checkout", 4).name("Checkout Code"))
.add_step(
Step::uses("actions-rust-lang", "setup-rust-toolchain", 1)
.name("Setup Rust Toolchain")
.with(("toolchain", self.version.clone())),
.with(("toolchain", self.version)),
);

if let Some(timeout) = self.timeout {
Expand All @@ -58,13 +83,15 @@ impl RustToolchain {
cargo_test_args.push("--workspace");
}

job = job.add_step(
Step::run(format!(
"RUSTFLAGS=\"-Awarnings\" cargo test {}",
cargo_test_args.join(" ")
))
.name("Run Cargo Test"),
);
if self.test {
job = job.add_step(
Step::run(format!(
"RUSTFLAGS=\"-Awarnings\" cargo test {}",
cargo_test_args.join(" ")
))
.name("Run Cargo Test"),
);
}

if self.fmt {
job = job.add_step(Step::run("cargo fmt -- --check").name("Check formatting"));
Expand All @@ -74,19 +101,6 @@ impl RustToolchain {
job = job.add_step(Step::run("cargo clippy -- -D warnings").name("Run clippy"));
}

Workflow::new("CI")
.permissions(Permissions::read())
.on(vec![
// TODO: enums
("push", vec![("branches", vec!["main"])]),
(
"pull_request",
vec![
("types", vec!["opened", "synchronize", "reopened"]),
("branches", vec!["main"]),
],
),
])
.add_job("rust", job)
job
}
}
28 changes: 21 additions & 7 deletions workspace/gh-workflow/src/workflow.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::{path::Path, time::Duration};

use convert_case::{Case, Casing};
use derive_setters::Setters;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::{path::Path, time::Duration};

use crate::error::{Error, Result};

Expand Down Expand Up @@ -48,6 +47,20 @@ pub enum Event {
RepositoryDispatch,
}

#[derive(Debug, Serialize, Deserialize, Clone, Hash, PartialEq, Eq)]
#[serde(transparent)]
pub struct JobKey(String);

impl JobKey {
fn new<T: ToString>(key: T) -> Self {
Self(key.to_string().to_case(Case::Kebab))
}

fn as_str(&self) -> &str {
&self.0
}
}

#[derive(Debug, Default, Setters, Serialize, Deserialize, Clone, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
#[setters(strip_option)]
Expand All @@ -62,7 +75,7 @@ pub struct Workflow {
#[serde(skip_serializing_if = "Option::is_none")]
pub permissions: Option<Permissions>,
#[serde(skip_serializing_if = "IndexMap::is_empty")]
pub jobs: IndexMap<String, Job>,
pub jobs: IndexMap<JobKey, Job>,
#[serde(skip_serializing_if = "Option::is_none")]
pub concurrency: Option<Concurrency>,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -93,12 +106,13 @@ impl Workflow {
Ok(serde_yaml::to_string(self)?)
}

pub fn add_job<T: ToString>(mut self, id: T, job: Job) -> Result<Self> {
if self.jobs.contains_key(id.to_string().as_str()) {
return Err(Error::JobIdAlreadyExists(id.to_string()));
pub fn add_job<T: ToString, J: Into<Job>>(mut self, id: T, job: J) -> Result<Self> {
let key = JobKey::new(id);
if self.jobs.contains_key(&key) {
return Err(Error::JobIdAlreadyExists(key.as_str().to_string()));
}

self.jobs.insert(id.to_string(), job);
self.jobs.insert(key, job.into());
Ok(self)
}

Expand Down

0 comments on commit 0e0b26d

Please sign in to comment.