feat: add cli args to help run locally
Some checks failed
Test / build (map[name:stable]) (push) Failing after 3m50s
Test / build (map[name:nightly]) (push) Failing after 3m54s

This commit is contained in:
Paul Campbell 2025-01-04 20:46:01 +00:00
parent 7ca81b1356
commit 0c1585ba7b
7 changed files with 85 additions and 13 deletions

View file

@ -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]

View file

@ -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<ISSUE_NUMBER>\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!

View file

@ -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<Config<'net, 'fs>> {
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 <OWNER>/<REPO> not provided")
})
.context("GITHUB_REPOSITORY environment not defined")
.suggestion("Try adding '--repo <OWNER>/<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 <URL> not provided"))
.context("GITHUB_SERVER_URL environment not defined")
.suggestion("Try adding '--site https://<FORGEJO_HOSTNAME>' 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();

View file

@ -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<Issue> = response.json().await?;
println!("< {}", response.status());
let body = response.text().await.context("reading issues body")?;
let issues: HashSet<Issue> =
serde_json::from_str(&body).with_context(|| format!("body: {body}"))?;
Ok(issues)
}

View file

@ -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<PathBuf>,
/// Forgejo site URL (e.g. https://git.kemitix.net)
#[clap(long)]
site: Option<String>,
/// Repo owner and name (e.g. kemitix/forgejo-todo-checker)
#[clap(long)]
repo: Option<String>,
}
#[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)?;

View file

@ -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);

View file

@ -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