Skip to content

update CI to run clippy and docs #907

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
ci:
name: CI
runs-on: ubuntu-latest
needs: [check, ci-linux, ci-clippy, ci-serde]
needs: [check, ci-linux, ci-docs-clippy, ci-serde]
if: always()
steps:
- name: Done
Expand Down Expand Up @@ -127,15 +127,33 @@ jobs:
# stable.
run: cargo +stable regress tests --toolchain 1.76.0 -m Nordic -- --strict --atomics

ci-clippy:
ci-docs-clippy:
runs-on: ubuntu-latest
needs: [check]
strategy:
fail-fast: false
matrix:
include:
# STMicro
- { chip: STM32F030 }
- { chip: STM32F410 }
- { chip: STM32L1xx }
# Espressif
- { chip: esp32c3 }
# Freescale
- { chip: MKW22D5 }
- { chip: MK02F12810 }
# Silicon Labs
# TODO: fix doc rendering bug when math `>` is present in description
#- { chip: SIM3L1x8_SVD }
# Nordic chips
- { chip: nrf51, options: "-- -f register_mod::s:_mod" }
- { chip: nrf52, options: "-- -f register_mod::s:_mod" }
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- uses: dtolnay/rust-toolchain@nightly
- uses: dtolnay/rust-toolchain@stable

- name: Cache
uses: Swatinem/rust-cache@v2
Expand All @@ -144,12 +162,8 @@ jobs:
run: |
cargo install svd2rust --path .

- name: Run CI script
env:
VENDOR: RISC-V
OPTIONS: ""
COMMAND: clippy
run: bash ci/script.sh
- name: Check docs and clippy on generated PACs
run: cargo regress test -c ${{ matrix.chip }} --docs-stable --docs-nightly --clippy ${{ matrix.options }}

