Skip to content

Commit eb389f8

Browse files
committed
extracting parser
1 parent fe8819d commit eb389f8

File tree

4 files changed

+239
-210
lines changed

4 files changed

+239
-210
lines changed

src/ownership.rs

Lines changed: 9 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use tracing::{info, instrument};
1212
mod file_generator;
1313
mod file_owner_finder;
1414
pub(crate) mod mapper;
15+
mod parser;
1516
mod validator;
1617

1718
use crate::{
@@ -24,6 +25,7 @@ pub use validator::Errors as ValidatorErrors;
2425
use self::{
2526
file_generator::FileGenerator,
2627
mapper::{JavascriptPackageMapper, Mapper, RubyPackageMapper, TeamFileMapper, TeamGemMapper, TeamGlobMapper, TeamYmlMapper},
28+
parser::parse_for_team,
2729
validator::Validator,
2830
};
2931

@@ -122,6 +124,12 @@ impl Ownership {
122124
validator.validate()
123125
}
124126

127+
#[instrument(level = "debug", skip_all)]
128+
pub fn fast_for_file(&self, file_path: &str) -> Result<(String, String), ValidatorErrors> {
129+
let file_owner = self.for_file(file_path)?;
130+
Ok((file_owner[0].team.name.clone(), file_owner[0].team.github_team.clone()))
131+
}
132+
125133
#[instrument(level = "debug", skip_all)]
126134
pub fn for_file(&self, file_path: &str) -> Result<Vec<FileOwner>, ValidatorErrors> {
127135
info!("getting file ownership for {}", file_path);
@@ -176,47 +184,10 @@ impl Ownership {
176184
}
177185
}
178186

179-
fn parse_for_team(team_name: String, codeowners_file: &str) -> Result<Vec<TeamOwnership>, Box<dyn Error>> {
180-
let mut output = vec![];
181-
let mut current_section: Option<TeamOwnership> = None;
182-
let input: String = codeowners_file.replace(&FileGenerator::disclaimer().join("\n"), "");
183-
let error_message = "CODEOWNERS out of date. Run `codeowners generate` to update the CODEOWNERS file";
184-
185-
for line in input.trim_start().lines() {
186-
match line {
187-
comment if comment.starts_with("#") => {
188-
if let Some(section) = current_section.take() {
189-
output.push(section);
190-
}
191-
current_section = Some(TeamOwnership::new(comment.to_string()));
192-
}
193-
"" => {
194-
if let Some(section) = current_section.take() {
195-
output.push(section);
196-
}
197-
}
198-
team_line if team_line.ends_with(&team_name) => {
199-
let section = current_section.as_mut().ok_or(error_message)?;
200-
201-
let glob = line.split_once(' ').ok_or(error_message)?.0.to_string();
202-
section.globs.push(glob);
203-
}
204-
_ => {}
205-
}
206-
}
207-
208-
if let Some(cs) = current_section {
209-
output.push(cs.clone());
210-
}
211-
212-
Ok(output)
213-
}
214-
215187
#[cfg(test)]
216188
mod tests {
217189
use super::*;
218-
use crate::common_test::tests::{build_ownership_with_all_mappers, vecs_match};
219-
use indoc::indoc;
190+
use crate::common_test::tests::build_ownership_with_all_mappers;
220191

221192
#[test]
222193
fn test_for_file_owner() -> Result<(), Box<dyn Error>> {
@@ -251,173 +222,4 @@ mod tests {
251222
assert!(team_ownership.is_err(), "Team not found");
252223
Ok(())
253224
}
254-
255-
#[test]
256-
fn test_parse_for_team_trims_header() -> Result<(), Box<dyn Error>> {
257-
let codeownership_file = indoc! {"
258-
# STOP! - DO NOT EDIT THIS FILE MANUALLY
259-
# This file was automatically generated by \"bin/codeownership validate\".
260-
#
261-
# CODEOWNERS is used for GitHub to suggest code/file owners to various GitHub
262-
# teams. This is useful when developers create Pull Requests since the
263-
# code/file owner is notified. Reference GitHub docs for more details:
264-
# https://help.github.com/en/articles/about-code-owners
265-
266-
267-
"};
268-
269-
let team_ownership = parse_for_team("@Bar".to_string(), codeownership_file)?;
270-
assert!(team_ownership.is_empty());
271-
Ok(())
272-
}
273-
274-
#[test]
275-
fn test_parse_for_team_includes_owned_globs() -> Result<(), Box<dyn Error>> {
276-
let codeownership_file = indoc! {"
277-
# First Section
278-
/path/to/owned @Foo
279-
/path/to/not/owned @Bar
280-
281-
# Last Section
282-
/another/owned/path @Foo
283-
"};
284-
285-
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file)?;
286-
vecs_match(
287-
&team_ownership,
288-
&vec![
289-
TeamOwnership {
290-
heading: "# First Section".to_string(),
291-
globs: vec!["/path/to/owned".to_string()],
292-
},
293-
TeamOwnership {
294-
heading: "# Last Section".to_string(),
295-
globs: vec!["/another/owned/path".to_string()],
296-
},
297-
],
298-
);
299-
Ok(())
300-
}
301-
302-
#[test]
303-
fn test_parse_for_team_with_partial_team_match() -> Result<(), Box<dyn Error>> {
304-
let codeownership_file = indoc! {"
305-
# First Section
306-
/path/to/owned @Foo
307-
/path/to/not/owned @FooBar
308-
"};
309-
310-
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file)?;
311-
vecs_match(
312-
&team_ownership,
313-
&vec![TeamOwnership {
314-
heading: "# First Section".to_string(),
315-
globs: vec!["/path/to/owned".to_string()],
316-
}],
317-
);
318-
Ok(())
319-
}
320-
321-
#[test]
322-
fn test_parse_for_team_with_trailing_newlines() -> Result<(), Box<dyn Error>> {
323-
let codeownership_file = indoc! {"
324-
# First Section
325-
/path/to/owned @Foo
326-
327-
# Last Section
328-
/another/owned/path @Foo
329-
330-
331-
332-
"};
333-
334-
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file)?;
335-
vecs_match(
336-
&team_ownership,
337-
&vec![
338-
TeamOwnership {
339-
heading: "# First Section".to_string(),
340-
globs: vec!["/path/to/owned".to_string()],
341-
},
342-
TeamOwnership {
343-
heading: "# Last Section".to_string(),
344-
globs: vec!["/another/owned/path".to_string()],
345-
},
346-
],
347-
);
348-
Ok(())
349-
}
350-
351-
#[test]
352-
fn test_parse_for_team_without_trailing_newline() -> Result<(), Box<dyn Error>> {
353-
let codeownership_file = indoc! {"
354-
# First Section
355-
/path/to/owned @Foo"};
356-
357-
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file)?;
358-
vecs_match(
359-
&team_ownership,
360-
&vec![TeamOwnership {
361-
heading: "# First Section".to_string(),
362-
globs: vec!["/path/to/owned".to_string()],
363-
}],
364-
);
365-
Ok(())
366-
}
367-
368-
#[test]
369-
fn test_parse_for_team_with_missing_section_header() -> Result<(), Box<dyn Error>> {
370-
let codeownership_file = indoc! {"
371-
# First Section
372-
/path/to/owned @Foo
373-
374-
/another/owned/path @Foo
375-
"};
376-
377-
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file);
378-
assert!(
379-
team_ownership
380-
.is_err_and(|e| e.to_string() == "CODEOWNERS out of date. Run `codeowners generate` to update the CODEOWNERS file")
381-
);
382-
Ok(())
383-
}
384-
385-
#[test]
386-
fn test_parse_for_team_with_malformed_team_line() -> Result<(), Box<dyn Error>> {
387-
let codeownership_file = indoc! {"
388-
# First Section
389-
@Foo
390-
"};
391-
392-
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file);
393-
assert!(
394-
team_ownership
395-
.is_err_and(|e| e.to_string() == "CODEOWNERS out of date. Run `codeowners generate` to update the CODEOWNERS file")
396-
);
397-
Ok(())
398-
}
399-
400-
#[test]
401-
fn test_parse_for_team_with_invalid_file() -> Result<(), Box<dyn Error>> {
402-
let codeownership_file = indoc! {"
403-
# First Section
404-
# Second Section
405-
path/to/owned @Foo
406-
"};
407-
let team_ownership = parse_for_team("@Foo".to_string(), codeownership_file)?;
408-
vecs_match(
409-
&team_ownership,
410-
&vec![
411-
TeamOwnership {
412-
heading: "# First Section".to_string(),
413-
globs: vec![],
414-
},
415-
TeamOwnership {
416-
heading: "# Second Section".to_string(),
417-
globs: vec!["path/to/owned".to_string()],
418-
},
419-
],
420-
);
421-
Ok(())
422-
}
423225
}

0 commit comments

Comments
 (0)