Skip to content

Commit 374d242

Browse files
authored
Merge pull request #23 from codex-team/fix/hasOwnProperty
Check before use
2 parents 5cd7734 + 878c51b commit 374d242

File tree

5 files changed

+165
-78
lines changed

5 files changed

+165
-78
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
# - "admin:org - read:org"
44
TOKEN=
55

6+
# HAWK Catcher TOKEN
7+
HAWK_TOKEN=
8+
69
# Node id
710
COLUMN_NODE_ID_TO_DO=
811
COLUMN_NODE_ID_PR=

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"get-projects": "node bin/get-projects.js"
1212
},
1313
"dependencies": {
14+
"@hawk.so/nodejs": "^2.2.0",
1415
"@octokit/core": "^3.1.2",
1516
"axios": "^0.19.2",
1617
"cron": "^1.8.2",

src/index.js

Lines changed: 129 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require('dotenv').config();
22

33
const Utils = require('./utils');
4+
const HawkCatcher = require('@hawk.so/nodejs').default;
45

56
const { Octokit } = require('@octokit/core');
67
const parseGithubUrl = require('parse-github-url');
@@ -9,6 +10,8 @@ const axios = require('axios').default;
910
const CronJob = require('cron').CronJob;
1011

1112
const TOKEN = process.env.TOKEN;
13+
const HAWK_TOKEN = process.env.HAWK_TOKEN;
14+
1215
const COLUMN_NODE_ID_TO_DO = process.env.COLUMN_NODE_ID_TO_DO;
1316
const COLUMN_NODE_ID_PR = process.env.COLUMN_NODE_ID_PR;
1417
const NOTIFIER_URL = process.env.NOTIFIER_URL;
@@ -40,6 +43,16 @@ const CARDS_QUERY = require('./queries/cards');
4043
const ISSUE_QUERY = require('./queries/issue');
4144
const PR_QUERY = require('./queries/pr');
4245

46+
/**
47+
* Initialize HawkCatcher.
48+
*/
49+
HawkCatcher.init({
50+
token: HAWK_TOKEN,
51+
context: {
52+
myOwnDebugInfo: '1234',
53+
},
54+
});
55+
4356
/**
4457
* Sends POST request to telegram bot
4558
*
@@ -144,28 +157,32 @@ function createReviewStatus(latestOpinionatedReviews, latestReviews, reviewReque
144157
/**
145158
* 💬 LatestReviews for adding commented status
146159
*/
147-
latestReviews.nodes.reverse().forEach(({ state, author }) => {
148-
const person = author.login;
160+
if (Utils.isPropertyExist(latestReviews, 'nodes')) {
161+
latestReviews.nodes.reverse().forEach(({ state, author }) => {
162+
const person = author.login;
149163

150-
reviewReport[person] = getReviewStateEmoji(state);
151-
});
164+
reviewReport[person] = getReviewStateEmoji(state);
165+
});
166+
}
152167

153168
/**
154169
* ✅❌ LatestOpinionatedReviews for the approved and changes requested
155170
*/
156-
latestOpinionatedReviews.nodes.forEach(({ state, author }) => {
157-
const person = author.login;
158-
159-
reviewReport[person] = getReviewStateEmoji(state);
160-
});
171+
if (Utils.isPropertyExist(latestOpinionatedReviews, 'nodes')) {
172+
latestOpinionatedReviews.nodes.forEach(({ state, author }) => {
173+
const person = author.login;
161174

175+
reviewReport[person] = getReviewStateEmoji(state);
176+
});
177+
}
162178
/**
163179
* 🔸 Requested review
164180
*/
165-
reviewRequests.nodes.forEach(({ requestedReviewer: { login } }) => {
166-
reviewReport[login] = getReviewStateEmoji();
167-
});
168-
181+
if (Utils.isPropertyExist(reviewRequests, 'nodes')) {
182+
reviewRequests.nodes.forEach(({ requestedReviewer: { login } }) => {
183+
reviewReport[login] = getReviewStateEmoji();
184+
});
185+
}
169186
let reviewStatus = '';
170187

171188
Object.entries(reviewReport).forEach(([login, state]) => {
@@ -196,15 +213,23 @@ function createTaskBadge(url) {
196213
* @returns {string} - parsed message.
197214
*/
198215
function pullRequestParser(content) {
199-
const taskTitle = Utils.trimString(escapeChars(content.title), TRIM_PR_NAME_LENGHT);
216+
const {
217+
title,
218+
latestOpinionatedReviews,
219+
latestReviews,
220+
reviewRequests,
221+
author,
222+
url,
223+
} = content;
224+
225+
const taskTitle = Utils.trimString(escapeChars(title), TRIM_PR_NAME_LENGHT);
200226
const reviewState = createReviewStatus(
201-
content.latestOpinionatedReviews,
202-
content.latestReviews,
203-
content.reviewRequests
227+
latestOpinionatedReviews,
228+
latestReviews,
229+
reviewRequests
204230
);
205231

206-
const parsedTask = `${createTaskBadge(content.url)}: <a href="${content.url
207-
}">${taskTitle}</a> ${reviewState} @${content.author.login}`;
232+
const parsedTask = `${createTaskBadge(url)}: <a href="${url}">${taskTitle}</a> ${reviewState} @${author.login}`;
208233

209234
/**
210235
* @todo discuss if it is necessary to duplicate links to pr
@@ -231,14 +256,20 @@ function pullRequestParser(content) {
231256
* @returns {string} - parsed message.
232257
*/
233258
function issuesParser(content) {
234-
const taskTitle = Utils.trimString(escapeChars(content.title), TRIM_PR_NAME_LENGHT);
235-
236-
let parsedTask = `${createTaskBadge(content.url)}: <a href="${content.url
237-
}">${escapeChars(taskTitle)}</a>`;
238-
239-
content.assignees.nodes.forEach((node) => {
240-
parsedTask += `@${node.login} `;
241-
});
259+
const {
260+
title,
261+
assignees,
262+
url,
263+
} = content;
264+
const taskTitle = Utils.trimString(escapeChars(title), TRIM_PR_NAME_LENGHT);
265+
266+
let parsedTask = `${createTaskBadge(url)}: <a href="${url}">${escapeChars(taskTitle)}</a>`;
267+
268+
if (Utils.isPropertyExist(assignees, 'nodes')) {
269+
assignees.nodes.forEach(({ login }) => {
270+
parsedTask += `@${login} `;
271+
});
272+
}
242273

243274
return parsedTask;
244275
}
@@ -273,10 +304,12 @@ async function parseGithubLink(message, parsable) {
273304
number: parseInt(id),
274305
});
275306

276-
return replaceGithubLink(
277-
message,
278-
pullRequestParser(response.repository.pullRequest)
279-
);
307+
if (Utils.isPropertyExist(response, 'repository', 'pullRequest')) {
308+
return replaceGithubLink(
309+
message,
310+
pullRequestParser(response.repository.pullRequest)
311+
);
312+
}
280313
}
281314
if (type === 'issues') {
282315
const response = await graphqlQuery(ISSUE_QUERY, {
@@ -285,7 +318,9 @@ async function parseGithubLink(message, parsable) {
285318
number: parseInt(id),
286319
});
287320

288-
return replaceGithubLink(message, issuesParser(response.repository.issue));
321+
if (Utils.isPropertyExist(response, 'repository', 'issue')) {
322+
return replaceGithubLink(message, issuesParser(response.repository.issue));
323+
}
289324
}
290325
}
291326

@@ -298,34 +333,47 @@ async function parseGithubLink(message, parsable) {
298333
*/
299334
async function parseQuery(members, response) {
300335
const parsedCardData = await Promise.all(
301-
await response.map(async (items) => {
302-
if (items.state === 'NOTE_ONLY') {
303-
for (let i = 0; i < members.length; i++) {
304-
if (items.note.includes(`@${members[i].name}`)) {
305-
const parsable = checkForParsableGithubLink(items.note);
306-
307-
return parsable[0]
308-
? await parseGithubLink(items.note, parsable)
309-
: escapeChars(items.note);
336+
await response.map(async (cardData) => {
337+
try {
338+
if (Utils.isPropertyExist(cardData, 'state')) {
339+
if (cardData.state === 'NOTE_ONLY') {
340+
if (Utils.isPropertyExist(cardData, 'note') && Utils.isPropertyExist(cardData, 'creator')) {
341+
for (let i = 0; i < members.length; i++) {
342+
if (cardData.note.includes(`@${members[i].name}`)) {
343+
const parsable = checkForParsableGithubLink(cardData.note);
344+
345+
return parsable[0]
346+
? await parseGithubLink(cardData.note, parsable)
347+
: escapeChars(cardData.note);
348+
}
349+
}
350+
const parsable = checkForParsableGithubLink(cardData.note);
351+
352+
return parsable[0]
353+
? await parseGithubLink(cardData.note, parsable)
354+
: `${cardData.note} @${cardData.creator.login}`;
355+
}
356+
} else if (cardData.state === 'CONTENT_ONLY') {
357+
if (Utils.isPropertyExist(cardData, 'content', '__typename')) {
358+
if (cardData.content.__typename === 'PullRequest') {
359+
return pullRequestParser(cardData.content);
360+
}
361+
362+
if (cardData.content.__typename === 'Issue') {
363+
return issuesParser(cardData.content);
364+
}
365+
}
310366
}
367+
368+
return '';
311369
}
312-
const parsable = checkForParsableGithubLink(items.note);
313-
314-
return parsable[0]
315-
? await parseGithubLink(items.note, parsable)
316-
: `${items.note} @${items.creator.login}`;
317-
} else if (items.state === 'CONTENT_ONLY') {
318-
if (items.content.__typename === 'PullRequest') {
319-
return pullRequestParser(items.content);
320-
}
321-
if (items.content.__typename === 'Issue') {
322-
return issuesParser(items.content);
323-
}
370+
} catch (e) {
371+
HawkCatcher.send(e, {
372+
cardData: cardData,
373+
});
324374
}
325-
326-
return '';
327375
})
328-
);
376+
).catch(HawkCatcher.send);
329377

330378
let cardDataWithoutMembers = [ ...parsedCardData ];
331379

@@ -338,9 +386,9 @@ async function parseQuery(members, response) {
338386
x.replace(/^\s+|\s+$/g, '')
339387
);
340388

341-
parsedCardData.forEach((items, index) => {
389+
parsedCardData.forEach((cardData, index) => {
342390
for (let i = 0; i < members.length; i++) {
343-
if (items.includes(`@${members[i].name}`)) {
391+
if (cardData.includes(`@${members[i].name}`)) {
344392
members[i].tasks.push(cardDataWithoutMembers[index]);
345393
}
346394
}
@@ -359,9 +407,9 @@ function getMembersName(memberList) {
359407
const members = [];
360408

361409
if (memberList) {
362-
memberList.split(' ').forEach((items) => {
410+
memberList.split(' ').forEach((memberName) => {
363411
members.push({
364-
name: items,
412+
name: memberName,
365413
tasks: [],
366414
});
367415
});
@@ -370,9 +418,9 @@ function getMembersName(memberList) {
370418
}
371419

372420
return octokit.graphql(MEMBERS_QUERY).then((query) => {
373-
query.organization.membersWithRole.nodes.forEach((items) => {
421+
query.organization.membersWithRole.nodes.forEach(({ login }) => {
374422
members.push({
375-
name: items.login,
423+
name: login,
376424
tasks: [],
377425
});
378426
});
@@ -393,25 +441,29 @@ function getMembersName(memberList) {
393441
async function notifyMessage(title, columnID, includePersonWithNoTask = false) {
394442
let dataToSend = title + ' \n\n';
395443
const queryResponse = await graphqlQuery(CARDS_QUERY, { id: columnID });
396-
const parsedData = await parseQuery(
397-
getMembersName(MENTION),
398-
queryResponse.node.cards.nodes
399-
);
444+
let parsedData = {};
445+
446+
if (Utils.isPropertyExist(queryResponse, 'node', 'cards', 'nodes')) {
447+
parsedData = await parseQuery(
448+
getMembersName(MENTION),
449+
queryResponse.node.cards.nodes
450+
);
451+
}
400452
const personWithNoTask = [];
401453

402-
parsedData.forEach((items) => {
454+
parsedData.forEach(({ tasks, name }) => {
403455
/** Skip person with no tasks */
404-
if (!items.tasks.length) {
405-
if (includePersonWithNoTask && items.name != 'dependabot') {
406-
personWithNoTask.push(items.name);
456+
if (!tasks.length) {
457+
if (includePersonWithNoTask && name != 'dependabot') {
458+
personWithNoTask.push(name);
407459
}
408460

409461
return;
410462
}
411463

412-
dataToSend += `<b>${items.name}</b>\n`;
464+
dataToSend += `<b>${name}</b>\n`;
413465

414-
items.tasks.forEach((data) => {
466+
tasks.forEach((data) => {
415467
dataToSend += `• ${data}\n`;
416468
});
417469

@@ -439,8 +491,8 @@ async function notifyMessage(title, columnID, includePersonWithNoTask = false) {
439491
function parseMeetingMessage(mentionList) {
440492
let message = `☝️ Join the meeting in Discord!\n\n`;
441493

442-
mentionList.split(' ').forEach((items) => {
443-
message += `@${items} `;
494+
mentionList.split(' ').forEach((mentionName) => {
495+
message += `@${mentionName} `;
444496
});
445497

446498
return message;
@@ -457,7 +509,7 @@ async function main() {
457509
await notifyMessage("📌 Sprint's backlog", COLUMN_NODE_ID_TO_DO, true)
458510
)
459511
.then(() => console.log('Tasks Job Completed.'))
460-
.catch(console.error);
512+
.catch(HawkCatcher.send);
461513
},
462514
null,
463515
true,
@@ -471,7 +523,7 @@ async function main() {
471523
await notifyMessage('👀 Pull requests for review', COLUMN_NODE_ID_PR)
472524
)
473525
.then(() => console.log('PR Job Completed.'))
474-
.catch(console.error);
526+
.catch(HawkCatcher.send);
475527
},
476528
null,
477529
true,
@@ -482,7 +534,7 @@ async function main() {
482534
() => {
483535
notify(parseMeetingMessage(MEETING_MENTION))
484536
.then(() => console.log('Meeting Job Completed.'))
485-
.catch(console.error);
537+
.catch(HawkCatcher.send);
486538
},
487539
null,
488540
true,

0 commit comments

Comments
 (0)