xtask: expand on coverage (#2449)
* Install nightly if it is not installed * Expand on coverage * Don't swallow stdout * Apply suggestions from code review Co-authored-by: mejrs <> Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
This commit is contained in:
parent
171b38a0a1
commit
cbdd2e3b5c
|
@ -21,3 +21,4 @@ extensions/stamps/
|
||||||
pip-wheel-metadata
|
pip-wheel-metadata
|
||||||
valgrind-python.supp
|
valgrind-python.supp
|
||||||
*.pyd
|
*.pyd
|
||||||
|
lcov.info
|
||||||
|
|
|
@ -128,6 +128,29 @@ First, there are Rust-based benchmarks located in the `benches` subdirectory. As
|
||||||
|
|
||||||
Second, there is a Python-based benchmark contained in the `pytests` subdirectory. You can read more about it [here](pytests).
|
Second, there is a Python-based benchmark contained in the `pytests` subdirectory. You can read more about it [here](pytests).
|
||||||
|
|
||||||
|
## Code coverage
|
||||||
|
|
||||||
|
You can view what code is and isn't covered by PyO3's tests. We aim to have 100% coverage - please check coverage and add tests if you notice a lack of coverage!
|
||||||
|
|
||||||
|
- First, generate a `lcov.info` file with
|
||||||
|
```shell
|
||||||
|
cargo xtask coverage
|
||||||
|
```
|
||||||
|
You can install an IDE plugin to view the coverage. For example, if you use VSCode:
|
||||||
|
- Add the [coverage-gutters](https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters) plugin.
|
||||||
|
- Add these settings to VSCode's `settings.json`:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"coverage-gutters.coverageFileNames": [
|
||||||
|
"lcov.info",
|
||||||
|
"cov.xml",
|
||||||
|
"coverage.xml",
|
||||||
|
],
|
||||||
|
"coverage-gutters.showLineCoverage": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- You should now be able to see green highlights for code that is tested, and red highlights for code that is not tested.
|
||||||
|
|
||||||
## Sponsor this project
|
## Sponsor this project
|
||||||
|
|
||||||
At the moment there is no official organisation that accepts sponsorship on PyO3's behalf. If you're seeking to provide significant funding to the PyO3 ecosystem, please reach out to us on [GitHub](https://github.com/PyO3/pyo3/issues/new) or [Gitter](https://gitter.im/PyO3/Lobby) and we can discuss.
|
At the moment there is no official organisation that accepts sponsorship on PyO3's behalf. If you're seeking to provide significant funding to the PyO3 ecosystem, please reach out to us on [GitHub](https://github.com/PyO3/pyo3/issues/new) or [Gitter](https://gitter.im/PyO3/Lobby) and we can discuss.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::utils::*;
|
use crate::utils::*;
|
||||||
use anyhow::{ensure, Result};
|
use anyhow::{ensure, Result};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::process::Command;
|
use std::process::{Command, Output};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
@ -33,11 +33,19 @@ impl Default for Subcommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(StructOpt, Default)]
|
#[derive(StructOpt)]
|
||||||
pub struct CoverageOpts {
|
pub struct CoverageOpts {
|
||||||
/// Creates an lcov output instead of printing to the terminal.
|
/// Creates an lcov output file.
|
||||||
#[structopt(long)]
|
#[structopt(long, default_value = "lcov.info")]
|
||||||
pub output_lcov: Option<String>,
|
pub output_lcov: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CoverageOpts {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
output_lcov: String::from("lcov.info"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(StructOpt)]
|
#[derive(StructOpt)]
|
||||||
|
@ -116,6 +124,7 @@ impl Subcommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run a command as a child process, inheriting stdin, stdout and stderr.
|
||||||
pub fn run(command: &mut Command) -> Result<()> {
|
pub fn run(command: &mut Command) -> Result<()> {
|
||||||
let command_str = format_command(command);
|
let command_str = format_command(command);
|
||||||
let github_actions = std::env::var_os("GITHUB_ACTIONS").is_some();
|
let github_actions = std::env::var_os("GITHUB_ACTIONS").is_some();
|
||||||
|
@ -143,6 +152,28 @@ pub fn run(command: &mut Command) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Like `run`, but does not inherit stdin, stdout and stderr.
|
||||||
|
pub fn run_with_output(command: &mut Command) -> Result<Output> {
|
||||||
|
let command_str = format_command(command);
|
||||||
|
|
||||||
|
println!("Running: {}", command_str);
|
||||||
|
|
||||||
|
let output = command.output()?;
|
||||||
|
|
||||||
|
ensure! {
|
||||||
|
output.status.success(),
|
||||||
|
"process did not run successfully ({exit}): {command}:\n{stderr}",
|
||||||
|
exit = match output.status.code() {
|
||||||
|
Some(code) => format!("exit code {}", code),
|
||||||
|
None => "terminated by signal".into(),
|
||||||
|
},
|
||||||
|
command = command_str,
|
||||||
|
stderr = String::from_utf8_lossy(&output.stderr)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Installed {
|
pub struct Installed {
|
||||||
pub nox: bool,
|
pub nox: bool,
|
||||||
|
|
|
@ -45,12 +45,9 @@ pub fn run(opts: CoverageOpts) -> Result<()> {
|
||||||
|
|
||||||
crate::pytests::run(&env)?;
|
crate::pytests::run(&env)?;
|
||||||
|
|
||||||
match opts.output_lcov {
|
cli::run(
|
||||||
Some(path) => {
|
llvm_cov_command(&["--no-run", "--lcov", "--output-path", &opts.output_lcov]).envs(&env),
|
||||||
cli::run(llvm_cov_command(&["--no-run", "--lcov", "--output-path", &path]).envs(&env))?
|
)?;
|
||||||
}
|
|
||||||
None => cli::run(llvm_cov_command(&["--no-run", "--summary-only"]).envs(&env))?,
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -73,7 +70,9 @@ fn llvm_cov_command(args: &[&str]) -> Command {
|
||||||
fn get_coverage_env() -> Result<HashMap<String, String>> {
|
fn get_coverage_env() -> Result<HashMap<String, String>> {
|
||||||
let mut env = HashMap::new();
|
let mut env = HashMap::new();
|
||||||
|
|
||||||
let output = String::from_utf8(llvm_cov_command(&["show-env"]).output()?.stdout)?;
|
let output = cli::run_with_output(&mut llvm_cov_command(&["show-env"])).context("Unable to run llvm-cov. If it is not installed, you can install it with `cargo install cargo-llvm-cov`.")?;
|
||||||
|
|
||||||
|
let output = std::str::from_utf8(&output.stdout)?;
|
||||||
|
|
||||||
for line in output.trim().split('\n') {
|
for line in output.trim().split('\n') {
|
||||||
let (key, value) = split_once(line, '=')
|
let (key, value) = split_once(line, '=')
|
||||||
|
|
|
@ -45,6 +45,14 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
.arg("--quiet"),
|
.arg("--quiet"),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// If the nightly toolchain is not installed, this will install it
|
||||||
|
cli::run(
|
||||||
|
Command::new("rustup")
|
||||||
|
.arg("toolchain")
|
||||||
|
.arg("install")
|
||||||
|
.arg("nightly"),
|
||||||
|
)?;
|
||||||
|
|
||||||
cli::run(
|
cli::run(
|
||||||
Command::new("cargo")
|
Command::new("cargo")
|
||||||
.arg("+nightly")
|
.arg("+nightly")
|
||||||
|
|
Loading…
Reference in New Issue