ci-serde:
runs-on: ubuntu-latest
Expand Down
10 changes: 7 additions & 3 deletions ci/svd2rust-regress/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ pub trait CommandExt {
fn run(&mut self, hide: bool) -> Result<(), anyhow::Error>;

#[track_caller]
fn get_output(&mut self, can_fail: bool) -> Result<std::process::Output, anyhow::Error>;
fn run_and_get_output(&mut self, can_fail: bool)
-> Result<std::process::Output, anyhow::Error>;

#[track_caller]
fn get_output_string(&mut self) -> Result<String, anyhow::Error>;
Expand All @@ -33,7 +34,10 @@ impl CommandExt for Command {
}

#[track_caller]
fn get_output(&mut self, can_fail: bool) -> Result<std::process::Output, anyhow::Error> {
fn run_and_get_output(
&mut self,
can_fail: bool,
) -> Result<std::process::Output, anyhow::Error> {
let output = self
.output()
.with_context(|| format!("command `{}` couldn't be run", self.display()))?;
Expand All @@ -51,7 +55,7 @@ impl CommandExt for Command {

#[track_caller]
fn get_output_string(&mut self) -> Result<String, anyhow::Error> {
String::from_utf8(self.get_output(true)?.stdout).map_err(Into::into)
String::from_utf8(self.run_and_get_output(true)?.stdout).map_err(Into::into)
}

fn display(&self) -> String {
Expand Down
2 changes: 1 addition & 1 deletion ci/svd2rust-regress/src/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ pub fn get_release_binary_artifact(
Command::new("gzip")
.arg("-d")
.arg(output_dir.join(artifact))
.get_output(false)?;
.run_and_get_output(false)?;
}
}
_ => {
Expand Down
42 changes: 40 additions & 2 deletions ci/svd2rust-regress/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ pub struct TestAll {
/// Enable splitting `lib.rs` with `form`
pub form_lib: bool,

/// Check generated crates with clippy.
#[clap(long)]
pub clippy: bool,

/// Check documentation build with stable.
#[clap(long)]
pub docs_stable: bool,

/// Check documentation build with nightly settings (docs.rs equivalent).
#[clap(long)]
pub docs_nightly: bool,

/// Print all available test using the specified filters
#[clap(long)]
pub list: bool,
Expand Down Expand Up @@ -143,6 +155,18 @@ pub struct Test {
/// Chip to use, use `--url` or `--svd-file` for another way to specify svd
pub chip: Option<String>,

/// Check generated crate with clippy.
#[arg(long)]
pub clippy: bool,

/// Check documentation build with stable.
#[clap(long)]
pub docs_stable: bool,

/// Check documentation build with nightly settings (docs.rs equivalent).
#[clap(long)]
pub docs_nightly: bool,

/// Path to an `svd2rust` binary, relative or absolute.
/// Defaults to `target/release/svd2rust[.exe]` of this repository
/// (which must be already built)
Expand Down Expand Up @@ -191,7 +215,14 @@ impl Test {
.ok_or_else(|| anyhow::anyhow!("no test found for chip"))?
.to_owned()
};
test.test(opts, &self.current_bin_path, &self.passthrough_opts)?;
test.test(
opts,
&self.current_bin_path,
self.clippy,
self.docs_stable,
self.docs_nightly,
&self.passthrough_opts,
)?;
Ok(())
}
}
Expand Down Expand Up @@ -247,7 +278,14 @@ impl TestAll {
tests.par_iter().for_each(|t| {
let start = Instant::now();

match t.test(opt, &self.current_bin_path, &self.passthrough_opts) {
match t.test(
opt,
&self.current_bin_path,
self.clippy,
self.docs_stable,
self.docs_nightly,
&self.passthrough_opts,
) {
Ok(s) => {
if let Some(stderrs) = s {
let mut buf = String::new();
Expand Down
107 changes: 90 additions & 17 deletions ci/svd2rust-regress/src/svd_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,27 +71,43 @@ impl std::fmt::Debug for ProcessFailed {
}

trait CommandHelper {
fn capture_outputs(
fn run_and_capture_outputs(
&mut self,
cant_fail: bool,
name: &str,
stdout: Option<&PathBuf>,
stderr: Option<&PathBuf>,
previous_processes_stderr: &[PathBuf],
) -> Result<(), TestError>;

fn run_and_capture_stderr(
&mut self,
cant_fail: bool,
name: &str,
stderr: &PathBuf,
previous_processes_stderr: &[PathBuf],
) -> Result<(), TestError> {
self.run_and_capture_outputs(
cant_fail,
name,
None,
Some(stderr),
previous_processes_stderr,
)
}
}

impl CommandHelper for Command {
#[tracing::instrument(skip_all, fields(stdout = tracing::field::Empty, stderr = tracing::field::Empty))]
fn capture_outputs(
fn run_and_capture_outputs(
&mut self,
cant_fail: bool,
name: &str,
stdout: Option<&PathBuf>,
stderr: Option<&PathBuf>,
previous_processes_stderr: &[PathBuf],
) -> Result<(), TestError> {
let output = self.get_output(true)?;
let output = self.run_and_get_output(true)?;
let out_payload = String::from_utf8_lossy(&output.stdout);
if let Some(out) = stdout {
file_helper(&out_payload, out)?;
Expand Down Expand Up @@ -142,41 +158,98 @@ impl TestCase {
&self,
opts: &Opts,
bin_path: &Path,
cli_opts: &Option<Vec<String>>,
run_clippy: bool,
run_docs_stable: bool,
run_docs_nightly: bool,
cli_passthrough_opts: &Option<Vec<String>>,
) -> Result<Option<Vec<PathBuf>>, TestError> {
let (chip_dir, mut process_stderr_paths) = self
.setup_case(&opts.output_dir, bin_path, cli_opts)
.setup_case(&opts.output_dir, bin_path, cli_passthrough_opts)
.with_context(|| anyhow!("when setting up case for {}", self.name()))?;
// Run `cargo check`, capturing stderr to a log file
if !self.skip_check {
let cargo_check_err_file = path_helper_base(&chip_dir, &["cargo-check.err.log"]);
Command::new("cargo")
.arg("check")
.current_dir(&chip_dir)
.capture_outputs(
.run_and_capture_stderr(
true,
"cargo check",
None,
Some(&cargo_check_err_file),
&cargo_check_err_file,
&process_stderr_paths,
)
.with_context(|| "failed to check")?;
.with_context(|| "failed to check with cargo check")?;
process_stderr_paths.push(cargo_check_err_file);
}
if run_docs_nightly {
tracing::info!("Checking docs build with nightly");
let cargo_docs_err_file = path_helper_base(&chip_dir, &["cargo-docs-nightly.err.log"]);
// Docs are built like docs.rs would build them. Additionally, build with all features.

// Set the RUSTDOCFLAGS environment variable
let rustdocflags = "--cfg docsrs --generate-link-to-definition -Z unstable-options";
Command::new("cargo")
.arg("+nightly")
.arg("doc")
.arg("--all-features")
.env("RUSTDOCFLAGS", rustdocflags) // Set the environment variable
.current_dir(&chip_dir)
.run_and_capture_stderr(
true,
"cargo docs nightly",
&cargo_docs_err_file,
&process_stderr_paths,
)
.with_context(|| "failed to generate docs with cargo docs")?;
}
if run_docs_stable {
tracing::info!("Checking docs build with stable");
let cargo_docs_err_file = path_helper_base(&chip_dir, &["cargo-docs-stable.err.log"]);
// Docs are built like docs.rs would build them. Additionally, build with all features.
Command::new("cargo")
.arg("+stable")
.arg("doc")
.arg("--all-features")
.current_dir(&chip_dir)
.run_and_capture_stderr(
true,
"cargo docs stable",
&cargo_docs_err_file,
&process_stderr_paths,
)
.with_context(|| "failed to generate docs with cargo docs")?;
}
if run_clippy {
tracing::info!("Checking with clippy");
let cargo_clippy_err_file = path_helper_base(&chip_dir, &["cargo-clippy.err.log"]);
Command::new("cargo")
.arg("clippy")
.arg("--")
.arg("-D")
.arg("warnings")
.current_dir(&chip_dir)
.run_and_capture_stderr(
true,
"cargo clippy",
&cargo_clippy_err_file,
&process_stderr_paths,
)
.with_context(|| "failed to check with cargo clippy")?;
}
Ok(if opts.verbose > 1 {
Some(process_stderr_paths)
} else {
None
})
}

#[tracing::instrument(skip(self, output_dir, command), fields(name = %self.name(), chip_dir = tracing::field::Empty))]
#[tracing::instrument(skip(self, output_dir, passthrough_opts), fields(name = %self.name(), chip_dir = tracing::field::Empty))]

pub fn setup_case(
&self,
output_dir: &Path,
svd2rust_bin_path: &Path,
command: &Option<Vec<String>>,
passthrough_opts: &Option<Vec<String>>,
) -> Result<(PathBuf, Vec<PathBuf>), TestError> {
let user = match std::env::var("USER") {
Ok(val) => val,
Expand Down Expand Up @@ -210,10 +283,10 @@ impl TestCase {
.arg("none")
.arg("--lib")
.arg(&chip_dir)
.capture_outputs(true, "cargo init", None, None, &[])
.run_and_capture_outputs(true, "cargo init", None, None, &[])
.with_context(|| "Failed to cargo init")?;

self.prepare_chip_test_toml(&chip_dir, command)?;
self.prepare_chip_test_toml(&chip_dir, passthrough_opts)?;
let chip_svd = self.prepare_svd_file(&chip_dir)?;
self.prepare_rust_toolchain_file(&chip_dir)?;

Expand All @@ -226,7 +299,7 @@ impl TestCase {
&chip_dir,
&lib_rs_file,
&svd2rust_err_file,
command,
passthrough_opts,
)?;
process_stderr_paths.push(svd2rust_err_file);
match self.arch {
Expand Down Expand Up @@ -262,7 +335,7 @@ impl TestCase {
.arg(&new_lib_rs_file)
.arg("--outdir")
.arg(&src_dir)
.capture_outputs(
.run_and_capture_outputs(
true,
"form",
None,
Expand Down Expand Up @@ -291,7 +364,7 @@ impl TestCase {
Command::new(rustfmt_bin_path)
.arg(entry)
.args(["--edition", "2021"])
.capture_outputs(
.run_and_capture_outputs(
false,
"rustfmt",
None,
Expand Down Expand Up @@ -417,7 +490,7 @@ impl TestCase {
if let Some(opts) = self.opts.as_ref() {
base_cmd.args(opts);
}
base_cmd.current_dir(chip_dir).capture_outputs(
base_cmd.current_dir(chip_dir).run_and_capture_outputs(
true,
"svd2rust",
Some(lib_rs_file).filter(|_| {
Expand Down
Loading