Compare commits
7 commits
bec15aeb3d
...
57f88bb832
Author | SHA1 | Date | |
---|---|---|---|
57f88bb832 | |||
d161d0104e | |||
b4552c7304 | |||
cf67463016 | |||
a2f7601eab | |||
c86ff97798 | |||
|
efaa435717 |
27 changed files with 475 additions and 134 deletions
|
@ -10,6 +10,10 @@ ureq = "2.10"
|
|||
kxio = "1.2"
|
||||
ignore = "0.4"
|
||||
bon = "2.3"
|
||||
tokio = { version = "1.37", features = [ "full" ] }
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
serde_json = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
assert2 = "0.3"
|
||||
pretty_assertions = "1.4"
|
||||
|
|
6
renovate.json
Normal file
6
renovate.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
]
|
||||
}
|
|
@ -3,8 +3,9 @@ use crate::model::Config;
|
|||
use crate::patterns::{issue_pattern, marker_pattern};
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
pub fn init_config() -> Result<Config, anyhow::Error> {
|
||||
pub fn init_config(net: kxio::network::Network) -> Result<Config, anyhow::Error> {
|
||||
let config = Config::builder()
|
||||
.net(net)
|
||||
.fs(kxio::fs::new(
|
||||
std::env::var("GITHUB_WORKSPACE")
|
||||
.context("GITHUB_WORKSPACE")?
|
||||
|
|
33
src/issues/fetch.rs
Normal file
33
src/issues/fetch.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
//
|
||||
use crate::model::Config;
|
||||
|
||||
use anyhow::Result;
|
||||
use kxio::network::{NetRequest, NetUrl};
|
||||
|
||||
use super::Issue;
|
||||
|
||||
pub async fn fetch_open_issues(config: &Config) -> Result<HashSet<Issue>> {
|
||||
let server_url = config.server();
|
||||
let repo = config.repo();
|
||||
let url = format!("{server_url}/api/v1/repos/{repo}/issues?state=open");
|
||||
let request_builder = NetRequest::get(NetUrl::new(url));
|
||||
let request = if let Some(auth_token) = config.auth_token() {
|
||||
request_builder.header("Authorization", auth_token)
|
||||
} else {
|
||||
request_builder
|
||||
}
|
||||
.build();
|
||||
|
||||
let issues: HashSet<Issue> = config
|
||||
.net()
|
||||
.get::<Vec<Issue>>(request)
|
||||
.await?
|
||||
.response_body()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
Ok(issues)
|
||||
}
|
35
src/issues/mod.rs
Normal file
35
src/issues/mod.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
mod fetch;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use fetch::fetch_open_issues;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize, Hash, PartialEq, Eq)]
|
||||
pub struct Issue {
|
||||
number: u64,
|
||||
}
|
||||
impl Issue {
|
||||
pub fn new(number: u64) -> Self {
|
||||
Self { number }
|
||||
}
|
||||
// #[cfg(test)]
|
||||
// pub fn number(&self) -> u64 {
|
||||
// self.number
|
||||
// }
|
||||
}
|
||||
impl TryFrom<&str> for Issue {
|
||||
type Error = <u64 as std::str::FromStr>::Err;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
let n: u64 = value.parse()?;
|
||||
Ok(Issue::new(n))
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for Issue {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.number)
|
||||
}
|
||||
}
|
32
src/issues/tests.rs
Normal file
32
src/issues/tests.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use crate::tests::a_config;
|
||||
|
||||
//
|
||||
use super::*;
|
||||
|
||||
use anyhow::Result;
|
||||
use kxio::network::StatusCode;
|
||||
|
||||
#[tokio::test]
|
||||
async fn fetch_lists_issues() -> Result<()> {
|
||||
//given
|
||||
let mut net = kxio::network::MockNetwork::new();
|
||||
net.add_get_response(
|
||||
"https://git.kemitix.net/api/v1/repos/kemitix/test/issues?state=open",
|
||||
StatusCode::OK,
|
||||
r#"[{"number":13},{"number":64}]"#,
|
||||
);
|
||||
let config = a_config(net.into(), kxio::fs::temp()?)?;
|
||||
|
||||
//when
|
||||
let result = fetch_open_issues(&config).await?;
|
||||
|
||||
//then
|
||||
assert_eq!(
|
||||
result,
|
||||
HashSet::from_iter(vec![Issue::new(13), Issue::new(64)])
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
40
src/main.rs
40
src/main.rs
|
@ -1,9 +1,11 @@
|
|||
//
|
||||
use anyhow::Result;
|
||||
use anyhow::{bail, Result};
|
||||
use init::init_config;
|
||||
use issues::fetch_open_issues;
|
||||
use scanner::find_markers;
|
||||
|
||||
mod init;
|
||||
mod issues;
|
||||
mod model;
|
||||
mod patterns;
|
||||
mod scanner;
|
||||
|
@ -11,23 +13,31 @@ mod scanner;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
#[tokio::main]
|
||||
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
Ok(run(kxio::network::Network::new_real()).await?)
|
||||
}
|
||||
|
||||
async fn run(net: kxio::network::Network) -> Result<()> {
|
||||
println!("Forgejo TODO Checker!");
|
||||
|
||||
let config = init_config()?;
|
||||
let config = init_config(net)?;
|
||||
let issues = fetch_open_issues(&config).await?;
|
||||
let markers = find_markers(&config, issues)?;
|
||||
|
||||
let markers = find_markers(config)?;
|
||||
println!("{markers}");
|
||||
|
||||
// TODO: add authentication when provided
|
||||
// let issues = ureq::get(&api).call()?.into_string()?;
|
||||
// TODO: parse issues to get list of open issue numbers
|
||||
|
||||
// TODO: loop over list of expected issues and drop any where they do exist and are open
|
||||
// TODO: if remaining list is not empty - add all to error list
|
||||
//
|
||||
// TODO: if error list is empty - exit okay
|
||||
// TODO: if error list is not empty - log erros and exit not okay
|
||||
let mut errors = false;
|
||||
for marker in (*markers).iter() {
|
||||
match marker {
|
||||
model::Marker::Closed(_, _) | model::Marker::Invalid(_) => {
|
||||
println!("{marker}");
|
||||
errors = true;
|
||||
}
|
||||
model::Marker::Unmarked | model::Marker::Valid(_, _) => {}
|
||||
}
|
||||
}
|
||||
|
||||
if errors {
|
||||
bail!("Invalid or closed TODO/FIXMEs found")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use regex::Regex;
|
|||
|
||||
#[derive(Debug, Builder)]
|
||||
pub struct Config {
|
||||
net: kxio::network::Network,
|
||||
fs: kxio::fs::FileSystem,
|
||||
repo: String,
|
||||
server: String,
|
||||
|
@ -14,18 +15,21 @@ pub struct Config {
|
|||
issue_pattern: Regex,
|
||||
}
|
||||
impl Config {
|
||||
pub fn net(&self) -> &kxio::network::Network {
|
||||
&self.net
|
||||
}
|
||||
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 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
|
||||
}
|
||||
|
|
|
@ -6,7 +6,10 @@ use std::path::PathBuf;
|
|||
use anyhow::{Context, Result};
|
||||
use bon::Builder;
|
||||
|
||||
use crate::patterns::{issue_pattern, marker_pattern};
|
||||
use crate::{
|
||||
issues::Issue,
|
||||
patterns::{issue_pattern, marker_pattern},
|
||||
};
|
||||
|
||||
use super::Marker;
|
||||
|
||||
|
@ -32,11 +35,11 @@ impl Line {
|
|||
if marker_pattern()?.find(&self.value).is_some() {
|
||||
match issue_pattern()?.captures(&self.value) {
|
||||
Some(capture) => {
|
||||
let issue = capture
|
||||
let issue: Issue = capture
|
||||
.name("ISSUE_NUMBER")
|
||||
.context("ISSUE_NUMBER")?
|
||||
.as_str()
|
||||
.to_owned();
|
||||
.try_into()?;
|
||||
Ok(Marker::Valid(self, issue))
|
||||
}
|
||||
None => Ok(Marker::Invalid(self)),
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
use super::Marker;
|
||||
|
||||
//
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FoundMarkers {
|
||||
markers: Vec<Marker>,
|
||||
}
|
||||
impl FoundMarkers {
|
||||
pub fn add_marker(&mut self, marker: Marker) {
|
||||
self.markers.push(marker);
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for FoundMarkers {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for marker in self.markers.iter() {
|
||||
// if !matches!(marker, Marker::Unmarked) {
|
||||
write!(f, "{marker}")?;
|
||||
// }
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
//
|
||||
#![allow(dead_code)]
|
||||
|
||||
use super::Marker;
|
||||
|
||||
use bon::Builder;
|
||||
|
||||
#[derive(Debug, Builder)]
|
||||
pub struct IssueMarker {
|
||||
/// The marker
|
||||
marker: Marker,
|
||||
|
||||
/// The issue number
|
||||
issue: usize,
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
//
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::model::Line;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Marker {
|
||||
Unmarked,
|
||||
Invalid(Line),
|
||||
Valid(Line, String),
|
||||
}
|
||||
impl std::fmt::Display for Marker {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Marker::Unmarked => Ok(()),
|
||||
Marker::Invalid(line) => write!(f, "- Invalid: {line}"),
|
||||
Marker::Valid(line, _) => write!(f, "- Valid : {line}"),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,61 @@
|
|||
//
|
||||
mod found;
|
||||
mod issue;
|
||||
mod marker;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use found::FoundMarkers;
|
||||
pub use marker::Marker;
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::{issues::Issue, model::Line};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Marker {
|
||||
Unmarked,
|
||||
Invalid(Line),
|
||||
#[allow(dead_code)]
|
||||
Valid(Line, Issue),
|
||||
Closed(Line, Issue),
|
||||
}
|
||||
impl Marker {
|
||||
pub fn into_closed(self) -> Self {
|
||||
match self {
|
||||
Self::Valid(line, issue) => Self::Closed(line, issue),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Marker {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Unmarked => Ok(()),
|
||||
Self::Invalid(line) => write!(f, "- Invalid: {line}"),
|
||||
Self::Valid(line, issue) => write!(f, "- Valid : ({issue}) {line}"),
|
||||
Self::Closed(line, issue) => write!(f, "- Closed : ({issue}) {line}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Markers {
|
||||
markers: Vec<Marker>,
|
||||
}
|
||||
impl Markers {
|
||||
pub fn add_marker(&mut self, marker: Marker) {
|
||||
self.markers.push(marker);
|
||||
}
|
||||
}
|
||||
impl Deref for Markers {
|
||||
type Target = Vec<Marker>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.markers
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for Markers {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for marker in self.markers.iter() {
|
||||
write!(f, "{marker}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use crate::model::Line;
|
||||
|
||||
//
|
||||
use super::*;
|
||||
use crate::model::{markers::Markers, Line};
|
||||
|
||||
#[test]
|
||||
fn found_when_displayed() -> anyhow::Result<()> {
|
||||
|
@ -10,7 +8,7 @@ fn found_when_displayed() -> anyhow::Result<()> {
|
|||
let file = fs.base().join("file-name");
|
||||
let relative = file.strip_prefix(fs.base())?.to_path_buf();
|
||||
|
||||
let mut found = FoundMarkers::default();
|
||||
let mut found = Markers::default();
|
||||
|
||||
let marker_unmarked = Line::builder()
|
||||
.file(file.clone())
|
||||
|
@ -23,14 +21,14 @@ fn found_when_displayed() -> anyhow::Result<()> {
|
|||
.file(file.clone())
|
||||
.relative_path(relative.clone())
|
||||
.num(10)
|
||||
.value("line // TODO: comment".to_owned())
|
||||
.value(format!("line // {}: comment", "TODO"))
|
||||
.build()
|
||||
.into_marker()?;
|
||||
let marker_valid = Line::builder()
|
||||
.file(file)
|
||||
.relative_path(relative)
|
||||
.num(11)
|
||||
.value("line // TODO: (#13) do this".to_owned())
|
||||
.value(format!("line // {}: (#13) do this", "TODO"))
|
||||
.build()
|
||||
.into_marker()?;
|
||||
|
||||
|
@ -47,9 +45,9 @@ fn found_when_displayed() -> anyhow::Result<()> {
|
|||
result,
|
||||
vec![
|
||||
"- Invalid: file-name#10:",
|
||||
" line // TODO: comment",
|
||||
"- Valid : file-name#11:",
|
||||
" line // TODO: (#13) do this"
|
||||
format!(" line // {}: comment", "TODO").as_str(),
|
||||
"- Valid : (13) file-name#11:",
|
||||
format!(" line // {}: (#13) do this", "TODO").as_str()
|
||||
]
|
||||
);
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
//
|
||||
use super::*;
|
||||
|
||||
mod found;
|
||||
mod issue;
|
||||
mod marker;
|
|
@ -8,5 +8,5 @@ mod tests;
|
|||
|
||||
pub use config::Config;
|
||||
pub use line::Line;
|
||||
pub use markers::FoundMarkers;
|
||||
pub use markers::Marker;
|
||||
pub use markers::Markers;
|
||||
|
|
|
@ -1,15 +1,32 @@
|
|||
//
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::patterns::{issue_pattern, marker_pattern};
|
||||
use crate::{
|
||||
patterns::{issue_pattern, marker_pattern},
|
||||
tests::a_config,
|
||||
};
|
||||
|
||||
//
|
||||
use super::*;
|
||||
#[tokio::test]
|
||||
async fn with_config_get_net() -> Result<()> {
|
||||
//given
|
||||
let net = kxio::network::Network::new_mock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
let config = a_config(net, fs)?;
|
||||
|
||||
//when
|
||||
config.net();
|
||||
|
||||
//then
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_config_get_fs() -> Result<()> {
|
||||
//given
|
||||
let net = kxio::network::Network::new_mock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
let config = a_config(fs.clone())?;
|
||||
let config = a_config(net, fs.clone())?;
|
||||
|
||||
//when
|
||||
let result = config.fs();
|
||||
|
@ -23,8 +40,9 @@ fn with_config_get_fs() -> Result<()> {
|
|||
#[test]
|
||||
fn with_config_get_prefix_pattern() -> Result<()> {
|
||||
//given
|
||||
let net = kxio::network::Network::new_mock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
let config = a_config(fs)?;
|
||||
let config = a_config(net, fs)?;
|
||||
|
||||
//when
|
||||
let result = config.prefix_pattern();
|
||||
|
@ -38,8 +56,9 @@ fn with_config_get_prefix_pattern() -> Result<()> {
|
|||
#[test]
|
||||
fn with_config_get_issue_pattern() -> Result<()> {
|
||||
//given
|
||||
let net = kxio::network::Network::new_mock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
let config = a_config(fs)?;
|
||||
let config = a_config(net, fs)?;
|
||||
|
||||
//when
|
||||
let result = config.issue_pattern();
|
||||
|
@ -50,11 +69,44 @@ fn with_config_get_issue_pattern() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_config_get_server() -> Result<()> {
|
||||
//given
|
||||
let net = kxio::network::Network::new_mock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
let config = a_config(net, fs)?;
|
||||
|
||||
//when
|
||||
let result = config.server();
|
||||
|
||||
//then
|
||||
assert_eq!(result, "https://git.kemitix.net");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_config_get_auth_token() -> Result<()> {
|
||||
//given
|
||||
let net = kxio::network::Network::new_mock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
let config = a_config(net, fs)?;
|
||||
|
||||
//when
|
||||
let result = config.auth_token();
|
||||
|
||||
//then
|
||||
assert_eq!(result, Some("secret"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_config_get_repo() -> Result<()> {
|
||||
//given
|
||||
let net = kxio::network::Network::new_mock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
let config = a_config(fs)?;
|
||||
let config = a_config(net, fs)?;
|
||||
|
||||
//when
|
||||
let result = config.repo();
|
||||
|
@ -64,13 +116,3 @@ fn with_config_get_repo() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn a_config(fs: kxio::fs::FileSystem) -> Result<Config> {
|
||||
Ok(Config::builder()
|
||||
.fs(fs)
|
||||
.server("https://git.kemitix.net".to_string())
|
||||
.repo("kemitix/test".to_string())
|
||||
.prefix_pattern(marker_pattern()?)
|
||||
.issue_pattern(issue_pattern()?)
|
||||
.build())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
//
|
||||
use super::*;
|
||||
|
||||
mod config;
|
||||
|
|
|
@ -1,21 +1,30 @@
|
|||
//
|
||||
use std::path::Path;
|
||||
use std::{collections::HashSet, path::Path};
|
||||
|
||||
use crate::model::{Config, FoundMarkers, Line, Marker};
|
||||
use crate::{
|
||||
issues::Issue,
|
||||
model::{Config, Line, Marker, Markers},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use ignore::Walk;
|
||||
|
||||
pub fn find_markers(config: Config) -> Result<FoundMarkers, anyhow::Error> {
|
||||
let mut markers = FoundMarkers::default();
|
||||
for file in ignore::Walk::new(config.fs().base()).flatten() {
|
||||
pub fn find_markers(config: &Config, issues: HashSet<Issue>) -> Result<Markers, anyhow::Error> {
|
||||
let mut markers = Markers::default();
|
||||
for file in Walk::new(config.fs().base()).flatten() {
|
||||
let path = file.path();
|
||||
if config.fs().path_is_file(path)? {
|
||||
scan_file(path, &config, &mut markers)?;
|
||||
scan_file(path, config, &mut markers, &issues)?;
|
||||
}
|
||||
}
|
||||
Ok(markers)
|
||||
}
|
||||
|
||||
fn scan_file(file: &Path, config: &Config, found_markers: &mut FoundMarkers) -> Result<()> {
|
||||
fn scan_file(
|
||||
file: &Path,
|
||||
config: &Config,
|
||||
found_markers: &mut Markers,
|
||||
issues: &HashSet<Issue>,
|
||||
) -> Result<()> {
|
||||
let relative_path = file.strip_prefix(config.fs().base())?.to_path_buf();
|
||||
config
|
||||
.fs()
|
||||
|
@ -26,13 +35,27 @@ fn scan_file(file: &Path, config: &Config, found_markers: &mut FoundMarkers) ->
|
|||
Line::builder()
|
||||
.file(file.to_path_buf())
|
||||
.relative_path(relative_path.clone())
|
||||
.num(n)
|
||||
.num(n + 1) // line numbers are not 0-based, but enumerate is
|
||||
.value(line.to_owned())
|
||||
.build()
|
||||
})
|
||||
.filter_map(|line| line.into_marker().ok())
|
||||
.filter(|marker| !matches!(marker, Marker::Unmarked))
|
||||
.map(|marker| has_open_issue(marker, issues))
|
||||
.for_each(|marker| found_markers.add_marker(marker));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn has_open_issue(marker: Marker, issues: &HashSet<Issue>) -> Marker {
|
||||
if let Marker::Valid(_, ref issue) = marker {
|
||||
let has_open_issue = issues.contains(issue);
|
||||
if has_open_issue {
|
||||
marker
|
||||
} else {
|
||||
marker.into_closed()
|
||||
}
|
||||
} else {
|
||||
marker
|
||||
}
|
||||
}
|
||||
|
|
9
src/tests/data/file_with_invalids.txt
Normal file
9
src/tests/data/file_with_invalids.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
This is a text file.
|
||||
|
||||
It contains a todo comment: // TODO: this is it
|
||||
|
||||
It also contains a fix-me comment: // FIXME: and this is it
|
||||
|
||||
Both of these are missing an issue identifier.
|
||||
|
||||
We also have a todo comment: // TODO: (#3) and it has an issue number, but it is closed
|
5
src/tests/data/file_with_valids.txt
Normal file
5
src/tests/data/file_with_valids.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
This is another text file.
|
||||
|
||||
It also has a todo comment: // TODO: (#23) and it has an issue number
|
||||
|
||||
Here is a fix-me comment: // FIXME: (#43) and is also has an issue number
|
|
@ -8,11 +8,14 @@ use patterns::{issue_pattern, marker_pattern};
|
|||
#[test]
|
||||
fn init_when_all_valid() -> anyhow::Result<()> {
|
||||
//given
|
||||
let _env = THE_ENVIRONMENT.lock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
std::env::set_var("GITHUB_WORKSPACE", fs.base());
|
||||
std::env::set_var("GITHUB_REPOSITORY", "repo");
|
||||
std::env::set_var("GITHUB_SERVER_URL", "server");
|
||||
let net = kxio::network::Network::new_mock();
|
||||
let expected = Config::builder()
|
||||
.net(net.clone())
|
||||
.fs(kxio::fs::new(fs.base().to_path_buf()))
|
||||
.repo("repo".to_string())
|
||||
.server("server".to_string())
|
||||
|
@ -22,7 +25,7 @@ fn init_when_all_valid() -> anyhow::Result<()> {
|
|||
.build();
|
||||
|
||||
//when
|
||||
let result = init_config()?;
|
||||
let result = init_config(net)?;
|
||||
|
||||
//then
|
||||
assert_eq!(result.fs().base(), expected.fs().base());
|
||||
|
@ -43,12 +46,13 @@ fn init_when_all_valid() -> anyhow::Result<()> {
|
|||
#[test]
|
||||
fn init_when_no_workspace() -> anyhow::Result<()> {
|
||||
//given
|
||||
let _env = THE_ENVIRONMENT.lock();
|
||||
std::env::remove_var("GITHUB_WORKSPACE");
|
||||
std::env::set_var("GITHUB_REPOSITORY", "repo");
|
||||
std::env::set_var("GITHUB_SERVER_URL", "server");
|
||||
|
||||
//when
|
||||
let result = init_config();
|
||||
let result = init_config(kxio::network::Network::new_mock());
|
||||
|
||||
//then
|
||||
let_assert!(Err(e) = result);
|
||||
|
@ -60,13 +64,14 @@ fn init_when_no_workspace() -> anyhow::Result<()> {
|
|||
#[test]
|
||||
fn init_when_no_repository() -> anyhow::Result<()> {
|
||||
//given
|
||||
let _env = THE_ENVIRONMENT.lock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
std::env::set_var("GITHUB_WORKSPACE", fs.base());
|
||||
std::env::remove_var("GITHUB_REPOSITORY");
|
||||
std::env::set_var("GITHUB_SERVER_URL", "server");
|
||||
|
||||
//when
|
||||
let result = init_config();
|
||||
let result = init_config(kxio::network::Network::new_mock());
|
||||
|
||||
//then
|
||||
let_assert!(Err(e) = result);
|
||||
|
@ -78,13 +83,14 @@ fn init_when_no_repository() -> anyhow::Result<()> {
|
|||
#[test]
|
||||
fn init_when_no_server_url() -> anyhow::Result<()> {
|
||||
//given
|
||||
let _env = THE_ENVIRONMENT.lock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
std::env::set_var("GITHUB_WORKSPACE", fs.base());
|
||||
std::env::set_var("GITHUB_REPOSITORY", "repo");
|
||||
std::env::remove_var("GITHUB_SERVER_URL");
|
||||
|
||||
//when
|
||||
let result = init_config();
|
||||
let result = init_config(kxio::network::Network::new_mock());
|
||||
|
||||
//then
|
||||
let_assert!(Err(e) = result);
|
||||
|
|
|
@ -1,4 +1,25 @@
|
|||
use std::sync::{LazyLock, Mutex};
|
||||
|
||||
use model::Config;
|
||||
use patterns::{issue_pattern, marker_pattern};
|
||||
|
||||
//
|
||||
use super::*;
|
||||
|
||||
mod init;
|
||||
mod run;
|
||||
mod scanner;
|
||||
|
||||
pub static THE_ENVIRONMENT: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
|
||||
|
||||
pub fn a_config(net: kxio::network::Network, fs: kxio::fs::FileSystem) -> Result<Config> {
|
||||
Ok(Config::builder()
|
||||
.net(net)
|
||||
.fs(fs)
|
||||
.server("https://git.kemitix.net".to_string())
|
||||
.repo("kemitix/test".to_string())
|
||||
.auth_token("secret".to_string())
|
||||
.prefix_pattern(marker_pattern()?)
|
||||
.issue_pattern(issue_pattern()?)
|
||||
.build())
|
||||
}
|
||||
|
|
68
src/tests/run.rs
Normal file
68
src/tests/run.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
use super::*;
|
||||
|
||||
use anyhow::Result;
|
||||
use kxio::network::StatusCode;
|
||||
|
||||
#[tokio::test]
|
||||
async fn run_with_some_invalids() -> Result<()> {
|
||||
//given
|
||||
let mut net = kxio::network::MockNetwork::new();
|
||||
net.add_get_response(
|
||||
"https://git.kemitix.net/api/v1/repos/kemitix/test/issues?state=open",
|
||||
StatusCode::OK,
|
||||
r#"[{"number": 13}]"#,
|
||||
);
|
||||
let _env = THE_ENVIRONMENT.lock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
fs.file_write(
|
||||
&fs.base().join("file_with_invalids.txt"),
|
||||
include_str!("data/file_with_invalids.txt"),
|
||||
)?;
|
||||
fs.file_write(
|
||||
&fs.base().join("file_with_valids.txt"),
|
||||
include_str!("data/file_with_valids.txt"),
|
||||
)?;
|
||||
std::env::set_var("GITHUB_WORKSPACE", fs.base());
|
||||
std::env::set_var("GITHUB_REPOSITORY", "kemitix/test");
|
||||
std::env::set_var("GITHUB_SERVER_URL", "https://git.kemitix.net");
|
||||
|
||||
//when
|
||||
run(net.into()).await?;
|
||||
|
||||
//then
|
||||
// TODO: add check that run fails because file_1.txt is invalid
|
||||
// TODO: add check that network requests were made to get issues
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn run_with_no_invalids() -> Result<()> {
|
||||
//given
|
||||
let mut net = kxio::network::MockNetwork::new();
|
||||
net.add_get_response(
|
||||
"https://git.kemitix.net/api/v1/repos/kemitix/test/issues?state=open",
|
||||
StatusCode::OK,
|
||||
r#"[{"number": 13}]"#,
|
||||
);
|
||||
let _env = THE_ENVIRONMENT.lock();
|
||||
let fs = kxio::fs::temp()?;
|
||||
fs.file_write(
|
||||
&fs.base().join("file_with_valids.txt"),
|
||||
include_str!("data/file_with_valids.txt"),
|
||||
)?;
|
||||
std::env::set_var("GITHUB_WORKSPACE", fs.base());
|
||||
std::env::set_var("GITHUB_REPOSITORY", "kemitix/test");
|
||||
std::env::set_var("GITHUB_SERVER_URL", "https://git.kemitix.net");
|
||||
|
||||
//when
|
||||
|
||||
run(net.into()).await?;
|
||||
|
||||
//then
|
||||
// TODO: add check that run fails because file_1.txt is invalid
|
||||
// TODO: add check that network requests were made to get issues
|
||||
|
||||
Ok(())
|
||||
}
|
55
src/tests/scanner.rs
Normal file
55
src/tests/scanner.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
use super::*;
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use issues::Issue;
|
||||
use model::Config;
|
||||
use patterns::{issue_pattern, marker_pattern};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn find_markers_in_dir() -> anyhow::Result<()> {
|
||||
//given
|
||||
let fs = kxio::fs::temp()?;
|
||||
fs.file_write(
|
||||
&fs.base().join("file_with_invalids.txt"),
|
||||
include_str!("data/file_with_invalids.txt"),
|
||||
)?;
|
||||
fs.file_write(
|
||||
&fs.base().join("file_with_valids.txt"),
|
||||
include_str!("data/file_with_valids.txt"),
|
||||
)?;
|
||||
|
||||
let config = Config::builder()
|
||||
.net(kxio::network::Network::new_mock())
|
||||
.fs(fs.clone())
|
||||
.server("".to_string())
|
||||
.repo("".to_string())
|
||||
.prefix_pattern(marker_pattern()?)
|
||||
.issue_pattern(issue_pattern()?)
|
||||
.build();
|
||||
let issues = HashSet::from_iter(vec![Issue::new(23), Issue::new(43)]);
|
||||
|
||||
//when
|
||||
let markers = find_markers(&config, issues)?;
|
||||
|
||||
//then
|
||||
assert_eq!(
|
||||
markers.to_string().lines().collect::<Vec<_>>(),
|
||||
vec![
|
||||
"- Invalid: file_with_invalids.txt#2:",
|
||||
" It contains a todo comment: // TODO: this is it",
|
||||
"- Invalid: file_with_invalids.txt#4:",
|
||||
" It also contains a fix-me comment: // FIXME: and this is it",
|
||||
"- Closed : (3) file_with_invalids.txt#8:",
|
||||
" We also have a todo comment: // TODO: (#3) and it has an issue number, but it is closed",
|
||||
"- Valid : (23) file_with_valids.txt#2:",
|
||||
" It also has a todo comment: // TODO: (#23) and it has an issue number",
|
||||
"- Valid : (43) file_with_valids.txt#4:",
|
||||
" Here is a fix-me comment: // FIXME: (#43) and is also has an issue number"
|
||||
]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in a new issue