Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Version 1.2.2 #98

Merged
merged 16 commits into from
Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 6 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module.exports = {
LOG_LEVEL: process.env.LOG_LEVEL || 'debug',
PARTITION: process.env.PARTITION || 0,
TOPIC: process.env.TOPIC || 'tc-x-events',
TOPIC_NOTIFICATION: process.env.TOPIC_NOTIFICATION || 'notifications.action.create',
KAFKA_OPTIONS: {
connectionString: process.env.KAFKA_URL || 'localhost:9092',
groupId: process.env.KAFKA_GROUP_ID || 'topcoder-x-processor',
Expand All @@ -25,6 +26,11 @@ module.exports = {
passphrase: 'secret', // NOTE:* This configuration specifies the private key passphrase used while creating it.
}
},
MAIL_NOTICIATION: {
type: 'tcx.mail_notification',
sendgridTemplateId: 'xxxxxx',
subject: 'Topcoder X Alert'
},
NEW_CHALLENGE_TEMPLATE: process.env.NEW_CHALLENGE_TEMPLATE || {
status: 'Draft'
},
Expand Down
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

const config = require('config');
const _ = require('lodash');
const kafka = require('./utils/kafka');
const kafkaConsumer = require('./utils/kafka-consumer');
const logger = require('./utils/logger');

process.on('uncaughtException', (err) => {
Expand Down Expand Up @@ -55,4 +55,4 @@ dumpConfigs(config, 0);
logger.debug('--- End of List of Configurations ---');

// run the server
kafka.run();
kafkaConsumer.run();
27 changes: 19 additions & 8 deletions services/GithubService.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ async function _authenticate(accessToken) {
});
return octokit.rest;
} catch (err) {
throw errors.convertGitHubError(err, 'Failed to authenticate to Github using access token of copilot.');
throw errors.handleGitHubError(err, 'Failed to authenticate to Github using access token of copilot.');
}
}

Expand All @@ -75,7 +75,7 @@ async function _removeAssignees(github, owner, repo, number, assignees) {
assignees
});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during remove assignees from issue.');
throw errors.handleGitHubError(err, 'Error occurred during remove assignees from issue.');
}
}

Expand All @@ -93,6 +93,17 @@ async function _getUsernameById(id) {
return user ? user.login : null;
}

/**
* Get github issue url
* @param {String} repoPath the repo path
* @param {Number} number the issue number
* @returns {String} the url
* @private
*/
function _getIssueUrl(repoPath, number) {
return `https://github.com/${repoPath}/issues/${number}`;
}

