diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db5e5df80..cadd41fb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,14 +108,15 @@ jobs: - name: Checkout sources uses: actions/checkout@v4 - - name: Check tokio-console README images - run: > - for filename in - $(grep 'https://raw.githubusercontent.com/tokio-rs/console/main/assets' tokio-console/ README.md - | perl -n -e '/(tokio-console-[\d\.]+\/\w+\.png)/; print "$1\n"' - ); do - ls -l assets/$filename; - done + - name: Install ${{ matrix.rust }} toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + + - uses: Swatinem/rust-cache@v2 + + - name: Run xtask check-docs-images + run: cargo run --bin xtask -- check-docs-images grpc_web: name: gRPC-web Example diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 74fc81d88..1296c6380 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -12,3 +12,4 @@ tonic-build = { version = "0.12", default-features = false, features = [ ] } clap = { version = "~4.5.4", features = ["derive"] } color-eyre = "0.6" +regex = "1.11.0" diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 1483690b2..63701821c 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,9 +1,16 @@ +use std::{ + fmt::Write, + fs, + io::{BufRead, BufReader}, + path::{Path, PathBuf}, +}; + use clap::Parser; use color_eyre::{ - eyre::{ensure, WrapErr}, + eyre::{ensure, eyre, WrapErr}, Result, }; -use std::{fs, path::PathBuf}; +use regex::Regex; /// tokio-console dev tasks #[derive(Debug, clap::Parser)] @@ -16,6 +23,9 @@ struct Args { enum Command { /// Generate `console-api` protobuf bindings. GenProto, + + /// Check images needed for tokio-console docs.rs main page + CheckDocsImages, } fn main() -> Result<()> { @@ -27,6 +37,7 @@ impl Command { fn run(&self) -> Result<()> { match self { Self::GenProto => gen_proto(), + Self::CheckDocsImages => check_docs_rs_images(), } } } @@ -78,3 +89,71 @@ fn gen_proto() -> Result<()> { .compile_protos(&proto_files[..], &[proto_dir]) .context("failed to compile protobuf files") } + +fn check_docs_rs_images() -> Result<()> { + eprintln!("checking images for tokio-console docs.rs page..."); + + let base_dir = { + let mut mydir = PathBuf::from(std::env!("CARGO_MANIFEST_DIR")); + ensure!(mydir.pop(), "manifest path should not be relative!"); + mydir + }; + + let readme_path = base_dir.join("tokio-console/README.md"); + let file = + fs::File::open(&readme_path).expect("couldn't open tokio-console README.md for reading"); + + let regex_line = line!() + 1; + let re = Regex::new( + r"https://raw.githubusercontent.com/tokio-rs/console-/main/(assets/tokio-console-[\d\.]+\/\w+\.png)", + ) + .expect("couldn't compile regex"); + let reader = BufReader::new(file); + let mut readme_images = Vec::new(); + for line in reader.lines() { + let Ok(line) = line else { + break; + }; + + let Some(image_match) = re.captures(&line) else { + continue; + }; + + let image_path = image_match.get(1).unwrap().as_str(); + readme_images.push(image_path.to_string()); + } + + if readme_images.is_empty() { + let regex_file = file!(); + let readme_path = readme_path.to_string_lossy(); + return Err(eyre!( + "No images found in tokio-console README.md!\n\n\ + The README that was read is located at: {readme_path}\n\n\ + This probably means that there is a problem with the regex defined at \ + {regex_file}:{regex_line}." + )); + } + + let mut missing = Vec::new(); + for image_path in &readme_images { + if !Path::new(image_path).exists() { + missing.push(image_path.to_string()); + } + } + + if missing.is_empty() { + eprintln!( + "OK: verified existance of image files in README, count: {}", + readme_images.len() + ); + + Ok(()) + } else { + let mut error_buffer = "Tokio console README images missing:\n".to_string(); + for path in missing { + writeln!(&mut error_buffer, " - {path}")?; + } + + Err(eyre!("{}", error_buffer)) + } +}