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

Commit 5a21789

Browse files
committed
UI updates and better processing of close events.
1 parent b2f0414 commit 5a21789

11 files changed

+460
-83
lines changed

README.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ The following config parameters are supported, they are defined in `config/defau
4141
|ISSUE_BID_EMAIL_RECEIVER| the email receiver about bid email||
4242
|TC_URL| the base URL of topcoder to get the challenge URL| defaults to `https://www.topcoder-dev.com`|
4343
|GITLAB_API_BASE_URL| the URL for gitlab host| defaults to `https://gitlab.com`|
44+
|PAID_ISSUE_LABEL|the label name for paid, should be one of the label configured in topcoder x ui|'Paid'|
45+
|FIX_ACCEPTED_ISSUE_LABEL|the label name for fix accepted, should be one of the label configured in topcoder x ui|'Fix Accepted'|
46+
|TC_OR_DETAIL_LINK|the link to online review detail of challenge| see `default.js`, OR link for dev environment|
4447

4548
KAFKA_OPTIONS should be object as described in https://github.com/SOHU-Co/kafka-node#kafkaclient
4649
For using with SSL, the options should be as
@@ -85,6 +88,7 @@ Now, receiver service can receive the webhooks from git host's project and proce
8588
- create a pull request, you can see the logs in `receiver` and `processor`, the `pull_request.created` event is generated.
8689
- close a pull request without merge, you can see the logs in `receiver` and `processor`, the `pull_request.closed` event is generated and the `merged` property is `false`.
8790
- merge a pull request, you can see the logs in `receiver` and `processor`, the `pull_request.closed` event is generated and the `merged` property is `true`.
91+
- close an issue in the repo, you can see the logs in `receiver` and `processor`, the `issue.closed` event is generated
8892

8993
### Create a new challenge for a new issue
9094
- Create a new issue in the repo. E.g.
@@ -132,7 +136,7 @@ Now, receiver service can receive the webhooks from git host's project and proce
132136
debug: nothing changed for issue 3
133137
```
134138
135-
- Update the tilte by removing `[$50 ]`, you'll get an error:
139+
- Update the title by removing `[$50 ]`, you'll get an error:
136140
```
137141
error: Error: Cannot parse prize from title: A new issue title - Updated the prize
138142
```
@@ -157,3 +161,38 @@ When an user is assigned to an issue then 'issue.assigned' event will be capture
157161
@username, please sign-up with Topcoder x Self-service tool.
158162
```
159163
- user will be unassigned from issue
164+
165+
### Closing issue
166+
167+
When an issue is closed it will first check if issue has any assignee or not,
168+
169+
- if there is no assignee then simply ignores the issue closed event with message in logger
170+
- if there is an assignee then it will
171+
- first set the current assignee user as challenge assignee,
172+
- activate the challenge with project's billing
173+
- closes the challenge with winner as assignee
174+
- you can verify the challenge closed in OR (link will be commented in same issue in git host)
175+
- issue label will be updated from configured paid and fix accepted label name
176+
177+
You can see following logs
178+
```
179+
debug: Looking up TC handle of git user: 82332
180+
debug: Getting the billing account ID for project ID: 15180
181+
debug: Getting project billing detail 15180
182+
debug: assigning the billing account id 70016668 to challenge
183+
debug: Updating challenge 30052019 with {"billingAccountId":70016668,"prizes":[234]}
184+
debug: Getting the topcoder member ID for member name: tonyj
185+
debug: Getting the topcoder member ID for copilot name : tonyj
186+
debug: adding resource to challenge 30052019
187+
debug: resource is added to challenge 30052019 successfully.
188+
debug: adding resource to challenge 30052019
189+
debug: Activating challenge 30052019
190+
debug: Challenge 30052019 is activated successfully.
191+
debug: close challenge with winner tonyj(8547899)
192+
debug: Closing challenge 30052019
193+
debug: Challenge 30052019 is closed successfully.
194+
debug: update issue as paid
195+
debug: Gitlab/Github issue is updated for as paid and fix accepted for 59
196+
```
197+
198+
- if issue have already paid label it won't process

config/default.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,7 @@ module.exports = {
8080
ISSUE_BID_EMAIL_RECEIVER: process.env.ISSUE_BID_EMAIL_RECEIVER || '',
8181
TC_URL: process.env.TC_URL || 'https://www.topcoder-dev.com',
8282
GITLAB_API_BASE_URL: process.env.GITLAB_API_BASE_URL || 'https://gitlab.com',
83+
PAID_ISSUE_LABEL: process.env.PAID_ISSUE_LABEL || 'Paid',
84+
FIX_ACCEPTED_ISSUE_LABEL: process.env.FIX_ACCEPTED_ISSUE_LABEL || 'Fix accepted',
85+
TC_OR_DETAIL_LINK: process.env.TC_OR_DETAIL_LINK || 'https://software.topcoder-dev.com/review/actions/ViewProjectDetails?pid='
8386
};

