mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-09 06:03:01 -05:00
185 lines
5.3 KiB
JavaScript
185 lines
5.3 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
// overview:
|
|
// 1. Fetch the issues that are linked to the PR
|
|
// 2. Filter out the issues that are not feature requests
|
|
// 3. For each feature request:
|
|
// 1. Remove the 'help wanted' & 'needs votes' labels
|
|
// 3. Find the automated comment, hide the comment as 'outdated'
|
|
// 5. Post a new comment saying that the feature request has been implemented, and will be released in the next version. Link to the PR.
|
|
|
|
async function makeAPIRequest(query, variables) {
|
|
const res = await fetch('https://api.github.com/graphql', {
|
|
method: 'POST',
|
|
headers: {
|
|
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json',
|
|
},
|
|
body: JSON.stringify({ query, variables }),
|
|
});
|
|
return res.json();
|
|
}
|
|
|
|
function group(name, body) {
|
|
console.log(`::group::${name}`);
|
|
const result = body();
|
|
if (result instanceof Promise) {
|
|
return result.finally(() => console.log(`::endgroup::`));
|
|
}
|
|
console.log(`::endgroup::`);
|
|
return result;
|
|
}
|
|
|
|
async function main() {
|
|
const featureRequests = await group('Pull Request API Response', async () => {
|
|
const res = await makeAPIRequest(
|
|
/* GraphQL */ `
|
|
query FetchLinkedIssues($pr: Int!) {
|
|
repository(owner: "actualbudget", name: "actual") {
|
|
pullRequest(number: $pr) {
|
|
closingIssuesReferences(first: 10) {
|
|
nodes {
|
|
id
|
|
number
|
|
labels(first: 10) {
|
|
nodes {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
{ pr: parseInt(process.env.PR_NUMBER) },
|
|
);
|
|
|
|
console.log(JSON.stringify(res, null, 2));
|
|
|
|
return res.data.repository.pullRequest.closingIssuesReferences.nodes.filter(
|
|
issue => issue.labels.nodes.some(label => label.name === 'feature'),
|
|
);
|
|
});
|
|
|
|
if (featureRequests.length === 0) {
|
|
console.log('No linked feature requests found');
|
|
return;
|
|
}
|
|
|
|
for (const { id, number, labels } of featureRequests) {
|
|
await group(`Issue #${number}: Remove labels`, async () => {
|
|
const toRemove = labels.nodes
|
|
.filter(
|
|
label =>
|
|
label.name === 'help wanted' ||
|
|
label.name === 'needs votes' ||
|
|
label.name === 'good first issue',
|
|
)
|
|
.map(label => label.id);
|
|
const res = await makeAPIRequest(
|
|
/* GraphQL */ `
|
|
mutation RemoveLabels($issue: ID!, $labels: [ID!]!) {
|
|
removeLabelsFromLabelable(
|
|
input: {
|
|
clientMutationId: "1"
|
|
labelIds: $labels
|
|
labelableId: $issue
|
|
}
|
|
) {
|
|
clientMutationId
|
|
}
|
|
}
|
|
`,
|
|
{
|
|
issue: id,
|
|
labels: toRemove,
|
|
},
|
|
);
|
|
console.log(JSON.stringify(res, null, 2));
|
|
});
|
|
|
|
await group(`Issue #${number}: Collapse automatic comment`, async () => {
|
|
const commentRes = await makeAPIRequest(
|
|
/* GraphQL */ `
|
|
query FetchComments($issue: Int!) {
|
|
repository(owner: "actualbudget", name: "actual") {
|
|
issue(number: $issue) {
|
|
comments(first: 100) {
|
|
nodes {
|
|
id
|
|
body
|
|
author {
|
|
login
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
{ issue: number },
|
|
);
|
|
console.log(JSON.stringify(commentRes, null, 2));
|
|
|
|
const comments = commentRes.data.repository.issue.comments.nodes.filter(
|
|
comment => comment.author.login === 'github-actions',
|
|
);
|
|
const commentToCollapse =
|
|
comments.find(comment =>
|
|
comment.body.includes('<!-- feature-auto-close-comment -->'),
|
|
) ||
|
|
comments.find(comment =>
|
|
comment.body.includes(
|
|
':sparkles: Thanks for sharing your idea! :sparkles:',
|
|
),
|
|
);
|
|
|
|
if (!commentToCollapse) {
|
|
console.log('No comment to collapse found');
|
|
process.exit(1);
|
|
}
|
|
|
|
const res = await makeAPIRequest(
|
|
/* GraphQL */ `
|
|
mutation CollapseComment($comment: ID!) {
|
|
minimizeComment(
|
|
input: { classifier: OUTDATED, subjectId: $comment }
|
|
) {
|
|
clientMutationId
|
|
}
|
|
}
|
|
`,
|
|
{ comment: commentToCollapse.id },
|
|
);
|
|
console.log(JSON.stringify(res, null, 2));
|
|
});
|
|
|
|
await group(`Issue #${number}: Post comment`, async () => {
|
|
const res = await makeAPIRequest(
|
|
/* GraphQL */ `
|
|
mutation PostComment($issue: ID!, $body: String!) {
|
|
addComment(
|
|
input: { subjectId: $issue, body: $body, clientMutationId: "1" }
|
|
) {
|
|
clientMutationId
|
|
}
|
|
}
|
|
`,
|
|
{
|
|
issue: id,
|
|
body: `:tada: This feature has been implemented in #${process.env.PR_NUMBER} and will be released in the next version. Thanks for sharing your idea! :tada:\n\n<!-- feature-implemented-comment -->`,
|
|
},
|
|
);
|
|
console.log(JSON.stringify(res, null, 2));
|
|
});
|
|
}
|
|
}
|
|
|
|
main().catch(err => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|