From 4be8d50dbe1f3ee866697017737a37db102169af Mon Sep 17 00:00:00 2001 From: Tom Dugovic Date: Tue, 25 Jun 2024 12:13:32 -0500 Subject: [PATCH] Extract CLA check into standalone Python script --- .github/scripts/check-cla.py | 72 +++++++++++++++++++++++++++++++++ .github/workflows/check-cla.yml | 42 ++++++++----------- 2 files changed, 89 insertions(+), 25 deletions(-) create mode 100644 .github/scripts/check-cla.py diff --git a/.github/scripts/check-cla.py b/.github/scripts/check-cla.py new file mode 100644 index 000000000000..391a4218151e --- /dev/null +++ b/.github/scripts/check-cla.py @@ -0,0 +1,72 @@ +import json +import sys +import urllib.request + +JSON_HEADER = {'Content-Type': 'application/json'} +TEXT_ENCODING = 'utf-8' + +URL_GITHUB = 'https://api.github.com/repos' +URL_JUCE_CLA_CHECK = 'https://cla.juce.com/check' + +ALLOWED_AUTHORS = set( + 'web-flow' +) + + +class NoAuthorsException(Exception): + __MESSAGE = "No author or committer user IDs contained within commit information." + + def __init__(self, commits: list): + message = f'{self.__MESSAGE}\n\n{commits}' + super().__init__(message) + + +class UnsignedAuthorsException(Exception): + __MESSAGE_0 = "The following GitHub users need to sign the JUCE CLA:", + __MESSAGE_1 = "Please go to https://cla.juce.com to sign the JUCE Contributor Licence Agreement." + + def __init__(self, authors: set[str]): + authors_str = ', '.join(authors) + message = f'{self.__MESSAGE_0} {authors_str}\n\n{self.__MESSAGE_1}' + super().__init__(message) + + +def _json_request(url: str, data: dict | None = None) -> dict: + if data is not None: + data = json.dumps(data).encode(TEXT_ENCODING) + request = urllib.request.Request(url, data, JSON_HEADER, JSON_HEADER) + with urllib.request.urlopen(request) as response: + raw_response = response.read().decode(TEXT_ENCODING) + return json.loads(raw_response) + + +def _get_authors(github_repository: str, github_event_number: int) -> set[str]: + pr_commit_list = _json_request(f'{URL_GITHUB}/{github_repository}/pulls/{github_event_number}/commits') + authors = set() + for commit in pr_commit_list: + for author_type in ['author', 'committer']: + if author_type in commit: + authors.add(commit[author_type]['login']) + return authors - ALLOWED_AUTHORS + + +def _verify_authors(authors: set[str]) -> None: + if not authors: + raise NoAuthorsException() + verification = _json_request(URL_JUCE_CLA_CHECK, {'logins': list(authors)}) + if verification['unsigned']: + raise UnsignedAuthorsException(verification['unsigned']) + + +def main(github_repository: str, github_event_number: int): + authors = _get_authors(github_repository, github_event_number) + try: + _verify_authors(authors) + except Exception as e: + print(e.message) + + +if __name__ == '__main__': + github_repository = sys.argv[1] + github_event_number = int(sys.argv[2]) + main(github_repository, github_event_number) \ No newline at end of file diff --git a/.github/workflows/check-cla.yml b/.github/workflows/check-cla.yml index 70d082413d39..dcb4b89e8eaa 100644 --- a/.github/workflows/check-cla.yml +++ b/.github/workflows/check-cla.yml @@ -1,32 +1,24 @@ -name: check-CLA -on: [pull_request_target] +name: Check CLA + +on: + pull_request: + jobs: check-cla: runs-on: ubuntu-latest + continue-on-error: ${{ github.repository_owner != 'juce' }} env: PR_NUMBER: ${{ github.event.number }} steps: + - name: Checkout Scripts + uses: actions/checkout@v4 + with: + sparse-checkout: | + .github/scripts + sparse-checkout-cone-mode: false + + - name: LS + run: ls -la + - name: check-CLA - run: | - import urllib.request - import json - import sys - def jsonRequest(url, data={}): - req = urllib.request.Request(url, - headers={'Content-Type': 'application/json'}, - data=json.dumps(data).encode('utf-8') if data else None) - with urllib.request.urlopen(req) as response: - return json.loads(response.read().decode('utf-8')) - prCommits = jsonRequest('https://api.github.com/repos/juce-framework/JUCE/pulls/${{ github.event.number }}/commits') - allAuthors = [commit[authorType]['login'] for authorType in ['author', 'committer'] for commit in prCommits if commit[authorType]] - uniqueAuthors = [name for name in list(set(allAuthors)) if name != 'web-flow'] - if (len(uniqueAuthors) == 0): - print(f'\nNo author or committer user IDs contained within commit information\n\n{prCommits}\n') - sys.exit(1) - print(f'Authors: {uniqueAuthors}') - claResult = jsonRequest('https://cla.juce.com/check', {'logins': uniqueAuthors}) - unsignedLogins = claResult['unsigned'] - if (len(unsignedLogins) != 0): - print(f'\nThe following GitHub users need to sign the JUCE CLA: {", ".join(unsignedLogins)}\n\nPlease go to https://cla.juce.com to sign the JUCE Contributor Licence Agreement\n') - sys.exit(1) - shell: python + run: python .github/scripts/check-cla.py ${{github.repository}} ${{ github.event.number }}