11const crypto = require ( 'crypto' ) ;
22const config = require ( '../config' ) ;
33const debug = require ( 'debug' ) ( 'handlers:hook' ) ;
4+ const Octokit = require ( '@octokit/rest' ) ;
5+ const _ = require ( 'lodash' ) ;
6+ const octokit = new Octokit ( {
7+ auth : `token ${ config . secret . github . token } ` ,
8+ log : console ,
9+ previews : [ 'hellcat-preview' , 'mercy-preview' ] , // enables nested teams API
10+ } ) ;
11+ // chinese bot: https://github.com/fanyijihua/robot
12+
13+ async function removeLabel ( labels , params ) {
14+ return await octokit . issues . removeLabel ( {
15+ owner : config . org ,
16+ ...params
17+ } ) ;
18+ }
19+
20+ async function addLabels ( params ) {
21+ return await octokit . issues . removeLabel ( {
22+ owner : config . org ,
23+ ...params
24+ } ) ;
25+ }
426
527exports . post = async function ( ctx ) {
628
@@ -22,40 +44,143 @@ exports.post = async function(ctx) {
2244
2345 //debug("github hook", ctx.request);
2446
25- debug ( "Hook data" , ctx . request . body ) ;
26-
27- let repo = config . secret . repos [ ctx . request . body . repository . full_name ] ;
28- if ( ! repo . lang ) {
29- // __proto__ as repo name
30- this . throw ( 400 ) ;
31- }
3247
3348 // koa-bodyparser gives that
3449 debug ( ctx . request . rawBody ) ;
3550
3651 signature = signature . replace ( / ^ s h a 1 = / , '' ) ;
3752 let computedSignature = crypto
38- . createHmac ( 'sha1' , Buffer . from ( repo . githubSecret , 'utf-8' ) )
53+ . createHmac ( 'sha1' , Buffer . from ( config . secret . github . hook , 'utf-8' ) )
3954 . update ( ctx . request . rawBody )
4055 . digest ( 'hex' ) ;
4156
57+ debug ( "Hook data" , event , ctx . request . body ) ;
58+
4259 debug ( "Compare signature" , computedSignature , signature ) ;
4360
4461 if ( computedSignature !== signature ) {
4562 ctx . throw ( 400 , 'X-Hub-Signature does not match blob signature' ) ;
4663 }
4764
48- if ( ctx . request . body . ref !== 'refs/heads/master' ) {
49- // ignore non-master pushes
50- ctx . body = { ok : true } ;
51- return ;
52- }
65+ let action = ctx . request . body . action ;
5366
67+ // new pr
68+ if ( event === 'pull_request' && action === 'opened' ) {
69+ await onPullOpen ( ctx . request . body ) ;
70+ }
5471
55- ctx . body = { ok : true } ;
72+ // changes requested
73+ if ( event === 'pull_request_review' && action === 'submitted' ) {
74+ await onPullRequestReviewSubmit ( ctx . request . body ) ;
75+ }
5676
57- await updateRepo ( ctx . request . body . repository . name ) ;
77+ // /done
78+ if ( event === 'issue_comment' && action === 'created' ) {
79+ await onIssueComment ( ctx . request . body ) ;
80+ }
5881
59- await Stats . instance ( ) . gather ( ctx . request . body . repository . name ) ;
82+ ctx . body = '' ;
6083
6184} ;
85+
86+ async function onIssueComment ( { issue, repository, comment} ) {
87+ debug ( "Comment to Issue" ) ;
88+
89+ if ( ! issue . pull_request ) {
90+ return ; // comment to issue, not to PR?
91+ }
92+
93+ debug ( "Comment to PR" ) ;
94+
95+ let labels = _ . keyBy ( issue . labels , 'name' ) ;
96+
97+ if ( comment . body . trim ( ) === '/done' ) {
98+ await removeLabel ( {
99+ repo : repository . name ,
100+ issue_number : issue . number ,
101+ name : 'changes requested' ,
102+ } ) ;
103+
104+ await addLabels ( {
105+ repo : repository . name ,
106+ issue_number : issue . number ,
107+ labels : [ 'review needed' ] ,
108+ } ) ;
109+ }
110+ }
111+
112+ async function onPullOpen ( { repository, number} ) {
113+ debug ( "PR open" ) ;
114+
115+ await addLabels ( {
116+ repo : repository . name ,
117+ issue_number : number ,
118+ labels : [ 'review needed' ] ,
119+ } ) ;
120+ }
121+
122+ async function onPullRequestReviewSubmit ( { repository, review, pull_request : { number, labels} } ) {
123+
124+ debug ( "PR request submitted" , review . state ) ;
125+
126+ labels = _ . keyBy ( labels , 'name' ) ;
127+
128+ if ( review . state === "changes_requested" ) {
129+ await removeLabel ( {
130+ repo : repository . name ,
131+ issue_number : number ,
132+ name : 'review needed' ,
133+ } ) ;
134+
135+ await addLabels ( {
136+ repo : repository . name ,
137+ issue_number : number ,
138+ labels : [ 'changes requested' ] ,
139+ } ) ;
140+ }
141+
142+ if ( review . state === "approved" ) {
143+ await removeLabel ( {
144+ repo : repository . name ,
145+ issue_number : number ,
146+ name : 'changes requested' ,
147+ } ) ;
148+
149+ debug ( "Labels" , labels ) ;
150+
151+ if ( ! labels [ 'need +1' ] ) {
152+ await removeLabel ( {
153+ repo : repository . name ,
154+ issue_number : number ,
155+ name : 'review needed'
156+ } ) ;
157+ await addLabels ( {
158+ repo : repository . name ,
159+ issue_number : number ,
160+ labels : [ 'need +1' ] ,
161+ } ) ;
162+ } else {
163+ // maybe just merge on 2nd approval, so this never happens
164+ await removeLabel ( {
165+ repo : repository . name ,
166+ issue_number : number ,
167+ name : 'need +1'
168+ } ) ;
169+ await addLabels ( {
170+ repo : repository . name ,
171+ issue_number : number ,
172+ labels : [ 'ready to merge' ]
173+ } ) ;
174+ }
175+ }
176+
177+ }
178+
179+
180+ /**
181+ 1) каждый PR помечается review needed
182+ 2) когда ревьювер request changes, PR помечается changes requested
183+ 3) когда чел вносит изменения, он пишет /done, и PR помечается review needed
184+ 4) когда изменения приняты (changes approved) PR помечается +1 review needed
185+ 5) то же самое еще раз для второго review (edited)
186+ */
0 commit comments