Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 39 additions & 31 deletions src/lib/github/webhookHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,15 @@ async function sendOpenerInitialStateMessage(opener, reviewers, prObj) {
async function requestReviewersAndAssignees(users, body) {
try {
const githubUsers = users.map(user => user.github);
const owner = body.pull_request.base.repo.owner.login;
const repo = body.pull_request.base.repo.name;
const number = body.pull_request.number;

// Should probably look at the results to check if reviewers are there.
const reviewRequests = await octokit.pullRequests.createReviewRequest({
owner: body.pull_request.base.repo.owner.login,
repo: body.pull_request.base.repo.name,
number: body.pull_request.number,
reviewers: githubUsers,
});

const assignees = await octokit.issues.addAssignees({
owner: body.pull_request.base.repo.owner.login,
repo: body.pull_request.base.repo.name,
number: body.pull_request.number,
assignees: githubUsers,
});
// Should probably look at the results to check if reviewres are there.
const [reviewRequests, assignees] = await Promise.all([
octokit.pullRequests.createReviewRequest({ owner, repo, number, reviewers: githubUsers }),
octokit.issues.addAssignees({ owner, repo, number, assignees: githubUsers }),
]);

logger.info(`[Add Users to PR] Repo: ${body.pull_request.base.repo.name}. ` +
`Assigned and Request reviews from: ${githubUsers}`);
Expand All @@ -105,9 +99,13 @@ async function requestReviewersAndAssignees(users, body) {

async function requestReviewByGithubName(body) {
const logId = shortid.generate();
const opener = await findByGithubName(body.pull_request.user.login, logId);

const [opener, requestedReviewer] = await Promise.all([
findByGithubName(body.pull_request.user.login, logId),
findByGithubName(body.requested_reviewer.login, logId),
]);

const openerName = opener ? opener.name : body.pull_request.user.login;
const requestedReviewer = await findByGithubName(body.requested_reviewer.login, logId);
if (requestedReviewer && requestedReviewer.slack) {
return await sendReviewRequestMessage(openerName, requestedReviewer, body);
}
Expand All @@ -132,9 +130,10 @@ async function prOpened(body) {
const numReviewersAlready = body.pull_request.assignees.length;
const numReviewersToRandomlySelect = NUM_REVIEWERS - numReviewersAlready;

const preselectedUsers = await Promise.all(body.pull_request.assignees.map(user => {
return findByGithubName(user.login, logId);
}));
const preselectedUsers = await Promise.all(
body.pull_request.assignees.map(user => findByGithubName(user.login, logId))
);

const notTheseUsers = opener ? preselectedUsers.concat(opener.github) : preselectedUsers;
const randomUsers = await selectRandomGithubUsers(notTheseUsers, body.repository.full_name, numReviewersToRandomlySelect);
const users = preselectedUsers.concat(randomUsers);
Expand Down Expand Up @@ -195,8 +194,11 @@ async function prReviewed(body) {
let reviewer, coder;
const logId = shortid.generate();
try {
reviewer = await findByGithubName(body.review.user.login, logId);
coder = await findByGithubName(body.pull_request.user.login, logId);
const [reviewer, coder] = await Promise.all(
findByGithubName(body.review.user.login, logId),
findByGithubName(body.pull_request.user.login, logId),
);

if (!reviewer) throw new Error(`[github.prReviewed:${logId}] Reviewer not registered with git slackin`);
if (!coder) throw new Error(`[github.prReviewed:${logId}] Coder not registered with git slackin`);
} catch (e) {
Expand Down Expand Up @@ -237,13 +239,16 @@ async function prReviewed(body) {

try {
// let coder know its been done
await send(coder.slack.id, message);
let shouldNotify = await checkForReviews({
owner: body.repository.owner.login,
repo: body.repository.name,
number: body.pull_request.number });
const [, passedReviewThreshold] = await Promise.all([
send(coder.slack.id, message),
checkForReviews({
owner: body.repository.owner.login,
repo: body.repository.name,
number: body.pull_request.number,
}),
]);

shouldNotify = shouldNotify && body.review.state.toUpperCase() === 'APPROVED';
const shouldNotify = passedReviewThreshold && body.review.state.toUpperCase() === 'APPROVED';

if (shouldNotify) {
const mergerMessage =
Expand Down Expand Up @@ -297,11 +302,14 @@ function sendPrUpdatedMessage(openerName, users, body) {

async function prSynchronize(body) {
const logId = shortid.generate();
const opener = await findByGithubName(body.pull_request.user.login, logId);
const reviewer_list = body.pull_request.requested_reviewers;

const [opener, ...reviewers] = await Promise.all(
findByGithubName(body.pull_request.user.login, logId),
...reviewer_list.map(user => findByGithubName(user.login, logId)),
);

const openerName = opener ? opener.name : body.pull_request.user.login;
const reviewers = await Promise.all(body.pull_request.requested_reviewers.map(user => {
return findByGithubName(user.login, logId);
}));

return await sendPrUpdatedMessage(openerName, reviewers, body);
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/github/webhookRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ async function routeIt(body, { signature }) {
throw new Error('Signatures do not match!');
}
}

logger.info(`[RouteIt] ${body.action} on ${body.pull_request.base.repo.name}`);

try {
Expand Down
21 changes: 7 additions & 14 deletions src/lib/slack/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,23 @@ const simpleGit = require('simple-git/promise')(appRoot.path);
const users = require('../users');

async function generateAndSendBootMessage(channel = null, { msgText = null } = {}) {
const { available, benched } = await users.listAllUserNamesByAvailability();
const SHA = await simpleGit.revparse(['HEAD']);
const [{ available, benched }, SHA] = await Promise.all([
users.listAllUserNamesByAvailability(),
simpleGit.revparse(['HEAD']),
]);

const messageObject = {
text: msgText || `Git Slackin: ONLINE. SHA \`${SHA.trim()}\``,
attachments: [
{
text: '',
color: 'good',
fields: [
{
title: 'Available Users',
value: available,
},
],
fields: [{ title: 'Available Users', value: available }],
},
{
text: '',
color: 'warning',
fields: [
{
title: 'Benched Users',
value: benched,
},
],
fields: [{ title: 'Benched Users', value: benched }],
},
],
};
Expand Down
86 changes: 49 additions & 37 deletions src/lib/slack/eventHandlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ async function updateConfigurations(configOverrides) {
// especially if changing branches.
async function updateGitSlackin(theEvent, branch = 'master') {
let updateResult = null;

try {
// Let's discard these changes first.
// Discard any unstaged changes.
await simpleGit.stash();
await simpleGit.stash(['drop']);

Expand All @@ -43,17 +44,17 @@ async function updateGitSlackin(theEvent, branch = 'master') {
}

const triggeringUser = await findBySlackUserId(theEvent.user);
return sendToChannel(theEvent.channel, `Update trigger by ${triggeringUser.name}. Be back shortly! :wave:\n` +
`Changes: ${updateResult}`)
.then(() => {
// this works since we've already pulled so restarting should work.
return process.exit(0);
});

const message = `Update trigger by ${triggeringUser.name}. Be back shortly! :wave:\nChanges: ${updateResult}`;
await sendToChannel(theEvent.channel, message);

// This works since we've already pulled so restarting should work.
return process.exit(0);
}

async function handleAdminCommands(command, theEvent, res, logId) {
if (!config.has('slack_manager_ids')
|| !config.get('slack_manager_ids').includes(theEvent.user)) {
if (!config.has('slack_manager_ids') ||
!config.get('slack_manager_ids').includes(theEvent.user)) {
return sendEphemeralMessage(theEvent.channel, theEvent.user, 'This command is Admin-only or does not exist.');
}

Expand All @@ -71,10 +72,8 @@ async function handleAdminCommands(command, theEvent, res, logId) {
try {
const newConfig = JSON.parse(setConfigRegexResult[1]);
await updateConfigurations(newConfig);
return await sendToChannel(theEvent.channel, 'Updated config, restarting Git Slackin...')
.then(() => {
return process.exit(0);
});
await sendToChannel(theEvent.channel, 'Updated config, restarting Git Slackin...');
return process.exit(0);
} catch (e) {
return sendEphemeralMessage(theEvent.channel, theEvent.user, 'Error updating configuration');
}
Expand All @@ -90,26 +89,33 @@ async function handleAdminCommands(command, theEvent, res, logId) {
if (!slackUserIdToBench) {
logger.warn(`[commands.admin.bench:${logId}] Could not find user to user ${slackUserIdToBench}`);

return await sendEphemeralMessage(theEvent.channel, theEvent.user,
`:whatsgoingon: I could not find the user '<@${slackUserIdToBench}>' to bench. ` +
`Please inform James if you think this is a bug. And refer to log code: \`${logId}\``);
const failureMessage = `:whatsgoingon: I could not find the user '<@${slackUserIdToBench}>' to bench. ` +
`Please inform James if you think this is a bug. And refer to log code: \`${logId}\``;

return await sendEphemeralMessage(theEvent.channel, theEvent.user, failureMessage);
}

const success = await benchUserBySlackId(slackUserIdToBench, logId);

if (success) {
await send(slackUserIdToBench, `You have been benched by <@${theEvent.user}>. ` +
'Send me, Git Slackin, `start` to start receiving Review Requests again.');
const responseMessage = `I have benched <@${slackUserIdToBench}> as requested.`;
const benchedUserMessage = `You have been benched by <@${theEvent.user}>. ` +
'Send me, Git Slackin, `start` to start receiving Review Requests again.';

return await sendEphemeralMessage(theEvent.channel, theEvent.user,
`I have benched <@${slackUserIdToBench}> as requested.`);
const [, result] = await Promise.all([
send(slackUserIdToBench, benchedUserMessage),
sendEphemeralMessage(theEvent.channel, theEvent.user, responseMessage),
]);

return result;
} else {
const logId = shortid.generate();
logger.warn(`[commands.admin.bench:${logId}] Could not bench user ${slackUserIdToBench}`);

return await sendEphemeralMessage(theEvent.channel, theEvent.user,
`:whatsgoingon: I could not bench <@${slackUserIdToBench}> as requested. ` +
`Please inform James if you think this is a bug. And refer to log code: \`${logId}\``);
const failureMessage = `:whatsgoingon: I could not bench <@${slackUserIdToBench}> as requested. ` +
`Please inform James if you think this is a bug. And refer to log code: \`${logId}\``;

return await sendEphemeralMessage(theEvent.channel, theEvent.user, failureMessage);
}
}

Expand All @@ -118,26 +124,33 @@ async function handleAdminCommands(command, theEvent, res, logId) {
if (!slackUserIdToUnbench) {
logger.warn(`[commands.admin.bench:${logId}] Could not find user to user ${slackUserIdToUnbench}`);

return await sendEphemeralMessage(theEvent.channel, theEvent.user,
`:whatsgoingon: I could not find the user '<@${slackUserIdToUnbench}>' to unbench. ` +
`Please inform James if you think this is a bug. And refer to log code: \`${logId}\``);
const failureMessage = `:whatsgoingon: I could not find the user '<@${slackUserIdToUnbench}>'. ` +
`Please inform James if you think this is a bug. And refer to log code: \`${logId}\``;

return await sendEphemeralMessage(theEvent.channel, theEvent.user, failureMessage);
}

const success = await activateUserBySlackId(slackUserIdToUnbench, logId);

if (success) {
send(slackUserIdToUnbench, `You have been unbenched by <@${theEvent.user}>. ` +
'Send me, Git Slackin, `start` to start receiving Review Requests again.');
const responseMessage = `I have unbenched <@${slackUserIdToUnbench}> as requested.`;
const unbenchedUserMessage = `You have been unbenched by <@${theEvent.user}>. ` +
'Send me, Git Slackin, `start` to start receiving Review Requests again.';

return sendEphemeralMessage(theEvent.channel, theEvent.user,
`I have unbenched <@${slackUserIdToUnbench}> as requested.`);
const [, result] = await Promise.all([
send(slackUserIdToUnbench, unbenchedUserMessage),
sendEphemeralMessage(theEvent.channel, theEvent.user, responseMessage),
]);

return result;
} else {
const logId = shortid.generate();
logger.warn(`[commands.admin.unbench:${logId}] Could not unbench user: ${slackUserIdToUnbench}`);

return await sendEphemeralMessage(theEvent.channel, theEvent.user,
`:whatsgoingon: I could not unbench <@${slackUserIdToUnbench}> as requested. ` +
`Please inform James if you think this is a bug. And refer to log code: \`${logId}\``);
const failureMessage = `:whatsgoingon: I could not unbench <@${slackUserIdToUnbench}> as requested. ` +
`Please inform James if you think this is a bug. And refer to log code: \`${logId}\``;

return await sendEphemeralMessage(theEvent.channel, theEvent.user, failureMessage);
}
}

Expand All @@ -151,10 +164,7 @@ async function handleAdminCommands(command, theEvent, res, logId) {

if (command === 'shutdown') {
logger.info(`[ADMIN Event] ${theEvent.user} requested shutdown`);
return sendToChannel(theEvent.channel, 'Shutting down!')
.then(() => {
return process.exit(0);
});
return sendToChannel(theEvent.channel, 'Shutting down!').then(() => process.exit(0));
}
}

Expand Down Expand Up @@ -259,7 +269,9 @@ async function handleCommands(text, theEvent, res, logId = 'NoId') {
}
if (smallText === 'status') {
const user = await findBySlackUserId(theEvent.user);

logger.info(`[commands.user.status:${logId}] ${theEvent.user} requested their status.`);

return sendEphemeralMessage(theEvent.channel, theEvent.user, `You are <@${user.slack.id}> here and ` +
`<https://github.com/${user.github}|@${user.github}> on GitHub.\n` +
`Your current Git Slackin' status is: ${user.requestable ? 'Requestable :yes:' : 'UnRequestable :no:'}.\n` +
Expand Down
30 changes: 21 additions & 9 deletions src/lib/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ async function benchUserBySlackId(id, logId) {
}
return user;
});

await synchronizeUserList();

if (updated) {
logger.info(`[users.benchUserBySlackId:${logId}] Benched user: ${id}. user_list file`);
} else {
Expand All @@ -131,7 +133,9 @@ async function activateUserBySlackId(id, logId) {
}
return user;
});

await synchronizeUserList();

if (updated) {
logger.info(`[users.activateUserBySlackId:${logId}] Benched user: ${id}. user_list file`);
} else {
Expand All @@ -147,9 +151,12 @@ async function muteNotificationsBySlackId(id, logId) {
if (user.slack && user.slack.id.toLowerCase() === id.toLowerCase()) {
user.notifications = false;
}

return user;
});

await synchronizeUserList();

logger.info('[USERS] Update user_list file');
return users;
}
Expand All @@ -161,24 +168,29 @@ async function unmuteNotificationsBySlackId(id, logId) {
if (user.slack && user.slack.id.toLowerCase() === id.toLowerCase()) {
user.notifications = true;
}

return user;
});

await synchronizeUserList();

return users;
}

async function listAllUserNamesByAvailability() {
const availableUsers = await listAvailableUsers(true);
const benchedUsers = await listBenchedUsers(true);

let availableUsersString = availableUsers.join();
let benchedUsersString = benchedUsers.join();
if (availableUsersString.length === 0) availableUsersString = 'None';
if (benchedUsersString.length === 0) benchedUsersString = 'None';
const [available, benched] = await Promise.all([
listAvailableUsers(true),
listBenchedUsers(true),
]);

const toString = (arr) => {
if (arr.length === 0) return 'None';
return arr.join();
};

return {
available: availableUsersString,
benched: benchedUsersString,
available: toString(available),
benched: toString(benched),
};
}

Expand Down
Loading