/**
* updates the title of github issue
* @param {Object} copilot the copilot
Expand All @@ -107,7 +118,7 @@ async function updateIssue(copilot, repoFullName, number, title) {
try {
await github.issues.update({owner, repo, issue_number: number, title});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during updating issue.');
throw errors.handleGitHubError(err, 'Error occurred during updating issue.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github issue title is updated for issue number ${number}`);
}
Expand Down Expand Up @@ -139,7 +150,7 @@ async function assignUser(copilot, repoFullName, number, user) {
}
await github.issues.addAssignees({owner, repo, issue_number: number, assignees: [user]});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during assigning issue user.');
throw errors.handleGitHubError(err, 'Error occurred during assigning issue user.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github issue with number ${number} is assigned to ${user}`);
}
Expand Down Expand Up @@ -184,7 +195,7 @@ async function createComment(copilot, repoFullName, number, body) {
body = helper.prepareAutomatedComment(body, copilot);
await github.issues.createComment({owner, repo, issue_number: number, body});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during creating comment on issue.');
throw errors.handleGitHubError(err, 'Error occurred during creating comment on issue.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github comment is added on issue with message: "${body}"`);
}
Expand Down Expand Up @@ -262,7 +273,7 @@ async function markIssueAsPaid(copilot, repoFullName, number, challengeUUID, exi
const body = helper.prepareAutomatedComment(commentMessage, copilot);
await github.issues.createComment({owner, repo, issue_number: number, body});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during updating issue as paid.');
throw errors.handleGitHubError(err, 'Error occurred during updating issue as paid.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github issue title is updated for as paid and fix accepted for ${number}`);
}
Expand Down Expand Up @@ -291,7 +302,7 @@ async function changeState(copilot, repoFullName, number, state) {
try {
await github.issues.update({owner, repo, issue_number: number, state});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during updating status of issue.');
throw errors.handleGitHubError(err, 'Error occurred during updating status of issue.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github issue state is updated to '${state}' for issue number ${number}`);
}
Expand All @@ -317,7 +328,7 @@ async function addLabels(copilot, repoFullName, number, labels) {
try {
await github.issues.update({owner, repo, issue_number: number, labels});
} catch (err) {
throw errors.convertGitHubError(err, 'Error occurred during adding label in issue.');
throw errors.handleGitHubError(err, 'Error occurred during adding label in issue.', copilot.topcoderUsername, _getIssueUrl(repoFullName, number));
}
logger.debug(`Github issue is updated with new labels for ${number}`);
}
Expand Down
62 changes: 40 additions & 22 deletions services/GitlabService.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async function _authenticate(accessToken) {
});
return gitlab;
} catch (err) {
throw errors.convertGitLabError(err, 'Failed to during authenticate to Github using access token of copilot.');
throw errors.handleGitLabError(err, 'Failed to during authenticate to Github using access token of copilot.');
}
}

Expand All @@ -55,25 +55,37 @@ async function _removeAssignees(gitlab, projectId, issueId, assignees) {
const oldAssignees = _.difference(issue.assignee_ids, assignees);
await gitlab.projects.issues.edit(projectId, issueId, {assignee_ids: oldAssignees});
} catch (err) {
throw errors.convertGitLabError(err, 'Error occurred during remove assignees from issue.');
throw errors.handleGitLabError(err, 'Error occurred during remove assignees from issue.');
}
}

/**
* Get gitlab issue url
* @param {String} repoPath the repo path
* @param {Number} issueId the issue number
* @returns {String} the url
* @private
*/
function _getIssueUrl(repoPath, issueId) {
return `https://gitlab.com/${repoPath}/issues/${issueId}`;
}

