mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-22 01:22:54 +00:00
refactor: move logger to monorepo
This commit is contained in:
189
configuration/projectmanagement/src/tasks/remind.ts
Normal file
189
configuration/projectmanagement/src/tasks/remind.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2022 Open StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {asyncPool} from '@krlwlfrt/async-pool';
|
||||
import {Api} from '@openstapps/gitlab-api';
|
||||
import {
|
||||
AccessLevel,
|
||||
MembershipScope,
|
||||
MergeRequestMergeStatus,
|
||||
MergeRequestState,
|
||||
Scope,
|
||||
User,
|
||||
} from '@openstapps/gitlab-api/lib/types';
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {WebClient} from '@slack/client';
|
||||
import {CONCURRENCY, GROUPS, MAX_DEPTH_FOR_REMINDER, NOTE_PREFIX, SLACK_CHANNEL} from '../configuration';
|
||||
|
||||
/**
|
||||
* Remind people of open merge requests
|
||||
*
|
||||
* @param api GitLab API to make requests with
|
||||
*/
|
||||
export async function remind(api: Api): Promise<void> {
|
||||
// get list of open merge requests
|
||||
const allMergeRequests = await api.getMergeRequests(
|
||||
MembershipScope.GROUPS,
|
||||
GROUPS[0],
|
||||
MergeRequestState.OPENED,
|
||||
);
|
||||
|
||||
const mergeRequests = allMergeRequests.filter(mergeRequest => {
|
||||
const parts = mergeRequest.web_url.split('/');
|
||||
|
||||
// remove protocol, server name and main group
|
||||
parts.splice(0, parts.indexOf('gitlab.com') + 1 + 1);
|
||||
|
||||
// remove merge_requests and INDEX parts
|
||||
parts.splice(-1 - 1);
|
||||
|
||||
return parts.length <= MAX_DEPTH_FOR_REMINDER;
|
||||
});
|
||||
|
||||
Logger.info(`Found ${mergeRequests.length} open merge requests.`);
|
||||
|
||||
// instantiate slack client
|
||||
const client =
|
||||
typeof process.env.SLACK_API_TOKEN !== 'undefined'
|
||||
? new WebClient(process.env.SLACK_API_TOKEN)
|
||||
: undefined;
|
||||
|
||||
// get members of main group
|
||||
const members = await api.getMembers(MembershipScope.GROUPS, GROUPS[0]);
|
||||
|
||||
// filter members with at least maintainer status
|
||||
const maintainers = members.filter(member => member.access_level >= AccessLevel.Maintainer);
|
||||
|
||||
// extract maintainer's usernames
|
||||
const maintainerUsernames = maintainers.map(maintainer => maintainer.username);
|
||||
|
||||
// sort maintainer's usernames alphabetically
|
||||
maintainerUsernames.sort((a, b) => {
|
||||
return a.localeCompare(b);
|
||||
});
|
||||
|
||||
Logger.info(`Found ${maintainers.length} maintainer(s).`);
|
||||
|
||||
await asyncPool(CONCURRENCY, mergeRequests, async mergeRequest => {
|
||||
// check if merge request is WIP
|
||||
if (mergeRequest.work_in_progress) {
|
||||
Logger.info(`Merge request '${mergeRequest.title}' is WIP.`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// get merge request approval
|
||||
const approval = await api.getMergeRequestApproval(mergeRequest.project_id, mergeRequest.iid);
|
||||
|
||||
// get merge request discussions
|
||||
const discussions = await api.getMergeRequestDiscussions(mergeRequest.project_id, mergeRequest.iid);
|
||||
|
||||
// check if at least one of the discussions is unresolved
|
||||
const hasUnresolvedDiscussions = discussions.some(discussion => {
|
||||
return discussion.notes.some(note => {
|
||||
return note.resolvable && (typeof note.resolved === 'undefined' || !note.resolved);
|
||||
});
|
||||
});
|
||||
|
||||
if (hasUnresolvedDiscussions) {
|
||||
let recipient = mergeRequest.author.username;
|
||||
|
||||
if (typeof mergeRequest.assignee !== 'undefined' && mergeRequest.assignee !== null) {
|
||||
recipient = mergeRequest.assignee.username;
|
||||
}
|
||||
|
||||
// create note in merge request
|
||||
await api.createNote(
|
||||
mergeRequest.project_id,
|
||||
Scope.MERGE_REQUESTS,
|
||||
mergeRequest.iid,
|
||||
`${NOTE_PREFIX} Please resolve pending discussions, @${recipient}!`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (approval.merge_status === MergeRequestMergeStatus.CAN_BE_MERGED) {
|
||||
if (approval.approvals_left > 0) {
|
||||
Logger.warn(`Merge request '${mergeRequest.title}' needs more approvals!`);
|
||||
|
||||
// get possible appropers, prefixed with '@' and joined with commas
|
||||
const possibleApprovers = maintainerUsernames
|
||||
.filter(username => {
|
||||
if (mergeRequest.assignee.username === username) {
|
||||
return false;
|
||||
}
|
||||
if (username.includes('openstapps') || username.includes('kphilipp')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (approval.approved_by.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return approval.approved_by.find(
|
||||
(approver: {
|
||||
/**
|
||||
* Possible approver
|
||||
*/
|
||||
user: User;
|
||||
}) => {
|
||||
return approver.user.username !== username;
|
||||
},
|
||||
);
|
||||
})
|
||||
.map(username => `@${username}`)
|
||||
.join(' ');
|
||||
|
||||
// send message to slack
|
||||
await client?.chat.postMessage({
|
||||
channel: SLACK_CHANNEL,
|
||||
text: `Merge request '${mergeRequest.title}' needs more approvals! See ${mergeRequest.web_url}!`,
|
||||
});
|
||||
|
||||
// assign reviewers
|
||||
await api.createNote(
|
||||
mergeRequest.project_id,
|
||||
Scope.MERGE_REQUESTS,
|
||||
mergeRequest.iid,
|
||||
`/assign_reviewer ${possibleApprovers}`,
|
||||
);
|
||||
} else {
|
||||
Logger.log(`Merge request '${mergeRequest.title}' is ready to be merged!`);
|
||||
|
||||
// send message to slack
|
||||
await client?.chat.postMessage({
|
||||
channel: SLACK_CHANNEL,
|
||||
text: `Merge request '${mergeRequest.title}' is ready to be merged! See ${mergeRequest.web_url}!`,
|
||||
});
|
||||
|
||||
// prefix maintainers with '@' and join with commas
|
||||
const possibleMergers = maintainerUsernames
|
||||
.filter(username => {
|
||||
return mergeRequest.assignee.username !== username;
|
||||
})
|
||||
.map(username => `@${username}`)
|
||||
.join(', ');
|
||||
|
||||
// create note in merge request
|
||||
await api.createNote(
|
||||
mergeRequest.project_id,
|
||||
Scope.MERGE_REQUESTS,
|
||||
mergeRequest.iid,
|
||||
`${NOTE_PREFIX} Merge request is ready to be merged, ${possibleMergers}!`,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user