1+ import os
2+ import sys
3+ import requests
4+ import json
5+ import subprocess
6+ import re
7+
8+
9+ print ("current working directory is: " ,os .getcwd ())
10+ STATUS_FAILED = 'FAILED'
11+ SUCCESS_MESSAGE = 'ok'
12+
13+
14+ def get_github_details ():
15+ github_info_file = open ('./.tmp/github.json' ,'r' )
16+ return json .load (github_info_file )
17+
18+
19+ def get_commit_details ():
20+ commit_info_file = open ('./.tmp/commitDetails.json' ,'r' )
21+ return json .load (commit_info_file )
22+
23+
24+ def process_git_local_details ():
25+ # Check if current dir is git dir
26+ is_git_dir = subprocess .check_output (
27+ ['/usr/bin/git' ,'rev-parse' ,'--is-inside-work-tree' ]).decode ('utf-8' )
28+ print ("Is git dir: " ,is_git_dir )
29+
30+ # git status
31+ git_status = subprocess .check_output (
32+ ['/usr/bin/git' ,'status' ]).decode ('utf-8' )
33+ print ("Git status: " ,git_status )
34+
35+ # last n commits
36+ last_10_commit_list = subprocess .check_output (
37+ ['/usr/bin/git' ,'rev-list' ,'--max-count=10' ,'HEAD' ]).decode ('utf-8' )
38+ print ("last 10 commit ids are: " ,last_10_commit_list )
39+
40+ return {
41+ 'is_git_dir' :is_git_dir ,
42+ 'last_10_commit_list' :last_10_commit_list
43+ }
44+
45+
46+ def collect_pr_details ():
47+ github = get_github_details ()
48+ commits = get_commit_details ()
49+ git_local = process_git_local_details ()
50+ return {
51+ 'github' :github ,
52+ 'commits' :commits ,
53+ 'num_commits_in_pr' :len (commits ),
54+ 'event_name' :github ["event_name" ],
55+ 'pr_submitter_github_login' :github ['event' ]['pull_request' ]['user' ]['login' ],
56+ 'github_repo' :github ['repository' ],
57+ 'pr_number' :github ['event' ]['number' ],
58+ 'is_git_dir' :git_local ['is_git_dir' ],
59+ 'last_10_commit_list' :git_local ['last_10_commit_list' ],
60+ }
61+
62+
63+ def write_comment (comment ):
64+ print (comment )
65+ f = open ("./.tmp/comment" ,"a" )
66+ f .write (comment )
67+ f .write ("\n " )
68+ f .close ()
69+
70+
71+ def task_failed (comment ):
72+ f = open ("./.tmp/failed" ,"a" )
73+ f .write (comment )
74+ f .write ("\n " )
75+ f .close ()
76+ write_comment (comment )
77+ return STATUS_FAILED
78+
79+
80+ def extract_personal_contributer_details ():
81+ personal_cla_link = sys .argv [1 ]
82+ f = requests .get (personal_cla_link )
83+ personal_cla_contents = f .text
84+
85+ personal_contributers_regex = re .compile ('\| *\[([^\s]+)\]\([^\s]+\) *\|' )
86+ personal_contributers = personal_contributers_regex .findall (
87+ personal_cla_contents )
88+
89+ return personal_contributers
90+
91+
92+ def extract_employer_contributer_details ():
93+ employer_cla_link = sys .argv [2 ]
94+ f = requests .get (employer_cla_link )
95+ employer_cla_contents = f .text
96+
97+ employer_contributers_regex = re .compile ('\| *\[([^\s]+)\]\([^\s]+\) *\|' )
98+ employer_contributers = employer_contributers_regex .findall (
99+ employer_cla_contents )
100+
101+ return employer_contributers
102+
103+
104+ def validate_is_pull_request (pr_details ):
105+ print ('Validate pull request called' )
106+ github_details = pr_details ['github' ]
107+ if github_details ["event_name" ]!= "pull_request" :
108+ print ("Error! This operation is valid on github pull requests. Exiting. Event received: " ,
109+ github_details ["event_name" ])
110+ sys .exit (1 )
111+
112+
113+ def validate_pr_raiser_cla (pr_raiser_login ,employer_contributors ,personal_contributors ):
114+ print ('PR raiser login: ' + pr_raiser_login )
115+ if pr_raiser_login not in employer_contributors and pr_raiser_login not in personal_contributors :
116+ return task_failed ('### Error: Contributor Licence Agreement Signature Missing\n ' +
117+ 'Please sign the Contributor Licence Agreement by clicking the following link.\n ' +
118+ '<p align="center"> <a href="https://phcode-dev.github.io/contributor-license-agreement/">Click here to sign the CLA</a></p>'
119+ )
120+ print ('Pass: Pull request raiser has signed the Contributor Licence Agreement' )
121+ return SUCCESS_MESSAGE
122+
123+
124+ def validate_commiters_cla (commits ,employer_contributors ,personal_contributors ):
125+ # github logins of all committers
126+ commit_logins = []
127+ for commit in commits :
128+ commiter_github_login = commit ['author' ]['login' ]
129+ if commiter_github_login not in commit_logins :
130+ commit_logins .append (commiter_github_login )
131+ print ("All github users who made changes to the pull request: " ,commit_logins )
132+
133+ unauthorized_commiters = []
134+ for user in commit_logins :
135+ if user not in personal_contributors and user not in employer_contributors :
136+ unauthorized_commiters .append (user )
137+ if len (unauthorized_commiters )!= 0 :
138+ return task_failed ('### Error: Contributor Licence Agreement Signature Missing\n ' +
139+ 'The following commiter(s) has not signed the Contributor Licence Agreement:\n ' +
140+ ', ' .join (unauthorized_commiters )+ '\n ' +
141+ 'Please sign the Contributor Licence Agreement by clicking the following link.\n ' +
142+ '<p align="center"> <a href="https://phcode-dev.github.io/contributor-license-agreement/">Click here to sign the CLA</a></p>'
143+ )
144+
145+ print ('Pass: All the commiters have signed the Contributor Licence Agreement' )
146+ return SUCCESS_MESSAGE
147+
148+
149+ def validate_cla_signature (pr_raiser_login ,commits ):
150+ employer_contributors = extract_employer_contributer_details ()
151+ personal_contributors = extract_personal_contributer_details ()
152+
153+ PR_RAISER_CLA_VALIDATION = validate_pr_raiser_cla (pr_raiser_login ,employer_contributors ,personal_contributors )
154+ COMMITERS_CLA_VALIDATION = validate_commiters_cla (commits ,employer_contributors ,personal_contributors )
155+
156+ if PR_RAISER_CLA_VALIDATION == STATUS_FAILED or COMMITERS_CLA_VALIDATION == STATUS_FAILED :
157+ return STATUS_FAILED
158+
159+ return SUCCESS_MESSAGE
160+
161+
162+ def review_pr ():
163+ print ('Reviewing PR' )
164+ pr_details = collect_pr_details ()
165+ validate_is_pull_request (pr_details )
166+ CLA_SIGNATURE_VALIDATION = validate_cla_signature (pr_details ['pr_submitter_github_login' ],pr_details ['commits' ])
167+
168+ if CLA_SIGNATURE_VALIDATION == STATUS_FAILED :
169+ print ('Validations failed. Exiting!' )
170+ return
171+
172+ write_comment ('\n ## Thank You for making this pull request.' )
173+
174+
175+ review_pr ()
176+
177+ # assert validate_cla_signature('psdhanesh7') == SUCCESS_MESSAGE