Skip to content

Permit subteams to have subteams #1046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,11 @@ impl Team {

// Return's whether the provided team is a subteam of this team
pub(crate) fn is_parent_of<'a>(&'a self, data: &'a Data, subteam: &Team) -> bool {
let mut visited = Vec::new();
let mut subteam = Some(subteam);
while let Some(s) = subteam {
while let Some(team) = subteam {
// Get subteam's parent
let Some(parent) = s.subteam_of() else {
let Some(parent) = team.subteam_of() else {
// The current subteam is a top level team.
// Therefore this team cannot be its parent.
return false;
Expand All @@ -198,7 +199,16 @@ impl Team {
if parent == self.name {
return true;
}

visited.push(team.name.as_str());

// Otherwise try the test again with the parent
// unless we have already visited it.

if visited.contains(&parent) {
// We have found a cycle, give up.
return false;
}
subteam = data.team(parent);
}
false
Expand Down
43 changes: 27 additions & 16 deletions src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,25 +161,36 @@ fn validate_name_prefixes(data: &Data, errors: &mut Vec<String>) {

/// Ensure `subteam-of` points to an existing team
fn validate_subteam_of(data: &Data, errors: &mut Vec<String>) {
let teams: HashMap<_, _> = data
.teams()
.map(|t| (t.name(), t.subteam_of().is_some()))
.collect();
wrapper(data.teams(), errors, |team, _| {
if let Some(subteam_of) = team.subteam_of() {
match teams.get(subteam_of) {
Some(false) => {}
Some(true) => bail!(
"team `{}` can't be a subteam of a subteam (`{}`)",
team.name(),
subteam_of
),
None => bail!(
wrapper(data.teams(), errors, |mut team, _| {
let mut visited = Vec::new();
while let Some(parent) = team.subteam_of() {
visited.push(team.name());

if visited.contains(&parent) {
bail!(
"team `{parent}` is a subteam of itself: {} => {parent}",
visited.join(" => "),
);
}

let Some(parent) = data.team(parent) else {
bail!(
"the parent of team `{}` doesn't exist: `{}`",
team.name(),
subteam_of
),
parent,
);
};

if !matches!(team.kind(), TeamKind::Team) && parent.subteam_of().is_some() {
bail!(
"{} `{}` can't be a subteam of a subteam (`{}`)",
team.kind(),
team.name(),
parent.name(),
);
}

team = parent;
}
Ok(())
});
Expand Down