From 091884e013fc00f65455de6002b97ef7faf72735 Mon Sep 17 00:00:00 2001 From: psdhanesh7 Date: Sun, 14 Nov 2021 13:55:26 +0530 Subject: [PATCH 1/3] Add cla checks action --- .../python/validate_cla_signature.py | 80 +++++++++++++++++++ .github/workflows/validate_cla_signature.yml | 49 ++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 .github/workflows/python/validate_cla_signature.py create mode 100644 .github/workflows/validate_cla_signature.yml diff --git a/.github/workflows/python/validate_cla_signature.py b/.github/workflows/python/validate_cla_signature.py new file mode 100644 index 000000000..27db85d66 --- /dev/null +++ b/.github/workflows/python/validate_cla_signature.py @@ -0,0 +1,80 @@ +import os +import sys +import json +import subprocess +import re +import requests + +def extract_personal_contributer_details(): + personal_cla_link = "https://raw.githubusercontent.com/brackets-cont/contributor-license-agreement/main/personal_contributor_licence_agreement.md" + f = requests.get(personal_cla_link) + personal_cla_contents = f.text + + personal_contributers_regex = re.compile('\| *\[([^\s]+)\]\([^\s]+\) *\|') + personal_contributers = personal_contributers_regex.findall(personal_cla_contents) + + return personal_contributers + + +def extract_employer_contributer_details(): + employer_cla_link = "https://raw.githubusercontent.com/brackets-cont/contributor-license-agreement/main/employer_contributor_license_agreement.md" + f = requests.get(employer_cla_link) + employer_cla_contents = f.text + + employer_contributers_regex = re.compile('\| *\[([^\s]+)\]\([^\s]+\) *\|') + employer_contributers = employer_contributers_regex.findall(employer_cla_contents) + + return employer_contributers + + +print("current working directory is: ", os.getcwd()) + +github_info_file = open('./.tmp/github.json', 'r') +github_details = json.load(github_info_file) + +commit_info_file = open('./.tmp/commitDetails.json', 'r') +commit_details = json.load(commit_info_file) + +if github_details["event_name"] != "pull_request": + print("Error! This operation is valid on github pull requests. Exiting") + sys.exit(1) + +print("Pull request submitted by github login: ", github_details['event']['pull_request']['user']['login']) +print("Number of commits in the pull request: ", len(commit_details)) + +# Check if current dir is git dir +is_git_dir = subprocess.check_output( + ['/usr/bin/git', 'rev-parse', '--is-inside-work-tree']).decode('utf-8') +print("Is git dir: ", is_git_dir) + +# git status +git_status = subprocess.check_output( + ['/usr/bin/git', 'status']).decode('utf-8') +print("Git status: ", git_status) + +# last n commits +last_n_commit_list = subprocess.check_output( + ['/usr/bin/git', 'rev-list', '--max-count=10', 'HEAD']).decode('utf-8') +print("last 10 commit ids are: ", last_n_commit_list) + +# github logins of all committers +commit_logins = [] + +for commit in commit_details: + commiter_github_login = commit['committer']['login'] + if commiter_github_login not in commit_logins: + commit_logins.append(commiter_github_login) + +print("All github users who made changes to the pull request: ", commit_logins) + +# github login of all contributers who has signed personal CLA +personal_contributers = extract_personal_contributer_details() +# github login of all contributers who has signed employer CLA +employer_contributers = extract_employer_contributer_details() + +for user in commit_logins: + if user != 'web-flow' and user not in personal_contributers and user not in employer_contributers: + print("Error!" + user + "has not signed the contributer licence agreement.") + sys.exit(1) + + diff --git a/.github/workflows/validate_cla_signature.yml b/.github/workflows/validate_cla_signature.yml new file mode 100644 index 000000000..1d43dd4d1 --- /dev/null +++ b/.github/workflows/validate_cla_signature.yml @@ -0,0 +1,49 @@ +name: Enforce CLA Signature +# https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context + +on: + pull_request: + branches: + - main + +jobs: + validate-cla-signature: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.8] + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 100 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Setting temp directory + run: | + mkdir ./.tmp + - name: Getting commit details + uses: wei/wget@v1 + with: + args: -O ./.tmp/commitDetails.json ${{ toJSON(github.event.pull_request._links.commits.href) }} + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJSON(github) }} + run: | + echo "$GITHUB_CONTEXT" > ./.tmp/github.json + cat ./.tmp/github.json + echo "commit details: " + cat ./.tmp/commitDetails.json + - name: CLA signature check + run: | + which git + if ! python ./.github/workflows/python/validate_cla_signature.py; then + echo "Please sign the Contributer Licence Agreement before contributing to this repository." + echo "You can sign the CLA here: http://brackets.io/contributor-license-agreement/" + exit 1 + else + echo "all good" + fi + From ce3b30e336a31fa2abea4f8dccd22713bac07ef3 Mon Sep 17 00:00:00 2001 From: psdhanesh7 Date: Fri, 3 Dec 2021 09:38:53 +0530 Subject: [PATCH 2/3] fix requests module not found error --- .../python/validate_cla_signature.py | 126 +++++++++++++++--- 1 file changed, 105 insertions(+), 21 deletions(-) diff --git a/.github/workflows/python/validate_cla_signature.py b/.github/workflows/python/validate_cla_signature.py index 27db85d66..536a76c78 100644 --- a/.github/workflows/python/validate_cla_signature.py +++ b/.github/workflows/python/validate_cla_signature.py @@ -4,57 +4,143 @@ import subprocess import re import requests +import typing +import urllib.error +import urllib.parse +import urllib.request +from email.message import Message + + +class Response(typing.NamedTuple): + body: str + headers: Message + status: int + error_count: int = 0 + + def json(self) -> typing.Any: + """ + Decode body's JSON. + + Returns: + Pythonic representation of the JSON object + """ + try: + output = json.loads(self.body) + except json.JSONDecodeError: + output = "" + return output + + +def request( + url: str, + data: dict = None, + params: dict = None, + headers: dict = None, + method: str = "GET", + data_as_json: bool = True, + error_count: int = 0, +) -> Response: + if not url.casefold().startswith("http"): + raise urllib.error.URLError( + "Incorrect and possibly insecure protocol in url") + method = method.upper() + request_data = None + headers = headers or {} + data = data or {} + params = params or {} + headers = {"Accept": "application/json", **headers} + + if method == "GET": + params = {**params, **data} + data = None + + if params: + url += "?" + urllib.parse.urlencode(params, doseq=True, safe="/") + + if data: + if data_as_json: + request_data = json.dumps(data).encode() + headers["Content-Type"] = "application/json; charset=UTF-8" + else: + request_data = urllib.parse.urlencode(data).encode() + + httprequest = urllib.request.Request( + url, data=request_data, headers=headers, method=method + ) + + try: + with urllib.request.urlopen(httprequest) as httpresponse: + response = Response( + headers=httpresponse.headers, + status=httpresponse.status, + body=httpresponse.read().decode( + httpresponse.headers.get_content_charset("utf-8") + ), + ) + except urllib.error.HTTPError as e: + response = Response( + body=str(e.reason), + headers=e.headers, + status=e.code, + error_count=error_count + 1, + ) + + return response + def extract_personal_contributer_details(): - personal_cla_link = "https://raw.githubusercontent.com/brackets-cont/contributor-license-agreement/main/personal_contributor_licence_agreement.md" - f = requests.get(personal_cla_link) - personal_cla_contents = f.text + personal_cla_link = "https://raw.githubusercontent.com/brackets-cont/contributor-license-agreement/main/personal_contributor_licence_agreement.md" + response = request(url=personal_cla_link, data_as_json=False) + personal_cla_contents = response.body - personal_contributers_regex = re.compile('\| *\[([^\s]+)\]\([^\s]+\) *\|') - personal_contributers = personal_contributers_regex.findall(personal_cla_contents) + personal_contributers_regex = re.compile('\| *\[([^\s]+)\]\([^\s]+\) *\|') + personal_contributers = personal_contributers_regex.findall( + personal_cla_contents) - return personal_contributers + return personal_contributers def extract_employer_contributer_details(): - employer_cla_link = "https://raw.githubusercontent.com/brackets-cont/contributor-license-agreement/main/employer_contributor_license_agreement.md" - f = requests.get(employer_cla_link) - employer_cla_contents = f.text + employer_cla_link = "https://raw.githubusercontent.com/brackets-cont/contributor-license-agreement/main/employer_contributor_license_agreement.md" + response = request(url=employer_cla_link, data_as_json=False) + employer_cla_contents = response.body - employer_contributers_regex = re.compile('\| *\[([^\s]+)\]\([^\s]+\) *\|') - employer_contributers = employer_contributers_regex.findall(employer_cla_contents) + employer_contributers_regex = re.compile('\| *\[([^\s]+)\]\([^\s]+\) *\|') + employer_contributers = employer_contributers_regex.findall( + employer_cla_contents) - return employer_contributers + return employer_contributers print("current working directory is: ", os.getcwd()) -github_info_file = open('./.tmp/github.json', 'r') +github_info_file = open('./.tmp/github.json', 'r') github_details = json.load(github_info_file) -commit_info_file = open('./.tmp/commitDetails.json', 'r') +commit_info_file = open('./.tmp/commitDetails.json', 'r') commit_details = json.load(commit_info_file) if github_details["event_name"] != "pull_request": print("Error! This operation is valid on github pull requests. Exiting") sys.exit(1) -print("Pull request submitted by github login: ", github_details['event']['pull_request']['user']['login']) +print("Pull request submitted by github login: ", + github_details['event']['pull_request']['user']['login']) print("Number of commits in the pull request: ", len(commit_details)) # Check if current dir is git dir is_git_dir = subprocess.check_output( - ['/usr/bin/git', 'rev-parse', '--is-inside-work-tree']).decode('utf-8') + ['/usr/bin/git', 'rev-parse', '--is-inside-work-tree']).decode('utf-8') print("Is git dir: ", is_git_dir) # git status git_status = subprocess.check_output( - ['/usr/bin/git', 'status']).decode('utf-8') + ['/usr/bin/git', 'status']).decode('utf-8') print("Git status: ", git_status) # last n commits last_n_commit_list = subprocess.check_output( - ['/usr/bin/git', 'rev-list', '--max-count=10', 'HEAD']).decode('utf-8') + ['/usr/bin/git', 'rev-list', '--max-count=10', 'HEAD']).decode('utf-8') print("last 10 commit ids are: ", last_n_commit_list) # github logins of all committers @@ -64,7 +150,7 @@ def extract_employer_contributer_details(): commiter_github_login = commit['committer']['login'] if commiter_github_login not in commit_logins: commit_logins.append(commiter_github_login) - + print("All github users who made changes to the pull request: ", commit_logins) # github login of all contributers who has signed personal CLA @@ -76,5 +162,3 @@ def extract_employer_contributer_details(): if user != 'web-flow' and user not in personal_contributers and user not in employer_contributers: print("Error!" + user + "has not signed the contributer licence agreement.") sys.exit(1) - - From c25d25de718ebdc8df0a204bb69287c014e2eb8a Mon Sep 17 00:00:00 2001 From: psdhanesh2000 <103040340+psdhanesh2000@users.noreply.github.com> Date: Tue, 10 May 2022 11:48:09 +0530 Subject: [PATCH 3/3] Create Test.md --- Test.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Test.md diff --git a/Test.md b/Test.md new file mode 100644 index 000000000..966a25e65 --- /dev/null +++ b/Test.md @@ -0,0 +1 @@ +This is a test file that is created to test the cla checks of the base repository.