diff --git a/.github/scripts/check-cla.py b/.github/scripts/check-cla.py new file mode 100644 index 000000000000..fab42fb40ca2 --- /dev/null +++ b/.github/scripts/check-cla.py @@ -0,0 +1,68 @@ +import json +import sys +import urllib + +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' + + +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, JSON_HEADER, data) + 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 + + +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..3d7c2942cc29 100644 --- a/.github/workflows/check-cla.yml +++ b/.github/workflows/check-cla.yml @@ -1,32 +1,20 @@ -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 + - 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 }}