refactor: adjust code to updated dependencies

This commit is contained in:
Karl-Philipp Wulfert
2019-05-27 12:57:26 +02:00
parent 0986b42897
commit 5fc36ad28c
6 changed files with 50 additions and 54 deletions

View File

@@ -22,17 +22,15 @@ import {remind} from './tasks/remind';
import {tidy} from './tasks/tidy'; import {tidy} from './tasks/tidy';
import {unlabel} from './tasks/unlabel'; import {unlabel} from './tasks/unlabel';
const logger = new Logger();
// add default handler for unhandled rejections // add default handler for unhandled rejections
process.on('unhandledRejection', (err) => { process.on('unhandledRejection', (err) => {
logger.error('UNHANDLED REJECTION', err.stack); Logger.error('UNHANDLED REJECTION', err.stack);
process.exit(1); process.exit(1);
}); });
// check that environment variable GITLAB_PRIVATE_TOKEN is set // check that environment variable GITLAB_PRIVATE_TOKEN is set
if (typeof process.env.GITLAB_PRIVATE_TOKEN !== 'string' || process.env.GITLAB_PRIVATE_TOKEN.length === 0) { 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); process.exit(1);
} }
@@ -46,21 +44,21 @@ commander
.command('unlabel') .command('unlabel')
.action(async () => { .action(async () => {
await unlabel(gitlabApi); await unlabel(gitlabApi);
logger.ok('Done!'); Logger.ok('Done!');
}); });
commander commander
.command('tidy') .command('tidy')
.action(async () => { .action(async () => {
await tidy(gitlabApi); await tidy(gitlabApi);
logger.ok('Done!'); Logger.ok('Done!');
}); });
commander commander
.command('remind') .command('remind')
.action(async () => { .action(async () => {
await remind(gitlabApi); await remind(gitlabApi);
logger.ok('Done!'); Logger.ok('Done!');
}); });
commander commander

View File

