diff --git a/src/cli.ts b/src/cli.ts index 24f461ad..1ac90bb3 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -22,17 +22,15 @@ import {remind} from './tasks/remind'; import {tidy} from './tasks/tidy'; import {unlabel} from './tasks/unlabel'; -const logger = new Logger(); - // add default handler for unhandled rejections process.on('unhandledRejection', (err) => { - logger.error('UNHANDLED REJECTION', err.stack); + Logger.error('UNHANDLED REJECTION', err.stack); process.exit(1); }); // check that environment variable GITLAB_PRIVATE_TOKEN is set if (typeof process.env.GITLAB_PRIVATE_TOKEN !== 'string' || process.env.GITLAB_PRIVATE_TOKEN.length === 0) { - logger.error('Environment variable GITLAB_PRIVATE_TOKEN is not set!'); + Logger.error('Environment variable GITLAB_PRIVATE_TOKEN is not set!'); process.exit(1); } @@ -46,21 +44,21 @@ commander .command('unlabel') .action(async () => { await unlabel(gitlabApi); - logger.ok('Done!'); + Logger.ok('Done!'); }); commander .command('tidy') .action(async () => { await tidy(gitlabApi); - logger.ok('Done!'); + Logger.ok('Done!'); }); commander .command('remind') .action(async () => { await remind(gitlabApi); - logger.ok('Done!'); + Logger.ok('Done!'); }); commander diff --git a/src/common.ts b/src/common.ts index 42973872..6ef96778 100644 --- a/src/common.ts +++ b/src/common.ts @@ -16,16 +16,11 @@ import {asyncPool} from '@krlwlfrt/async-pool'; import {Api} from '@openstapps/gitlab-api'; import {Group, Project} from '@openstapps/gitlab-api/lib/types'; import {Logger} from '@openstapps/logger'; -import {readFile, unlink, writeFile} from 'fs'; -import * as glob from 'glob'; +import {readFile, writeFile} from 'fs'; import {promisify} from 'util'; export const readFilePromisified = promisify(readFile); -export const globPromisified = promisify(glob); export const writeFilePromisified = promisify(writeFile); -export const unlinkPromisified = promisify(unlink); - -export const logger = new Logger(); /** * Get projects for a list of groups @@ -34,7 +29,7 @@ export const logger = new Logger(); * @param groups List of groups */ export async function getProjects(api: Api, groups: number[]): Promise { - logger.info('Fetching all projects for specified groups (' + groups.length + ')...'); + Logger.info('Fetching all projects for specified groups (' + groups.length + ')...'); const projectResults = await asyncPool(3, groups, (groupId) => { return api.getProjectsForGroup(groupId); @@ -42,7 +37,7 @@ export async function getProjects(api: Api, groups: number[]): Promise { // get list of open merge requests const mergeRequests = await api.getMergeRequests(MembershipScope.GROUPS, GROUPS[0], MergeRequestState.OPENED); - logger.info(`Found ${mergeRequests.length} open merge requests.`); + Logger.info(`Found ${mergeRequests.length} open merge requests.`); // instantiate slack client const client = new WebClient(process.env.SLACK_API_TOKEN); @@ -49,12 +49,12 @@ export async function remind(api: Api): Promise { return a.localeCompare(b); }); - logger.info(`Found ${maintainers.length} maintainer(s).`); + Logger.info(`Found ${maintainers.length} maintainer(s).`); await asyncPool(2, mergeRequests, async (mergeRequest) => { // check if merge request is WIP if (mergeRequest.work_in_progress) { - logger.info(`Merge request '${mergeRequest.title}' is WIP.`); + Logger.info(`Merge request '${mergeRequest.title}' is WIP.`); return; } @@ -91,7 +91,7 @@ export async function remind(api: Api): Promise { if (approval.merge_status === MergeRequestMergeStatus.CAN_BE_MERGED) { if (approval.approvals_left > 0) { - logger.warn(`Merge request '${mergeRequest.title}' needs more approvals!`); + Logger.warn(`Merge request '${mergeRequest.title}' needs more approvals!`); // get possible appropers, prefixed with '@' and joined with commas const possibleApprovers = maintainerUsernames @@ -121,7 +121,7 @@ export async function remind(api: Api): Promise { `${NOTE_PREFIX} Please review, ${possibleApprovers}!`, ); } else { - logger.log(`Merge request '${mergeRequest.title}' is ready to be merged!`); + Logger.log(`Merge request '${mergeRequest.title}' is ready to be merged!`); // send message to slack await client.chat.postMessage({ diff --git a/src/tasks/report.ts b/src/tasks/report.ts index 248f1d7f..8cd91edf 100644 --- a/src/tasks/report.ts +++ b/src/tasks/report.ts @@ -15,11 +15,12 @@ import {asyncPool} from '@krlwlfrt/async-pool'; import {Api} from '@openstapps/gitlab-api'; import {Issue, IssueState, MembershipScope, MergeRequestState, Project, User} from '@openstapps/gitlab-api/lib/types'; +import {Logger} from '@openstapps/logger'; import * as moment from 'moment'; import {render} from 'mustache'; import {join, resolve} from 'path'; import {cwd} from 'process'; -import {flatten2dArray, getProjects, logger, readFilePromisified, writeFilePromisified} from '../common'; +import {flatten2dArray, getProjects, readFilePromisified, writeFilePromisified} from '../common'; import {BOLD_LABELS, GROUPS, LABEL_WEIGHTS} from '../configuration'; /** @@ -124,7 +125,7 @@ export async function getIssues(api: Api, label: string, groups: number[]): Prom return issue.labels.indexOf(label) >= 0; }); - logger.log('Fetched ' + issues.length + ' issue(s).'); + Logger.log('Fetched ' + issues.length + ' issue(s).'); return issues; } @@ -182,7 +183,7 @@ export async function getIssuesGroupedByAssignees(api: Api, label: string): Prom issues.forEach((issue) => { if (issue.assignee === null) { - logger.warn('Issue without assignee!', issue.web_url); + Logger.warn('Issue without assignee!', issue.web_url); return; } @@ -289,7 +290,7 @@ export function getNextMeetingDay() { const meetingDay = meetingDayMoment.format('YYYY-MM-DD'); // log found meeting day - logger.info('Generating report for ' + meetingDay + ' of ' + GROUPS.length + ' group(s)...'); + Logger.info('Generating report for ' + meetingDay + ' of ' + GROUPS.length + ' group(s)...'); return meetingDay; } @@ -376,5 +377,5 @@ export async function report(api: Api, label: string) { await writeFilePromisified(filename, markdown); - logger.ok(`Wrote file '${filename}'.`); + Logger.ok(`Wrote file '${filename}'.`); } diff --git a/src/tasks/tidy.ts b/src/tasks/tidy.ts index 312b059d..e30cfaac 100644 --- a/src/tasks/tidy.ts +++ b/src/tasks/tidy.ts @@ -15,7 +15,8 @@ import {asyncPool} from '@krlwlfrt/async-pool'; import {Api} from '@openstapps/gitlab-api'; import {AccessLevel, IssueState, MembershipScope, Milestone, Project, Scope} from '@openstapps/gitlab-api/lib/types'; -import {flatten2dArray, getProjects, logger} from '../common'; +import {Logger} from '@openstapps/logger'; +import {flatten2dArray, getProjects} from '../common'; import {GROUPS, NEEDED_LABELS, NEEDED_MILESTONES, NOTE_PREFIX, PROTECTED_BRANCHES, SCHOOLS} from '../configuration'; /** @@ -38,7 +39,7 @@ export async function tidyIssuesWithoutMilestone(api: Api): Promise { // flatten structure, e.g. put all issues in one array const issuesWithoutMilestone = flatten2dArray(issueResults); - logger.info('Found `' + issuesWithoutMilestone.length + '` issue(s) without milestone.'); + Logger.info('Found `' + issuesWithoutMilestone.length + '` issue(s) without milestone.'); const milestoneCache: { [s: number]: Milestone[] } = {}; @@ -56,13 +57,13 @@ export async function tidyIssuesWithoutMilestone(api: Api): Promise { }); if (milestoneId === null) { - logger.warn('Milestone `Meeting` was not available for issue ' + issue.title + ' (' + issue.web_url + ').'); + Logger.warn('Milestone `Meeting` was not available for issue ' + issue.title + ' (' + issue.web_url + ').'); return; } await api.setMilestoneForIssue(issue, milestoneId); - logger.log('Milestone was set to `Meeting` for issue ' + issue.title + ' (' + issue.web_url + ').'); + Logger.log('Milestone was set to `Meeting` for issue ' + issue.title + ' (' + issue.web_url + ').'); await api.createNote( issue.project_id, @@ -72,7 +73,7 @@ export async function tidyIssuesWithoutMilestone(api: Api): Promise { ); }); - logger.ok('Tidied issues without milestones.'); + Logger.ok('Tidied issues without milestones.'); } /** @@ -94,18 +95,18 @@ export async function tidyOpenIssuesWithoutMeetingLabel(api: Api): Promise // flatten structure, e.g. put all issues in one array const openIssues = flatten2dArray(issueResults); - logger.info(`Found ${openIssues.length} open issue(s).`); + Logger.info(`Found ${openIssues.length} open issue(s).`); // filter issues without meeting label const openIssuesWithoutMeetingLabel = openIssues.filter((openIssue) => { return openIssue.labels.indexOf('meeting') === -1; }); - logger.info(`Filtered ${openIssuesWithoutMeetingLabel.length} open issue(s) without label 'meeting'.`); + Logger.info(`Filtered ${openIssuesWithoutMeetingLabel.length} open issue(s) without label 'meeting'.`); await asyncPool(5, openIssuesWithoutMeetingLabel, async (issue) => { if (issue.milestone !== null && issue.milestone.title === 'Backlog') { - logger.info(`Skipping issue "${issue.title}" because it is in backlog.`); + Logger.info(`Skipping issue "${issue.title}" because it is in backlog.`); return; } @@ -116,7 +117,7 @@ export async function tidyOpenIssuesWithoutMeetingLabel(api: Api): Promise `${NOTE_PREFIX} Automatically adding label 'meeting'\n\n/label ~meeting`); }); - logger.ok(`Tidied open issues without label 'meeting'.`); + Logger.ok(`Tidied open issues without label 'meeting'.`); } /** @@ -150,17 +151,17 @@ export async function tidyLabels(api: Api, projects: Project[]): Promise { await asyncPool(2, neededLabels, async (neededLabel) => { await api.createLabel(project.id, neededLabel.name, neededLabel.description, neededLabel.color); - logger.log('Created label `' + neededLabel.name + '` in ' + project.name_with_namespace + '.'); + Logger.log('Created label `' + neededLabel.name + '` in ' + project.name_with_namespace + '.'); }); // await asyncPool(2, extraneousLabels, async (extraneousLabel) => { // await api.deleteLabel(project.id, extraneousLabel.name); // - // logger.log('Deleted label `' + extraneousLabel.name + '` from ' + project.name_with_namespace + '.'); + // Logger.log('Deleted label `' + extraneousLabel.name + '` from ' + project.name_with_namespace + '.'); // }); }); - logger.ok('Tidied labels.'); + Logger.ok('Tidied labels.'); } /** @@ -185,12 +186,12 @@ export async function tidyMilestones(api: Api, projects: Project[]): Promise 0) { await asyncPool(2, missingMilestones, async (milestone) => { await api.createMilestone(project.id, milestone); - logger.log('Created milestone ' + milestone + ' for project ' + project.name_with_namespace + '.'); + Logger.log('Created milestone ' + milestone + ' for project ' + project.name_with_namespace + '.'); }); } }); - logger.ok('Tidied milestones.'); + Logger.ok('Tidied milestones.'); } /** @@ -214,11 +215,11 @@ export async function tidyProtectedBranches(api: Api, projects: Project[]): Prom await asyncPool(2, unprotectedBranches, async (branch) => { await api.protectBranch(project.id, branch.name); - logger.log('Added protected branch `' + branch.name + '` in project `' + project.name_with_namespace + '`...'); + Logger.log('Added protected branch `' + branch.name + '` in project `' + project.name_with_namespace + '`...'); }); }); - logger.ok('Tidied protected branches.'); + Logger.ok('Tidied protected branches.'); } /** @@ -248,11 +249,11 @@ export async function tidyProtectedTags(api: Api, projects: Project[]): Promise< method: 'POST', }); - logger.log(`Added protected version tag in project '${project.name_with_namespace}'.`); + Logger.log(`Added protected version tag in project '${project.name_with_namespace}'.`); } }); - logger.ok('Tidied protected tags.'); + Logger.ok('Tidied protected tags.'); } /** @@ -278,7 +279,7 @@ export async function tidySubGroupMembers(api: Api): Promise { if (memberIds.indexOf(stappsMember.id) === -1) { await api.addMember(MembershipScope.GROUPS, groupId, stappsMember.id, AccessLevel.Developer); - logger.log('Added ' + stappsMember.name + ' to group ' + groupIdsToSchool[groupId] + '.'); + Logger.log('Added ' + stappsMember.name + ' to group ' + groupIdsToSchool[groupId] + '.'); } }); @@ -286,12 +287,12 @@ export async function tidySubGroupMembers(api: Api): Promise { if (stappsMemberIds.indexOf(member.id) === -1) { await api.deleteMember(MembershipScope.GROUPS, groupId, member.id); - logger.log('Deleted member ' + member.name + ' from group ' + groupIdsToSchool[groupId] + '.'); + Logger.log('Deleted member ' + member.name + ' from group ' + groupIdsToSchool[groupId] + '.'); } }); }); - logger.ok('Tidied "sub" group members.'); + Logger.ok('Tidied "sub" group members.'); } /** @@ -317,12 +318,12 @@ export async function tidyIssuesWithoutAssignee(api: Api): Promise { return issue.assignee === null; }); - logger.info('Found `' + issuesWithoutAssignee.length + '` issue(s) without assignee.'); + Logger.info('Found `' + issuesWithoutAssignee.length + '` issue(s) without assignee.'); await asyncPool(3, issuesWithoutAssignee, async (issue) => { await api.setAssigneeForIssue(issue, issue.author.id); - logger.log('Set assignee for `' + issue.title + '` to ' + issue.author.name + '.'); + Logger.log('Set assignee for `' + issue.title + '` to ' + issue.author.name + '.'); await api.createNote( issue.project_id, @@ -332,7 +333,7 @@ export async function tidyIssuesWithoutAssignee(api: Api): Promise { ); }); - logger.ok('Tidied issues without assignee.'); + Logger.ok('Tidied issues without assignee.'); } /** diff --git a/src/tasks/unlabel.ts b/src/tasks/unlabel.ts index c136fdcf..bf4ee56d 100644 --- a/src/tasks/unlabel.ts +++ b/src/tasks/unlabel.ts @@ -15,7 +15,8 @@ import {asyncPool} from '@krlwlfrt/async-pool'; import {Api} from '@openstapps/gitlab-api'; import {IssueState, Scope} from '@openstapps/gitlab-api/lib/types'; -import {flatten2dArray, logger} from '../common'; +import {Logger} from '@openstapps/logger'; +import {flatten2dArray} from '../common'; import {GROUPS, NOTE_PREFIX} from '../configuration'; /** @@ -33,11 +34,11 @@ export async function unlabel(api: Api) { const issues = flatten2dArray(issueResults); - logger.log('Fetched ' + issues.length + ' closed issue(s).'); + Logger.log('Fetched ' + issues.length + ' closed issue(s).'); await asyncPool(1, issues, async (issue) => { if (issue.labels.indexOf('meeting') >= 0) { - logger.info(`Issue ${issue.title} is closed and has label "meeting". Removing it.`); + Logger.info(`Issue ${issue.title} is closed and has label "meeting". Removing it.`); await api.createNote( issue.project_id, @@ -49,5 +50,5 @@ export async function unlabel(api: Api) { } }); - logger.ok('Label `meeting` has been removed from closed issues.'); + Logger.ok('Label `meeting` has been removed from closed issues.'); }