From 0c1585ba7ba42770292246694e1b4830faef823e Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 4 Jan 2025 20:46:01 +0000 Subject: [PATCH] feat: add cli args to help run locally --- Cargo.toml | 2 ++ README.md | 14 ++++++++++++++ src/init.rs | 24 +++++++++++++++++++++--- src/issues/fetch.rs | 8 ++++++-- src/main.rs | 40 +++++++++++++++++++++++++++++++++++++--- src/tests/init.rs | 6 +++--- src/tests/run.rs | 4 ++-- 7 files changed, 85 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ec81216..0f1192b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,14 @@ publish = false # NOTE: Not a CLI tool or a library, so don't release to crates. [dependencies] bon = "3.0" +clap = {version = "4.5", features = ["derive"]} color-eyre = "0.6" file-format = { version = "0.26", features = ["reader-txt"] } ignore = "0.4" kxio = "5.0" regex = "1.10" serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" tokio = { version = "1.37", features = ["full"] } [dev-dependencies] diff --git a/README.md b/README.md index a5a9bb9..4aa9148 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ This mirror allows you to refer to the action as simply `kemitix/todo-checker@${ ## Usage +### Forgejo Action + ```yaml jobs: tests: @@ -34,6 +36,16 @@ jobs: uses: kemitix/todo-checker@${LATEST} ``` +### Local CLI + +You can also run the command in your local environment: + +```bash +forgejo-todo-checker --workspace $PWD --site https://git.kemitix.net --repo kemitix/forgejo-todo-checker +``` + +Replace the site url with the Forgejo instance where the issues are held. + ## Comments Format This Action looks for comments in the following formats: @@ -69,6 +81,8 @@ Forgejo TODO Checker! Repo : kemitix/my-project Regex: (#|//)\s*(TODO|FIXME):?\s*\(#?(?P\d+)\) +> https://git.kemitix.net/api/v1/repos/kemitix/forgejo-todo-checker/issues?state=open +< 200 OK - Issue number missing: src/main.rs#38: // TODO: implement this cool feature and get rich! diff --git a/src/init.rs b/src/init.rs index db52bc5..8fa5d23 100644 --- a/src/init.rs +++ b/src/init.rs @@ -1,7 +1,9 @@ // -use crate::model::Config; use crate::patterns::issue_pattern; use crate::printer::Printer; +use crate::{model::Config, Args}; +use color_eyre::eyre::ContextCompat as _; +use color_eyre::Section; use color_eyre::{eyre::Context, Result}; use kxio::{fs::FileSystem, net::Net}; @@ -9,12 +11,28 @@ pub fn init_config<'net, 'fs>( printer: &impl Printer, fs: &'fs FileSystem, net: &'net Net, + args: &Args, ) -> Result> { let config = Config::builder() .net(net) .fs(fs) - .repo(std::env::var("GITHUB_REPOSITORY").context("GITHUB_REPOSITORY")?) - .server(std::env::var("GITHUB_SERVER_URL").context("GITHUB_SERVER_URL")?) + .repo( + std::env::var("GITHUB_REPOSITORY") + .or_else(|_| { + args.repo + .as_ref() + .map(|repo| repo.to_string()) + .context("--repo / not provided") + }) + .context("GITHUB_REPOSITORY environment not defined") + .suggestion("Try adding '--repo /' if running from the command line.")?, + ) + .server( + std::env::var("GITHUB_SERVER_URL") + .or_else(|_| args.site.as_ref().map(|url| url.to_string()).context("--site not provided")) + .context("GITHUB_SERVER_URL environment not defined") + .suggestion("Try adding '--site https://' if running from the command line. Use the URL of the Forgejo instance where the issues are held.")?, + ) .issue_pattern(issue_pattern()?) .maybe_auth_token(std::env::var("REPO_TOKEN").ok()) .build(); diff --git a/src/issues/fetch.rs b/src/issues/fetch.rs index b8340ed..a90043d 100644 --- a/src/issues/fetch.rs +++ b/src/issues/fetch.rs @@ -3,7 +3,7 @@ use std::collections::HashSet; use crate::model::Config; -use color_eyre::Result; +use color_eyre::{eyre::Context, Result}; use super::Issue; @@ -11,6 +11,7 @@ pub async fn fetch_open_issues<'net, 'fs>(config: &Config<'net, 'fs>) -> Result< let server_url = config.server(); let repo = config.repo(); let url = format!("{server_url}/api/v1/repos/{repo}/issues?state=open"); + println!("> {url}"); let net = config.net(); let response = net .get(url) @@ -18,7 +19,10 @@ pub async fn fetch_open_issues<'net, 'fs>(config: &Config<'net, 'fs>) -> Result< .some(|request, auth_token| request.header("Authorization", auth_token)) .send() .await?; - let issues: HashSet = response.json().await?; + println!("< {}", response.status()); + let body = response.text().await.context("reading issues body")?; + let issues: HashSet = + serde_json::from_str(&body).with_context(|| format!("body: {body}"))?; Ok(issues) } diff --git a/src/main.rs b/src/main.rs index 52f9347..6bfa5ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + // use color_eyre::{ eyre::{bail, Context as _}, @@ -18,27 +20,59 @@ mod scanner; #[cfg(test)] mod tests; +#[derive(clap::Parser, Default)] +struct Args { + /// Root directory of the project to be scanned. + #[clap(long)] + workspace: Option, + + /// Forgejo site URL (e.g. https://git.kemitix.net) + #[clap(long)] + site: Option, + + /// Repo owner and name (e.g. kemitix/forgejo-todo-checker) + #[clap(long)] + repo: Option, +} + #[tokio::main] #[cfg(not(tarpaulin_include))] #[cfg_attr(test, mutants::skip)] async fn main() -> Result<()> { + use clap::Parser; + use color_eyre::{eyre::ContextCompat as _, Section}; + color_eyre::install()?; - let github_workspace = std::env::var("GITHUB_WORKSPACE").context("GITHUB_WORKSPACE")?; + let args = Args::parse(); + let github_workspace = std::env::var("GITHUB_WORKSPACE") + .or_else(|_| { + args.workspace.as_ref() + .map(|cd| cd.display().to_string()) + .context("--workspace $PWD not provided") + }) + .context("GITHUB_WORKSPACE environment not defined") + .suggestion("Try adding '--workspace $PWD' if running from the command line. N.B. The path MUST be absolute.")?; let fs = kxio::fs::new(github_workspace); let net = kxio::net::new(); - run(&StandardPrinter, &fs, &net).await + let printer = &StandardPrinter; + + run(printer, &fs, &net, &args).await?; + + printer.println("Okay - no problems found"); + Ok(()) } async fn run( printer: &impl Printer, fs: &kxio::fs::FileSystem, net: &kxio::net::Net, + args: &Args, ) -> Result<()> { printer.println("Forgejo TODO Checker!"); - let config = init_config(printer, fs, net)?; + let config = init_config(printer, fs, net, args)?; let issues = fetch_open_issues(&config).await?; let errors = find_markers(printer, &config, issues, &DefaultFileScanner)?; diff --git a/src/tests/init.rs b/src/tests/init.rs index 7c109e5..720b715 100644 --- a/src/tests/init.rs +++ b/src/tests/init.rs @@ -32,7 +32,7 @@ fn init_when_all_valid() { .build(); //when - let result = init_config(&printer, &fs, &net).expect("config"); + let result = init_config(&printer, &fs, &net, &Args::default()).expect("config"); //then assert_eq!(result.fs().base(), expected.fs().base()); @@ -60,7 +60,7 @@ fn init_when_no_repository() { let net = Net::from(mock_net); //when - let result = init_config(&printer, &fs, &net); + let result = init_config(&printer, &fs, &net, &Args::default()); //then let_assert!(Err(e) = result); @@ -83,7 +83,7 @@ fn init_when_no_server_url() { let net = Net::from(mock_net); //when - let result = init_config(&printer, &fs, &net); + let result = init_config(&printer, &fs, &net, &Args::default()); //then let_assert!(Err(e) = result); diff --git a/src/tests/run.rs b/src/tests/run.rs index c1a9ac4..00b1062 100644 --- a/src/tests/run.rs +++ b/src/tests/run.rs @@ -31,7 +31,7 @@ async fn run_with_some_invalids() /* -> Result<()> */ std::env::set_var("GITHUB_SERVER_URL", "https://git.kemitix.net"); //when - let result = run(&TestPrinter::default(), &fs, &net).await; + let result = run(&TestPrinter::default(), &fs, &net, &Args::default()).await; //then assert!(result.is_err()); // there is an invalid file @@ -61,7 +61,7 @@ async fn run_with_no_invalids() { std::env::set_var("GITHUB_SERVER_URL", "https://git.kemitix.net"); //when - let result = run(&TestPrinter::default(), &fs, &net).await; + let result = run(&TestPrinter::default(), &fs, &net, &Args::default()).await; //then assert!(result.is_ok()); // there is an invalid file