/**
* creates the comments on gitlab issue
* @param {Object} copilot the copilot
* @param {Number} projectId the project id
* @param {Object} project the project object
* @param {Number} issueId the issue number
* @param {string} body the comment body text
*/
async function createComment(copilot, projectId, issueId, body) {
async function createComment(copilot, project, issueId, body) {
const projectId = project.id;
Joi.attempt({copilot, projectId, issueId, body}, createComment.schema);
const gitlab = await _authenticate(copilot.accessToken);
try {
body = helper.prepareAutomatedComment(body, copilot);
await gitlab.projects.issues.notes.create(projectId, issueId, {body});
} catch (err) {
throw errors.convertGitLabError(err, 'Error occurred during creating comment on issue.');
throw errors.handleGitLabError(err, 'Error occurred during creating comment on issue.', copilot.topcoderUsername, _getIssueUrl(project.full_name, issueId));
}
logger.debug(`Gitlab comment is added on issue with message: "${body}"`);
}
Expand All @@ -88,17 +100,18 @@ createComment.schema = {
/**
* updates the title of gitlab issue
* @param {Object} copilot the copilot
* @param {Number} projectId the project id
* @param {Object} project the project object
* @param {Number} issueId the issue number
* @param {string} title new title
*/
async function updateIssue(copilot, projectId, issueId, title) {
async function updateIssue(copilot, project, issueId, title) {
const projectId = project.id;
Joi.attempt({copilot, projectId, issueId, title}, updateIssue.schema);
const gitlab = await _authenticate(copilot.accessToken);
try {
await gitlab.projects.issues.edit(projectId, issueId, {title});
} catch (err) {
throw errors.convertGitLabError(err, 'Error occurred during updating issue.');
throw errors.handleGitLabError(err, 'Error occurred during updating issue.', copilot.topcoderUsername, _getIssueUrl(project.full_name, issueId));
}
logger.debug(`Gitlab issue title is updated for issue number ${issueId}`);
}
Expand All @@ -113,11 +126,12 @@ updateIssue.schema = {
/**
* Assigns the issue to user login
* @param {Object} copilot the copilot
* @param {Number} projectId the project id
* @param {Object} project the project object
* @param {Number} issueId the issue number
* @param {Number} userId the user id of assignee
*/
async function assignUser(copilot, projectId, issueId, userId) {
async function assignUser(copilot, project, issueId, userId) {
const projectId = project.id;
Joi.attempt({copilot, projectId, issueId, userId}, assignUser.schema);
const gitlab = await _authenticate(copilot.accessToken);
try {
Expand All @@ -128,7 +142,7 @@ async function assignUser(copilot, projectId, issueId, userId) {
}
await gitlab.projects.issues.edit(projectId, issueId, {assignee_ids: [userId]});
} catch (err) {
throw errors.convertGitLabError(err, 'Error occurred during assigning issue user.');
throw errors.handleGitLabError(err, 'Error occurred during assigning issue user.', copilot.topcoderUsername, _getIssueUrl(project.full_name, issueId));
}
logger.debug(`Gitlab issue with number ${issueId} is assigned to ${issueId}`);
}
Expand All @@ -143,11 +157,12 @@ assignUser.schema = {
/**
* Removes an assignee from the issue
* @param {Object} copilot the copilot
* @param {Number} projectId the project id
* @param {Object} project the project object
* @param {Number} issueId the issue number
* @param {Number} userId the user id of assignee to remove
*/
async function removeAssign(copilot, projectId, issueId, userId) {
async function removeAssign(copilot, project, issueId, userId) {
const projectId = project.id;
Joi.attempt({copilot, projectId, issueId, userId}, removeAssign.schema);
const gitlab = await _authenticate(copilot.accessToken);
await _removeAssignees(gitlab, projectId, issueId, [userId]);
Expand Down Expand Up @@ -195,14 +210,15 @@ getUserIdByLogin.schema = {
/**
* updates the gitlab issue as paid and fix accepted
* @param {Object} copilot the copilot
* @param {Number} projectId the project id
* @param {Object} project the project object
* @param {Number} issueId the issue number
* @param {String} challengeUUID the challenge uuid
* @param {Array} existLabels the issue labels
* @param {String} winner the winner topcoder handle
* @param {Boolean} createCopilotPayments the option to create copilot payments or not
*/
async function markIssueAsPaid(copilot, projectId, issueId, challengeUUID, existLabels, winner, createCopilotPayments) { // eslint-disable-line max-params
async function markIssueAsPaid(copilot, project, issueId, challengeUUID, existLabels, winner, createCopilotPayments) { // eslint-disable-line max-params
const projectId = project.id;
Joi.attempt({copilot, projectId, issueId, challengeUUID, existLabels, winner, createCopilotPayments}, markIssueAsPaid.schema);
const gitlab = await _authenticate(copilot.accessToken);
const labels = _(existLabels).filter((i) => i !== config.FIX_ACCEPTED_ISSUE_LABEL)
Expand All @@ -222,7 +238,7 @@ async function markIssueAsPaid(copilot, projectId, issueId, challengeUUID, exist
const body = helper.prepareAutomatedComment(commentMessage, copilot);
await gitlab.projects.issues.notes.create(projectId, issueId, {body});
} catch (err) {
throw errors.convertGitLabError(err, 'Error occurred during updating issue as paid.');
throw errors.handleGitLabError(err, 'Error occurred during updating issue as paid.', copilot.topcoderUsername, _getIssueUrl(project.full_name, issueId));
}
logger.debug(`Gitlab issue is updated for as paid and fix accepted for ${issueId}`);
}
Expand All @@ -240,17 +256,18 @@ markIssueAsPaid.schema = {
/**
* change the state of gitlab issue
* @param {Object} copilot the copilot
* @param {string} projectId the project id
* @param {Object} project the project object
* @param {Number} issueId the issue issue id
* @param {string} state new state
*/
async function changeState(copilot, projectId, issueId, state) {
async function changeState(copilot, project, issueId, state) {
const projectId = project.id;
Joi.attempt({copilot, projectId, issueId, state}, changeState.schema);
const gitlab = await _authenticate(copilot.accessToken);
try {
await gitlab.projects.issues.edit(projectId, issueId, {state_event: state});
} catch (err) {
throw errors.convertGitLabError(err, 'Error occurred during updating status of issue.');
throw errors.handleGitLabError(err, 'Error occurred during updating status of issue.', copilot.topcoderUsername, _getIssueUrl(project.full_name, issueId));
}
logger.debug(`Gitlab issue state is updated to '${state}' for issue number ${issueId}`);
}
Expand All @@ -265,17 +282,18 @@ changeState.schema = {
/**
* updates the gitlab issue with new labels
* @param {Object} copilot the copilot
* @param {string} projectId the project id
* @param {Object} project the project object
* @param {Number} issueId the issue issue id
* @param {Number} labels the labels
*/
async function addLabels(copilot, projectId, issueId, labels) {
async function addLabels(copilot, project, issueId, labels) {
const projectId = project.id;
Joi.attempt({copilot, projectId, issueId, labels}, addLabels.schema);
const gitlab = await _authenticate(copilot.accessToken);
try {
await gitlab.projects.issues.edit(projectId, issueId, {labels: _.join(labels, ',')});
} catch (err) {
throw errors.convertGitLabError(err, 'Error occurred during adding label in issue.');
throw errors.handleGitLabError(err, 'Error occurred during adding label in issue.', copilot.topcoderUsername, _getIssueUrl(project.full_name, issueId));
}
logger.debug(`Gitlab issue is updated with new labels for ${issueId}`);
}
Expand Down
19 changes: 15 additions & 4 deletions utils/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

const _ = require('lodash');
const constants = require('../constants');
const notification = require('./notification');

// the error class wrapper
class ProcessorError extends Error {
Expand All @@ -27,12 +28,17 @@ class ProcessorError extends Error {
const errors = {};

/**
* Convert github api error.
* Handle github api error. Return converted error.
* @param {Error} err the github api error
* @param {String} message the error message
* @param {String} copilotHandle the handle name of the copilot
* @param {String} repoPath the link to related github page
* @returns {Error} converted error
*/
errors.convertGitHubError = function convertGitHubError(err, message) {
errors.handleGitHubError = function handleGitHubError(err, message, copilotHandle, repoPath) {
if (err.statusCode === 401 && copilotHandle && repoPath) { // eslint-disable-line no-magic-numbers
notification.sendTokenExpiredAlert(copilotHandle, repoPath, 'Github');
}
let resMsg = `${message}. ${err.message}.`;
const detail = _.get(err, 'response.body.message');
if (detail) {
Expand All @@ -47,12 +53,17 @@ errors.convertGitHubError = function convertGitHubError(err, message) {
};

/**
* Convert gitlab api error.
* Handle gitlab api error. Return converted error.
* @param {Error} err the gitlab api error
* @param {String} message the error message
* @param {String} copilotHandle the handle name of the copilot
* @param {String} repoPath the link to related gitlab page
* @returns {Error} converted error
*/
errors.convertGitLabError = function convertGitLabError(err, message) {
errors.handleGitLabError = function handleGitLabError(err, message, copilotHandle, repoPath) {
if (err.statusCode === 401 && copilotHandle && repoPath) { // eslint-disable-line no-magic-numbers
notification.sendTokenExpiredAlert(copilotHandle, repoPath, 'Gitlab');
}
let resMsg = `${message}. ${err.message}.`;
const detail = _.get(err, 'response.body.message');
if (detail) {
Expand Down
Loading