Skip to content
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

Generate teams for WG area reviewers and bots #378

Merged
merged 1 commit into from
Aug 9, 2022
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
75 changes: 52 additions & 23 deletions org/org_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ def _validate_contributors(contributors):
"properties": {
"name": {"type": "string"},
"approvers": {"type": "array", "items": {"$ref": "#/$defs/githubUser"}},
"reviewers": {"type": "array", "items": {"$ref": "#/$defs/githubUser"}},
"bots": {"type": "array", "items": {"$ref": "#/$defs/githubUser"}},
"repositories": {"type": "array", "items": {"type": "string"}},
},
"required": ["name", "approvers", "repositories"],
Expand Down Expand Up @@ -238,34 +240,61 @@ def _generate_wg_teams(wg) -> Tuple[str, Dict[str, Any]]:
"maintainers": sorted(maintainers),
"members": sorted(approvers - maintainers),
"teams": {
OrgGenerator._kebab_case(f"{name}-{a['name']}-approvers"): {
"description": f"Approvers for {wg['name']} WG, {a['name']} area",
f"{name}-leads": {
"description": f"Leads for {wg['name']} WG",
"privacy": "closed",
"maintainers": sorted(maintainers),
"members": sorted({u["github"] for u in a["approvers"]} - maintainers),
"repos": {
r[OrgGenerator._CF_ORG_PREFIX_LEN :]: "write"
for r in a["repositories"]
if r.startswith(OrgGenerator._CF_ORG_PREFIX)
},
}
for a in wg["areas"]
"repos": {r: "admin" for r in repositories},
},
f"{name}-bots": {
"description": f"Bot accounts for {wg['name']} WG",
"privacy": "closed",
"maintainers": sorted(maintainers),
"members": sorted({u["github"] for u in wg["bots"]} - maintainers),
"repos": {r: "write" for r in repositories},
},
},
}
# WG leads
team["teams"][name + "-leads"] = {
"description": f"Leads for {wg['name']} WG",
"privacy": "closed",
"maintainers": sorted(maintainers),
"repos": {r: "admin" for r in repositories},
# approvers per area
team["teams"] |= {
OrgGenerator._kebab_case(f"{name}-{a['name']}-approvers"): {
"description": f"Approvers for {wg['name']} WG, {a['name']} area",
"privacy": "closed",
"maintainers": sorted(maintainers),
"members": sorted({u["github"] for u in a["approvers"]} - maintainers),
"repos": {
r[OrgGenerator._CF_ORG_PREFIX_LEN :]: "write" for r in a["repositories"] if r.startswith(OrgGenerator._CF_ORG_PREFIX)
},
}
for a in wg["areas"]
}
# WG bots
team["teams"][name + "-bots"] = {
"description": f"Bot accounts for {wg['name']} WG",
"privacy": "closed",
"maintainers": sorted(maintainers),
"members": sorted({u["github"] for u in wg["bots"]} - maintainers),
"repos": {r: "write" for r in repositories},
# optional reviewers per area
team["teams"] |= {
OrgGenerator._kebab_case(f"{name}-{a['name']}-reviewers"): {
"description": f"Reviewers for {wg['name']} WG, {a['name']} area",
"privacy": "closed",
"maintainers": sorted(maintainers),
"members": sorted({u["github"] for u in a["reviewers"]} - maintainers),
"repos": {
r[OrgGenerator._CF_ORG_PREFIX_LEN :]: "read" for r in a["repositories"] if r.startswith(OrgGenerator._CF_ORG_PREFIX)
},
}
for a in wg["areas"]
if "reviewers" in a
}
# optional bots per area
team["teams"] |= {
OrgGenerator._kebab_case(f"{name}-{a['name']}-bots"): {
"description": f"Bot accounts for {wg['name']} WG, {a['name']} area",
"privacy": "closed",
"maintainers": sorted(maintainers),
"members": sorted({u["github"] for u in a["bots"]} - maintainers),
"repos": {
r[OrgGenerator._CF_ORG_PREFIX_LEN :]: "write" for r in a["repositories"] if r.startswith(OrgGenerator._CF_ORG_PREFIX)
},
}
for a in wg["areas"]
if "bots" in a
}
return (name, team)

Expand Down
6 changes: 3 additions & 3 deletions org/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ Once approved and merged, the github action [org-management.yml](https://github.
[org_management.py](https://github.com/cloudfoundry/community/blob/main/org/org-management.py) generates the following parts of the resulting cloudfoundry org configuration:

### Organization Members
Organization members are generated according to [rfc-0002-github-members](https://github.com/cloudfoundry/community/blob/main/toc/rfc/rfc-0002-github-members.md) and [rfc-draft-role-change-process](https://github.com/cloudfoundry/community/pull/248):
Organization members are generated according to [rfc-0002-github-members](https://github.com/cloudfoundry/community/blob/main/toc/rfc/rfc-0002-github-members.md) and [rfc-0008-role-change-process](https://github.com/cloudfoundry/community/blob/main/toc/rfc/rfc-0008-role-change-process.md):
- any members specified in [cloudfoundry.yml](https://github.com/cloudfoundry/community/blob/main/org/cloudfoundry.yml) (should be none)
- all contributors from [contributors.yml](https://github.com/cloudfoundry/community/blob/main/org/contributors.yml)
- all working group leads and approvers specified in the [Working Group Charters](https://github.com/cloudfoundry/community/tree/main/toc/working-groups)
- org admins and TOC members must not be added to org member list

### Organization Admins
Organization admins are:
- any admin specified in [cloudfoundry.yml](https://github.com/cloudfoundry/community/blob/main/org/cloudfoundry.yml)
- any admin specified in [cloudfoundry.yml](https://github.com/cloudfoundry/community/blob/main/org/cloudfoundry.yml) (should be none)
- all TOC execution leads and technical leads specified in [TOC.md](https://github.com/cloudfoundry/community/blob/main/toc/TOC.md)

### Github Teams for Working Group Areas
Github Teams for the TOC, all Working Group Leads, Working Groups and Working Group Areas are generated according to [rfc-0005-github-teams-and-access](https://github.com/cloudfoundry/community/blob/main/toc/rfc/rfc-0005-github-teams-and-access.md).
Github Teams for the TOC, all Working Group Leads, Working Groups and Working Group Areas are generated according to [rfc-0014-github-teams-and-access.md](https://github.com/cloudfoundry/community/blob/main/toc/rfc/rfc-0014-github-teams-and-access.md).
Repositories listed in the working group yaml block that belong to github organizations other than `cloudfoundry` are ignored.

## Development
Expand Down
22 changes: 22 additions & 0 deletions org/test_org_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
name: User 2
- github: user3
name: User 3
reviewers:
- github: user4
name: User 4
bots:
- github: bot2
name: WG1 Area2 Bot
repositories:
- cloudfoundry/repo3
- cloudfoundry/repo4
Expand Down Expand Up @@ -246,11 +252,24 @@ def test_generate_wg_teams(self):
self.assertListEqual(["user1", "user2"], team["members"])
self.assertDictEqual({"repo1": "write", "repo2": "write"}, team["repos"])

self.assertNotIn("wg-wg1-name-area-1-reviewers", wg_team["teams"])
self.assertNotIn("wg-wg1-name-area-1-bots", wg_team["teams"])

team = wg_team["teams"]["wg-wg1-name-area-2-approvers"]
self.assertListEqual(["execution-lead-1", "technical-lead-1"], team["maintainers"])
self.assertListEqual(["user2", "user3"], team["members"])
self.assertDictEqual({"repo3": "write", "repo4": "write"}, team["repos"])

team = wg_team["teams"]["wg-wg1-name-area-2-reviewers"]
self.assertListEqual(["execution-lead-1", "technical-lead-1"], team["maintainers"])
self.assertListEqual(["user4"], team["members"])
self.assertDictEqual({"repo3": "read", "repo4": "read"}, team["repos"])

team = wg_team["teams"]["wg-wg1-name-area-2-bots"]
self.assertListEqual(["execution-lead-1", "technical-lead-1"], team["maintainers"])
self.assertListEqual(["bot2"], team["members"])
self.assertDictEqual({"repo3": "write", "repo4": "write"}, team["repos"])

def test_generate_wg_teams_exclude_non_cf_repos(self):
_wg2 = yaml.safe_load(wg2)
(name, wg_team) = OrgGenerator._generate_wg_teams(_wg2)
Expand All @@ -273,6 +292,9 @@ def test_generate_wg_teams_exclude_non_cf_repos(self):
self.assertListEqual(["user10"], team["members"])
self.assertDictEqual({"repo10": "write", "repo11": "write"}, team["repos"])

self.assertNotIn("wg-wg2-name-area-1-reviewers", wg_team["teams"])
self.assertNotIn("wg-wg2-name-area-1-bots", wg_team["teams"])

def test_generate_toc_team(self):
_toc = yaml.safe_load(toc)
(name, team) = OrgGenerator._generate_toc_team(_toc)
Expand Down