From a77d46a4fe0f6b660143bd266890b7e32dbf1ffb Mon Sep 17 00:00:00 2001 From: Carly Gundy Date: Thu, 28 Nov 2024 14:49:20 +0100 Subject: [PATCH 1/7] update code --- .../check_membership/check_membership.py | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/reusable_workflows/check_membership/check_membership.py b/reusable_workflows/check_membership/check_membership.py index d05090c..272c676 100644 --- a/reusable_workflows/check_membership/check_membership.py +++ b/reusable_workflows/check_membership/check_membership.py @@ -3,6 +3,22 @@ import github3 +APPROVED_BOT_LIST = [ + "dependabot[bot]", + "github-actions[bot]", + "sa-github-api", + "pr-automation-bot-public[bot]", + "pr-automation-bot-private[bot]", +] + + +def is_approved_bot(user: str) -> bool: + """ + Return whether the user is an approved bot. + """ + return user in APPROVED_BOT_LIST + + def is_member_of_org(gh: github3.login, org: str, user: str) -> bool: """ Return whether the user is a member of the organisation. @@ -21,13 +37,18 @@ def main() -> None: raise Exception("github login failed - maybe GH_TOKEN was not correctly set") is_member = is_member_of_org(gh, org, user) + is_approved_bot = is_approved_bot(user) + + org_member = is_member or is_approved_bot + if is_approved_bot: + print(f"{user} is an approved bot and can contribute.") if is_member: print(f"{user} is member of {org} and can contribute.") - else: + elif not org_member: print(f"{user} is an external contributor.") - os.system(f"""echo 'is_member={is_member}' >> $GITHUB_OUTPUT""") + os.system(f"""echo 'is_member={org_member}' >> $GITHUB_OUTPUT""") if __name__ == "__main__": From 20bdab2b1128b4287bd8a55d9f3024f80e944312 Mon Sep 17 00:00:00 2001 From: Carly Gundy Date: Thu, 28 Nov 2024 14:49:29 +0100 Subject: [PATCH 2/7] update tests --- reusable_workflows/tests/test_membership.py | 39 +++++++++++++++++---- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/reusable_workflows/tests/test_membership.py b/reusable_workflows/tests/test_membership.py index 1345132..bfbd2ee 100644 --- a/reusable_workflows/tests/test_membership.py +++ b/reusable_workflows/tests/test_membership.py @@ -4,7 +4,7 @@ from github3.exceptions import NotFoundError import pytest -from check_membership.check_membership import is_member_of_org, main +from check_membership.check_membership import is_approved_bot, is_member_of_org, main def test_is_member(): @@ -29,6 +29,15 @@ def test_not_member(): assert is_member is False +def test_is_approved_bot(): + assert is_approved_bot("dependabot[bot]") is True + assert is_approved_bot("github-actions[bot]") is True + assert is_approved_bot("sa-github-api") is True + assert is_approved_bot("pr-automation-bot-public[bot]") is True + assert is_approved_bot("pr-automation-bot-private[bot]") is True + assert is_approved_bot("random_user") is False + + @mock.patch.dict( os.environ, {"GH_ORG": "my_org", "GH_TOKEN": "secret", "USER": "username"} ) @@ -48,7 +57,27 @@ def test_end_to_end_is_member(os_system, github_login_mock, capfd): gh.organization.assert_called_with("my_org") gh_org.is_member.assert_called_with("username") assert out == "username is member of my_org and can contribute.\n" - os_system.assert_called_once_with("echo 'is_member=True' >> $GITHUB_OUTPUT") + os_system.assert_called_once_with("echo 'org_member=True' >> $GITHUB_OUTPUT") + + +@mock.patch.dict( + os.environ, {"GH_ORG": "my_org", "GH_TOKEN": "secret", "USER": "dependabot[bot]"} +) +@mock.patch("github3.login") +@mock.patch("os.system") +def test_end_to_end_is_approved_bot(os_system, github_login_mock, capfd): + gh = mock.Mock() + gh_org = mock.Mock() + gh.organization.return_value = gh_org + gh_org.is_member.return_value = True + github_login_mock.return_value = gh + + main() + out, err = capfd.readouterr() + + github_login_mock.assert_called_with(token="secret") + assert out == "dependabot[bot] is an approved bot and can contribute..\n" + os_system.assert_called_once_with("echo 'org_member=True' >> $GITHUB_OUTPUT") @mock.patch.dict( @@ -70,7 +99,7 @@ def test_end_to_end_is_not_member(os_system, github_login_mock, capfd): gh.organization.assert_called_with("my_org") gh_org.is_member.assert_called_with("username") assert out == "username is an external contributor.\n" - os_system.assert_called_once_with("echo 'is_member=False' >> $GITHUB_OUTPUT") + os_system.assert_called_once_with("echo 'org_member=False' >> $GITHUB_OUTPUT") @mock.patch.dict( @@ -90,9 +119,7 @@ def test_end_to_end_api_fails(os_system, github_login_mock): os_system.assert_not_called() -@mock.patch.dict( - os.environ, {"GH_ORG": "my_org", "GH_TOKEN": "", "USER": "username"} -) +@mock.patch.dict(os.environ, {"GH_ORG": "my_org", "GH_TOKEN": "", "USER": "username"}) @mock.patch("github3.login") def test_github_token_not_passed_in(github_login_mock): github_login_mock.return_value = None From 11c5881d71d214e1648ded81fecaf745691ed49e Mon Sep 17 00:00:00 2001 From: Carly Gundy Date: Thu, 28 Nov 2024 14:50:23 +0100 Subject: [PATCH 3/7] update workflow --- .github/workflows/check_cla.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check_cla.yml b/.github/workflows/check_cla.yml index 02bb714..3c6732c 100644 --- a/.github/workflows/check_cla.yml +++ b/.github/workflows/check_cla.yml @@ -9,8 +9,8 @@ jobs: check-membership: name: Check Membership runs-on: ubuntu-latest - # Dont run this workflow if it was triggered by one of these bots - if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' && github.event.pull_request.user.login != 'github-actions[bot]' && github.event.pull_request.user.login != 'sa-github-api' && github.event.pull_request.user.login != 'pr-automation-bot-public[bot]' && github.event_name != 'merge_group' }} + # Dont run this workflow on merge queue + if: ${{ github.event_name != 'merge_group' }} outputs: is_member: ${{ steps.check-membership.outputs.is_member}} steps: From 88483bf9c87bd8ac81bb6515a61d2c091ccb5d78 Mon Sep 17 00:00:00 2001 From: Carly Gundy Date: Thu, 28 Nov 2024 14:55:30 +0100 Subject: [PATCH 4/7] update name --- reusable_workflows/check_membership/check_membership.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reusable_workflows/check_membership/check_membership.py b/reusable_workflows/check_membership/check_membership.py index 272c676..eb11fa5 100644 --- a/reusable_workflows/check_membership/check_membership.py +++ b/reusable_workflows/check_membership/check_membership.py @@ -37,11 +37,11 @@ def main() -> None: raise Exception("github login failed - maybe GH_TOKEN was not correctly set") is_member = is_member_of_org(gh, org, user) - is_approved_bot = is_approved_bot(user) + is_bot = is_approved_bot(user) - org_member = is_member or is_approved_bot + org_member = is_member or is_bot - if is_approved_bot: + if is_bot: print(f"{user} is an approved bot and can contribute.") if is_member: print(f"{user} is member of {org} and can contribute.") From fb778b04e9d331e1eb47ca8f610629438e14b19a Mon Sep 17 00:00:00 2001 From: Carly Gundy Date: Thu, 28 Nov 2024 15:00:26 +0100 Subject: [PATCH 5/7] fix --- reusable_workflows/tests/test_membership.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reusable_workflows/tests/test_membership.py b/reusable_workflows/tests/test_membership.py index bfbd2ee..95708dd 100644 --- a/reusable_workflows/tests/test_membership.py +++ b/reusable_workflows/tests/test_membership.py @@ -57,7 +57,7 @@ def test_end_to_end_is_member(os_system, github_login_mock, capfd): gh.organization.assert_called_with("my_org") gh_org.is_member.assert_called_with("username") assert out == "username is member of my_org and can contribute.\n" - os_system.assert_called_once_with("echo 'org_member=True' >> $GITHUB_OUTPUT") + os_system.assert_called_once_with("echo 'is_member=True' >> $GITHUB_OUTPUT") @mock.patch.dict( @@ -77,7 +77,7 @@ def test_end_to_end_is_approved_bot(os_system, github_login_mock, capfd): github_login_mock.assert_called_with(token="secret") assert out == "dependabot[bot] is an approved bot and can contribute..\n" - os_system.assert_called_once_with("echo 'org_member=True' >> $GITHUB_OUTPUT") + os_system.assert_called_once_with("echo 'is_member=True' >> $GITHUB_OUTPUT") @mock.patch.dict( @@ -99,7 +99,7 @@ def test_end_to_end_is_not_member(os_system, github_login_mock, capfd): gh.organization.assert_called_with("my_org") gh_org.is_member.assert_called_with("username") assert out == "username is an external contributor.\n" - os_system.assert_called_once_with("echo 'org_member=False' >> $GITHUB_OUTPUT") + os_system.assert_called_once_with("echo 'is_member=False' >> $GITHUB_OUTPUT") @mock.patch.dict( From a56d738eff899e4eaa094259b064b5735bfe8082 Mon Sep 17 00:00:00 2001 From: Carly Gundy Date: Thu, 28 Nov 2024 15:03:08 +0100 Subject: [PATCH 6/7] fix --- reusable_workflows/tests/test_membership.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/reusable_workflows/tests/test_membership.py b/reusable_workflows/tests/test_membership.py index 95708dd..2108dfa 100644 --- a/reusable_workflows/tests/test_membership.py +++ b/reusable_workflows/tests/test_membership.py @@ -75,8 +75,7 @@ def test_end_to_end_is_approved_bot(os_system, github_login_mock, capfd): main() out, err = capfd.readouterr() - github_login_mock.assert_called_with(token="secret") - assert out == "dependabot[bot] is an approved bot and can contribute..\n" + assert out == "dependabot[bot] is an approved bot and can contribute.\n" os_system.assert_called_once_with("echo 'is_member=True' >> $GITHUB_OUTPUT") From 85277fe8326c5f41b5ff487d057915a141c5a078 Mon Sep 17 00:00:00 2001 From: Carly Gundy Date: Thu, 28 Nov 2024 15:10:12 +0100 Subject: [PATCH 7/7] fix --- reusable_workflows/tests/test_membership.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reusable_workflows/tests/test_membership.py b/reusable_workflows/tests/test_membership.py index 2108dfa..18b1141 100644 --- a/reusable_workflows/tests/test_membership.py +++ b/reusable_workflows/tests/test_membership.py @@ -69,7 +69,7 @@ def test_end_to_end_is_approved_bot(os_system, github_login_mock, capfd): gh = mock.Mock() gh_org = mock.Mock() gh.organization.return_value = gh_org - gh_org.is_member.return_value = True + gh_org.is_member.return_value = False github_login_mock.return_value = gh main()