From e356aab7f44f6cb4abdf02406639aa349d353a64 Mon Sep 17 00:00:00 2001 From: Edoardo Balzano Date: Mon, 27 Nov 2023 17:38:14 +0100 Subject: [PATCH 01/11] Add detailed `console.log` statements for enhanced debugging in GitHub Actions --- .../js/src/project_automation/issues.mjs | 81 +++++++++++-------- automations/js/src/project_automation/prs.mjs | 80 ++++++++++-------- 2 files changed, 94 insertions(+), 67 deletions(-) diff --git a/automations/js/src/project_automation/issues.mjs b/automations/js/src/project_automation/issues.mjs index 95f37e91f4b..5f7c6a13831 100644 --- a/automations/js/src/project_automation/issues.mjs +++ b/automations/js/src/project_automation/issues.mjs @@ -9,14 +9,18 @@ import { getBoard } from '../utils/projects.mjs' * @param card {import('../utils/projects.mjs').Card} */ async function syncPriority(issue, board, card) { - const priority = issue.labels.find((label) => - label.name.includes('priority') - )?.name + console.log("::debug::Starting syncPriority for issue:", issue.number); + const priority = issue.labels.find((label) => label.name.includes('priority'))?.name; + if (priority) { - await board.setCustomChoiceField(card.id, 'Priority', priority) + console.log("::debug::Setting priority:", priority, "for card:", card.id); + await board.setCustomChoiceField(card.id, 'Priority', priority); + console.log("::debug::Priority set for card:", card.id); } if (priority === '🟥 priority: critical') { - await board.moveCard(card.id, board.columns.ToDo) + console.log("::debug::Moving card to 'To Do' for critical priority issue"); + await board.moveCard(card.id, board.columns.ToDo); + console.log("::debug::Card moved to 'To Do' column"); } } @@ -27,65 +31,74 @@ async function syncPriority(issue, board, card) { * @param context {import('@actions/github').context} info about the current event */ export const main = async (octokit, context) => { - const { EVENT_ACTION: eventAction } = process.env + const { EVENT_ACTION: eventAction } = process.env; + console.log("::debug::Event action received:", eventAction); - const issue = context.payload.issue - const label = context.payload.label + const issue = context.payload.issue; + const label = context.payload.label; + console.log("::debug::Issue details:", issue); if (issue.labels.some((label) => label.name === '🧭 project: thread')) { - // Do not add project threads to the Backlog board. - process.exit(0) + console.log("::debug::Issue is a project thread. Exiting."); + process.exit(0); } - const backlogBoard = await getBoard(octokit, 'Backlog') + const backlogBoard = await getBoard(octokit, 'Backlog'); + console.log("::debug::Backlog board fetched"); - // Create new, or get the existing, card for the current issue. - const card = await backlogBoard.addCard(issue.node_id) + const card = await backlogBoard.addCard(issue.node_id); + console.log("::debug::Card created or fetched for the issue:", card.id); switch (eventAction) { case 'opened': case 'reopened': { + console.log("::debug::Issue opened or reopened"); if (issue.labels.some((label) => label.name === '⛔ status: blocked')) { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) + console.log("::debug::Issue is blocked. Moving card to 'Blocked' column"); + await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked); } else { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) + console.log("::debug::Moving card to 'Backlog'"); + await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog); } - - await syncPriority(issue, backlogBoard, card) - break + await syncPriority(issue, backlogBoard, card); + break; } - case 'closed': { + console.log("::debug::Issue closed"); if (issue.state_reason === 'completed') { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Done) + console.log("::debug::Issue completed. Moving card to 'Done'"); + await backlogBoard.moveCard(card.id, backlogBoard.columns.Done); } else { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Discarded) + console.log("::debug::Issue not completed. Moving card to 'Discarded'"); + await backlogBoard.moveCard(card.id, backlogBoard.columns.Discarded); } - break + break; } - case 'assigned': { + console.log("::debug::Issue assigned"); if (card.status === backlogBoard.columns.Backlog) { - await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo) + console.log("::debug::Moving card to 'To Do'"); + await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo); } - break + break; } - case 'labeled': { + console.log("::debug::Issue labeled:", label.name); if (label.name === '⛔ status: blocked') { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) + console.log("::debug::Issue is blocked. Moving card to 'Blocked' column"); + await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked); } - await syncPriority(issue, backlogBoard, card) - break + await syncPriority(issue, backlogBoard, card); + break; } - case 'unlabeled': { + console.log("::debug::Label removed:", label.name); if (label.name === '⛔ status: blocked') { - // TODO: Move back to the column it came from. - await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) + console.log("::debug::'Blocked' label removed. Moving card to 'Backlog'"); + await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog); } - await syncPriority(issue, backlogBoard, card) - break + await syncPriority(issue, backlogBoard, card); + break; } } } diff --git a/automations/js/src/project_automation/prs.mjs b/automations/js/src/project_automation/prs.mjs index 4264e8280e6..54bd67e6f49 100644 --- a/automations/js/src/project_automation/prs.mjs +++ b/automations/js/src/project_automation/prs.mjs @@ -11,17 +11,22 @@ import { PullRequest } from '../utils/pr.mjs' * @param prCard {Card} */ async function syncReviews(pr, prBoard, prCard) { - const reviewDecision = pr.reviewDecision - const reviewCounts = pr.reviewCounts + console.log("::debug::Synchronizing reviews for PR:", pr.nodeId); + const reviewDecision = pr.reviewDecision; + console.log("::debug::Review decision:", reviewDecision); if (reviewDecision === 'APPROVED') { - await prBoard.moveCard(prCard.id, prBoard.columns.Approved) + console.log("::debug::Moving PR to 'Approved'"); + await prBoard.moveCard(prCard.id, prBoard.columns.Approved); } else if (reviewDecision === 'CHANGES_REQUESTED') { - await prBoard.moveCard(prCard.id, prBoard.columns.ChangesRequested) - } else if (reviewCounts.APPROVED === 1) { - await prBoard.moveCard(prCard.id, prBoard.columns.Needs1Review) + console.log("::debug::Changes requested for PR. Moving to 'ChangesRequested'"); + await prBoard.moveCard(prCard.id, prBoard.columns.ChangesRequested); + } else if (pr.reviewCounts.APPROVED === 1) { + console.log("::debug::PR needs 1 more review. Moving to 'Needs1Review'"); + await prBoard.moveCard(prCard.id, prBoard.columns.Needs1Review); } else { - await prBoard.moveCard(prCard.id, prBoard.columns.Needs2Reviews) + console.log("::debug::PR needs 2 more reviews. Moving to 'Needs2Reviews'"); + await prBoard.moveCard(prCard.id, prBoard.columns.Needs2Reviews); } } @@ -33,9 +38,12 @@ async function syncReviews(pr, prBoard, prCard) { * @param destColumn {string} */ async function syncIssues(pr, backlogBoard, destColumn) { + console.log("::debug::Synchronizing linked issues for PR:", pr.nodeId); for (let linkedIssue of pr.linkedIssues) { - const issueCard = await backlogBoard.addCard(linkedIssue) - await backlogBoard.moveCard(issueCard.id, backlogBoard.columns[destColumn]) + console.log("::debug::Processing linked issue:", linkedIssue); + const issueCard = await backlogBoard.addCard(linkedIssue); + console.log("::debug::Moving linked issue to column:", destColumn); + await backlogBoard.moveCard(issueCard.id, backlogBoard.columns[destColumn]); } } @@ -45,54 +53,60 @@ async function syncIssues(pr, backlogBoard, destColumn) { * @param octokit {import('@octokit/rest').Octokit} the Octokit instance to use */ export const main = async (octokit) => { + console.log("::debug::Starting PR script"); + const { eventName, eventAction, prNodeId } = JSON.parse( readFileSync('/tmp/event.json', 'utf-8') - ) + ); + console.log("::debug::Event details - Name:", eventName, ", Action:", eventAction, ", PR Node ID:", prNodeId); - const pr = new PullRequest(octokit, prNodeId) - await pr.init() + const pr = new PullRequest(octokit, prNodeId); + await pr.init(); - const prBoard = await getBoard(octokit, 'PRs') - const backlogBoard = await getBoard(octokit, 'Backlog') + const prBoard = await getBoard(octokit, 'PRs'); + const backlogBoard = await getBoard(octokit, 'Backlog'); - // Create new, or get the existing, card for the current pull request. - const prCard = await prBoard.addCard(pr.nodeId) + const prCard = await prBoard.addCard(pr.nodeId); + console.log("::debug::PR card created or fetched:", prCard.id); if (eventName === 'pull_request_review') { - await syncReviews(pr, prBoard, prCard) + await syncReviews(pr, prBoard, prCard); } else { switch (eventAction) { case 'opened': case 'reopened': { + console.log("::debug::PR opened or reopened"); if (pr.isDraft) { - await prBoard.moveCard(prCard.id, prBoard.columns.Draft) + console.log("::debug::PR is a draft. Moving to 'Draft'"); + await prBoard.moveCard(prCard.id, prBoard.columns.Draft); } else { - await syncReviews(pr, prBoard, prCard) + await syncReviews(pr, prBoard, prCard); } - await syncIssues(pr, backlogBoard, 'InProgress') - break + await syncIssues(pr, backlogBoard, 'InProgress'); + break; } - case 'edited': { - await syncIssues(pr, backlogBoard, 'InProgress') - break + console.log("::debug::PR edited"); + await syncIssues(pr, backlogBoard, 'InProgress'); + break; } - case 'converted_to_draft': { - await prBoard.moveCard(prCard.id, prBoard.columns.Draft) - break + console.log("::debug::PR converted to draft"); + await prBoard.moveCard(prCard.id, prBoard.columns.Draft); + break; } - case 'ready_for_review': { - await syncReviews(pr, prBoard, prCard) - break + console.log("::debug::PR ready for review"); + await syncReviews(pr, prBoard, prCard); + break; } - case 'closed': { + console.log("::debug::PR closed"); if (!pr.isMerged) { - await syncIssues(pr, backlogBoard, 'Backlog') + console.log("::debug::PR not merged. Moving linked issues to 'Backlog'"); + await syncIssues(pr, backlogBoard, 'Backlog'); } - break + break; } } } From 680d7712bdad11b609a2ef6d907d5f5e900652f9 Mon Sep 17 00:00:00 2001 From: edoardo Date: Tue, 28 Nov 2023 01:33:23 +0100 Subject: [PATCH 02/11] temp update of console.log --- .../js/src/project_automation/issues.mjs | 100 +++++++++-------- automations/js/src/project_automation/prs.mjs | 101 ++++++++++-------- automations/js/src/utils/projects.mjs | 4 + 3 files changed, 114 insertions(+), 91 deletions(-) diff --git a/automations/js/src/project_automation/issues.mjs b/automations/js/src/project_automation/issues.mjs index 5f7c6a13831..844aca41841 100644 --- a/automations/js/src/project_automation/issues.mjs +++ b/automations/js/src/project_automation/issues.mjs @@ -1,5 +1,7 @@ import { getBoard } from '../utils/projects.mjs' +import { debug } from '@actions/core' + /** * Set the "Priority" custom field based on the issue's labels. Also move * the card for critical issues directly to the "📅 To Do" column. @@ -9,18 +11,18 @@ import { getBoard } from '../utils/projects.mjs' * @param card {import('../utils/projects.mjs').Card} */ async function syncPriority(issue, board, card) { - console.log("::debug::Starting syncPriority for issue:", issue.number); - const priority = issue.labels.find((label) => label.name.includes('priority'))?.name; + debug('Starting syncPriority for issue:', issue.number) + const priority = issue.labels.find((label) => + label.name.includes('priority') + )?.name if (priority) { - console.log("::debug::Setting priority:", priority, "for card:", card.id); - await board.setCustomChoiceField(card.id, 'Priority', priority); - console.log("::debug::Priority set for card:", card.id); + await board.setCustomChoiceField(card.id, 'Priority', priority) } if (priority === '🟥 priority: critical') { - console.log("::debug::Moving card to 'To Do' for critical priority issue"); - await board.moveCard(card.id, board.columns.ToDo); - console.log("::debug::Card moved to 'To Do' column"); + console.log("::debug::Moving card to 'To Do' for critical priority issue") + await board.moveCard(card.id, board.columns.ToDo) + console.log("::debug::Card moved to 'To Do' column") } } @@ -31,74 +33,80 @@ async function syncPriority(issue, board, card) { * @param context {import('@actions/github').context} info about the current event */ export const main = async (octokit, context) => { - const { EVENT_ACTION: eventAction } = process.env; - console.log("::debug::Event action received:", eventAction); + const { EVENT_ACTION: eventAction } = process.env + console.log('::debug::Event action received:', eventAction) - const issue = context.payload.issue; - const label = context.payload.label; - console.log("::debug::Issue details:", issue); + const issue = context.payload.issue + const label = context.payload.label + console.log('::debug::Issue details:', issue) if (issue.labels.some((label) => label.name === '🧭 project: thread')) { - console.log("::debug::Issue is a project thread. Exiting."); - process.exit(0); + console.log('::debug::Issue is a project thread. Exiting.') + process.exit(0) } - const backlogBoard = await getBoard(octokit, 'Backlog'); - console.log("::debug::Backlog board fetched"); + const backlogBoard = await getBoard(octokit, 'Backlog') + console.log('::debug::Backlog board fetched') - const card = await backlogBoard.addCard(issue.node_id); - console.log("::debug::Card created or fetched for the issue:", card.id); + const card = await backlogBoard.addCard(issue.node_id) + console.log('::debug::Card created or fetched for the issue:', card.id) switch (eventAction) { case 'opened': case 'reopened': { - console.log("::debug::Issue opened or reopened"); + console.log('::debug::Issue opened or reopened') if (issue.labels.some((label) => label.name === '⛔ status: blocked')) { - console.log("::debug::Issue is blocked. Moving card to 'Blocked' column"); - await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked); + console.log( + "::debug::Issue is blocked. Moving card to 'Blocked' column" + ) + await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) } else { - console.log("::debug::Moving card to 'Backlog'"); - await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog); + console.log("::debug::Moving card to 'Backlog'") + await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) } - await syncPriority(issue, backlogBoard, card); - break; + await syncPriority(issue, backlogBoard, card) + break } case 'closed': { - console.log("::debug::Issue closed"); + console.log('::debug::Issue closed') if (issue.state_reason === 'completed') { - console.log("::debug::Issue completed. Moving card to 'Done'"); - await backlogBoard.moveCard(card.id, backlogBoard.columns.Done); + console.log("::debug::Issue completed. Moving card to 'Done'") + await backlogBoard.moveCard(card.id, backlogBoard.columns.Done) } else { - console.log("::debug::Issue not completed. Moving card to 'Discarded'"); - await backlogBoard.moveCard(card.id, backlogBoard.columns.Discarded); + console.log("::debug::Issue not completed. Moving card to 'Discarded'") + await backlogBoard.moveCard(card.id, backlogBoard.columns.Discarded) } - break; + break } case 'assigned': { - console.log("::debug::Issue assigned"); + console.log('::debug::Issue assigned') if (card.status === backlogBoard.columns.Backlog) { - console.log("::debug::Moving card to 'To Do'"); - await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo); + console.log("::debug::Moving card to 'To Do'") + await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo) } - break; + break } case 'labeled': { - console.log("::debug::Issue labeled:", label.name); + console.log('::debug::Issue labeled:', label.name) if (label.name === '⛔ status: blocked') { - console.log("::debug::Issue is blocked. Moving card to 'Blocked' column"); - await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked); + console.log( + "::debug::Issue is blocked. Moving card to 'Blocked' column" + ) + await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) } - await syncPriority(issue, backlogBoard, card); - break; + await syncPriority(issue, backlogBoard, card) + break } case 'unlabeled': { - console.log("::debug::Label removed:", label.name); + console.log('::debug::Label removed:', label.name) if (label.name === '⛔ status: blocked') { - console.log("::debug::'Blocked' label removed. Moving card to 'Backlog'"); - await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog); + console.log( + "::debug::'Blocked' label removed. Moving card to 'Backlog'" + ) + await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) } - await syncPriority(issue, backlogBoard, card); - break; + await syncPriority(issue, backlogBoard, card) + break } } } diff --git a/automations/js/src/project_automation/prs.mjs b/automations/js/src/project_automation/prs.mjs index 54bd67e6f49..f3df72906c1 100644 --- a/automations/js/src/project_automation/prs.mjs +++ b/automations/js/src/project_automation/prs.mjs @@ -11,22 +11,24 @@ import { PullRequest } from '../utils/pr.mjs' * @param prCard {Card} */ async function syncReviews(pr, prBoard, prCard) { - console.log("::debug::Synchronizing reviews for PR:", pr.nodeId); - const reviewDecision = pr.reviewDecision; - console.log("::debug::Review decision:", reviewDecision); + console.log('::debug::Synchronizing reviews for PR:', pr.nodeId) + const reviewDecision = pr.reviewDecision + console.log('::debug::Review decision:', reviewDecision) if (reviewDecision === 'APPROVED') { - console.log("::debug::Moving PR to 'Approved'"); - await prBoard.moveCard(prCard.id, prBoard.columns.Approved); + console.log("::debug::Moving PR to 'Approved'") + await prBoard.moveCard(prCard.id, prBoard.columns.Approved) } else if (reviewDecision === 'CHANGES_REQUESTED') { - console.log("::debug::Changes requested for PR. Moving to 'ChangesRequested'"); - await prBoard.moveCard(prCard.id, prBoard.columns.ChangesRequested); + console.log( + "::debug::Changes requested for PR. Moving to 'ChangesRequested'" + ) + await prBoard.moveCard(prCard.id, prBoard.columns.ChangesRequested) } else if (pr.reviewCounts.APPROVED === 1) { - console.log("::debug::PR needs 1 more review. Moving to 'Needs1Review'"); - await prBoard.moveCard(prCard.id, prBoard.columns.Needs1Review); + console.log("::debug::PR needs 1 more review. Moving to 'Needs1Review'") + await prBoard.moveCard(prCard.id, prBoard.columns.Needs1Review) } else { - console.log("::debug::PR needs 2 more reviews. Moving to 'Needs2Reviews'"); - await prBoard.moveCard(prCard.id, prBoard.columns.Needs2Reviews); + console.log("::debug::PR needs 2 more reviews. Moving to 'Needs2Reviews'") + await prBoard.moveCard(prCard.id, prBoard.columns.Needs2Reviews) } } @@ -38,12 +40,12 @@ async function syncReviews(pr, prBoard, prCard) { * @param destColumn {string} */ async function syncIssues(pr, backlogBoard, destColumn) { - console.log("::debug::Synchronizing linked issues for PR:", pr.nodeId); + console.log('::debug::Synchronizing linked issues for PR:', pr.nodeId) for (let linkedIssue of pr.linkedIssues) { - console.log("::debug::Processing linked issue:", linkedIssue); - const issueCard = await backlogBoard.addCard(linkedIssue); - console.log("::debug::Moving linked issue to column:", destColumn); - await backlogBoard.moveCard(issueCard.id, backlogBoard.columns[destColumn]); + console.log('::debug::Processing linked issue:', linkedIssue) + const issueCard = await backlogBoard.addCard(linkedIssue) + console.log('::debug::Moving linked issue to column:', destColumn) + await backlogBoard.moveCard(issueCard.id, backlogBoard.columns[destColumn]) } } @@ -53,60 +55,69 @@ async function syncIssues(pr, backlogBoard, destColumn) { * @param octokit {import('@octokit/rest').Octokit} the Octokit instance to use */ export const main = async (octokit) => { - console.log("::debug::Starting PR script"); + console.log('::debug::Starting PR script') const { eventName, eventAction, prNodeId } = JSON.parse( readFileSync('/tmp/event.json', 'utf-8') - ); - console.log("::debug::Event details - Name:", eventName, ", Action:", eventAction, ", PR Node ID:", prNodeId); + ) + console.log( + '::debug::Event details - Name:', + eventName, + ', Action:', + eventAction, + ', PR Node ID:', + prNodeId + ) - const pr = new PullRequest(octokit, prNodeId); - await pr.init(); + const pr = new PullRequest(octokit, prNodeId) + await pr.init() - const prBoard = await getBoard(octokit, 'PRs'); - const backlogBoard = await getBoard(octokit, 'Backlog'); + const prBoard = await getBoard(octokit, 'PRs') + const backlogBoard = await getBoard(octokit, 'Backlog') - const prCard = await prBoard.addCard(pr.nodeId); - console.log("::debug::PR card created or fetched:", prCard.id); + const prCard = await prBoard.addCard(pr.nodeId) + console.log('::debug::PR card created or fetched:', prCard.id) if (eventName === 'pull_request_review') { - await syncReviews(pr, prBoard, prCard); + await syncReviews(pr, prBoard, prCard) } else { switch (eventAction) { case 'opened': case 'reopened': { - console.log("::debug::PR opened or reopened"); + console.log('::debug::PR opened or reopened') if (pr.isDraft) { - console.log("::debug::PR is a draft. Moving to 'Draft'"); - await prBoard.moveCard(prCard.id, prBoard.columns.Draft); + console.log("::debug::PR is a draft. Moving to 'Draft'") + await prBoard.moveCard(prCard.id, prBoard.columns.Draft) } else { - await syncReviews(pr, prBoard, prCard); + await syncReviews(pr, prBoard, prCard) } - await syncIssues(pr, backlogBoard, 'InProgress'); - break; + await syncIssues(pr, backlogBoard, 'InProgress') + break } case 'edited': { - console.log("::debug::PR edited"); - await syncIssues(pr, backlogBoard, 'InProgress'); - break; + console.log('::debug::PR edited') + await syncIssues(pr, backlogBoard, 'InProgress') + break } case 'converted_to_draft': { - console.log("::debug::PR converted to draft"); - await prBoard.moveCard(prCard.id, prBoard.columns.Draft); - break; + console.log('::debug::PR converted to draft') + await prBoard.moveCard(prCard.id, prBoard.columns.Draft) + break } case 'ready_for_review': { - console.log("::debug::PR ready for review"); - await syncReviews(pr, prBoard, prCard); - break; + console.log('::debug::PR ready for review') + await syncReviews(pr, prBoard, prCard) + break } case 'closed': { - console.log("::debug::PR closed"); + console.log('::debug::PR closed') if (!pr.isMerged) { - console.log("::debug::PR not merged. Moving linked issues to 'Backlog'"); - await syncIssues(pr, backlogBoard, 'Backlog'); + console.log( + "::debug::PR not merged. Moving linked issues to 'Backlog'" + ) + await syncIssues(pr, backlogBoard, 'Backlog') } - break; + break } } } diff --git a/automations/js/src/utils/projects.mjs b/automations/js/src/utils/projects.mjs index 3a307d78ac2..051d1b1349a 100644 --- a/automations/js/src/utils/projects.mjs +++ b/automations/js/src/utils/projects.mjs @@ -9,6 +9,8 @@ * @typedef {{projectId: string, fields: {[p: string]: Field}}} ProjectDetails */ +import { debug } from '@actions/core' + const PROJECT_NUMBERS = { Backlog: 75, PRs: 98, @@ -164,6 +166,7 @@ class Project { * @returns {Promise} the ID of the card that was updated */ async setCustomChoiceField(cardId, fieldName, optionName) { + debug('Setting priority:', priority, 'for card:', card.id) // Preliminary validation if (!this.fields[fieldName]) { throw new Error(`Unknown field name "${fieldName}".`) @@ -194,6 +197,7 @@ class Project { optionId: this.fields[fieldName].options[optionName], } ) + debug('Priority set for card:', card.id) return res.updateProjectV2ItemFieldValue.projectV2Item.id } From 77b75a63c2cba8b2b47f53ba93d156c74cf76c1e Mon Sep 17 00:00:00 2001 From: edoardo Date: Tue, 28 Nov 2023 20:53:49 +0100 Subject: [PATCH 03/11] Refactor logging to use `@actions/core` and remove redundant logs --- .../js/src/project_automation/issues.mjs | 151 +++++++++-------- automations/js/src/project_automation/prs.mjs | 159 ++++++++---------- automations/js/src/utils/projects.mjs | 6 +- 3 files changed, 156 insertions(+), 160 deletions(-) diff --git a/automations/js/src/project_automation/issues.mjs b/automations/js/src/project_automation/issues.mjs index 844aca41841..0917ed8e617 100644 --- a/automations/js/src/project_automation/issues.mjs +++ b/automations/js/src/project_automation/issues.mjs @@ -1,7 +1,5 @@ import { getBoard } from '../utils/projects.mjs' -import { debug } from '@actions/core' - /** * Set the "Priority" custom field based on the issue's labels. Also move * the card for critical issues directly to the "📅 To Do" column. @@ -9,9 +7,10 @@ import { debug } from '@actions/core' * @param issue {import('@octokit/rest')} * @param board {import('../utils/projects.mjs').Project} * @param card {import('../utils/projects.mjs').Card} + * @param core {import('@actions/core')} for logging */ -async function syncPriority(issue, board, card) { - debug('Starting syncPriority for issue:', issue.number) +async function syncPriority(issue, board, card, core) { + core.debug(`Starting syncPriority for issue: ${issue.number}`) const priority = issue.labels.find((label) => label.name.includes('priority') )?.name @@ -20,9 +19,7 @@ async function syncPriority(issue, board, card) { await board.setCustomChoiceField(card.id, 'Priority', priority) } if (priority === '🟥 priority: critical') { - console.log("::debug::Moving card to 'To Do' for critical priority issue") - await board.moveCard(card.id, board.columns.ToDo) - console.log("::debug::Card moved to 'To Do' column") + await board.moveCard(card.id, board.columns.ToDo, core) } } @@ -31,82 +28,92 @@ async function syncPriority(issue, board, card) { * * @param octokit {import('@octokit/rest').Octokit} the Octokit instance to use * @param context {import('@actions/github').context} info about the current event + * @param core {import('@actions/core')} Core functions for setting results, logging, registering secrets and exporting variables across actions */ -export const main = async (octokit, context) => { +export const main = async (octokit, context, core) => { const { EVENT_ACTION: eventAction } = process.env - console.log('::debug::Event action received:', eventAction) + + core.debug(`Event action received: ${eventAction}`) const issue = context.payload.issue const label = context.payload.label - console.log('::debug::Issue details:', issue) + core.info('Issue details:', issue) if (issue.labels.some((label) => label.name === '🧭 project: thread')) { - console.log('::debug::Issue is a project thread. Exiting.') + core.warning('Issue is a project thread. Exiting.') process.exit(0) } - const backlogBoard = await getBoard(octokit, 'Backlog') - console.log('::debug::Backlog board fetched') + await core.group('Processing Issue or PR', async () => { + core.debug('Getting instance for the project') + const backlogBoard = await getBoard(octokit, 'Backlog') - const card = await backlogBoard.addCard(issue.node_id) - console.log('::debug::Card created or fetched for the issue:', card.id) + core.debug('Adding the issue or PR to the project') + const card = await backlogBoard.addCard(issue.node_id) - switch (eventAction) { - case 'opened': - case 'reopened': { - console.log('::debug::Issue opened or reopened') - if (issue.labels.some((label) => label.name === '⛔ status: blocked')) { - console.log( - "::debug::Issue is blocked. Moving card to 'Blocked' column" - ) - await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) - } else { - console.log("::debug::Moving card to 'Backlog'") - await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) - } - await syncPriority(issue, backlogBoard, card) - break - } - case 'closed': { - console.log('::debug::Issue closed') - if (issue.state_reason === 'completed') { - console.log("::debug::Issue completed. Moving card to 'Done'") - await backlogBoard.moveCard(card.id, backlogBoard.columns.Done) - } else { - console.log("::debug::Issue not completed. Moving card to 'Discarded'") - await backlogBoard.moveCard(card.id, backlogBoard.columns.Discarded) - } - break - } - case 'assigned': { - console.log('::debug::Issue assigned') - if (card.status === backlogBoard.columns.Backlog) { - console.log("::debug::Moving card to 'To Do'") - await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo) - } - break - } - case 'labeled': { - console.log('::debug::Issue labeled:', label.name) - if (label.name === '⛔ status: blocked') { - console.log( - "::debug::Issue is blocked. Moving card to 'Blocked' column" - ) - await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) - } - await syncPriority(issue, backlogBoard, card) - break - } - case 'unlabeled': { - console.log('::debug::Label removed:', label.name) - if (label.name === '⛔ status: blocked') { - console.log( - "::debug::'Blocked' label removed. Moving card to 'Backlog'" - ) - await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) - } - await syncPriority(issue, backlogBoard, card) - break + switch (eventAction) { + case 'opened': + case 'reopened': + core.info('Issue opened or reopened') + if (issue.labels.some((label) => label.name === '⛔ status: blocked')) { + await backlogBoard.moveCard( + card.id, + backlogBoard.columns.Blocked, + core + ) + } else { + await backlogBoard.moveCard( + card.id, + backlogBoard.columns.Backlog, + core + ) + } + await syncPriority(issue, backlogBoard, card, core) + break + + case 'closed': + core.info('Issue closed') + if (issue.state_reason === 'completed') { + await backlogBoard.moveCard(card.id, backlogBoard.columns.Done, core) + } else { + await backlogBoard.moveCard( + card.id, + backlogBoard.columns.Discarded, + core + ) + } + break + + case 'assigned': + core.info('Issue assigned') + if (card.status === backlogBoard.columns.Backlog) { + await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo, core) + } + break + + case 'labeled': + core.info(`Issue labeled: ${label.name}`) + if (label.name === '⛔ status: blocked') { + await backlogBoard.moveCard( + card.id, + backlogBoard.columns.Blocked, + core + ) + } + await syncPriority(issue, backlogBoard, card, core) + break + + case 'unlabeled': + core.info(`Label removed: ${label.name}`) + if (label.name === '⛔ status: blocked') { + await backlogBoard.moveCard( + card.id, + backlogBoard.columns.Backlog, + core + ) + } + await syncPriority(issue, backlogBoard, card, core) + break } - } + }) } diff --git a/automations/js/src/project_automation/prs.mjs b/automations/js/src/project_automation/prs.mjs index f3df72906c1..d125282c618 100644 --- a/automations/js/src/project_automation/prs.mjs +++ b/automations/js/src/project_automation/prs.mjs @@ -3,49 +3,43 @@ import { readFileSync } from 'fs' import { getBoard } from '../utils/projects.mjs' import { PullRequest } from '../utils/pr.mjs' -/** - * Move the PR to the right column based on the number of reviews. - * - * @param pr {PullRequest} - * @param prBoard {Project} - * @param prCard {Card} - */ -async function syncReviews(pr, prBoard, prCard) { - console.log('::debug::Synchronizing reviews for PR:', pr.nodeId) +async function syncReviews(pr, prBoard, prCard, core) { + core.debug(`Synchronizing reviews for PR: ${pr.nodeId}`) const reviewDecision = pr.reviewDecision - console.log('::debug::Review decision:', reviewDecision) + core.debug(`Review decision: ${reviewDecision}`) - if (reviewDecision === 'APPROVED') { - console.log("::debug::Moving PR to 'Approved'") - await prBoard.moveCard(prCard.id, prBoard.columns.Approved) - } else if (reviewDecision === 'CHANGES_REQUESTED') { - console.log( - "::debug::Changes requested for PR. Moving to 'ChangesRequested'" - ) - await prBoard.moveCard(prCard.id, prBoard.columns.ChangesRequested) - } else if (pr.reviewCounts.APPROVED === 1) { - console.log("::debug::PR needs 1 more review. Moving to 'Needs1Review'") - await prBoard.moveCard(prCard.id, prBoard.columns.Needs1Review) - } else { - console.log("::debug::PR needs 2 more reviews. Moving to 'Needs2Reviews'") - await prBoard.moveCard(prCard.id, prBoard.columns.Needs2Reviews) - } + await core.group( + `Handling review decision for PR: ${pr.nodeId}`, + async () => { + if (reviewDecision === 'APPROVED') { + await prBoard.moveCard(prCard.id, prBoard.columns.Approved, core) + } else if (reviewDecision === 'CHANGES_REQUESTED') { + await prBoard.moveCard( + prCard.id, + prBoard.columns.ChangesRequested, + core + ) + } else if (pr.reviewCounts.APPROVED === 1) { + await prBoard.moveCard(prCard.id, prBoard.columns.Needs1Review, core) + } else { + await prBoard.moveCard(prCard.id, prBoard.columns.Needs2Reviews, core) + } + } + ) } -/** - * Move all linked issues to the specified column. - * - * @param pr {PullRequest} - * @param backlogBoard {Project} - * @param destColumn {string} - */ -async function syncIssues(pr, backlogBoard, destColumn) { - console.log('::debug::Synchronizing linked issues for PR:', pr.nodeId) +async function syncIssues(pr, backlogBoard, destColumn, core) { + core.debug(`Synchronizing linked issues for PR: ${pr.nodeId}`) for (let linkedIssue of pr.linkedIssues) { - console.log('::debug::Processing linked issue:', linkedIssue) - const issueCard = await backlogBoard.addCard(linkedIssue) - console.log('::debug::Moving linked issue to column:', destColumn) - await backlogBoard.moveCard(issueCard.id, backlogBoard.columns[destColumn]) + await core.group(`Processing linked issue: ${linkedIssue}`, async () => { + core.debug('Adding linked issue to board') + const issueCard = await backlogBoard.addCard(linkedIssue) + await backlogBoard.moveCard( + issueCard.id, + backlogBoard.columns[destColumn], + core + ) + }) } } @@ -53,20 +47,17 @@ async function syncIssues(pr, backlogBoard, destColumn) { * This is the entrypoint of the script. * * @param octokit {import('@octokit/rest').Octokit} the Octokit instance to use + * @param context {import('@actions/github').context} info about the current event + * @param core {import('@actions/core')} Core functions for setting results, logging, registering secrets and exporting variables across actions */ -export const main = async (octokit) => { - console.log('::debug::Starting PR script') +export const main = async (octokit, context, core) => { + core.debug('Starting PR script') const { eventName, eventAction, prNodeId } = JSON.parse( readFileSync('/tmp/event.json', 'utf-8') ) - console.log( - '::debug::Event details - Name:', - eventName, - ', Action:', - eventAction, - ', PR Node ID:', - prNodeId + core.debug( + `Event details - Name: ${eventName}, Action: ${eventAction}, PR Node ID: ${prNodeId}` ) const pr = new PullRequest(octokit, prNodeId) @@ -76,49 +67,45 @@ export const main = async (octokit) => { const backlogBoard = await getBoard(octokit, 'Backlog') const prCard = await prBoard.addCard(pr.nodeId) - console.log('::debug::PR card created or fetched:', prCard.id) + core.debug(`PR card created or fetched: ${prCard.id}`) - if (eventName === 'pull_request_review') { - await syncReviews(pr, prBoard, prCard) - } else { - switch (eventAction) { - case 'opened': - case 'reopened': { - console.log('::debug::PR opened or reopened') - if (pr.isDraft) { - console.log("::debug::PR is a draft. Moving to 'Draft'") - await prBoard.moveCard(prCard.id, prBoard.columns.Draft) - } else { + await core.group('Processing PR based on event action', async () => { + if (eventName === 'pull_request_review') { + await syncReviews(pr, prBoard, prCard) + } else { + switch (eventAction) { + case 'opened': + case 'reopened': { + core.debug('PR opened or reopened') + if (pr.isDraft) { + await prBoard.moveCard(prCard.id, prBoard.columns.Draft, core) + } else { + await syncReviews(pr, prBoard, prCard) + } + await syncIssues(pr, backlogBoard, 'InProgress') + break + } + case 'edited': { + await syncIssues(pr, backlogBoard, 'InProgress') + break + } + case 'converted_to_draft': { + await prBoard.moveCard(prCard.id, prBoard.columns.Draft, core) + break + } + case 'ready_for_review': { + core.debug('PR ready for review') await syncReviews(pr, prBoard, prCard) + break } - await syncIssues(pr, backlogBoard, 'InProgress') - break - } - case 'edited': { - console.log('::debug::PR edited') - await syncIssues(pr, backlogBoard, 'InProgress') - break - } - case 'converted_to_draft': { - console.log('::debug::PR converted to draft') - await prBoard.moveCard(prCard.id, prBoard.columns.Draft) - break - } - case 'ready_for_review': { - console.log('::debug::PR ready for review') - await syncReviews(pr, prBoard, prCard) - break - } - case 'closed': { - console.log('::debug::PR closed') - if (!pr.isMerged) { - console.log( - "::debug::PR not merged. Moving linked issues to 'Backlog'" - ) - await syncIssues(pr, backlogBoard, 'Backlog') + case 'closed': { + core.debug('PR closed') + if (!pr.isMerged) { + await syncIssues(pr, backlogBoard, 'Backlog') + } + break } - break } } - } + }) } diff --git a/automations/js/src/utils/projects.mjs b/automations/js/src/utils/projects.mjs index 051d1b1349a..ff88d558313 100644 --- a/automations/js/src/utils/projects.mjs +++ b/automations/js/src/utils/projects.mjs @@ -208,8 +208,10 @@ class Project { * @param cardId {string} the ID of the card to move * @param destColumn {string} the name of the column where to move it * @returns {Promise} the ID of the card that was moved + * @param core {import('@actions/core')} for logging */ - async moveCard(cardId, destColumn) { + async moveCard(cardId, destColumn, core = null) { + if (core) core.debug(`Moving card to '${destColumn}'`) return await this.setCustomChoiceField(cardId, 'Status', destColumn) } } @@ -219,7 +221,7 @@ class Project { * * @param octokit {import('@octokit/rest').Octokit} the Octokit instance to use * @param name {string} the name of the project (without the 'Openverse' prefix) - * @returns {Project} the `Project` instance to interact with the project board + * @returns {Promise} the `Project` instance to interact with the project board */ export async function getBoard(octokit, name) { const projectNumber = PROJECT_NUMBERS[name] From ce70e6f57dd311c65cf6cee775c75af6a6df5386 Mon Sep 17 00:00:00 2001 From: edoardo Date: Tue, 28 Nov 2023 20:58:01 +0100 Subject: [PATCH 04/11] Remove `debug` import from issues.mjs --- automations/js/src/project_automation/issues.mjs | 2 +- automations/js/src/utils/projects.mjs | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/automations/js/src/project_automation/issues.mjs b/automations/js/src/project_automation/issues.mjs index 0917ed8e617..e0caa143687 100644 --- a/automations/js/src/project_automation/issues.mjs +++ b/automations/js/src/project_automation/issues.mjs @@ -16,7 +16,7 @@ async function syncPriority(issue, board, card, core) { )?.name if (priority) { - await board.setCustomChoiceField(card.id, 'Priority', priority) + await board.setCustomChoiceField(card.id, 'Priority', priority, core) } if (priority === '🟥 priority: critical') { await board.moveCard(card.id, board.columns.ToDo, core) diff --git a/automations/js/src/utils/projects.mjs b/automations/js/src/utils/projects.mjs index ff88d558313..12e956acc19 100644 --- a/automations/js/src/utils/projects.mjs +++ b/automations/js/src/utils/projects.mjs @@ -9,8 +9,6 @@ * @typedef {{projectId: string, fields: {[p: string]: Field}}} ProjectDetails */ -import { debug } from '@actions/core' - const PROJECT_NUMBERS = { Backlog: 75, PRs: 98, @@ -165,8 +163,8 @@ class Project { * @param optionName {string} the updated value of the field * @returns {Promise} the ID of the card that was updated */ - async setCustomChoiceField(cardId, fieldName, optionName) { - debug('Setting priority:', priority, 'for card:', card.id) + async setCustomChoiceField(cardId, fieldName, optionName, core) { + core.debug('Setting priority:', priority, 'for card:', card.id) // Preliminary validation if (!this.fields[fieldName]) { throw new Error(`Unknown field name "${fieldName}".`) @@ -197,7 +195,7 @@ class Project { optionId: this.fields[fieldName].options[optionName], } ) - debug('Priority set for card:', card.id) + core.debug(`Priority set for card: ${card.id}`) return res.updateProjectV2ItemFieldValue.projectV2Item.id } @@ -210,9 +208,9 @@ class Project { * @returns {Promise} the ID of the card that was moved * @param core {import('@actions/core')} for logging */ - async moveCard(cardId, destColumn, core = null) { - if (core) core.debug(`Moving card to '${destColumn}'`) - return await this.setCustomChoiceField(cardId, 'Status', destColumn) + async moveCard(cardId, destColumn, core) { + core.debug(`Moving card to '${destColumn}'`) + return await this.setCustomChoiceField(cardId, 'Status', destColumn, core) } } From df83e81c7f82a9511cf00430e7fa86b7126c37f7 Mon Sep 17 00:00:00 2001 From: Dhruv Bhanushali Date: Fri, 1 Dec 2023 16:14:42 +0400 Subject: [PATCH 05/11] Pass `core` to from YAML to `main` to `Project` --- .github/workflows/issue_automations.yml | 2 +- .github/workflows/pr_automations.yml | 2 +- automations/js/src/project_automation/issues.mjs | 6 +++--- automations/js/src/project_automation/prs.mjs | 9 ++++----- automations/js/src/utils/projects.mjs | 9 ++++++--- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/.github/workflows/issue_automations.yml b/.github/workflows/issue_automations.yml index 887b9dbcd77..fd6fefbfcf7 100644 --- a/.github/workflows/issue_automations.yml +++ b/.github/workflows/issue_automations.yml @@ -31,4 +31,4 @@ jobs: github-token: ${{ secrets.ACCESS_TOKEN }} script: | const { main } = await import('${{ github.workspace }}/automations/js/src/project_automation/issues.mjs') - await main(github, context) + await main(github, core, context) diff --git a/.github/workflows/pr_automations.yml b/.github/workflows/pr_automations.yml index 9bd165b4c6d..56e0d3a9e54 100644 --- a/.github/workflows/pr_automations.yml +++ b/.github/workflows/pr_automations.yml @@ -71,4 +71,4 @@ jobs: github-token: ${{ secrets.ACCESS_TOKEN }} script: | const { main } = await import('${{ github.workspace }}/automations/js/src/project_automation/prs.mjs') - await main(github) + await main(github, core) diff --git a/automations/js/src/project_automation/issues.mjs b/automations/js/src/project_automation/issues.mjs index e0caa143687..38c60f0583b 100644 --- a/automations/js/src/project_automation/issues.mjs +++ b/automations/js/src/project_automation/issues.mjs @@ -27,10 +27,10 @@ async function syncPriority(issue, board, card, core) { * This is the entrypoint of the script. * * @param octokit {import('@octokit/rest').Octokit} the Octokit instance to use + * @param core {import('@actions/core')} GitHub Actions toolkit, for logging * @param context {import('@actions/github').context} info about the current event - * @param core {import('@actions/core')} Core functions for setting results, logging, registering secrets and exporting variables across actions */ -export const main = async (octokit, context, core) => { +export const main = async (octokit, core, context) => { const { EVENT_ACTION: eventAction } = process.env core.debug(`Event action received: ${eventAction}`) @@ -46,7 +46,7 @@ export const main = async (octokit, context, core) => { await core.group('Processing Issue or PR', async () => { core.debug('Getting instance for the project') - const backlogBoard = await getBoard(octokit, 'Backlog') + const backlogBoard = await getBoard(octokit, core, 'Backlog') core.debug('Adding the issue or PR to the project') const card = await backlogBoard.addCard(issue.node_id) diff --git a/automations/js/src/project_automation/prs.mjs b/automations/js/src/project_automation/prs.mjs index d125282c618..0cd1a81f9d6 100644 --- a/automations/js/src/project_automation/prs.mjs +++ b/automations/js/src/project_automation/prs.mjs @@ -47,10 +47,9 @@ async function syncIssues(pr, backlogBoard, destColumn, core) { * This is the entrypoint of the script. * * @param octokit {import('@octokit/rest').Octokit} the Octokit instance to use - * @param context {import('@actions/github').context} info about the current event - * @param core {import('@actions/core')} Core functions for setting results, logging, registering secrets and exporting variables across actions + * @param core {import('@actions/core')} GitHub Actions toolkit, for logging */ -export const main = async (octokit, context, core) => { +export const main = async (octokit, core) => { core.debug('Starting PR script') const { eventName, eventAction, prNodeId } = JSON.parse( @@ -63,8 +62,8 @@ export const main = async (octokit, context, core) => { const pr = new PullRequest(octokit, prNodeId) await pr.init() - const prBoard = await getBoard(octokit, 'PRs') - const backlogBoard = await getBoard(octokit, 'Backlog') + const prBoard = await getBoard(octokit, core, 'PRs') + const backlogBoard = await getBoard(octokit, core, 'Backlog') const prCard = await prBoard.addCard(pr.nodeId) core.debug(`PR card created or fetched: ${prCard.id}`) diff --git a/automations/js/src/utils/projects.mjs b/automations/js/src/utils/projects.mjs index 12e956acc19..1092e27bb5e 100644 --- a/automations/js/src/utils/projects.mjs +++ b/automations/js/src/utils/projects.mjs @@ -27,11 +27,13 @@ class Project { * owner number * * @param octokit {import('@octokit/rest').Octokit} the Octokit instance to use + * @param core {import('@actions/core')} GitHub Actions toolkit, for logging * @param owner {string} the login of the owner (org) of the project * @param number {number} the number of the project */ - constructor(octokit, owner, number) { + constructor(octokit, core, owner, number) { this.octokit = octokit + this.core = core this.owner = owner this.number = number @@ -218,16 +220,17 @@ class Project { * Get the `Project` instance for the project board with the given name. * * @param octokit {import('@octokit/rest').Octokit} the Octokit instance to use + * @param core {import('@actions/core')} GitHub Actions toolkit, for logging * @param name {string} the name of the project (without the 'Openverse' prefix) * @returns {Promise} the `Project` instance to interact with the project board */ -export async function getBoard(octokit, name) { +export async function getBoard(octokit, core, name) { const projectNumber = PROJECT_NUMBERS[name] if (!projectNumber) { throw new Error(`Unknown project board "${name}".`) } - const project = new Project(octokit, 'WordPress', projectNumber) + const project = new Project(octokit, core, 'WordPress', projectNumber) await project.init() return project } From 8742c21123420321515422fd6a6fae2fd4d5dc12 Mon Sep 17 00:00:00 2001 From: Dhruv Bhanushali Date: Fri, 1 Dec 2023 16:17:30 +0400 Subject: [PATCH 06/11] Use `this.core` to log info, error and debug lines --- automations/js/src/utils/projects.mjs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/automations/js/src/utils/projects.mjs b/automations/js/src/utils/projects.mjs index 1092e27bb5e..72896d6e506 100644 --- a/automations/js/src/utils/projects.mjs +++ b/automations/js/src/utils/projects.mjs @@ -165,20 +165,24 @@ class Project { * @param optionName {string} the updated value of the field * @returns {Promise} the ID of the card that was updated */ - async setCustomChoiceField(cardId, fieldName, optionName, core) { - core.debug('Setting priority:', priority, 'for card:', card.id) + async setCustomChoiceField(cardId, fieldName, optionName) { + this.core.info( + `Setting field "${fieldName}" to value "${optionName}" for card "${cardId}".` + ) // Preliminary validation if (!this.fields[fieldName]) { - throw new Error(`Unknown field name "${fieldName}".`) + const msg = `Unknown field name "${fieldName}".` + this.core.error(msg) + throw new Error(msg) } if (!this.fields[fieldName].options[optionName]) { - throw new Error( - `Unknown option name "${optionName}" for field "${fieldName}".` - ) + const msg = `Unknown option name "${optionName}" for field "${fieldName}".` + this.core.error(msg) + throw new Error(msg) } const res = await this.octokit.graphql( - `mutation setCustomField($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) { + `mutation setCustomChoiceField($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) { updateProjectV2ItemFieldValue(input: { projectId: $projectId, itemId: $itemId, @@ -197,7 +201,7 @@ class Project { optionId: this.fields[fieldName].options[optionName], } ) - core.debug(`Priority set for card: ${card.id}`) + this.core.debug('setCustomChoiceField response:', JSON.stringify(res)) return res.updateProjectV2ItemFieldValue.projectV2Item.id } @@ -208,11 +212,10 @@ class Project { * @param cardId {string} the ID of the card to move * @param destColumn {string} the name of the column where to move it * @returns {Promise} the ID of the card that was moved - * @param core {import('@actions/core')} for logging */ - async moveCard(cardId, destColumn, core) { - core.debug(`Moving card to '${destColumn}'`) - return await this.setCustomChoiceField(cardId, 'Status', destColumn, core) + async moveCard(cardId, destColumn) { + this.core.info(`Moving card "${cardId}" to column "${destColumn}".`) + return await this.setCustomChoiceField(cardId, 'Status', destColumn) } } From e2394a9f81595fdf9871811e3b6cb343364b0b73 Mon Sep 17 00:00:00 2001 From: edoardo Date: Sat, 2 Dec 2023 01:13:53 +0100 Subject: [PATCH 07/11] Refactored Project class, updated moveCard and YAML files - Implemented core in Project class. - Removed core from moveCard functions. - Added core integration in YAML configurations. --- .github/workflows/issue_automations.yml | 2 +- .github/workflows/pr_automations.yml | 2 +- .../js/src/project_automation/issues.mjs | 40 +++++-------------- automations/js/src/utils/projects.mjs | 22 +++++----- 4 files changed, 23 insertions(+), 43 deletions(-) diff --git a/.github/workflows/issue_automations.yml b/.github/workflows/issue_automations.yml index 887b9dbcd77..fd6fefbfcf7 100644 --- a/.github/workflows/issue_automations.yml +++ b/.github/workflows/issue_automations.yml @@ -31,4 +31,4 @@ jobs: github-token: ${{ secrets.ACCESS_TOKEN }} script: | const { main } = await import('${{ github.workspace }}/automations/js/src/project_automation/issues.mjs') - await main(github, context) + await main(github, core, context) diff --git a/.github/workflows/pr_automations.yml b/.github/workflows/pr_automations.yml index 9bd165b4c6d..56e0d3a9e54 100644 --- a/.github/workflows/pr_automations.yml +++ b/.github/workflows/pr_automations.yml @@ -71,4 +71,4 @@ jobs: github-token: ${{ secrets.ACCESS_TOKEN }} script: | const { main } = await import('${{ github.workspace }}/automations/js/src/project_automation/prs.mjs') - await main(github) + await main(github, core) diff --git a/automations/js/src/project_automation/issues.mjs b/automations/js/src/project_automation/issues.mjs index e0caa143687..4f77a6ec785 100644 --- a/automations/js/src/project_automation/issues.mjs +++ b/automations/js/src/project_automation/issues.mjs @@ -10,7 +10,7 @@ import { getBoard } from '../utils/projects.mjs' * @param core {import('@actions/core')} for logging */ async function syncPriority(issue, board, card, core) { - core.debug(`Starting syncPriority for issue: ${issue.number}`) + core.debug(`Syncing priority for issue "${issue.number}".`) const priority = issue.labels.find((label) => label.name.includes('priority') )?.name @@ -19,7 +19,7 @@ async function syncPriority(issue, board, card, core) { await board.setCustomChoiceField(card.id, 'Priority', priority, core) } if (priority === '🟥 priority: critical') { - await board.moveCard(card.id, board.columns.ToDo, core) + await board.moveCard(card.id, board.columns.ToDo) } } @@ -46,7 +46,7 @@ export const main = async (octokit, context, core) => { await core.group('Processing Issue or PR', async () => { core.debug('Getting instance for the project') - const backlogBoard = await getBoard(octokit, 'Backlog') + const backlogBoard = await getBoard(octokit, 'Backlog', core) core.debug('Adding the issue or PR to the project') const card = await backlogBoard.addCard(issue.node_id) @@ -56,17 +56,9 @@ export const main = async (octokit, context, core) => { case 'reopened': core.info('Issue opened or reopened') if (issue.labels.some((label) => label.name === '⛔ status: blocked')) { - await backlogBoard.moveCard( - card.id, - backlogBoard.columns.Blocked, - core - ) + await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) } else { - await backlogBoard.moveCard( - card.id, - backlogBoard.columns.Backlog, - core - ) + await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) } await syncPriority(issue, backlogBoard, card, core) break @@ -74,31 +66,23 @@ export const main = async (octokit, context, core) => { case 'closed': core.info('Issue closed') if (issue.state_reason === 'completed') { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Done, core) + await backlogBoard.moveCard(card.id, backlogBoard.columns.Done) } else { - await backlogBoard.moveCard( - card.id, - backlogBoard.columns.Discarded, - core - ) + await backlogBoard.moveCard(card.id, backlogBoard.columns.Discarded) } break case 'assigned': core.info('Issue assigned') if (card.status === backlogBoard.columns.Backlog) { - await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo, core) + await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo) } break case 'labeled': core.info(`Issue labeled: ${label.name}`) if (label.name === '⛔ status: blocked') { - await backlogBoard.moveCard( - card.id, - backlogBoard.columns.Blocked, - core - ) + await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) } await syncPriority(issue, backlogBoard, card, core) break @@ -106,11 +90,7 @@ export const main = async (octokit, context, core) => { case 'unlabeled': core.info(`Label removed: ${label.name}`) if (label.name === '⛔ status: blocked') { - await backlogBoard.moveCard( - card.id, - backlogBoard.columns.Backlog, - core - ) + await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) } await syncPriority(issue, backlogBoard, card, core) break diff --git a/automations/js/src/utils/projects.mjs b/automations/js/src/utils/projects.mjs index 12e956acc19..223a9ccc14f 100644 --- a/automations/js/src/utils/projects.mjs +++ b/automations/js/src/utils/projects.mjs @@ -27,12 +27,13 @@ class Project { * owner number * * @param octokit {import('@octokit/rest').Octokit} the Octokit instance to use + * @param core {import('@actions/core')} for logging * @param owner {string} the login of the owner (org) of the project * @param number {number} the number of the project */ - constructor(octokit, owner, number) { + constructor(octokit, core, owner, number) { this.octokit = octokit - + this.core = core this.owner = owner this.number = number } @@ -163,8 +164,8 @@ class Project { * @param optionName {string} the updated value of the field * @returns {Promise} the ID of the card that was updated */ - async setCustomChoiceField(cardId, fieldName, optionName, core) { - core.debug('Setting priority:', priority, 'for card:', card.id) + async setCustomChoiceField(cardId, fieldName, optionName) { + this.core.debug('Setting priority:', priority, 'for card:', card.id) // Preliminary validation if (!this.fields[fieldName]) { throw new Error(`Unknown field name "${fieldName}".`) @@ -195,7 +196,7 @@ class Project { optionId: this.fields[fieldName].options[optionName], } ) - core.debug(`Priority set for card: ${card.id}`) + this.core.debug(`Priority set for card: ${card.id}`) return res.updateProjectV2ItemFieldValue.projectV2Item.id } @@ -206,11 +207,10 @@ class Project { * @param cardId {string} the ID of the card to move * @param destColumn {string} the name of the column where to move it * @returns {Promise} the ID of the card that was moved - * @param core {import('@actions/core')} for logging */ - async moveCard(cardId, destColumn, core) { - core.debug(`Moving card to '${destColumn}'`) - return await this.setCustomChoiceField(cardId, 'Status', destColumn, core) + async moveCard(cardId, destColumn) { + this.core.debug(`Moving card to '${destColumn}'`) + return await this.setCustomChoiceField(cardId, 'Status', destColumn) } } @@ -221,13 +221,13 @@ class Project { * @param name {string} the name of the project (without the 'Openverse' prefix) * @returns {Promise} the `Project` instance to interact with the project board */ -export async function getBoard(octokit, name) { +export async function getBoard(octokit, name, core) { const projectNumber = PROJECT_NUMBERS[name] if (!projectNumber) { throw new Error(`Unknown project board "${name}".`) } - const project = new Project(octokit, 'WordPress', projectNumber) + const project = new Project(octokit, core, 'WordPress', projectNumber) await project.init() return project } From ed588944a1d4334e33af533b3d1e86f44f9ca598 Mon Sep 17 00:00:00 2001 From: edoardo Date: Sat, 2 Dec 2023 01:37:43 +0100 Subject: [PATCH 08/11] Applied suggested changes in issue.mjs and projects.mjs. --- .../js/src/project_automation/issues.mjs | 20 +++++++++---------- automations/js/src/utils/projects.mjs | 9 ++++++--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/automations/js/src/project_automation/issues.mjs b/automations/js/src/project_automation/issues.mjs index 4f77a6ec785..0a263614862 100644 --- a/automations/js/src/project_automation/issues.mjs +++ b/automations/js/src/project_automation/issues.mjs @@ -53,8 +53,7 @@ export const main = async (octokit, context, core) => { switch (eventAction) { case 'opened': - case 'reopened': - core.info('Issue opened or reopened') + case 'reopened': { if (issue.labels.some((label) => label.name === '⛔ status: blocked')) { await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) } else { @@ -62,38 +61,39 @@ export const main = async (octokit, context, core) => { } await syncPriority(issue, backlogBoard, card, core) break + } - case 'closed': - core.info('Issue closed') + case 'closed': { if (issue.state_reason === 'completed') { await backlogBoard.moveCard(card.id, backlogBoard.columns.Done) } else { await backlogBoard.moveCard(card.id, backlogBoard.columns.Discarded) } break + } - case 'assigned': - core.info('Issue assigned') + case 'assigned': { if (card.status === backlogBoard.columns.Backlog) { await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo) } break + } - case 'labeled': - core.info(`Issue labeled: ${label.name}`) + case 'labeled': { if (label.name === '⛔ status: blocked') { await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) } await syncPriority(issue, backlogBoard, card, core) break + } - case 'unlabeled': - core.info(`Label removed: ${label.name}`) + case 'unlabeled': { if (label.name === '⛔ status: blocked') { await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) } await syncPriority(issue, backlogBoard, card, core) break + } } }) } diff --git a/automations/js/src/utils/projects.mjs b/automations/js/src/utils/projects.mjs index 223a9ccc14f..36f7a2e9eb1 100644 --- a/automations/js/src/utils/projects.mjs +++ b/automations/js/src/utils/projects.mjs @@ -165,13 +165,15 @@ class Project { * @returns {Promise} the ID of the card that was updated */ async setCustomChoiceField(cardId, fieldName, optionName) { - this.core.debug('Setting priority:', priority, 'for card:', card.id) + this.core.info( + `Setting field "${fieldName}" to value "${optionName}" for card "${cardId}".` + ) // Preliminary validation if (!this.fields[fieldName]) { - throw new Error(`Unknown field name "${fieldName}".`) + this.core.error(`Unknown field name "${fieldName}".`) } if (!this.fields[fieldName].options[optionName]) { - throw new Error( + this.core.error( `Unknown option name "${optionName}" for field "${fieldName}".` ) } @@ -196,6 +198,7 @@ class Project { optionId: this.fields[fieldName].options[optionName], } ) + this.core.debug('setCustomChoiceField response:', JSON.stringify(res)) this.core.debug(`Priority set for card: ${card.id}`) return res.updateProjectV2ItemFieldValue.projectV2Item.id } From b99d5ed6a57dbfd4c96082c5995d7180de19e7a7 Mon Sep 17 00:00:00 2001 From: Dhruv Bhanushali Date: Thu, 14 Dec 2023 12:21:05 +0400 Subject: [PATCH 09/11] Add more logging --- automations/js/src/project_automation/prs.mjs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/automations/js/src/project_automation/prs.mjs b/automations/js/src/project_automation/prs.mjs index 38586fef895..f1b88984a8a 100644 --- a/automations/js/src/project_automation/prs.mjs +++ b/automations/js/src/project_automation/prs.mjs @@ -20,10 +20,13 @@ async function syncReviews(core, pr, prBoard, prCard) { core.debug(`PR reviews decision: ${reviewDecision}`) if (reviewDecision === 'APPROVED') { + core.info('Moving PR on the basis of review decision.') await prBoard.moveCard(prCard.id, prBoard.columns.Approved) } else if (reviewDecision === 'CHANGES_REQUESTED') { + core.info('Moving PR on the basis of review decision.') await prBoard.moveCard(prCard.id, prBoard.columns.ChangesRequested) } else if (reviewCounts.APPROVED === 1) { + core.info('Moving PR on the basis of 1 approval.') await prBoard.moveCard(prCard.id, prBoard.columns.Needs1Review) } else { await prBoard.moveCard(prCard.id, prBoard.columns.Needs2Reviews) @@ -42,6 +45,9 @@ async function syncIssues(core, pr, backlogBoard, destColumn) { core.info(`Synchronizing issues for PR ${pr.nodeId}.`) for (let linkedIssue of pr.linkedIssues) { + core.info(`Syncing issue ${linkedIssue.id}.`) + + // Create new, or get the existing, card for the current issue. const issueCard = await backlogBoard.addCard(linkedIssue.id) core.debug(`Issue card ID: ${issueCard.id}`) From e7ecf6c8e2de85fdca9389fbbfbc60b42fb1330f Mon Sep 17 00:00:00 2001 From: Dhruv Bhanushali Date: Thu, 14 Dec 2023 12:22:51 +0400 Subject: [PATCH 10/11] Dedent code and increase logging --- .../js/src/project_automation/issues.mjs | 111 ++++++++++-------- 1 file changed, 60 insertions(+), 51 deletions(-) diff --git a/automations/js/src/project_automation/issues.mjs b/automations/js/src/project_automation/issues.mjs index e64284a52de..c38b8ea34e7 100644 --- a/automations/js/src/project_automation/issues.mjs +++ b/automations/js/src/project_automation/issues.mjs @@ -4,22 +4,25 @@ import { getBoard } from '../utils/projects.mjs' * Set the "Priority" custom field based on the issue's labels. Also move * the card for critical issues directly to the "📅 To Do" column. * - * @param issue {import('@octokit/rest')} - * @param board {import('../utils/projects.mjs').Project} - * @param card {import('../utils/projects.mjs').Card} - * @param core {import('@actions/core')} for logging + * @param core {import('@actions/core')} GitHub Actions toolkit, for logging + * @param issue {Issue} the issue for which to set the "Priority" custom field + * @param backlogBoard {Project} the project board for issues + * @param issueCard {Card} the card for the issue to sync */ -async function syncPriority(issue, board, card, core) { - core.debug(`Syncing priority for issue "${issue.number}".`) +async function syncPriority(core, issue, backlogBoard, issueCard) { + core.info(`Syncing priority for issue "${issue.number}".`) + const priority = issue.labels.find((label) => label.name.includes('priority') )?.name + core.debug(`Priority: ${priority}`) if (priority) { - await board.setCustomChoiceField(card.id, 'Priority', priority, core) + await backlogBoard.setCustomChoiceField(issueCard.id, 'Priority', priority) } if (priority === '🟥 priority: critical') { - await board.moveCard(card.id, board.columns.ToDo) + core.info('Moving critical issue to "📅 To Do" column.') + await backlogBoard.moveCard(issueCard.id, backlogBoard.columns.ToDo) } } @@ -31,69 +34,75 @@ async function syncPriority(issue, board, card, core) { * @param context {import('@actions/github').context} info about the current event */ export const main = async (octokit, core, context) => { - const { EVENT_ACTION: eventAction } = process.env + core.info('Starting script `issues.mjs`.') - core.debug(`Event action received: ${eventAction}`) + const { EVENT_ACTION: eventAction } = process.env + core.debug(`Event action: ${eventAction}`) const issue = context.payload.issue + core.debug(`Issue node ID: ${issue.node_id}`) + const label = context.payload.label core.info('Issue details:', issue) if (issue.labels.some((label) => label.name === '🧭 project: thread')) { core.warning('Issue is a project thread. Exiting.') - process.exit(0) + return } - await core.group('Processing Issue or PR', async () => { - core.debug('Getting instance for the project') - const backlogBoard = await getBoard(octokit, core, 'Backlog') + const backlogBoard = await getBoard(octokit, core, 'Backlog') - core.debug('Adding the issue or PR to the project') - const card = await backlogBoard.addCard(issue.node_id) + // Create new, or get the existing, card for the current issue. + const card = await backlogBoard.addCard(issue.node_id) + core.debug(`Issue card ID: ${card.id}`) - switch (eventAction) { - case 'opened': - case 'reopened': { - if (issue.labels.some((label) => label.name === '⛔ status: blocked')) { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) - } else { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) - } - await syncPriority(issue, backlogBoard, card, core) - break + switch (eventAction) { + case 'opened': + case 'reopened': { + if (issue.labels.some((label) => label.name === '⛔ status: blocked')) { + core.info('Issue was opened, labelled as blocked.') + await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) + } else { + await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) } + await syncPriority(core, issue, backlogBoard, card) + break + } - case 'closed': { - if (issue.state_reason === 'completed') { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Done) - } else { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Discarded) - } - break + case 'closed': { + if (issue.state_reason === 'completed') { + core.info('Issue was closed as completed.') + await backlogBoard.moveCard(card.id, backlogBoard.columns.Done) + } else { + core.info('Issue was closed as discarded.') + await backlogBoard.moveCard(card.id, backlogBoard.columns.Discarded) } + break + } - case 'assigned': { - if (card.status === backlogBoard.columns.Backlog) { - await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo) - } - break + case 'assigned': { + if (card.status === backlogBoard.columns.Backlog) { + await backlogBoard.moveCard(card.id, backlogBoard.columns.ToDo) } + break + } - case 'labeled': { - if (label.name === '⛔ status: blocked') { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) - } - await syncPriority(issue, backlogBoard, card, core) - break + case 'labeled': { + if (label.name === '⛔ status: blocked') { + core.info('Issue was labeled as blocked.') + await backlogBoard.moveCard(card.id, backlogBoard.columns.Blocked) } + await syncPriority(core, issue, backlogBoard, card) + break + } - case 'unlabeled': { - if (label.name === '⛔ status: blocked') { - await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) - } - await syncPriority(issue, backlogBoard, card, core) - break + case 'unlabeled': { + if (label.name === '⛔ status: blocked') { + core.info('Issue was unlabeled as blocked.') + await backlogBoard.moveCard(card.id, backlogBoard.columns.Backlog) } + await syncPriority(core, issue, backlogBoard, card) + break } - }) + } } From 9c58a2d9e8c87a46400904303fec79df4fc9a007 Mon Sep 17 00:00:00 2001 From: Dhruv Bhanushali Date: Thu, 14 Dec 2023 12:29:08 +0400 Subject: [PATCH 11/11] Add more `info` and `debug` logs --- automations/js/src/utils/pr.mjs | 3 ++- automations/js/src/utils/projects.mjs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/automations/js/src/utils/pr.mjs b/automations/js/src/utils/pr.mjs index 3c8900b8215..3fe24c7f176 100644 --- a/automations/js/src/utils/pr.mjs +++ b/automations/js/src/utils/pr.mjs @@ -89,6 +89,7 @@ export class PullRequest { id: this.nodeId, } ) + this.core.debug(`getPrDetails response: ${JSON.stringify(res, null, 2)}`) const pr = res.node return { isMerged: pr.merged, @@ -137,7 +138,7 @@ export class PullRequest { labelIds, } ) - this.core.debug('addLabels response:', JSON.stringify(res)) + this.core.debug(`addLabels response: ${JSON.stringify(res, null, 2)}`) return res.addLabelsToLabelable.labelable.labels.nodes } diff --git a/automations/js/src/utils/projects.mjs b/automations/js/src/utils/projects.mjs index 2e5dba415c2..af00e163140 100644 --- a/automations/js/src/utils/projects.mjs +++ b/automations/js/src/utils/projects.mjs @@ -97,6 +97,7 @@ class Project { number: this.number, } ) + this.core.debug(`getProjectId response: ${JSON.stringify(res, null, 2)}`) const project = res.organization.projectV2 return { projectId: project.id, @@ -127,6 +128,7 @@ class Project { * @returns {Promise} the info of the added card */ async addCard(issueId) { + this.core.info(`Adding card for issue/PR "${issueId}".`) const res = await this.octokit.graphql( `mutation addCard($projectId: ID!, $contentId: ID!) { addProjectV2ItemById(input: { @@ -148,6 +150,7 @@ class Project { contentId: issueId, } ) + this.core.debug(`addCard response: ${JSON.stringify(res, null, 2)}`) const card = res.addProjectV2ItemById.item return { id: card.id,