feat: add cli args to help run locally
This commit is contained in:
parent
7ca81b1356
commit
b50f73b7b7
7 changed files with 87 additions and 15 deletions
|
@ -6,12 +6,14 @@ publish = false # NOTE: Not a CLI tool or a library, so don't release to crates.
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bon = "3.0"
|
bon = "3.0"
|
||||||
|
clap = {version = "4.5", features = ["derive"]}
|
||||||
color-eyre = "0.6"
|
color-eyre = "0.6"
|
||||||
file-format = { version = "0.26", features = ["reader-txt"] }
|
file-format = { version = "0.26", features = ["reader-txt"] }
|
||||||
ignore = "0.4"
|
ignore = "0.4"
|
||||||
kxio = "5.0"
|
kxio = "5.0"
|
||||||
regex = "1.10"
|
regex = "1.10"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
tokio = { version = "1.37", features = ["full"] }
|
tokio = { version = "1.37", features = ["full"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
14
README.md
14
README.md
|
@ -20,6 +20,8 @@ This mirror allows you to refer to the action as simply `kemitix/todo-checker@${
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
### Forgejo Action
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
|
@ -34,6 +36,16 @@ jobs:
|
||||||
uses: kemitix/todo-checker@${LATEST}
|
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
|
## Comments Format
|
||||||
|
|
||||||
This Action looks for comments in the following formats:
|
This Action looks for comments in the following formats:
|
||||||
|
@ -69,6 +81,8 @@ Forgejo TODO Checker!
|
||||||
Repo : kemitix/my-project
|
Repo : kemitix/my-project
|
||||||
Regex: (#|//)\s*(TODO|FIXME):?\s*\(#?(?P<ISSUE_NUMBER>\d+)\)
|
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:
|
- Issue number missing: src/main.rs#38:
|
||||||
// TODO: implement this cool feature and get rich!
|
// TODO: implement this cool feature and get rich!
|
||||||
|
|
||||||
|
|
24
src/init.rs
24
src/init.rs
|
@ -1,7 +1,9 @@
|
||||||
//
|
//
|
||||||
use crate::model::Config;
|
|
||||||
use crate::patterns::issue_pattern;
|
use crate::patterns::issue_pattern;
|
||||||
use crate::printer::Printer;
|
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 color_eyre::{eyre::Context, Result};
|
||||||
use kxio::{fs::FileSystem, net::Net};
|
use kxio::{fs::FileSystem, net::Net};
|
||||||
|
|
||||||
|
@ -9,12 +11,28 @@ pub fn init_config<'net, 'fs>(
|
||||||
printer: &impl Printer,
|
printer: &impl Printer,
|
||||||
fs: &'fs FileSystem,
|
fs: &'fs FileSystem,
|
||||||
net: &'net Net,
|
net: &'net Net,
|
||||||
|
args: &Args,
|
||||||
) -> Result<Config<'net, 'fs>> {
|
) -> Result<Config<'net, 'fs>> {
|
||||||
let config = Config::builder()
|
let config = Config::builder()
|
||||||
.net(net)
|
.net(net)
|
||||||
.fs(fs)
|
.fs(fs)
|
||||||
.repo(std::env::var("GITHUB_REPOSITORY").context("GITHUB_REPOSITORY")?)
|
.repo(
|
||||||
.server(std::env::var("GITHUB_SERVER_URL").context("GITHUB_SERVER_URL")?)
|
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()?)
|
.issue_pattern(issue_pattern()?)
|
||||||
.maybe_auth_token(std::env::var("REPO_TOKEN").ok())
|
.maybe_auth_token(std::env::var("REPO_TOKEN").ok())
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::model::Config;
|
use crate::model::Config;
|
||||||
|
|
||||||
use color_eyre::Result;
|
use color_eyre::{eyre::Context, Result};
|
||||||
|
|
||||||
use super::Issue;
|
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 server_url = config.server();
|
||||||
let repo = config.repo();
|
let repo = config.repo();
|
||||||
let url = format!("{server_url}/api/v1/repos/{repo}/issues?state=open");
|
let url = format!("{server_url}/api/v1/repos/{repo}/issues?state=open");
|
||||||
|
println!("> {url}");
|
||||||
let net = config.net();
|
let net = config.net();
|
||||||
let response = net
|
let response = net
|
||||||
.get(url)
|
.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))
|
.some(|request, auth_token| request.header("Authorization", auth_token))
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.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)
|
Ok(issues)
|
||||||
}
|
}
|
||||||
|
|
40
src/main.rs
40
src/main.rs
|
@ -1,3 +1,5 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
//
|
//
|
||||||
use color_eyre::{
|
use color_eyre::{
|
||||||
eyre::{bail, Context as _},
|
eyre::{bail, Context as _},
|
||||||
|
@ -18,27 +20,59 @@ mod scanner;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
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]
|
#[tokio::main]
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
#[cfg_attr(test, mutants::skip)]
|
#[cfg_attr(test, mutants::skip)]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
|
use clap::Parser;
|
||||||
|
use color_eyre::{eyre::ContextCompat as _, Section};
|
||||||
|
|
||||||
color_eyre::install()?;
|
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 fs = kxio::fs::new(github_workspace);
|
||||||
|
|
||||||
let net = kxio::net::new();
|
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(
|
async fn run(
|
||||||
printer: &impl Printer,
|
printer: &impl Printer,
|
||||||
fs: &kxio::fs::FileSystem,
|
fs: &kxio::fs::FileSystem,
|
||||||
net: &kxio::net::Net,
|
net: &kxio::net::Net,
|
||||||
|
args: &Args,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
printer.println("Forgejo TODO Checker!");
|
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 issues = fetch_open_issues(&config).await?;
|
||||||
let errors = find_markers(printer, &config, issues, &DefaultFileScanner)?;
|
let errors = find_markers(printer, &config, issues, &DefaultFileScanner)?;
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ fn init_when_all_valid() {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
//when
|
//when
|
||||||
let result = init_config(&printer, &fs, &net).expect("config");
|
let result = init_config(&printer, &fs, &net, &Args::default()).expect("config");
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assert_eq!(result.fs().base(), expected.fs().base());
|
assert_eq!(result.fs().base(), expected.fs().base());
|
||||||
|
@ -60,11 +60,11 @@ fn init_when_no_repository() {
|
||||||
let net = Net::from(mock_net);
|
let net = Net::from(mock_net);
|
||||||
|
|
||||||
//when
|
//when
|
||||||
let result = init_config(&printer, &fs, &net);
|
let result = init_config(&printer, &fs, &net, &Args::default());
|
||||||
|
|
||||||
//then
|
//then
|
||||||
let_assert!(Err(e) = result);
|
let_assert!(Err(e) = result);
|
||||||
assert_eq!(e.to_string(), "GITHUB_REPOSITORY");
|
assert_eq!(e.to_string(), "GITHUB_REPOSITORY environment not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -83,9 +83,9 @@ fn init_when_no_server_url() {
|
||||||
let net = Net::from(mock_net);
|
let net = Net::from(mock_net);
|
||||||
|
|
||||||
//when
|
//when
|
||||||
let result = init_config(&printer, &fs, &net);
|
let result = init_config(&printer, &fs, &net, &Args::default());
|
||||||
|
|
||||||
//then
|
//then
|
||||||
let_assert!(Err(e) = result);
|
let_assert!(Err(e) = result);
|
||||||
assert_eq!(e.to_string(), "GITHUB_SERVER_URL");
|
assert_eq!(e.to_string(), "GITHUB_SERVER_URL environment not defined");
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ async fn run_with_some_invalids() /* -> Result<()> */
|
||||||
std::env::set_var("GITHUB_SERVER_URL", "https://git.kemitix.net");
|
std::env::set_var("GITHUB_SERVER_URL", "https://git.kemitix.net");
|
||||||
|
|
||||||
//when
|
//when
|
||||||
let result = run(&TestPrinter::default(), &fs, &net).await;
|
let result = run(&TestPrinter::default(), &fs, &net, &Args::default()).await;
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assert!(result.is_err()); // there is an invalid file
|
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");
|
std::env::set_var("GITHUB_SERVER_URL", "https://git.kemitix.net");
|
||||||
|
|
||||||
//when
|
//when
|
||||||
let result = run(&TestPrinter::default(), &fs, &net).await;
|
let result = run(&TestPrinter::default(), &fs, &net, &Args::default()).await;
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assert!(result.is_ok()); // there is an invalid file
|
assert!(result.is_ok()); // there is an invalid file
|
||||||
|
|
Loading…
Reference in a new issue