mirror of
https://github.com/Devolutions/IronRDP.git
synced 2025-07-07 17:45:01 +00:00
ci: add web client check job
This commit is contained in:
parent
124c3aa251
commit
493e8f13a4
13 changed files with 507 additions and 360 deletions
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
|
@ -67,7 +67,7 @@ jobs:
|
|||
cargo xtask wasm install
|
||||
|
||||
- name: Check
|
||||
run: cargo xtask check wasm
|
||||
run: cargo xtask wasm check
|
||||
|
||||
tests:
|
||||
name: Tests [${{ matrix.os }}]
|
||||
|
@ -124,3 +124,27 @@ jobs:
|
|||
# Simply run all fuzz targets for a few seconds, just making there is nothing obviously wrong at a quick glance
|
||||
- name: Fuzz
|
||||
run: cargo xtask fuzz run
|
||||
|
||||
web:
|
||||
name: Web Client
|
||||
runs-on: ubuntu-20.04
|
||||
needs: formatting
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry/
|
||||
~/.cargo/git/
|
||||
./target/
|
||||
./.cargo/local_root/
|
||||
key: ${{ runner.os }}-${{ github.job }}-${{ hashFiles('fuzz/Cargo.lock') }}
|
||||
|
||||
- name: Prepare runner
|
||||
run: cargo xtask web install
|
||||
|
||||
- name: Check
|
||||
run: cargo xtask web check
|
||||
|
|
|
@ -33,7 +33,7 @@ Pay attention to the "**Architecture Invariant**" sections.
|
|||
|
||||
**Architectural Invariant**: no non-essential dependency is allowed.
|
||||
|
||||
**Architectural Invariant**: must be `#[no_std]`-compatible (eventually using the `alloc` crate). Usage of the standard
|
||||
**Architectural Invariant**: must be `#[no_std]`-compatible (optionally using the `alloc` crate). Usage of the standard
|
||||
library must be opt-in through a feature flag called `std` that is enabled by default. When the `alloc` crate is optional,
|
||||
a feature flag called `alloc` must exist to enable its use.
|
||||
|
||||
|
|
11
fuzz/Cargo.lock
generated
11
fuzz/Cargo.lock
generated
|
@ -282,6 +282,7 @@ dependencies = [
|
|||
"num-derive",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"pkcs1",
|
||||
"sha1",
|
||||
"tap",
|
||||
"thiserror",
|
||||
|
@ -398,6 +399,16 @@ version = "1.17.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "pkcs1"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
|
|
36
xtask/src/check.rs
Normal file
36
xtask/src/check.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
pub fn fmt(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FORMATTING");
|
||||
|
||||
let output = cmd!(sh, "{CARGO} fmt --all -- --check").ignore_status().output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
anyhow::bail!("Bad formatting, please run 'cargo +stable fmt --all'");
|
||||
}
|
||||
|
||||
println!("All good!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn lints(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("LINTS");
|
||||
cmd!(sh, "{CARGO} clippy --workspace --locked -- -D warnings").run()?;
|
||||
println!("All good!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn tests_compile(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("TESTS-COMPILE");
|
||||
cmd!(sh, "{CARGO} test --workspace --locked --no-run").run()?;
|
||||
println!("All good!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn tests_run(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("TESTS-RUN");
|
||||
cmd!(sh, "{CARGO} test --workspace --locked").run()?;
|
||||
println!("All good!");
|
||||
Ok(())
|
||||
}
|
19
xtask/src/clean.rs
Normal file
19
xtask/src/clean.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
pub fn workspace(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("CLEAN");
|
||||
|
||||
cmd!(sh, "{CARGO} clean").run()?;
|
||||
|
||||
println!("Remove wasm package folder…");
|
||||
sh.remove_path("./crates/ironrdp-web/pkg")?;
|
||||
println!("Done.");
|
||||
|
||||
println!("Remove npm folders…");
|
||||
sh.remove_path("./web-client/iron-remote-gui/node_modules")?;
|
||||
sh.remove_path("./web-client/iron-remote-gui/dist")?;
|
||||
sh.remove_path("./web-client/iron-svelte-client/node_modules")?;
|
||||
println!("Done.");
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -8,22 +8,25 @@ FLAGS:
|
|||
-h, --help Prints help information
|
||||
|
||||
TASKS:
|
||||
check [all] Runs all checks
|
||||
check fmt Checks formatting
|
||||
check lints Checks lints
|
||||
check tests Runs tests
|
||||
check wasm Ensures wasm module is compatible for the web
|
||||
ci Runs all checks required on CI
|
||||
clean Clean workspace
|
||||
coverage install Install dependencies required to generate the coverage report
|
||||
coverage report Generate code-coverage data using tests and fuzz targets
|
||||
fuzz corpus-fetch Minify fuzzing corpus
|
||||
fuzz corpus-min Minify fuzzing corpus
|
||||
fuzz corpus-push Minify fuzzing corpus
|
||||
fuzz install Install dependencies required for fuzzing
|
||||
fuzz run [--duration] [--target] Fuzz a specific target if any or all targets for a limited duration (default is 5s)
|
||||
svelte-run Runs SvelteKit-based standalone Web Client
|
||||
wasm install Install dependencies required to build the wasm target
|
||||
check fmt Check formatting
|
||||
check lints Check lints
|
||||
check tests [--no-run] Compile tests and, unless specified otherwise, run them
|
||||
check wasm Ensure WASM module is compatible for the web
|
||||
ci Run all checks required on CI
|
||||
clean Clean workspace
|
||||
coverage install Install dependencies required to generate the coverage report
|
||||
coverage report Generate code-coverage data using tests and fuzz targets
|
||||
fuzz corpus-fetch Fetch fuzzing corpus from Azure storage
|
||||
fuzz corpus-min Minify fuzzing corpus
|
||||
fuzz corpus-push Push fuzzing corpus to Azure storage
|
||||
fuzz install Install dependencies required for fuzzing
|
||||
fuzz run [--duration <SECONDS>] [--target <NAME>]
|
||||
Fuzz a specific target if any or all targets for a limited duration (default is 5s)
|
||||
wasm check Ensure WASM module is compatible for the web
|
||||
wasm install Install dependencies required to build the WASM target
|
||||
web check Ensure Web Client is building without error
|
||||
web install Install dependencies required to build and run Web Client
|
||||
web run Run SvelteKit-based standalone Web Client
|
||||
";
|
||||
|
||||
pub fn print_help() {
|
||||
|
@ -31,14 +34,16 @@ pub fn print_help() {
|
|||
}
|
||||
|
||||
pub enum Action {
|
||||
CheckAll,
|
||||
ShowHelp,
|
||||
CheckFmt,
|
||||
CheckLints,
|
||||
CheckTests,
|
||||
CheckWasm,
|
||||
CheckTests {
|
||||
no_run: bool,
|
||||
},
|
||||
Ci,
|
||||
Clean,
|
||||
CoverageInstall,
|
||||
CoverageReport,
|
||||
CovInstall,
|
||||
CovReport,
|
||||
FuzzCorpusFetch,
|
||||
FuzzCorpusMin,
|
||||
FuzzCorpusPush,
|
||||
|
@ -47,9 +52,11 @@ pub enum Action {
|
|||
duration: Option<u32>,
|
||||
target: Option<String>,
|
||||
},
|
||||
ShowHelp,
|
||||
SvelteRun,
|
||||
WasmCheck,
|
||||
WasmInstall,
|
||||
WebCheck,
|
||||
WebInstall,
|
||||
WebRun,
|
||||
}
|
||||
|
||||
pub fn parse_args() -> anyhow::Result<Action> {
|
||||
|
@ -59,26 +66,28 @@ pub fn parse_args() -> anyhow::Result<Action> {
|
|||
Action::ShowHelp
|
||||
} else {
|
||||
match args.subcommand()?.as_deref() {
|
||||
Some("ci") => Action::CheckAll,
|
||||
Some("check") => match args.subcommand()?.as_deref() {
|
||||
Some("all") | None => Action::CheckAll,
|
||||
Some("fmt") => Action::CheckFmt,
|
||||
Some("lints") => Action::CheckLints,
|
||||
Some("tests") => Action::CheckTests,
|
||||
Some("wasm") => Action::CheckWasm,
|
||||
Some(_) => anyhow::bail!("unknown check action"),
|
||||
Some("tests") => Action::CheckTests {
|
||||
no_run: args.contains("--no-run"),
|
||||
},
|
||||
Some(unknown) => anyhow::bail!("unknown check action: {unknown}"),
|
||||
None => Action::ShowHelp,
|
||||
},
|
||||
Some("ci") => Action::Ci,
|
||||
Some("clean") => Action::Clean,
|
||||
Some("coverage") => match args.subcommand()?.as_deref() {
|
||||
Some("install") => Action::CoverageInstall,
|
||||
Some("report") => Action::CoverageReport,
|
||||
Some(_) => anyhow::bail!("unknown coverage action"),
|
||||
Some("cov") => match args.subcommand()?.as_deref() {
|
||||
Some("install") => Action::CovInstall,
|
||||
Some("report") => Action::CovReport,
|
||||
Some(unknown) => anyhow::bail!("unknown coverage action: {unknown}"),
|
||||
None => Action::ShowHelp,
|
||||
},
|
||||
Some("fuzz") => match args.subcommand()?.as_deref() {
|
||||
Some("corpus-fetch") => Action::FuzzCorpusFetch,
|
||||
Some("corpus-min") => Action::FuzzCorpusMin,
|
||||
Some("corpus-push") => Action::FuzzCorpusPush,
|
||||
Some("install") => Action::FuzzInstall,
|
||||
Some("run") => Action::FuzzRun {
|
||||
duration: args.opt_value_from_str("--duration")?,
|
||||
target: args.opt_value_from_str("--target")?,
|
||||
|
@ -87,13 +96,19 @@ pub fn parse_args() -> anyhow::Result<Action> {
|
|||
duration: None,
|
||||
target: None,
|
||||
},
|
||||
Some("install") => Action::FuzzInstall,
|
||||
Some(_) => anyhow::bail!("unknown fuzz action"),
|
||||
Some(unknown) => anyhow::bail!("unknown fuzz action: {unknown}"),
|
||||
},
|
||||
Some("svelte-run") => Action::SvelteRun,
|
||||
Some("wasm") => match args.subcommand()?.as_deref() {
|
||||
Some("check") => Action::WasmCheck,
|
||||
Some("install") => Action::WasmInstall,
|
||||
Some(_) => anyhow::bail!("unknown wasm action"),
|
||||
Some(unknown) => anyhow::bail!("unknown wasm action: {unknown}"),
|
||||
None => Action::ShowHelp,
|
||||
},
|
||||
Some("web") => match args.subcommand()?.as_deref() {
|
||||
Some("check") => Action::WebCheck,
|
||||
Some("install") => Action::WebInstall,
|
||||
Some("run") => Action::WebRun,
|
||||
Some(unknown) => anyhow::bail!("unknown web action: {unknown}"),
|
||||
None => Action::ShowHelp,
|
||||
},
|
||||
None | Some(_) => Action::ShowHelp,
|
||||
|
|
113
xtask/src/cov.rs
Normal file
113
xtask/src/cov.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
pub fn install(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("COVERAGE-INSTALL");
|
||||
|
||||
cmd!(sh, "rustup install nightly --profile=minimal").run()?;
|
||||
cmd!(sh, "rustup component add --toolchain nightly llvm-tools-preview").run()?;
|
||||
cmd!(sh, "rustup component add llvm-tools-preview").run()?;
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"{CARGO} install --debug --locked --root {LOCAL_CARGO_ROOT} cargo-fuzz@{CARGO_FUZZ_VERSION}"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"{CARGO} install --debug --locked --root {LOCAL_CARGO_ROOT} grcov@{GRCOV_VERSION}"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn report(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("COVERAGE-REPORT");
|
||||
|
||||
println!("Remove leftovers");
|
||||
sh.remove_path("./fuzz/coverage/")?;
|
||||
sh.remove_path("./coverage/")?;
|
||||
|
||||
sh.create_dir("./coverage/binaries")?;
|
||||
|
||||
{
|
||||
// Fuzz coverage
|
||||
|
||||
let _guard = sh.push_dir("./fuzz");
|
||||
|
||||
cmd!(sh, "{CARGO} clean").run()?;
|
||||
|
||||
for target in FUZZ_TARGETS {
|
||||
cmd!(sh, "../{LOCAL_CARGO_ROOT}/bin/cargo-fuzz coverage {target}")
|
||||
.env("RUSTUP_TOOLCHAIN", "nightly")
|
||||
.run()?;
|
||||
}
|
||||
|
||||
cmd!(sh, "cp -r ./target ../coverage/binaries/").run()?;
|
||||
}
|
||||
|
||||
{
|
||||
// Test coverage
|
||||
|
||||
cmd!(sh, "{CARGO} clean").run()?;
|
||||
|
||||
cmd!(sh, "rustup run nightly cargo test --workspace")
|
||||
.env("CARGO_INCREMENTAL", "0")
|
||||
.env("RUSTFLAGS", "-C instrument-coverage")
|
||||
.env("LLVM_PROFILE_FILE", "./coverage/default-%m-%p.profraw")
|
||||
.run()?;
|
||||
|
||||
cmd!(sh, "cp -r ./target/debug ./coverage/binaries/").run()?;
|
||||
}
|
||||
|
||||
sh.create_dir("./docs")?;
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"./{LOCAL_CARGO_ROOT}/bin/grcov . ./fuzz
|
||||
--source-dir .
|
||||
--binary-path ./coverage/binaries/
|
||||
--output-type html
|
||||
--branch
|
||||
--ignore-not-existing
|
||||
--ignore xtask/*
|
||||
--ignore src/*
|
||||
--ignore **/tests/*
|
||||
--ignore crates/*-generators/*
|
||||
--ignore crates/web/*
|
||||
--ignore crates/client/*
|
||||
--ignore crates/glutin-renderer/*
|
||||
--ignore crates/glutin-client/*
|
||||
--ignore crates/replay-client/*
|
||||
--ignore crates/tls/*
|
||||
--ignore fuzz/fuzz_targets/*
|
||||
--ignore target/*
|
||||
--ignore fuzz/target/*
|
||||
--excl-start begin-no-coverage
|
||||
--excl-stop end-no-coverage
|
||||
-o ./docs/coverage"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
println!("Code coverage report available in `./docs/coverage` folder");
|
||||
|
||||
println!("Clean up");
|
||||
|
||||
sh.remove_path("./coverage/")?;
|
||||
sh.remove_path("./fuzz/coverage/")?;
|
||||
sh.remove_path("./xtask/coverage/")?;
|
||||
|
||||
sh.read_dir("./crates")?
|
||||
.into_iter()
|
||||
.try_for_each(|crate_path| -> xshell::Result<()> {
|
||||
for path in sh.read_dir(crate_path)? {
|
||||
if path.ends_with("coverage") {
|
||||
sh.remove_path(path)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
93
xtask/src/fuzz.rs
Normal file
93
xtask/src/fuzz.rs
Normal file
|
@ -0,0 +1,93 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
pub fn corpus_minify(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FUZZ-CORPUS-MINIFY");
|
||||
|
||||
let _guard = sh.push_dir("./fuzz");
|
||||
|
||||
for target in FUZZ_TARGETS {
|
||||
cmd!(sh, "../{LOCAL_CARGO_ROOT}/bin/cargo-fuzz cmin {target}")
|
||||
.env("RUSTUP_TOOLCHAIN", "nightly")
|
||||
.run()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn corpus_fetch(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FUZZ-CORPUS-FETCH");
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"az storage blob download-batch --account-name fuzzingcorpus --source ironrdp --destination fuzz --output none"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn corpus_push(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FUZZ-CORPUS-PUSH");
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"az storage blob sync --account-name fuzzingcorpus --container ironrdp --source fuzz/corpus --destination corpus --delete-destination true --output none"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"az storage blob sync --account-name fuzzingcorpus --container ironrdp --source fuzz/artifacts --destination artifacts --delete-destination true --output none"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn install(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FUZZ-INSTALL");
|
||||
|
||||
let cargo_fuzz_path: std::path::PathBuf = [LOCAL_CARGO_ROOT, "bin", "cargo-fuzz"].iter().collect();
|
||||
|
||||
if !sh.path_exists(cargo_fuzz_path) {
|
||||
// Install in debug because it's faster to compile and we don't need execution speed anyway.
|
||||
// cargo-fuzz version is pinned so we don’t get different versions without intervention.
|
||||
cmd!(
|
||||
sh,
|
||||
"{CARGO} install --debug --locked --root {LOCAL_CARGO_ROOT} cargo-fuzz@{CARGO_FUZZ_VERSION}"
|
||||
)
|
||||
.run()?;
|
||||
}
|
||||
|
||||
cmd!(sh, "rustup install nightly --profile=minimal").run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run(sh: &Shell, duration: Option<u32>, target: Option<String>) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FUZZ-RUN");
|
||||
|
||||
let _guard = sh.push_dir("./fuzz");
|
||||
|
||||
let duration = duration.unwrap_or(5).to_string();
|
||||
let target_from_user = target.as_deref().map(|value| [value]);
|
||||
|
||||
let targets = if let Some(targets) = &target_from_user {
|
||||
targets
|
||||
} else {
|
||||
FUZZ_TARGETS
|
||||
};
|
||||
|
||||
for target in targets {
|
||||
cmd!(
|
||||
sh,
|
||||
"../{LOCAL_CARGO_ROOT}/bin/cargo-fuzz run {target} -- -max_total_time={duration}"
|
||||
)
|
||||
.env("RUSTUP_TOOLCHAIN", "nightly")
|
||||
.run()?;
|
||||
}
|
||||
|
||||
println!("All good!");
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,6 +1,12 @@
|
|||
mod check;
|
||||
mod clean;
|
||||
mod cli;
|
||||
mod cov;
|
||||
mod fuzz;
|
||||
mod prelude;
|
||||
mod section;
|
||||
mod tasks;
|
||||
mod wasm;
|
||||
mod web;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
@ -23,27 +29,38 @@ fn main() -> anyhow::Result<()> {
|
|||
|
||||
match action {
|
||||
Action::ShowHelp => cli::print_help(),
|
||||
Action::CheckAll => {
|
||||
tasks::check_formatting(&sh)?;
|
||||
tasks::run_tests(&sh)?;
|
||||
tasks::check_lints(&sh)?;
|
||||
tasks::check_wasm(&sh)?;
|
||||
tasks::fuzz_run(&sh, None, None)?;
|
||||
Action::CheckFmt => check::fmt(&sh)?,
|
||||
Action::CheckLints => check::lints(&sh)?,
|
||||
Action::CheckTests { no_run } => {
|
||||
if no_run {
|
||||
check::tests_compile(&sh)?;
|
||||
} else {
|
||||
check::tests_run(&sh)?;
|
||||
}
|
||||
}
|
||||
Action::CheckFmt => tasks::check_formatting(&sh)?,
|
||||
Action::CheckLints => tasks::check_lints(&sh)?,
|
||||
Action::CheckTests => tasks::run_tests(&sh)?,
|
||||
Action::CheckWasm => tasks::check_wasm(&sh)?,
|
||||
Action::Clean => tasks::clean_workspace(&sh)?,
|
||||
Action::CoverageInstall => tasks::coverage_install(&sh)?,
|
||||
Action::CoverageReport => tasks::coverage_report(&sh)?,
|
||||
Action::FuzzCorpusFetch => tasks::fuzz_corpus_fetch(&sh)?,
|
||||
Action::FuzzCorpusMin => tasks::fuzz_corpus_minify(&sh)?,
|
||||
Action::FuzzCorpusPush => tasks::fuzz_corpus_push(&sh)?,
|
||||
Action::FuzzInstall => tasks::fuzz_install(&sh)?,
|
||||
Action::FuzzRun { duration, target } => tasks::fuzz_run(&sh, duration, target)?,
|
||||
Action::SvelteRun => tasks::svelte_run(&sh)?,
|
||||
Action::WasmInstall => tasks::wasm_install(&sh)?,
|
||||
Action::Ci => {
|
||||
check::fmt(&sh)?;
|
||||
check::tests_compile(&sh)?;
|
||||
check::tests_run(&sh)?;
|
||||
check::lints(&sh)?;
|
||||
wasm::check(&sh)?;
|
||||
fuzz::run(&sh, None, None)?;
|
||||
web::install(&sh)?;
|
||||
web::check(&sh)?;
|
||||
}
|
||||
Action::Clean => clean::workspace(&sh)?,
|
||||
Action::CovInstall => cov::install(&sh)?,
|
||||
Action::CovReport => cov::report(&sh)?,
|
||||
Action::FuzzCorpusFetch => fuzz::corpus_fetch(&sh)?,
|
||||
Action::FuzzCorpusMin => fuzz::corpus_minify(&sh)?,
|
||||
Action::FuzzCorpusPush => fuzz::corpus_push(&sh)?,
|
||||
Action::FuzzInstall => fuzz::install(&sh)?,
|
||||
Action::FuzzRun { duration, target } => fuzz::run(&sh, duration, target)?,
|
||||
Action::WasmCheck => wasm::check(&sh)?,
|
||||
Action::WasmInstall => wasm::install(&sh)?,
|
||||
Action::WebCheck => web::check(&sh)?,
|
||||
Action::WebInstall => web::install(&sh)?,
|
||||
Action::WebRun => web::run(&sh)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
15
xtask/src/prelude.rs
Normal file
15
xtask/src/prelude.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
pub use anyhow::Context as _;
|
||||
pub use xshell::{cmd, Shell};
|
||||
|
||||
pub use crate::section::Section;
|
||||
|
||||
pub const CARGO: &str = env!("CARGO");
|
||||
pub const LOCAL_CARGO_ROOT: &str = ".cargo/local_root/";
|
||||
|
||||
pub const CARGO_FUZZ_VERSION: &str = "0.11.2";
|
||||
pub const GRCOV_VERSION: &str = "0.8.18";
|
||||
pub const WASM_PACK_VERSION: &str = "0.11.1";
|
||||
|
||||
pub const WASM_PACKAGES: &[&str] = &["ironrdp-web"];
|
||||
|
||||
pub const FUZZ_TARGETS: &[&str] = &["pdu_decoding", "rle_decompression", "bitmap_stream"];
|
|
@ -1,302 +1 @@
|
|||
use anyhow::Context as _;
|
||||
use xshell::{cmd, Shell};
|
||||
|
||||
use crate::section::Section;
|
||||
|
||||
const CARGO: &str = env!("CARGO");
|
||||
const CARGO_FUZZ_VERSION: &str = "0.11.2";
|
||||
const GRCOV_VERSION: &str = "0.8.18";
|
||||
const LOCAL_CARGO_ROOT: &str = ".cargo/local_root/";
|
||||
const WASM_PACKAGES: &[&str] = &["ironrdp-web"];
|
||||
const FUZZ_TARGETS: &[&str] = &["pdu_decoding", "rle_decompression", "bitmap_stream"];
|
||||
|
||||
pub fn check_formatting(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FORMATTING");
|
||||
|
||||
let output = cmd!(sh, "{CARGO} fmt --all -- --check").ignore_status().output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
anyhow::bail!("Bad formatting, please run 'cargo +stable fmt --all'");
|
||||
}
|
||||
|
||||
println!("All good!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_tests(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("TESTS");
|
||||
cmd!(sh, "{CARGO} test --workspace --locked").run()?;
|
||||
println!("All good!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_lints(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("LINTS");
|
||||
cmd!(sh, "{CARGO} clippy --workspace --locked -- -D warnings").run()?;
|
||||
println!("All good!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_wasm(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("WASM-CHECK");
|
||||
|
||||
for package in WASM_PACKAGES {
|
||||
println!("Check {package}");
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"{CARGO} rustc --locked --target wasm32-unknown-unknown --package {package} --lib --crate-type cdylib"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
// When building a library, `-` in the artifact name are replaced by `_`
|
||||
let artifact_name = format!("{}.wasm", package.replace('-', "_"));
|
||||
|
||||
let output = cmd!(sh, "wasm2wat ./target/wasm32-unknown-unknown/debug/{artifact_name}").output()?;
|
||||
let stdout = std::str::from_utf8(&output.stdout).context("wasm2wat output is not valid UTF-8")?;
|
||||
|
||||
if stdout.contains("import \"env\"") {
|
||||
anyhow::bail!("Found undefined symbols in generated wasm file");
|
||||
}
|
||||
}
|
||||
|
||||
println!("All good!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn fuzz_run(sh: &Shell, duration: Option<u32>, target: Option<String>) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FUZZ-RUN");
|
||||
|
||||
let _guard = sh.push_dir("./fuzz");
|
||||
|
||||
let duration = duration.unwrap_or(5).to_string();
|
||||
let target_from_user = target.as_deref().map(|value| [value]);
|
||||
|
||||
let targets = if let Some(targets) = &target_from_user {
|
||||
targets
|
||||
} else {
|
||||
FUZZ_TARGETS
|
||||
};
|
||||
|
||||
for target in targets {
|
||||
cmd!(
|
||||
sh,
|
||||
"../{LOCAL_CARGO_ROOT}/bin/cargo-fuzz run {target} -- -max_total_time={duration}"
|
||||
)
|
||||
.env("RUSTUP_TOOLCHAIN", "nightly")
|
||||
.run()?;
|
||||
}
|
||||
|
||||
println!("All good!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn fuzz_corpus_minify(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FUZZ-CORPUS-MINIFY");
|
||||
|
||||
let _guard = sh.push_dir("./fuzz");
|
||||
|
||||
for target in FUZZ_TARGETS {
|
||||
cmd!(sh, "../{LOCAL_CARGO_ROOT}/bin/cargo-fuzz cmin {target}")
|
||||
.env("RUSTUP_TOOLCHAIN", "nightly")
|
||||
.run()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn fuzz_corpus_fetch(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FUZZ-CORPUS-FETCH");
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"az storage blob download-batch --account-name fuzzingcorpus --source ironrdp --destination fuzz --output none"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn fuzz_corpus_push(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FUZZ-CORPUS-PUSH");
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"az storage blob sync --account-name fuzzingcorpus --container ironrdp --source fuzz/corpus --destination corpus --delete-destination true --output none"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"az storage blob sync --account-name fuzzingcorpus --container ironrdp --source fuzz/artifacts --destination artifacts --delete-destination true --output none"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn fuzz_install(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("FUZZ-INSTALL");
|
||||
|
||||
let cargo_fuzz_path: std::path::PathBuf = [LOCAL_CARGO_ROOT, "bin", "cargo-fuzz"].iter().collect();
|
||||
|
||||
if !sh.path_exists(cargo_fuzz_path) {
|
||||
// Install in debug because it's faster to compile and we don't need execution speed anyway.
|
||||
// cargo-fuzz version is pinned so we don’t get different versions without intervention.
|
||||
cmd!(
|
||||
sh,
|
||||
"{CARGO} install --debug --locked --root {LOCAL_CARGO_ROOT} cargo-fuzz@{CARGO_FUZZ_VERSION}"
|
||||
)
|
||||
.run()?;
|
||||
}
|
||||
|
||||
cmd!(sh, "rustup install nightly --profile=minimal").run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn svelte_run(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("SVELTE-RUN");
|
||||
|
||||
{
|
||||
let _guard = sh.push_dir("./web-client/iron-remote-gui");
|
||||
cmd!(sh, "npm install").run()?;
|
||||
}
|
||||
|
||||
{
|
||||
let _guard = sh.push_dir("./web-client/iron-svelte-client");
|
||||
cmd!(sh, "npm install").run()?;
|
||||
cmd!(sh, "npm run dev-all").run()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn coverage_install(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("COVERAGE-INSTALL");
|
||||
|
||||
cmd!(sh, "rustup install nightly --profile=minimal").run()?;
|
||||
cmd!(sh, "rustup component add --toolchain nightly llvm-tools-preview").run()?;
|
||||
cmd!(sh, "rustup component add llvm-tools-preview").run()?;
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"{CARGO} install --debug --locked --root {LOCAL_CARGO_ROOT} cargo-fuzz@{CARGO_FUZZ_VERSION}"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"{CARGO} install --debug --locked --root {LOCAL_CARGO_ROOT} grcov@{GRCOV_VERSION}"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn coverage_report(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("COVERAGE-REPORT");
|
||||
|
||||
println!("Remove leftovers");
|
||||
sh.remove_path("./fuzz/coverage/")?;
|
||||
sh.remove_path("./coverage/")?;
|
||||
|
||||
sh.create_dir("./coverage/binaries")?;
|
||||
|
||||
{
|
||||
// Fuzz coverage
|
||||
|
||||
let _guard = sh.push_dir("./fuzz");
|
||||
|
||||
cmd!(sh, "{CARGO} clean").run()?;
|
||||
|
||||
for target in FUZZ_TARGETS {
|
||||
cmd!(sh, "../{LOCAL_CARGO_ROOT}/bin/cargo-fuzz coverage {target}")
|
||||
.env("RUSTUP_TOOLCHAIN", "nightly")
|
||||
.run()?;
|
||||
}
|
||||
|
||||
cmd!(sh, "cp -r ./target ../coverage/binaries/").run()?;
|
||||
}
|
||||
|
||||
{
|
||||
// Test coverage
|
||||
|
||||
cmd!(sh, "{CARGO} clean").run()?;
|
||||
|
||||
cmd!(sh, "rustup run nightly cargo test --workspace")
|
||||
.env("CARGO_INCREMENTAL", "0")
|
||||
.env("RUSTFLAGS", "-C instrument-coverage")
|
||||
.env("LLVM_PROFILE_FILE", "./coverage/default-%m-%p.profraw")
|
||||
.run()?;
|
||||
|
||||
cmd!(sh, "cp -r ./target/debug ./coverage/binaries/").run()?;
|
||||
}
|
||||
|
||||
sh.create_dir("./docs")?;
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"./{LOCAL_CARGO_ROOT}/bin/grcov . ./fuzz
|
||||
--source-dir .
|
||||
--binary-path ./coverage/binaries/
|
||||
--output-type html
|
||||
--branch
|
||||
--ignore-not-existing
|
||||
--ignore xtask/*
|
||||
--ignore src/*
|
||||
--ignore **/tests/*
|
||||
--ignore crates/*-generators/*
|
||||
--ignore crates/web/*
|
||||
--ignore crates/client/*
|
||||
--ignore crates/glutin-renderer/*
|
||||
--ignore crates/glutin-client/*
|
||||
--ignore crates/replay-client/*
|
||||
--ignore crates/tls/*
|
||||
--ignore fuzz/fuzz_targets/*
|
||||
--ignore target/*
|
||||
--ignore fuzz/target/*
|
||||
--excl-start begin-no-coverage
|
||||
--excl-stop end-no-coverage
|
||||
-o ./docs/coverage"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
println!("Code coverage report available in `./docs/coverage` folder");
|
||||
|
||||
println!("Clean up");
|
||||
|
||||
sh.remove_path("./coverage/")?;
|
||||
sh.remove_path("./fuzz/coverage/")?;
|
||||
sh.remove_path("./xtask/coverage/")?;
|
||||
|
||||
sh.read_dir("./crates")?
|
||||
.into_iter()
|
||||
.try_for_each(|crate_path| -> xshell::Result<()> {
|
||||
for path in sh.read_dir(crate_path)? {
|
||||
if path.ends_with("coverage") {
|
||||
sh.remove_path(path)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clean_workspace(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("CLEAN");
|
||||
cmd!(sh, "{CARGO} clean").run()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn wasm_install(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("WASM-INSTALL");
|
||||
|
||||
cmd!(sh, "rustup target add wasm32-unknown-unknown").run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
37
xtask/src/wasm.rs
Normal file
37
xtask/src/wasm.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
pub fn check(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("WASM-CHECK");
|
||||
|
||||
for package in WASM_PACKAGES {
|
||||
println!("Check {package}");
|
||||
|
||||
cmd!(
|
||||
sh,
|
||||
"{CARGO} rustc --locked --target wasm32-unknown-unknown --package {package} --lib --crate-type cdylib"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
// When building a library, `-` in the artifact name are replaced by `_`
|
||||
let artifact_name = format!("{}.wasm", package.replace('-', "_"));
|
||||
|
||||
let output = cmd!(sh, "wasm2wat ./target/wasm32-unknown-unknown/debug/{artifact_name}").output()?;
|
||||
let stdout = std::str::from_utf8(&output.stdout).context("wasm2wat output is not valid UTF-8")?;
|
||||
|
||||
if stdout.contains("import \"env\"") {
|
||||
anyhow::bail!("Found undefined symbols in generated wasm file");
|
||||
}
|
||||
}
|
||||
|
||||
println!("All good!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn install(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("WASM-INSTALL");
|
||||
|
||||
cmd!(sh, "rustup target add wasm32-unknown-unknown").run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
68
xtask/src/web.rs
Normal file
68
xtask/src/web.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
const IRON_REMOTE_GUI_PREFIX: &str = "./web-client/iron-remote-gui";
|
||||
const IRON_SVELTE_CLIENT_PREFIX: &str = "./web-client/iron-svelte-client";
|
||||
|
||||
pub fn install(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("WEB-INSTALL");
|
||||
|
||||
cmd!(sh, "npm install --prefix {IRON_REMOTE_GUI_PREFIX}").run()?;
|
||||
cmd!(sh, "npm install --prefix {IRON_SVELTE_CLIENT_PREFIX}").run()?;
|
||||
|
||||
let wasm_pack_path: std::path::PathBuf = [LOCAL_CARGO_ROOT, "bin", "wasm-pack"].iter().collect();
|
||||
|
||||
if !sh.path_exists(wasm_pack_path) {
|
||||
// Install in debug because it's faster to compile and we don't need execution speed anyway.
|
||||
// cargo-fuzz version is pinned so we don’t get different versions without intervention.
|
||||
cmd!(
|
||||
sh,
|
||||
"{CARGO} install
|
||||
--debug --locked
|
||||
--root {LOCAL_CARGO_ROOT}
|
||||
--no-default-features
|
||||
--features sys-openssl
|
||||
wasm-pack@{WASM_PACK_VERSION}"
|
||||
)
|
||||
.run()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("WEB-CHECK");
|
||||
|
||||
build(sh, true)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run(sh: &Shell) -> anyhow::Result<()> {
|
||||
let _s = Section::new("WEB-RUN");
|
||||
|
||||
build(sh, false)?;
|
||||
|
||||
cmd!(sh, "npm run dev-no-wasm --prefix {IRON_SVELTE_CLIENT_PREFIX}").run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build(sh: &Shell, wasm_pack_dev: bool) -> anyhow::Result<()> {
|
||||
{
|
||||
let _guard = sh.push_dir("./crates/ironrdp-web");
|
||||
|
||||
if wasm_pack_dev {
|
||||
cmd!(sh, "../../{LOCAL_CARGO_ROOT}/bin/wasm-pack build --dev --target web").run()?;
|
||||
} else {
|
||||
cmd!(sh, "../../{LOCAL_CARGO_ROOT}/bin/wasm-pack build --target web").run()?;
|
||||
}
|
||||
}
|
||||
|
||||
cmd!(sh, "npm run check --prefix {IRON_REMOTE_GUI_PREFIX}").run()?;
|
||||
cmd!(sh, "npm run build-alone --prefix {IRON_REMOTE_GUI_PREFIX}").run()?;
|
||||
|
||||
// cmd!(sh, "npm run check --prefix {IRON_SVELTE_CLIENT_PREFIX}").run()?; // FIXME: failing on master
|
||||
cmd!(sh, "npm run build-no-wasm --prefix {IRON_SVELTE_CLIENT_PREFIX}").run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue