Skip to content

Commit f430034

Browse files
committed
Fix command handling
1 parent 730f863 commit f430034

File tree

3 files changed

+77
-42
lines changed

3 files changed

+77
-42
lines changed

src/main.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,19 @@ fn cli() -> Result<(), Error> {
138138
}
139139
}
140140
}
141-
Command::ForTeam { name } => {
142-
let team_ownership = ownership.for_team(&name);
143-
match team_ownership {
144-
Ok(output) => println!("{:?}", output),
145-
Err(err) => eprintln!("{}", err),
141+
Command::ForTeam { name } => match ownership.for_team(&name) {
142+
Ok(team_ownerships) => {
143+
println!("# Code Ownership Report for `{}` Team", name);
144+
for team_ownership in team_ownerships {
145+
println!("\n#{}", team_ownership.heading);
146+
match team_ownership.globs.len() {
147+
0 => println!("This team owns nothing in this category."),
148+
_ => println!("{}", team_ownership.globs.join("\n")),
149+
}
150+
}
146151
}
147-
}
152+
Err(err) => eprintln!("{}", err),
153+
},
148154
}
149155

150156
Ok(())

src/ownership.rs

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use file_owner_finder::FileOwnerFinder;
22
use mapper::{OwnerMatcher, Source, TeamName};
33
use std::{
4+
error::Error,
45
fmt::{self, Display},
56
path::Path,
67
sync::Arc,
@@ -38,6 +39,15 @@ pub struct TeamOwnership {
3839
pub globs: Vec<String>,
3940
}
4041

42+
impl TeamOwnership {
43+
fn new(heading: String) -> Self {
44+
Self {
45+
heading,
46+
..Default::default()
47+
}
48+
}
49+
}
50+
4151
impl Display for FileOwner {
4252
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4353
let sources = self
@@ -128,7 +138,7 @@ impl Ownership {
128138
}
129139

130140
#[instrument(level = "debug", skip_all)]
131-
pub fn for_team(&self, team_name: &str) -> Result<Vec<TeamOwnership>, Box<dyn std::error::Error>> {
141+
pub fn for_team(&self, team_name: &str) -> Result<Vec<TeamOwnership>, Box<dyn Error>> {
132142
info!("getting team ownership for {}", team_name);
133143
let team = self.project.get_team(team_name).ok_or("Team not found")?;
134144

@@ -155,33 +165,37 @@ impl Ownership {
155165
}
156166
}
157167

158-
fn parse_for_team(team_name: String, codeowners_file: &str) -> Result<Vec<TeamOwnership>, Box<dyn std::error::Error>> {
168+
fn parse_for_team(team_name: String, codeowners_file: &str) -> Result<Vec<TeamOwnership>, Box<dyn Error>> {
159169
let mut output = vec![];
160-
let mut current_section = TeamOwnership::default();
170+
let mut current_section: Option<TeamOwnership> = None;
161171
let input: String = codeowners_file.replace(&FileGenerator::disclaimer().join("\n"), "");
162172

163173
for line in input.trim_start().lines() {
164174
match line {
165175
comment if comment.starts_with("#") => {
166-
current_section.heading = comment.to_string();
176+
current_section = Some(TeamOwnership::new(comment.to_string()));
167177
}
168178
"" => {
169-
if current_section != TeamOwnership::default() {
170-
output.push(current_section.clone());
171-
current_section = TeamOwnership::default();
179+
if let Some(cs) = current_section {
180+
output.push(cs.clone());
181+
current_section = None;
172182
}
173183
}
174-
team_line if team_line.ends_with(&team_name) => {
175-
let v: Vec<&str> = team_line.split(' ').collect();
176-
let s = v.first().ok_or("malformed team line")?;
184+
team_line if team_line.ends_with(&team_name) => match current_section {
185+
Some(ref mut cs) => {
186+
let v: Vec<&str> = team_line.split(' ').collect();
187+
let s = v.first().ok_or("Malformed team line")?;
177188

178-
current_section.globs.push(s.to_string());
179-
}
189+
cs.globs.push(s.to_string());
190+
}
191+
_ => return Err(Box::from("Missing preceding section header")),
192+
},
180193
_ => {}
181194
}
182195
}
183-
if current_section != TeamOwnership::default() {
184-
output.push(current_section.clone());
196+
197+
if let Some(cs) = current_section {
198+
output.push(cs.clone());
185199
}
186200

187201
Ok(output)
@@ -193,7 +207,7 @@ mod tests {
193207
use crate::common_test::tests::{build_ownership_with_all_mappers, vecs_match};
194208

195209
#[test]
196-
fn test_for_file_owner() -> Result<(), Box<dyn std::error::Error>> {
210+
fn test_for_file_owner() -> Result<(), Box<dyn Error>> {
197211
let ownership = build_ownership_with_all_mappers()?;
198212
let file_owners = ownership.for_file("app/consumers/directory_owned.rb").unwrap();
199213
assert_eq!(file_owners.len(), 1);
@@ -203,31 +217,31 @@ mod tests {
203217
}
204218

205219
#[test]
206-
fn test_for_file_no_owner() -> Result<(), Box<dyn std::error::Error>> {
220+
fn test_for_file_no_owner() -> Result<(), Box<dyn Error>> {
207221
let ownership = build_ownership_with_all_mappers()?;
208222
let file_owners = ownership.for_file("app/madeup/foo.rb").unwrap();
209223
assert_eq!(file_owners.len(), 0);
210224
Ok(())
211225
}
212226

213227
#[test]
214-
fn test_for_team_not_found() -> Result<(), Box<dyn std::error::Error>> {
228+
fn test_for_team() -> Result<(), Box<dyn Error>> {
215229
let ownership = build_ownership_with_all_mappers()?;
216-
let team_ownership = ownership.for_team("Nope");
217-
assert!(team_ownership.is_err(), "Team not found");
230+
let team_ownership = ownership.for_team("Bar");
231+
assert!(team_ownership.is_ok());
218232
Ok(())
219233
}
220234

221235
#[test]
222-
fn test_for_team() -> Result<(), Box<dyn std::error::Error>> {
236+
fn test_for_team_not_found() -> Result<(), Box<dyn Error>> {
223237
let ownership = build_ownership_with_all_mappers()?;
224-
let team_ownership = ownership.for_team("Bar");
225-
assert!(team_ownership.is_ok());
238+
let team_ownership = ownership.for_team("Nope");
239+
assert!(team_ownership.is_err(), "Team not found");
226240
Ok(())
227241
}
228242

229243
#[test]
230-
fn test_parse_for_team_trims_header() -> Result<(), Box<dyn std::error::Error>> {
244+
fn test_parse_for_team_trims_header() -> Result<(), Box<dyn Error>> {
231245
let codeownership_file = r#"
232246
# STOP! - DO NOT EDIT THIS FILE MANUALLY
233247
# This file was automatically generated by "bin/codeownership validate".
@@ -240,29 +254,29 @@ mod tests {
240254
241255
"#;
242256

243-
let team_ownership = parse_for_team("@Bar".to_string(), &codeownership_file)?;
257+
let team_ownership = parse_for_team("@Bar".to_string(), codeownership_file)?;
244258
assert!(team_ownership.is_empty());
245259
Ok(())
246260
}
247261

248262
#[test]
249-
fn test_parse_for_team_includes_owned_globs() -> Result<(), Box<dyn std::error::Error>> {
263+
fn test_parse_for_team_includes_owned_globs() -> Result<(), Box<dyn Error>> {
250264
let codeownership_file = r#"
251265
# First Section
252-
/path/to/owned/**/* @Foo
253-
/path/to/not/owned/**/* @Bar
266+
/path/to/owned @Foo
267+
/path/to/not/owned @Bar
254268
255269
# Last Section
256270
/another/owned/path @Foo
257271
"#;
258272

259-
let team_ownership = parse_for_team("@Foo".to_string(), &codeownership_file)?;
273+
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file)?;
260274
vecs_match(
261275
&team_ownership,
262276
&vec![
263277
TeamOwnership {
264278
heading: "# First Section".to_string(),
265-
globs: vec!["/path/to/owned/**/*".to_string()],
279+
globs: vec!["/path/to/owned".to_string()],
266280
},
267281
TeamOwnership {
268282
heading: "# Last Section".to_string(),
@@ -274,14 +288,14 @@ mod tests {
274288
}
275289

276290
#[test]
277-
fn test_parse_for_team_with_partial_team_match() -> Result<(), Box<dyn std::error::Error>> {
291+
fn test_parse_for_team_with_partial_team_match() -> Result<(), Box<dyn Error>> {
278292
let codeownership_file = r#"
279293
# First Section
280294
/path/to/owned @Foo
281295
/path/to/not/owned @FooBar
282296
"#;
283297

284-
let team_ownership = parse_for_team("@Foo".to_string(), &codeownership_file)?;
298+
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file)?;
285299
vecs_match(
286300
&team_ownership,
287301
&vec![TeamOwnership {
@@ -293,7 +307,7 @@ mod tests {
293307
}
294308

295309
#[test]
296-
fn test_parse_for_team_with_trailing_newlines() -> Result<(), Box<dyn std::error::Error>> {
310+
fn test_parse_for_team_with_trailing_newlines() -> Result<(), Box<dyn Error>> {
297311
let codeownership_file = r#"
298312
# First Section
299313
/path/to/owned @Foo
@@ -305,7 +319,7 @@ mod tests {
305319
306320
"#;
307321

308-
let team_ownership = parse_for_team("@Foo".to_string(), &codeownership_file)?;
322+
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file)?;
309323
vecs_match(
310324
&team_ownership,
311325
&vec![
@@ -323,12 +337,12 @@ mod tests {
323337
}
324338

325339
#[test]
326-
fn test_parse_for_team_without_trailing_newline() -> Result<(), Box<dyn std::error::Error>> {
340+
fn test_parse_for_team_without_trailing_newline() -> Result<(), Box<dyn Error>> {
327341
let codeownership_file = r#"
328342
# First Section
329343
/path/to/owned @Foo"#;
330344

331-
let team_ownership = parse_for_team("@Foo".to_string(), &codeownership_file)?;
345+
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file)?;
332346
vecs_match(
333347
&team_ownership,
334348
&vec![TeamOwnership {
@@ -338,4 +352,19 @@ mod tests {
338352
);
339353
Ok(())
340354
}
355+
356+
#[test]
357+
fn test_parse_for_team_with_missing_section_header() -> Result<(), Box<dyn Error>> {
358+
let codeownership_file = r#"
359+
# First Section
360+
/path/to/owned @Foo
361+
362+
/another/owned/path @Foo
363+
"#;
364+
365+
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file);
366+
dbg!(&team_ownership);
367+
assert!(team_ownership.is_err());
368+
Ok(())
369+
}
341370
}

tests/valid_project_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ fn test_for_team() -> Result<(), Box<dyn Error>> {
5858
/ruby/app/models/payroll.rb
5959
6060
## Team-specific owned globs
61+
This team owns nothing in this category.
6162
6263
## Owner in .codeowner
6364
/ruby/app/payroll/**/**
@@ -73,7 +74,6 @@ fn test_for_team() -> Result<(), Box<dyn Error>> {
7374
7475
## Team owned gems
7576
/gems/payroll_calculator/**/**
76-
7777
"#
7878
.trim_start();
7979

0 commit comments

Comments
 (0)