Skip to content

Commit 77a0b73

Browse files
authored
Fast Team from File (#56)
* team from file * only build teams by name once * from_team_file_path for reuse * memoize codeowners
1 parent 846a7ba commit 77a0b73

File tree

15 files changed

+464
-85
lines changed

15 files changed

+464
-85
lines changed

Cargo.lock

Lines changed: 87 additions & 6 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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ clap_derive = "4.5.18"
1515
error-stack = "0.5.0"
1616
enum_dispatch = "0.3.13"
1717
fast-glob = "0.4.0"
18+
glob = "0.3.2"
1819
ignore = "0.4.23"
1920
itertools = "0.14.0"
2021
lazy_static = "1.5.0"
22+
memoize = "0.5.1"
2123
path-clean = "1.0.1"
2224
rayon = "1.10.0"
2325
regex = "1.11.1"
@@ -30,7 +32,6 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
3032

3133
[dev-dependencies]
3234
assert_cmd = "2.0.16"
33-
glob = "0.3.1"
3435
rusty-hook = "^0.11.2"
3536
predicates = "3.1.2"
3637
pretty_assertions = "1.4.1" # Shows a more readable diff when comparing objects

src/cli.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
use clap::{Parser, Subcommand};
2-
use codeowners::runner::{Error as RunnerError, RunResult};
3-
use codeowners::runner::{RunConfig, Runner};
2+
use codeowners::runner::RunConfig;
3+
use codeowners::runner::{self, Error as RunnerError, RunResult};
44
use error_stack::{Result, ResultExt};
55
use path_clean::PathClean;
66
use std::path::{Path, PathBuf};
77

88
#[derive(Subcommand, Debug)]
99
enum Command {
1010
#[clap(about = "Finds the owner of a given file.", visible_alias = "f")]
11-
ForFile { name: String },
11+
ForFile {
12+
#[arg(
13+
short,
14+
long,
15+
default_value = "false",
16+
help = "Find the owner from the CODEOWNERS file and just return the team name and yml path"
17+
)]
18+
fast: bool,
19+
name: String,
20+
},
1221

1322
#[clap(about = "Finds code ownership information for a given team ", visible_alias = "t")]
1423
ForTeam { name: String },
@@ -90,15 +99,13 @@ pub fn cli() -> Result<RunResult, RunnerError> {
9099
no_cache: args.no_cache,
91100
};
92101

93-
let runner = Runner::new(&run_config)?;
94-
95102
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(),
103+
Command::Validate => runner::validate(&run_config, vec![]),
104+
Command::Generate => runner::generate(&run_config),
105+
Command::GenerateAndValidate => runner::generate_and_validate(&run_config, vec![]),
106+
Command::ForFile { name, fast } => runner::for_file(&run_config, &name, fast),
107+
Command::ForTeam { name } => runner::for_team(&run_config, &name),
108+
Command::DeleteCache => runner::delete_cache(&run_config),
102109
};
103110

104111
Ok(runner_result)

src/config.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
use serde::Deserialize;
22

