diff --git a/Cargo.toml b/Cargo.toml index 928d2c6..f6932b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,4 @@ regex = "1.10" ureq = "2.10" kxio = "1.2" ignore = "0.4" +bon = "2.3" diff --git a/src/main.rs b/src/main.rs index 3d8d574..d4f1844 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,53 +1,44 @@ -use std::path::{Path, PathBuf}; +// +use std::path::Path; use anyhow::{Context, Result}; -use kxio::fs::DirItem; -use regex::Regex; +use model::{Config, FoundMarkers, Line, Marker, MarkerKind}; + +mod model; fn main() -> Result<()> { println!("Forgejo TODO Checker!"); - let config = Config { - fs: kxio::fs::new( + let config = Config::builder() + .fs(kxio::fs::new( std::env::var("GITHUB_WORKSPACE") .context("GITHUB_WORKSPACE")? .into(), - ), - repo: std::env::var("GITHUB_REPOSITORY").context("GITHUB_REPOSITORY")?, - server: std::env::var("GITHUB_SERVER_URL").context("GITHUB_SERVER_URL")?, - auth_token: std::env::var("REPO_TOKEN").ok(), - prefix_pattern: regex::Regex::new(r"(#|//)\s*(TODO|FIXME)").context("prefix regex")?, - issue_pattern: regex::Regex::new(r"( |)(\(|\(#)(?P\d+)(\))") - .context("issue regex")?, - }; + )) + .repo(std::env::var("GITHUB_REPOSITORY").context("GITHUB_REPOSITORY")?) + .server(std::env::var("GITHUB_SERVER_URL").context("GITHUB_SERVER_URL")?) + .prefix_pattern(regex::Regex::new(r"(#|//)\s*(TODO|FIXME)").context("prefix regex")?) + .issue_pattern( + regex::Regex::new(r"( |)(\(|\(#)(?P\d+)(\))").context("issue regex")?, + ) + .maybe_auth_token(std::env::var("REPO_TOKEN").ok()) + .build(); - println!("Repo: {}", config.repo); - println!("Prefix: {}", config.prefix_pattern); - println!("Issues: {}", config.issue_pattern); + println!("Repo: {}", config.repo()); + println!("Prefix: {}", config.prefix_pattern()); + println!("Issues: {}", config.issue_pattern()); let mut found_markers = FoundMarkers::default(); - for file in ignore::Walk::new(config.fs.base()).flatten() { + for file in ignore::Walk::new(config.fs().base()).flatten() { let path = file.path(); - if config.fs.path_is_file(path)? { + if config.fs().path_is_file(path)? { scan_file(path, &config, &mut found_markers)?; } } println!("{found_markers:?}"); - // list files in current directory to get a feel for what we have access to - // std::fs::read_dir(workdir)? - // .filter_map(Result::ok) - // .map(|e| e.path()) - // .for_each(|e| println!("{e:?}")); - - // Collect open issues: - // let limit = 10; - // let page = 0; - // let api = format!( - // "{ci_server_url}/api/v1/repos/{ci_repo}/issues?state=open&limit=${limit}&page=${page}" - // ); // TODO: add authentication when provided // let issues = ureq::get(&api).call()?.into_string()?; // TODO: parse issues to get list of open issue numbers @@ -61,42 +52,19 @@ fn main() -> Result<()> { Ok(()) } -struct Config { - fs: kxio::fs::FileSystem, - repo: String, - server: String, - auth_token: Option, - prefix_pattern: Regex, - issue_pattern: Regex, -} - -#[derive(Debug, Default)] -struct FoundMarkers { - markers: Vec, - issue_markers: Vec, -} -impl FoundMarkers { - fn add_marker(&mut self, marker: Marker) { - self.markers.push(marker); - } - fn add_issue_marker(&mut self, issue_marker: IssueMarker) { - self.issue_markers.push(issue_marker); - } -} - fn scan_file(file: &Path, config: &Config, found_markers: &mut FoundMarkers) -> Result<()> { println!("file: {}", file.to_string_lossy()); config - .fs + .fs() .file_read_to_string(file)? .lines() .enumerate() .filter_map(|(n, line)| prefix_match(n, line, file, config)) .for_each(|marker| { - println!("- {}", marker.line.value); + println!("- {}", marker.line().value()); if let Some(issue) = config - .issue_pattern - .find(&marker.line.value) + .issue_pattern() + .find(marker.line().value()) .map(|issue| issue.as_str()) .and_then(|issue| issue.parse::().ok()) { @@ -109,61 +77,17 @@ fn scan_file(file: &Path, config: &Config, found_markers: &mut FoundMarkers) -> } fn prefix_match(num: usize, line: &str, path: &Path, config: &Config) -> Option { - let find = config.prefix_pattern.find(line)?; - let marker_type = match find.as_str() { - "TODO" => Some(MarkerType::Todo), - "FIXME" => Some(MarkerType::Fixme), + let find = config.prefix_pattern().find(line)?; + let kind = match find.as_str() { + "TODO" => Some(MarkerKind::Todo), + "FIXME" => Some(MarkerKind::Fixme), _ => None, }?; - Some(Marker { - marker_type, - file: path.to_path_buf(), - line: Line { - num, - value: line.to_owned(), - }, - }) -} - -/// What type of comment -#[derive(Debug)] -enum MarkerType { - Todo, - Fixme, -} - -#[derive(Debug)] -struct Line { - num: usize, - value: String, -} - -/// Represents a TODO or FIXME comment that doesn't have any issue number -#[derive(Debug)] -struct Marker { - /// What type of marker - marker_type: MarkerType, - - /// Path of the file - file: PathBuf, - - /// The line from the file - line: Line, -} -impl Marker { - fn into_issue_marker(self, issue: usize) -> IssueMarker { - IssueMarker { - marker: self, - issue, - } - } -} - -#[derive(Debug)] -struct IssueMarker { - /// The marker - marker: Marker, - - /// The issue number - issue: usize, + Some( + Marker::builder() + .kind(kind) + .file(path.to_path_buf()) + .line(Line::builder().num(num).value(line.to_owned()).build()) + .build(), + ) } diff --git a/src/model/config.rs b/src/model/config.rs new file mode 100644 index 0000000..4ff8c9e --- /dev/null +++ b/src/model/config.rs @@ -0,0 +1,35 @@ +// +#![allow(dead_code)] + +use bon::Builder; +use regex::Regex; + +#[derive(Builder)] +pub struct Config { + fs: kxio::fs::FileSystem, + repo: String, + server: String, + auth_token: Option, + prefix_pattern: Regex, + issue_pattern: Regex, +} +impl Config { + pub fn fs(&self) -> &kxio::fs::FileSystem { + &self.fs + } + pub fn repo(&self) -> &str { + &self.repo + } + pub fn server(&self) -> &str { + &self.server + } + pub fn auth_token(&self) -> Option<&str> { + self.auth_token.as_deref() + } + pub fn prefix_pattern(&self) -> &Regex { + &self.prefix_pattern + } + pub fn issue_pattern(&self) -> &Regex { + &self.issue_pattern + } +} diff --git a/src/model/line.rs b/src/model/line.rs new file mode 100644 index 0000000..6d21791 --- /dev/null +++ b/src/model/line.rs @@ -0,0 +1,18 @@ +// +#![allow(dead_code)] + +use bon::Builder; + +#[derive(Debug, Builder)] +pub struct Line { + num: usize, + value: String, +} +impl Line { + pub fn num(&self) -> usize { + self.num + } + pub fn value(&self) -> &str { + &self.value + } +} diff --git a/src/model/markers/found.rs b/src/model/markers/found.rs new file mode 100644 index 0000000..c2fa490 --- /dev/null +++ b/src/model/markers/found.rs @@ -0,0 +1,16 @@ +use super::{IssueMarker, Marker}; + +// +#[derive(Debug, Default)] +pub struct FoundMarkers { + markers: Vec, + issue_markers: Vec, +} +impl FoundMarkers { + pub fn add_marker(&mut self, marker: Marker) { + self.markers.push(marker); + } + pub fn add_issue_marker(&mut self, issue_marker: IssueMarker) { + self.issue_markers.push(issue_marker); + } +} diff --git a/src/model/markers/issue.rs b/src/model/markers/issue.rs new file mode 100644 index 0000000..ce65558 --- /dev/null +++ b/src/model/markers/issue.rs @@ -0,0 +1,15 @@ +// +#![allow(dead_code)] + +use super::Marker; + +use bon::Builder; + +#[derive(Debug, Builder)] +pub struct IssueMarker { + /// The marker + marker: Marker, + + /// The issue number + issue: usize, +} diff --git a/src/model/markers/kind.rs b/src/model/markers/kind.rs new file mode 100644 index 0000000..fc5a4bc --- /dev/null +++ b/src/model/markers/kind.rs @@ -0,0 +1,7 @@ +// +/// What type of comment #[derive(Debug)] +#[derive(Debug)] +pub enum MarkerKind { + Todo, + Fixme, +} diff --git a/src/model/markers/marker.rs b/src/model/markers/marker.rs new file mode 100644 index 0000000..c7b32c1 --- /dev/null +++ b/src/model/markers/marker.rs @@ -0,0 +1,37 @@ +// +#![allow(dead_code)] + +use std::path::{Path, PathBuf}; + +use bon::Builder; + +use crate::model::Line; + +use super::{IssueMarker, MarkerKind}; + +/// Represents a TODO or FIXME comment that doesn't have any issue number +#[derive(Debug, Builder)] +pub struct Marker { + /// What type of marker + kind: MarkerKind, + + /// Path of the file + file: PathBuf, + + /// The line from the file + line: Line, +} +impl Marker { + pub fn kind(&self) -> &MarkerKind { + &self.kind + } + pub fn file(&self) -> &Path { + &self.file + } + pub fn line(&self) -> &Line { + &self.line + } + pub fn into_issue_marker(self, issue: usize) -> IssueMarker { + IssueMarker::builder().marker(self).issue(issue).build() + } +} diff --git a/src/model/markers/mod.rs b/src/model/markers/mod.rs new file mode 100644 index 0000000..7f1f014 --- /dev/null +++ b/src/model/markers/mod.rs @@ -0,0 +1,10 @@ +// +mod found; +mod issue; +mod kind; +mod marker; + +pub use found::FoundMarkers; +pub use issue::IssueMarker; +pub use kind::MarkerKind; +pub use marker::Marker; diff --git a/src/model/mod.rs b/src/model/mod.rs new file mode 100644 index 0000000..b6820a5 --- /dev/null +++ b/src/model/mod.rs @@ -0,0 +1,8 @@ +// +mod config; +mod line; +mod markers; + +pub use config::Config; +pub use line::Line; +pub use markers::*;