Skip to content

Commit 39859d2

Browse files
authored
Refactoring for magnus integration and multiple output formats (#54)
* rust 2024 * introducing runner for reuse * reorg main * better io errors * extracting parser
1 parent 361cda6 commit 39859d2

18 files changed

+537
-324
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "codeowners"
33
version = "0.2.3"
4-
edition = "2021"
4+
edition = "2024"
55

66
[profile.release]
77
debug = true
@@ -16,7 +16,7 @@ error-stack = "0.5.0"
1616
enum_dispatch = "0.3.13"
1717
fast-glob = "0.4.0"
1818
ignore = "0.4.23"
19-
itertools = "0.13.0"
19+
itertools = "0.14.0"
2020
lazy_static = "1.5.0"
2121
path-clean = "1.0.1"
2222
rayon = "1.10.0"

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[toolchain]
2-
channel = "1.83.0"
2+
channel = "1.85.0"
33
components = ["clippy", "rustfmt"]
44
targets = ["x86_64-apple-darwin", "aarch64-apple-darwin", "x86_64-unknown-linux-gnu"]

src/cli.rs

Lines changed: 28 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
11
use clap::{Parser, Subcommand};
2-
use codeowners::{
3-
cache::{file::GlobalCache, noop::NoopCache, Cache, Caching},
4-
config::Config,
5-
ownership::{FileOwner, Ownership},
6-
project_builder::ProjectBuilder,
7-
};
8-
use core::fmt;
9-
use error_stack::{Context, Result, ResultExt};
2+
use codeowners::runner::{Error as RunnerError, RunResult};
3+
use codeowners::runner::{RunConfig, Runner};
4+
use error_stack::{Result, ResultExt};
105
use path_clean::PathClean;
11-
use std::{
12-
fs::File,
13-
path::{Path, PathBuf},
14-
};
6+
use std::path::{Path, PathBuf};
157

168
#[derive(Subcommand, Debug)]
179
enum Command {
@@ -64,105 +56,50 @@ struct Args {
6456
}
6557

6658
impl Args {
67-
fn absolute_project_root(&self) -> Result<PathBuf, Error> {
68-
self.project_root.canonicalize().change_context(Error::Io)
59+
fn absolute_project_root(&self) -> Result<PathBuf, RunnerError> {
60+
self.project_root.canonicalize().change_context(RunnerError::Io(format!(
61+
"Can't canonicalize project root: {}",
62+
&self.project_root.to_string_lossy()
63+
)))
6964
}
7065

71-
fn absolute_config_path(&self) -> Result<PathBuf, Error> {
66+
fn absolute_config_path(&self) -> Result<PathBuf, RunnerError> {
7267
Ok(self.absolute_path(&self.config_path)?.clean())
7368
}
7469

75-
fn absolute_codeowners_path(&self) -> Result<PathBuf, Error> {
70+
fn absolute_codeowners_path(&self) -> Result<PathBuf, RunnerError> {
7671
Ok(self.absolute_path(&self.codeowners_file_path)?.clean())
7772
}
7873

79-
fn absolute_path(&self, path: &Path) -> Result<PathBuf, Error> {
74+
fn absolute_path(&self, path: &Path) -> Result<PathBuf, RunnerError> {
8075
Ok(self.absolute_project_root()?.join(path))
8176
}
8277
}
8378

84-
#[derive(Debug)]
85-
pub enum Error {
86-
Io,
87-
ValidationFailed,
88-
}
89-
90-
impl Context for Error {}
91-
92-
pub fn cli() -> Result<(), Error> {
79+
pub fn cli() -> Result<RunResult, RunnerError> {
9380
let args = Args::parse();
9481

9582
let config_path = args.absolute_config_path()?;
9683
let codeowners_file_path = args.absolute_codeowners_path()?;
9784
let project_root = args.absolute_project_root()?;
9885

99-
let config_file = File::open(&config_path)
100-
.change_context(Error::Io)
101-
.attach_printable(format!("Can't open config file: {}", config_path.to_string_lossy()))?;
102-
103-
let config: Config = serde_yaml::from_reader(config_file).change_context(Error::Io)?;
104-
let cache: Cache = if args.no_cache {
105-
NoopCache::default().into()
106-
} else {
107-
GlobalCache::new(project_root.clone(), config.cache_directory.clone())
108-
.change_context(Error::Io)?
109-
.into()
86+
let run_config = RunConfig {
87+
config_path,
88+
codeowners_file_path,
89+
project_root,
90+
no_cache: args.no_cache,
11091
};
11192

112-
let mut project_builder = ProjectBuilder::new(&config, project_root.clone(), codeowners_file_path.clone(), &cache);
113-
let project = project_builder.build().change_context(Error::Io)?;
114-
let ownership = Ownership::build(project);
115-
116-
cache.persist_cache().change_context(Error::Io)?;
117-
118-
match args.command {
119-
Command::Validate => ownership.validate().change_context(Error::ValidationFailed)?,
120-
Command::Generate => {
121-
std::fs::write(codeowners_file_path, ownership.generate_file()).change_context(Error::Io)?;
122-
}
123-
Command::GenerateAndValidate => {
124-
std::fs::write(codeowners_file_path, ownership.generate_file()).change_context(Error::Io)?;
125-
ownership.validate().change_context(Error::ValidationFailed)?
126-
}
127-
Command::ForFile { name } => {
128-
let file_owners = ownership.for_file(&name).change_context(Error::Io)?;
129-
match file_owners.len() {
130-
0 => println!("{}", FileOwner::default()),
131-
1 => println!("{}", file_owners[0]),
132-
_ => {
133-
println!("Error: file is owned by multiple teams!");
134-
for file_owner in file_owners {
135-
println!("\n{}", file_owner);
136-
}
137-
}
138-
}
139-
}
140-
Command::ForTeam { name } => match ownership.for_team(&name) {
141-
Ok(team_ownerships) => {
142-
println!("# Code Ownership Report for `{}` Team", name);
143-
for team_ownership in team_ownerships {
144-
println!("\n#{}", team_ownership.heading);
145-
match team_ownership.globs.len() {
146-
0 => println!("This team owns nothing in this category."),
147-
_ => println!("{}", team_ownership.globs.join("\n")),
148-
}
149-
}
150-
}
151-
Err(err) => println!("{}", err),
152-
},
153-
Command::DeleteCache => {
154-
cache.delete_cache().change_context(Error::Io)?;
155-
}
156-
}
93+
let runner = Runner::new(&run_config)?;
15794

158-
Ok(())
159-
}
95+
let runner_result = match args.command {
96+
Command::Validate => runner.validate(),
97+
Command::Generate => runner.generate(),
98+
Command::GenerateAndValidate => runner.generate_and_validate(),
99+
Command::ForFile { name } => runner.for_file(&name),
100+
Command::ForTeam { name } => runner.for_team(&name),
101+
Command::DeleteCache => runner.delete_cache(),
102+
};
160103

161-
impl fmt::Display for Error {
162-
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
163-
match self {
164-
Error::Io => fmt.write_str("Error::Io"),
165-
Error::ValidationFailed => fmt.write_str("Error::ValidationFailed"),
166-
}
167-
}
104+
Ok(runner_result)
168105
}

src/common_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub mod tests {
1111
use tempfile::tempdir;
1212

1313
use crate::{
14-
cache::{noop::NoopCache, Cache},
14+
cache::{Cache, noop::NoopCache},
1515
config::Config,
1616
ownership::Ownership,
1717
project_builder::ProjectBuilder,

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ pub mod ownership;
55
pub(crate) mod project;
66
pub mod project_builder;
77
pub mod project_file_builder;
8+
pub mod runner;

src/main.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
11
mod cli;
22
use std::process;
33

4-
use cli::Error;
5-
use codeowners::ownership;
4+
use codeowners::runner::{Error as RunnerError, RunResult};
65
use error_stack::Result;
76

87
use crate::cli::cli;
98

10-
fn main() -> Result<(), Error> {
9+
fn main() -> Result<(), RunnerError> {
1110
install_logger();
12-
maybe_print_errors(cli())?;
11+
maybe_print_errors(cli()?)?;
1312

1413
Ok(())
1514
}
1615

17-
fn maybe_print_errors(result: Result<(), Error>) -> Result<(), Error> {
18-
if let Err(error) = result {
19-
if let Some(validation_errors) = error.downcast_ref::<ownership::ValidatorErrors>() {
20-
println!("{}", validation_errors);
21-
process::exit(-1);
22-
} else {
23-
Err(error)?
16+
fn maybe_print_errors(result: RunResult) -> Result<(), RunnerError> {
17+
dbg!(&result);
18+
if !result.info_messages.is_empty() {
19+
for msg in result.info_messages {
20+
println!("{}", msg);
2421
}
2522
}
23+
if !result.io_errors.is_empty() || !result.validation_errors.is_empty() {
24+
for msg in result.io_errors {
25+
println!("{}", msg);
26+
}
27+
for msg in result.validation_errors {
28+
println!("{}", msg);
29+
}
30+
process::exit(-1);
31+
}
2632

2733
Ok(())
2834
}

0 commit comments

Comments
 (0)