3-
#[derive(Deserialize, Debug)]
3+
#[derive(Deserialize, Debug, Clone)]
44
pub struct Config {
55
pub owned_globs: Vec<String>,
66

77
#[serde(default = "ruby_package_paths")]
88
pub ruby_package_paths: Vec<String>,
99

10-
#[serde(alias = "js_package_paths")]
10+
#[serde(alias = "js_package_paths", default = "javascript_package_paths")]
1111
pub javascript_package_paths: Vec<String>,
1212

1313
#[serde(default = "team_file_glob")]
1414
pub team_file_glob: Vec<String>,
15+
16+
#[serde(default = "unowned_globs")]
1517
pub unowned_globs: Vec<String>,
1618

17-
#[serde(alias = "unbuilt_gems_path")]
19+
#[serde(alias = "unbuilt_gems_path", default = "vendored_gems_path")]
1820
pub vendored_gems_path: String,
1921

2022
#[serde(default = "default_cache_directory")]
@@ -39,3 +41,58 @@ fn team_file_glob() -> Vec<String> {
3941
fn default_cache_directory() -> String {
4042
String::from("tmp/cache/codeowners")
4143
}
44+
45+
fn javascript_package_paths() -> Vec<String> {
46+
vec!["frontend/**/*".to_owned()]
47+
}
48+
49+
fn unowned_globs() -> Vec<String> {
50+
vec![
51+
"frontend/**/node_modules/**/*".to_owned(),
52+
"frontend/**/__generated__/**/*".to_owned(),
53+
]
54+
}
55+
56+
fn vendored_gems_path() -> String {
57+
"vendored/".to_string()
58+
}
59+
60+
#[cfg(test)]
61+
mod tests {
62+
use std::{
63+
error::Error,
64+
fs::{self, File},
65+
};
66+
67+
use indoc::indoc;
68+
use tempfile::tempdir;
69+
70+
use super::*;
71+
72+
#[test]
73+
fn test_parse_config() -> Result<(), Box<dyn Error>> {
74+
let temp_dir = tempdir()?;
75+
let config_path = temp_dir.path().join("config.yml");
76+
let config_str = indoc! {"
77+
---
78+
owned_globs:
79+
- \"{app,components,config,frontend,lib,packs,spec}/**/*.{rb,rake,js,jsx,ts,tsx,json,yml}\"
80+
"};
81+
fs::write(&config_path, config_str)?;
82+
let config_file = File::open(&config_path)?;
83+
let config: Config = serde_yaml::from_reader(config_file)?;
84+
assert_eq!(
85+
config.owned_globs,
86+
vec!["{app,components,config,frontend,lib,packs,spec}/**/*.{rb,rake,js,jsx,ts,tsx,json,yml}"]
87+
);
88+
assert_eq!(config.ruby_package_paths, vec!["packs/**/*", "components/**"]);
89+
assert_eq!(config.javascript_package_paths, vec!["frontend/**/*"]);
90+
assert_eq!(config.team_file_glob, vec!["config/teams/**/*.yml"]);
91+
assert_eq!(
92+
config.unowned_globs,
93+
vec!["frontend/**/node_modules/**/*", "frontend/**/__generated__/**/*"]
94+
);
95+
assert_eq!(config.vendored_gems_path, "vendored/");
96+
Ok(())
97+
}
98+
}

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ fn maybe_print_errors(result: RunResult) -> Result<(), RunnerError> {
2121
}
2222
if !result.io_errors.is_empty() || !result.validation_errors.is_empty() {
2323
for msg in result.io_errors {
24-
println!("{}", msg);
24+
eprintln!("{}", msg);
2525
}
2626
for msg in result.validation_errors {
2727
println!("{}", msg);

src/ownership.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use tracing::{info, instrument};
1212
mod file_generator;
1313
mod file_owner_finder;
1414
pub(crate) mod mapper;
15-
mod parser;
15+
pub(crate) mod parser;
1616
mod validator;
1717

1818
use crate::{

src/ownership/mapper/directory_mapper.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl DirectoryMapper {
1818
impl Mapper for DirectoryMapper {
1919
fn entries(&self) -> Vec<Entry> {
2020
let mut entries: Vec<Entry> = Vec::new();
21-
let team_by_name = self.project.team_by_name();
21+
let team_by_name = self.project.teams_by_name.clone();
2222

2323
for directory_codeowner_file in &self.project.directory_codeowner_files {
2424
let dir_root = directory_codeowner_file.directory_root().to_string_lossy();

src/ownership/mapper/package_mapper.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl PackageMapper {
6666
impl PackageMapper {
6767
fn entries(&self, package_type: &PackageType) -> Vec<Entry> {
6868
let mut entries: Vec<Entry> = Vec::new();
69-
let team_by_name = self.project.team_by_name();
69+
let team_by_name = self.project.teams_by_name.clone();
7070

7171
for package in self.project.packages.iter().filter(|package| &package.package_type == package_type) {
7272
let package_root = package.package_root().to_string_lossy();
@@ -87,7 +87,7 @@ impl PackageMapper {
8787

8888
fn owner_matchers(&self, package_type: &PackageType) -> Vec<OwnerMatcher> {
8989
let mut owner_matchers: Vec<OwnerMatcher> = Vec::new();
90-
let team_by_name = self.project.team_by_name();
90+
let team_by_name = self.project.teams_by_name.clone();
9191

9292
let packages = &self.project.packages;
9393
let packages: Vec<&Package> = packages.iter().filter(|package| &package.package_type == package_type).collect();

0 commit comments

Comments
 (0)