@@ -16,16 +16,11 @@ import {asyncPool} from '@krlwlfrt/async-pool';
import {Api} from '@openstapps/gitlab-api'; import {Api} from '@openstapps/gitlab-api';
import {Group, Project} from '@openstapps/gitlab-api/lib/types'; import {Group, Project} from '@openstapps/gitlab-api/lib/types';
import {Logger} from '@openstapps/logger'; import {Logger} from '@openstapps/logger';
import {readFile, unlink, writeFile} from 'fs'; import {readFile, writeFile} from 'fs';
import * as glob from 'glob';
import {promisify} from 'util'; import {promisify} from 'util';
export const readFilePromisified = promisify(readFile); export const readFilePromisified = promisify(readFile);
export const globPromisified = promisify(glob);
export const writeFilePromisified = promisify(writeFile); export const writeFilePromisified = promisify(writeFile);
export const unlinkPromisified = promisify(unlink);
export const logger = new Logger();
/** /**
* Get projects for a list of groups * Get projects for a list of groups
@@ -34,7 +29,7 @@ export const logger = new Logger();
* @param groups List of groups * @param groups List of groups
*/ */
export async function getProjects(api: Api, groups: number[]): Promise<Project[]> { export async function getProjects(api: Api, groups: number[]): Promise<Project[]> {
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) => { const projectResults = await asyncPool(3, groups, (groupId) => {
return api.getProjectsForGroup(groupId); return api.getProjectsForGroup(groupId);
@@ -42,7 +37,7 @@ export async function getProjects(api: Api, groups: number[]): Promise<Project[]
const projects = flatten2dArray(projectResults); const projects = flatten2dArray(projectResults);
logger.log('Fetched ' + projects.length + ' project(s).'); Logger.log('Fetched ' + projects.length + ' project(s).');
return projects; return projects;
} }

View File

@@ -22,15 +22,15 @@ import {
Scope, Scope,
User, User,
} from '@openstapps/gitlab-api/lib/types'; } from '@openstapps/gitlab-api/lib/types';
import {Logger} from '@openstapps/logger';
import {WebClient} from '@slack/client'; import {WebClient} from '@slack/client';
import {logger} from '../common';
import {GROUPS, NOTE_PREFIX, SLACK_CHANNEL} from '../configuration'; import {GROUPS, NOTE_PREFIX, SLACK_CHANNEL} from '../configuration';
export async function remind(api: Api): Promise<void> { export async function remind(api: Api): Promise<void> {
// get list of open merge requests // get list of open merge requests
const mergeRequests = await api.getMergeRequests(MembershipScope.GROUPS, GROUPS[0], MergeRequestState.OPENED); 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 // instantiate slack client
const client = new WebClient(process.env.SLACK_API_TOKEN); const client = new WebClient(process.env.SLACK_API_TOKEN);
@@ -49,12 +49,12 @@ export async function remind(api: Api): Promise<void> {
return a.localeCompare(b); return a.localeCompare(b);
}); });
logger.info(`Found ${maintainers.length} maintainer(s).`); Logger.info(`Found ${maintainers.length} maintainer(s).`);
await asyncPool(2, mergeRequests, async (mergeRequest) => { await asyncPool(2, mergeRequests, async (mergeRequest) => {
// check if merge request is WIP // check if merge request is WIP
if (mergeRequest.work_in_progress) { if (mergeRequest.work_in_progress) {
logger.info(`Merge request '${mergeRequest.title}' is WIP.`); Logger.info(`Merge request '${mergeRequest.title}' is WIP.`);
return; return;
} }
@@ -91,7 +91,7 @@ export async function remind(api: Api): Promise<void> {
if (approval.merge_status === MergeRequestMergeStatus.CAN_BE_MERGED) { if (approval.merge_status === MergeRequestMergeStatus.CAN_BE_MERGED) {
if (approval.approvals_left > 0) { 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 // get possible appropers, prefixed with '@' and joined with commas
const possibleApprovers = maintainerUsernames const possibleApprovers = maintainerUsernames
@@ -121,7 +121,7 @@ export async function remind(api: Api): Promise<void> {
`${NOTE_PREFIX} Please review, ${possibleApprovers}!`, `${NOTE_PREFIX} Please review, ${possibleApprovers}!`,
); );
} else { } 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 // send message to slack
await client.chat.postMessage({ await client.chat.postMessage({

View File

@@ -15,11 +15,12 @@
import {asyncPool} from '@krlwlfrt/async-pool'; import {asyncPool} from '@krlwlfrt/async-pool';
import {Api} from '@openstapps/gitlab-api'; import {Api} from '@openstapps/gitlab-api';
import {Issue, IssueState, MembershipScope, MergeRequestState, Project, User} from '@openstapps/gitlab-api/lib/types'; import {Issue, IssueState, MembershipScope, MergeRequestState, Project, User} from '@openstapps/gitlab-api/lib/types';
import {Logger} from '@openstapps/logger';
import * as moment from 'moment'; import * as moment from 'moment';
import {render} from 'mustache'; import {render} from 'mustache';
import {join, resolve} from 'path'; import {join, resolve} from 'path';
import {cwd} from 'process'; 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'; 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; return issue.labels.indexOf(label) >= 0;
}); });
logger.log('Fetched ' + issues.length + ' issue(s).'); Logger.log('Fetched ' + issues.length + ' issue(s).');
return issues; return issues;
} }
@@ -182,7 +183,7 @@ export async function getIssuesGroupedByAssignees(api: Api, label: string): Prom
issues.forEach((issue) => { issues.forEach((issue) => {
if (issue.assignee === null) { if (issue.assignee === null) {
logger.warn('Issue without assignee!', issue.web_url); Logger.warn('Issue without assignee!', issue.web_url);
return; return;
} }
@@ -289,7 +290,7 @@ export function getNextMeetingDay() {
const meetingDay = meetingDayMoment.format('YYYY-MM-DD'); const meetingDay = meetingDayMoment.format('YYYY-MM-DD');
// log found meeting day // 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; return meetingDay;
} }
@@ -376,5 +377,5 @@ export async function report(api: Api, label: string) {
await writeFilePromisified(filename, markdown); await writeFilePromisified(filename, markdown);
logger.ok(`Wrote file '${filename}'.`); Logger.ok(`Wrote file '${filename}'.`);
} }

View File

@@ -15,7 +15,8 @@
import {asyncPool} from '@krlwlfrt/async-pool'; import {asyncPool} from '@krlwlfrt/async-pool';
import {Api} from '@openstapps/gitlab-api'; import {Api} from '@openstapps/gitlab-api';
import {AccessLevel, IssueState, MembershipScope, Milestone, Project, Scope} from '@openstapps/gitlab-api/lib/types'; 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'; import {GROUPS, NEEDED_LABELS, NEEDED_MILESTONES, NOTE_PREFIX, PROTECTED_BRANCHES, SCHOOLS} from '../configuration';
/** /**
@@ -38,7 +39,7 @@ export async function tidyIssuesWithoutMilestone(api: Api): Promise<void> {
// flatten structure, e.g. put all issues in one array // flatten structure, e.g. put all issues in one array
const issuesWithoutMilestone = flatten2dArray(issueResults); 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[] } = {}; const milestoneCache: { [s: number]: Milestone[] } = {};
@@ -56,13 +57,13 @@ export async function tidyIssuesWithoutMilestone(api: Api): Promise<void> {
}); });
if (milestoneId === null) { 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; return;
} }
await api.setMilestoneForIssue(issue, milestoneId); 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( await api.createNote(
issue.project_id, issue.project_id,
@@ -72,7 +73,7 @@ export async function tidyIssuesWithoutMilestone(api: Api): Promise<void> {
); );
}); });
logger.ok('Tidied issues without milestones.'); Logger.ok('Tidied issues without milestones.');
} }
/** /**
@@ -94,18 +95,18 @@ export async function tidyOpenIssuesWithoutMeetingLabel(api: Api): Promise<void>
// flatten structure, e.g. put all issues in one array // flatten structure, e.g. put all issues in one array
const openIssues = flatten2dArray(issueResults); 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 // filter issues without meeting label
const openIssuesWithoutMeetingLabel = openIssues.filter((openIssue) => { const openIssuesWithoutMeetingLabel = openIssues.filter((openIssue) => {
return openIssue.labels.indexOf('meeting') === -1; 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) => { await asyncPool(5, openIssuesWithoutMeetingLabel, async (issue) => {
if (issue.milestone !== null && issue.milestone.title === 'Backlog') { 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; return;
} }
@@ -116,7 +117,7 @@ export async function tidyOpenIssuesWithoutMeetingLabel(api: Api): Promise<void>
`${NOTE_PREFIX} Automatically adding label 'meeting'\n\n/label ~meeting`); `${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<void> {
await asyncPool(2, neededLabels, async (neededLabel) => { await asyncPool(2, neededLabels, async (neededLabel) => {
await api.createLabel(project.id, neededLabel.name, neededLabel.description, neededLabel.color); 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 asyncPool(2, extraneousLabels, async (extraneousLabel) => {
// await api.deleteLabel(project.id, extraneousLabel.name); // 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<voi
if (missingMilestones.length > 0) { if (missingMilestones.length > 0) {
await asyncPool(2, missingMilestones, async (milestone) => { await asyncPool(2, missingMilestones, async (milestone) => {
await api.createMilestone(project.id, 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 asyncPool(2, unprotectedBranches, async (branch) => {
await api.protectBranch(project.id, branch.name); 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', 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<void> {
if (memberIds.indexOf(stappsMember.id) === -1) { if (memberIds.indexOf(stappsMember.id) === -1) {
await api.addMember(MembershipScope.GROUPS, groupId, stappsMember.id, AccessLevel.Developer); 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<void> {
if (stappsMemberIds.indexOf(member.id) === -1) { if (stappsMemberIds.indexOf(member.id) === -1) {
await api.deleteMember(MembershipScope.GROUPS, groupId, member.id); 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<void> {
return issue.assignee === null; 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 asyncPool(3, issuesWithoutAssignee, async (issue) => {
await api.setAssigneeForIssue(issue, issue.author.id); 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( await api.createNote(
issue.project_id, issue.project_id,
@@ -332,7 +333,7 @@ export async function tidyIssuesWithoutAssignee(api: Api): Promise<void> {
); );
}); });
logger.ok('Tidied issues without assignee.'); Logger.ok('Tidied issues without assignee.');
} }
/** /**

View File

@@ -15,7 +15,8 @@
import {asyncPool} from '@krlwlfrt/async-pool'; import {asyncPool} from '@krlwlfrt/async-pool';
import {Api} from '@openstapps/gitlab-api'; import {Api} from '@openstapps/gitlab-api';
import {IssueState, Scope} from '@openstapps/gitlab-api/lib/types'; 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'; import {GROUPS, NOTE_PREFIX} from '../configuration';
/** /**
@@ -33,11 +34,11 @@ export async function unlabel(api: Api) {
const issues = flatten2dArray(issueResults); 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) => { await asyncPool(1, issues, async (issue) => {
if (issue.labels.indexOf('meeting') >= 0) { 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( await api.createNote(
issue.project_id, 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.');
} }