Skip to content

Commit 3743e0e

Browse files
authored
Fix #214: Introduce Github action to perform CLA Check (#233)
1 parent e053814 commit 3743e0e

File tree

8 files changed

+343602
-23821
lines changed

8 files changed

+343602
-23821
lines changed

actions/src/dispatcher.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
const core = require('@actions/core');
2020
const { context } = require('@actions/github');
2121
const issueLabelsModule = require('./issues/checkIssueLabels');
22+
const claCheckGithubActionModule = require('./pull_requests/claCheck');
2223
const constants = require('../../constants');
2324

2425
module.exports = {
@@ -36,6 +37,9 @@ module.exports = {
3637
case constants.issuesLabelCheck:
3738
await issueLabelsModule.checkLabels();
3839
break;
40+
case constants.claCheckGithubAction:
41+
await claCheckGithubActionModule.claCheckGithubAction();
42+
break;
3943
}
4044
}
4145
}

actions/src/pull_requests/claCheck.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2021 The Oppia Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS-IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/**
16+
* @fileoverview File to check if PR Author has signed the CLA
17+
*/
18+
19+
const core = require('@actions/core');
20+
const { context, GitHub } = require('@actions/github');
21+
const { google } = require('googleapis');
22+
23+
/**
24+
* Create an OAuth2 client with the given credentials, and then execute the
25+
* given claCheck function.
26+
*/
27+
const authorize = async function() {
28+
try {
29+
const CREDENTIALS = JSON.parse(process.env.SHEETS_CRED);
30+
const SHEETS_TOKEN = JSON.parse(process.env.SHEETS_TOKEN);
31+
// eslint-disable-next-line camelcase
32+
const { client_secret, client_id, redirect_uris } = CREDENTIALS.installed;
33+
var oAuth2Client = new google.auth.OAuth2(
34+
client_id,
35+
client_secret,
36+
redirect_uris[0]
37+
);
38+
oAuth2Client.credentials = SHEETS_TOKEN;
39+
return oAuth2Client;
40+
} catch (err) {
41+
core.setFailed('Auth failure: ' + err);
42+
}
43+
};
44+
45+
const generateOutput = async (hasClaSigned) => {
46+
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
47+
const LINK_RESULT = 'here'.link(
48+
'https://github.com/oppia/oppia/wiki/' +
49+
'Contributing-code-to-Oppia#setting-things-up'
50+
);
51+
const octokit = new GitHub(GITHUB_TOKEN);
52+
const PR_NUMBER = context.payload.pull_request.number;
53+
const PR_AUTHOR = context.payload.pull_request.user.login;
54+
55+
let comment = '';
56+
if (!hasClaSigned) {
57+
comment = ('Hi! @' +
58+
PR_AUTHOR +
59+
' Welcome to Oppia! Could you please ' +
60+
'follow the instructions ' + LINK_RESULT +
61+
" and sign the CLA Sheet to get started? You'll need to do " +
62+
'this before we can accept your PR. Thanks!');
63+
core.info('Commenting in PR...');
64+
65+
await octokit.issues.createComment(
66+
{
67+
body: comment,
68+
issue_number: PR_NUMBER,
69+
owner: context.repo.owner,
70+
repo: context.repo.repo,
71+
}
72+
);
73+
core.setFailed(PR_AUTHOR + ' has not signed the CLA');
74+
} else {
75+
core.info(`${PR_AUTHOR} has signed the CLA`);
76+
}
77+
};
78+
79+
80+
/**
81+
* Checks if the PR Author has signed the CLA Sheet.
82+
* @param {google.auth.OAuth2} auth The authenticated Google OAuth client.
83+
*/
84+
const checkSheet = async (auth) => {
85+
const PR_AUTHOR = context.payload.pull_request.user.login;
86+
const sheets = google.sheets({ version: 'v4', auth });
87+
const SPREADSHEET_ID = process.env.SPREADSHEET_ID;
88+
await sheets.spreadsheets.values.get(
89+
{
90+
spreadsheetId: SPREADSHEET_ID,
91+
range: 'Usernames!A:A',
92+
},
93+
async (err, res) => {
94+
if (err) {
95+
core.setFailed('The API returned an error: ' + err);
96+
}
97+
const rows = res.data.values;
98+
const flatRows = [].concat.apply([], rows);
99+
if (!rows || rows.length === 0) {
100+
core.setFailed('No data found.');
101+
} else {
102+
core.info(`Checking if ${PR_AUTHOR} has signed the CLA`);
103+
const hasUserSignedCla = flatRows.includes(PR_AUTHOR);
104+
await generateOutput(hasUserSignedCla);
105+
}
106+
}
107+
);
108+
};
109+
110+
const claCheckGithubAction = async () => {
111+
// Authorize a client with the loaded credentials.
112+
const auth = await authorize();
113+
114+
// Call the sheets API with the authorized client.
115+
await checkSheet(auth);
116+
};
117+
118+
module.exports = {
119+
claCheckGithubAction,
120+
};

0 commit comments

Comments
 (0)