refactor: prepare for adding tests
All checks were successful
Test / test (push) Successful in 4s

This commit is contained in:
Paul Campbell 2024-09-18 11:55:33 +01:00
parent ed0b1c4535
commit 21ff321402
10 changed files with 183 additions and 112 deletions

View file

@ -9,3 +9,4 @@ regex = "1.10"
ureq = "2.10"
kxio = "1.2"
ignore = "0.4"
bon = "2.3"

View file

@ -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<ISSUE_NUMBER>\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<ISSUE_NUMBER>\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<String>,
prefix_pattern: Regex,
issue_pattern: Regex,
}
#[derive(Debug, Default)]
struct FoundMarkers {
markers: Vec<Marker>,
issue_markers: Vec<IssueMarker>,
}
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::<usize>().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<Marker> {
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(),
)
}

35
src/model/config.rs Normal file
View file

@ -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<String>,
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
}
}

18
src/model/line.rs Normal file
View file

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

View file

@ -0,0 +1,16 @@
use super::{IssueMarker, Marker};
//
#[derive(Debug, Default)]
pub struct FoundMarkers {
markers: Vec<Marker>,
issue_markers: Vec<IssueMarker>,
}
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);
}
}

View file

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

View file

@ -0,0 +1,7 @@
//
/// What type of comment #[derive(Debug)]
#[derive(Debug)]
pub enum MarkerKind {
Todo,
Fixme,
}

View file

@ -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()
}
}

10
src/model/markers/mod.rs Normal file
View file

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

8
src/model/mod.rs Normal file
View file

@ -0,0 +1,8 @@
//
mod config;
mod line;
mod markers;
pub use config::Config;
pub use line::Line;
pub use markers::*;