Skip to content

Commit 361cda6

Browse files
authored
Sorting special characters feature parity (#51)
* bumping rust to 1.83.0 * sorting special characters
1 parent 3b05bc1 commit 361cda6

File tree

11 files changed

+164
-5
lines changed

11 files changed

+164
-5
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "codeowners"
3-
version = "0.2.2"
3+
version = "0.2.3"
44
edition = "2021"
55

66
[profile.release]

rust-toolchain.toml

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

src/ownership/file_generator.rs

+155-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::cmp::Ordering;
2+
13
use super::{Entry, Mapper};
24

35
pub struct FileGenerator {
@@ -41,7 +43,159 @@ impl FileGenerator {
4143

4244
fn to_sorted_lines(entries: &[Entry]) -> Vec<String> {
4345
let mut lines: Vec<String> = entries.iter().map(|entry| entry.to_row()).collect();
44-
lines.sort();
46+
lines.sort_by(|a, b| {
47+
if let Some((prefix, _)) = a.split_once("**") {
48+
if b.starts_with(prefix) {
49+
return Ordering::Less;
50+
}
51+
}
52+
if let Some((prefix, _)) = b.split_once("**") {
53+
if a.starts_with(prefix) {
54+
return Ordering::Greater;
55+
}
56+
}
57+
a.cmp(b)
58+
});
4559
lines
4660
}
4761
}
62+
63+
#[cfg(test)]
64+
mod tests {
65+
use super::*;
66+
67+
#[test]
68+
fn test_to_sorted_lines_with_special_characters() {
69+
// The `(` character is less than `*` in the default sort order.
70+
let mut illustrate_issue = vec!["*".to_string(), "(".to_string()];
71+
illustrate_issue.sort();
72+
assert_eq!(illustrate_issue, vec!["(".to_string(), "*".to_string()]);
73+
74+
let entries = vec![
75+
Entry {
76+
// Problem is when a dir name starts with `(`.
77+
path: "directory/owner/(my_folder)/**/**".to_string(),
78+
github_team: "@foo".to_string(),
79+
team_name: "footeam".to_string(),
80+
disabled: false,
81+
},
82+
Entry {
83+
// Another example of a dir starting with `(`.
84+
path: "directory/owner/(my_folder)/without_glob".to_string(),
85+
github_team: "@zoo".to_string(),
86+
team_name: "zooteam".to_string(),
87+
disabled: false,
88+
},
89+
Entry {
90+
// And is compared to a glob that starts with `*`.
91+
path: "directory/owner/**".to_string(),
92+
github_team: "@bar".to_string(),
93+
team_name: "barteam".to_string(),
94+
disabled: false,
95+
},
96+
Entry {
97+
path: "directory/owner/my_folder/**".to_string(),
98+
github_team: "@baz".to_string(),
99+
team_name: "bazteam".to_string(),
100+
disabled: false,
101+
},
102+
Entry {
103+
path: "directory/**".to_string(),
104+
github_team: "@bop".to_string(),
105+
team_name: "bopteam".to_string(),
106+
disabled: false,
107+
},
108+
];
109+
let sorted = FileGenerator::to_sorted_lines(&entries);
110+
assert_eq!(
111+
sorted,
112+
vec![
113+
"/directory/** @bop",
114+
"/directory/owner/** @bar",
115+
"/directory/owner/(my_folder)/**/** @foo",
116+
"/directory/owner/(my_folder)/without_glob @zoo",
117+
"/directory/owner/my_folder/** @baz"
118+
]
119+
);
120+
}
121+
122+
#[test]
123+
fn test_basic_sorting() {
124+
let entries = vec![
125+
Entry {
126+
path: "b_directory/owner/**".to_string(),
127+
github_team: "@bar".to_string(),
128+
team_name: "barteam".to_string(),
129+
disabled: false,
130+
},
131+
Entry {
132+
path: "a_directory/owner/**".to_string(),
133+
github_team: "@foo".to_string(),
134+
team_name: "footeam".to_string(),
135+
disabled: false,
136+
},
137+
];
138+
let sorted = FileGenerator::to_sorted_lines(&entries);
139+
assert_eq!(sorted, vec!["/a_directory/owner/** @foo", "/b_directory/owner/** @bar"]);
140+
}
141+
142+
#[test]
143+
fn test_sorting_with_mixed_case() {
144+
let entries = vec![
145+
Entry {
146+
path: "directory/Owner/**".to_string(),
147+
github_team: "@bar".to_string(),
148+
team_name: "barteam".to_string(),
149+
disabled: false,
150+
},
151+
Entry {
152+
path: "directory/owner/**".to_string(),
153+
github_team: "@foo".to_string(),
154+
team_name: "footeam".to_string(),
155+
disabled: false,
156+
},
157+
];
158+
let sorted = FileGenerator::to_sorted_lines(&entries);
159+
assert_eq!(sorted, vec!["/directory/Owner/** @bar", "/directory/owner/** @foo"]);
160+
}
161+
162+
#[test]
163+
fn test_sorting_with_numbers() {
164+
let entries = vec![
165+
Entry {
166+
path: "directory/owner1/**".to_string(),
167+
github_team: "@foo".to_string(),
168+
team_name: "footeam".to_string(),
169+
disabled: false,
170+
},
171+
Entry {
172+
path: "directory/owner2/**".to_string(),
173+
github_team: "@bar".to_string(),
174+
team_name: "barteam".to_string(),
175+
disabled: false,
176+
},
177+
];
178+
let sorted = FileGenerator::to_sorted_lines(&entries);
179+
assert_eq!(sorted, vec!["/directory/owner1/** @foo", "/directory/owner2/** @bar"]);
180+
}
181+
182+
#[test]
183+
fn test_sorting_with_special_characters() {
184+
let entries = vec![
185+
Entry {
186+
path: "directory/owner-1/**".to_string(),
187+
github_team: "@foo".to_string(),
188+
team_name: "footeam".to_string(),
189+
disabled: false,
190+
},
191+
Entry {
192+
path: "directory/owner_2/**".to_string(),
193+
github_team: "@bar".to_string(),
194+
team_name: "barteam".to_string(),
195+
disabled: false,
196+
},
197+
];
198+
let sorted = FileGenerator::to_sorted_lines(&entries);
199+
assert_eq!(sorted, vec!["/directory/owner-1/** @foo", "/directory/owner_2/** @bar"]);
200+
}
201+
}

src/ownership/file_owner_finder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub struct FileOwnerFinder<'a> {
1212
pub owner_matchers: &'a [OwnerMatcher],
1313
}
1414

15-
impl<'a> FileOwnerFinder<'a> {
15+
impl FileOwnerFinder<'_> {
1616
pub fn find(&self, relative_path: &Path) -> Vec<Owner> {
1717
let mut team_sources_map: HashMap<&TeamName, Vec<Source>> = HashMap::new();
1818
let mut directory_overrider = DirectoryOverrider::default();

tests/fixtures/valid_project/.github/CODEOWNERS

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
/ruby/app/payments/**/* @PaymentsTeam
1717

1818
# Owner in .codeowner
19+
/javascript/packages/items/**/** @PayrollTeam
20+
/javascript/packages/items/(special)/**/** @PaymentsTeam
1921
/ruby/app/payroll/**/** @PayrollTeam
2022

2123
# Owner metadata key in package.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Payments

tests/fixtures/valid_project/javascript/packages/items/(special)/pay.ts

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Payroll

tests/fixtures/valid_project/javascript/packages/items/item.ts

Whitespace-only changes.

tests/valid_project_test.rs

+1
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ fn test_for_team() -> Result<(), Box<dyn Error>> {
120120
This team owns nothing in this category.
121121
122122
## Owner in .codeowner
123+
/javascript/packages/items/**/**
123124
/ruby/app/payroll/**/**
124125
125126
## Owner metadata key in package.yml

0 commit comments

Comments
 (0)