configuration.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ The following config parameters are supported, they are defined in `config/defau
2323
|ISSUE_BID_EMAIL_RECEIVER| the email receiver about bid email||
2424
|TC_URL| the base URL of topcoder to get the challenge URL| defaults to `https://www.topcoder-dev.com`|
2525
|GITLAB_API_BASE_URL| the URL for gitlab host| defaults to `https://gitlab.com`|
26+
|PAID_ISSUE_LABEL|the label name for paid, should be one of the label configured in topcoder x ui|'Paid'|
27+
|FIX_ACCEPTED_ISSUE_LABEL|the label name for fix accepted, should be one of the label configured in topcoder x ui|'Fix Accepted'|
28+
|TC_OR_DETAIL_LINK|the link to online review detail of challenge| see `default.js`, OR link for dev environment|
2629

2730
KAFKA_OPTIONS should be object as described in https://github.com/SOHU-Co/kafka-node#kafkaclient
2831
For using with SSL, the options should be as

models/Project.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,13 @@ const schema = new mongoose.Schema({
1414
title: {type: String, required: true},
1515
tcDirectId: {type: Number, required: true},
1616
repoUrl: {type: String, required: true},
17-
rocketChatWebhook: {type: String, required: true},
18-
rocketChatChannelName: {type: String, required: true},
17+
rocketChatWebhook: {type: String, required: false},
18+
rocketChatChannelName: {type: String, required: false},
1919
archived: {type: String, required: true},
2020
username: {type: String, required: true},
2121
secretWebhookKey: {type: String, required: true}
2222
});
2323

24-
// project id, provider, repositoryId must be unique
25-
schema.index({tcDirectId: 1}, {unique: true});
26-
24+
schema.index({tcDirectId: 1});
2725

2826
module.exports = schema;

models/UserMapping.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ const schema = new Schema({
1515
gitlabUserId: Number
1616
});
1717

18-
schema.index({topcoderUsername: 1});
18+
schema.index({topcoderUsername: 1}, {unique: true});
1919

2020
module.exports = schema;

services/GithubService.js

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
const _ = require('lodash');
1313
const Joi = require('joi');
1414
const GitHubApi = require('github');
15+
const config = require('config');
1516
const logger = require('../utils/logger');
1617

1718
const copilotUserSchema = Joi.object().keys({
1819
accessToken: Joi.string().required(),
19-
userProviderId: Joi.number().required()
20+
userProviderId: Joi.number().required(),
21+
topcoderUsername: Joi.string()
2022
}).required();
2123

2224
/**
@@ -147,7 +149,7 @@ async function createComment(copilot, repo, number, body) {
147149
const github = await _authenticate(copilot.accessToken);
148150
const owner = await _getUsernameById(github, copilot.userProviderId);
149151
await github.issues.createComment({owner, repo, number, body});
150-
logger.debug('Github comment is added on issue notifying user to assign using Topcoder x tool');
152+
logger.debug(`Github comment is added on issue with message: "${body}"`);
151153
}
152154

153155
createComment.schema = {
@@ -193,11 +195,60 @@ getUserIdByLogin.schema = {
193195
login: Joi.string().required()
194196
};
195197

198+
/**
199+
* updates the github issue as paid and fix accepted
200+
* @param {Object} copilot the copilot
201+
* @param {string} repo the repository
202+
* @param {Number} number the issue number
203+
* @param {Number} challengeId the challenge id
204+
*/
205+
async function markIssueAsPaid(copilot, repo, number, challengeId) {
206+
Joi.attempt({copilot, repo, number, challengeId}, markIssueAsPaid.schema);
207+
const github = await _authenticate(copilot.accessToken);
208+
const owner = await _getUsernameById(github, copilot.userProviderId);
209+
const labels = [config.PAID_ISSUE_LABEL, config.FIX_ACCEPTED_ISSUE_LABEL];
210+
await github.issues.edit({owner, repo, number, labels});
211+
const body = `Payment task has been updated: ${config.TC_OR_DETAIL_LINK}${challengeId}`;
212+
await github.issues.createComment({owner, repo, number, body});
213+
logger.debug(`Github issue title is updated for as paid and fix accepted for ${number}`);
214+
}
215+
216+
markIssueAsPaid.schema = {
217+
copilot: copilotUserSchema,
218+
repo: Joi.string().required(),
219+
number: Joi.number().required(),
220+
challengeId: Joi.number().positive().required()
221+
};
222+
223+
/**
224+
* change the state of github issue
225+
* @param {Object} copilot the copilot
226+
* @param {string} repo the repository
227+
* @param {Number} number the issue number
228+
* @param {string} state new state
229+
*/
230+
async function changeState(copilot, repo, number, state) {
231+
Joi.attempt({copilot, repo, number, state}, changeState.schema);
232+
const github = await _authenticate(copilot.accessToken);
233+
const owner = await _getUsernameById(github, copilot.userProviderId);
234+
await github.issues.edit({owner, repo, number, state});
235+
logger.debug(`Github issue state is updated to '${state}' for issue number ${number}`);
236+
}
237+
238+
changeState.schema = {
239+
copilot: copilotUserSchema,
240+
repo: Joi.string().required(),
241+
number: Joi.number().required(),
242+
state: Joi.string().required()
243+
};
244+
196245
module.exports = {
197246
updateIssue,
198247
assignUser,
199248
removeAssign,
200249
createComment,
201250
getUsernameById,
202-
getUserIdByLogin
251+
getUserIdByLogin,
252+
markIssueAsPaid,
253+
changeState
203254
};

