Skip to content

Commit

Permalink
Generate teams for WG area reviewers and bots
Browse files Browse the repository at this point in the history
- reviewers: read permission to area repos
- bots: write permission to area repos
- WG area reviewers and bots are optional
  • Loading branch information
stephanme committed Aug 9, 2022
1 parent 36b9fb5 commit 0825e13
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 26 deletions.
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

0 comments on commit 0825e13

Please sign in to comment.