services/GitlabService.js

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ const logger = require('../utils/logger');
1717

1818
const copilotUserSchema = Joi.object().keys({
1919
accessToken: Joi.string().required(),
20-
userProviderId: Joi.number().required()
20+
userProviderId: Joi.number().required(),
21+
topcoderUsername: Joi.string()
2122
}).required();
2223

2324
/**
@@ -59,7 +60,7 @@ async function createComment(copilot, projectId, issueId, body) {
5960
Joi.attempt({copilot, projectId, issueId, body}, createComment.schema);
6061
const gitlab = await _authenticate(copilot.accessToken);
6162
await gitlab.projects.issues.notes.create(projectId, issueId, {body});
62-
logger.debug(`Gitlab comment is added on issue with message "${body}"`);
63+
logger.debug(`Gitlab comment is added on issue with message: "${body}"`);
6364
}
6465

6566
createComment.schema = {
@@ -168,11 +169,58 @@ getUserIdByLogin.schema = {
168169
login: Joi.string().required()
169170
};
170171

172+
/**
173+
* updates the gitlab issue as paid and fix accepted
174+
* @param {Object} copilot the copilot
175+
* @param {Number} projectId the project id
176+
* @param {Number} issueId the issue number
177+
* @param {Number} challengeId the challenge id
178+
*/
179+
async function markIssueAsPaid(copilot, projectId, issueId, challengeId) {
180+
Joi.attempt({copilot, projectId, issueId, challengeId}, markIssueAsPaid.schema);
181+
const gitlab = await _authenticate(copilot.accessToken);
182+
await gitlab.projects.issues.edit(projectId, issueId, {labels: `${config.PAID_ISSUE_LABEL},${config.FIX_ACCEPTED_ISSUE_LABEL}`});
183+
const body = `Payment task has been updated: ${config.TC_OR_DETAIL_LINK}${challengeId}`;
184+
await gitlab.projects.issues.notes.create(projectId, issueId, {body});
185+
logger.debug(`Gitlab issue is updated for as paid and fix accepted for ${issueId}`);
186+
}
187+
188+
markIssueAsPaid.schema = {
189+
copilot: copilotUserSchema,
190+
projectId: Joi.number().positive().required(),
191+
issueId: Joi.number().positive().required(),
192+
challengeId: Joi.number().positive().required()
193+
};
194+
195+
/**
196+
* change the state of gitlab issue
197+
* @param {Object} copilot the copilot
198+
* @param {string} projectId the project id
199+
* @param {Number} issueId the issue issue id
200+
* @param {string} state new state
201+
*/
202+
async function changeState(copilot, projectId, issueId, state) {
203+
Joi.attempt({copilot, projectId, issueId, state}, changeState.schema);
204+
const gitlab = await _authenticate(copilot.accessToken);
205+
await gitlab.projects.issues.edit(projectId, issueId, {state_event: state});
206+
logger.debug(`Gitlab issue state is updated to '${state}' for issue number ${issueId}`);
207+
}
208+
209+
changeState.schema = {
210+
copilot: copilotUserSchema,
211+
projectId: Joi.number().positive().required(),
212+
issueId: Joi.number().positive().required(),
213+
state: Joi.string().required()
214+
};
215+
216+
171217
module.exports = {
172218
createComment,
173219
updateIssue,
174220
assignUser,
175221
removeAssign,
176222
getUsernameById,
177-
getUserIdByLogin
223+
getUserIdByLogin,
224+
markIssueAsPaid,
225+
changeState
178226
};

0 commit comments

Comments
 (0)