From 52add7be807808e63cb2e840585153413c22d201 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 11 Mar 2025 19:59:44 +0100 Subject: [PATCH 1/2] Add "issue-number" as parameter --- README.md | 46 ++++++++++++++++++++++++++++++ action.yml | 3 ++ dist/index.js | 78 +++++++++++++++++++++++++++++---------------------- index.js | 78 +++++++++++++++++++++++++++++---------------------- 4 files changed, 139 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 3b5c24b..5c09913 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ A GitHub Action to move issues between GitHub Projects V2 columns based on speci | `ignored-columns` | Comma-separated list of column names to ignore (e.g., "Ready, In Progress, In Review, Done"). | Yes | | `default-column` | The column to move the issue to when a target label is removed. If not specified, no action will be taken on unlabeling. | No | | `skip-if-not-in-project` | Skip moving the issue if it is not already in the project (default: `false`) | No | +| `issue-number` | Issue number to handle (default: derived from issue itself) | No | ## Example Workflow @@ -47,3 +48,48 @@ Get the latest `{release}` tag from https://github.com/m7kvqbe1/github-action-mo - If a default column is specified, the issue will be moved to that column. - If no default column is specified, no action will be taken. - The action will not move issues that are already in one of the ignored columns. + +## Advanced Behavior + +When a pull request is closed, one might want to move the issue, too. +Then, the issue number has to be determined based on the pull request. +For instance, this can be done with the [ticket-check-action](https://github.com/neofinancial/ticket-check-action/pull/58). +Then, one can move the issue to another state as intended. + +Example: Move the issue to "In Progress" as soon as a PR is opened or reopened: + +```yaml +name: Mark issue as in progress + +on: + pull_request_target: + +jobs: + move_issue: + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Determine issue number + id: get_issue_number + uses: koppor/ticket-check-action@add-output + with: + token: ${{ secrets.GITHUB_TOKEN }} + ticketLink: 'https://github.com/:owner/:repo/issues/%ticketNumber%' + ticketPrefix: '#' + titleRegex: '^#(?\d+)' + branchRegex: '^(?\d+)' + bodyRegex: '#(?\d+)' + bodyURLRegex: 'http(s?):\/\/(github.com)(\/:owner)(\/:repo)(\/issues)\/(?\d+)' + outputOnly: true + - name: Move issue "In progress" + uses: m7kvqbe1/github-action-move-issues/@main + with: + github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} + project-url: "https://github.com/users/koppor/projects/7" + target-labels: "📍 Assigned" + target-column: "In progress" + ignored-columns: "" + default-column: "In progress" + issue-number: ${{ steps.get_issue_number.outputs.ticketNumber }} +``` diff --git a/action.yml b/action.yml index 20c80a7..be4a809 100644 --- a/action.yml +++ b/action.yml @@ -21,6 +21,9 @@ inputs: default-column: description: 'The column to move the issue to when a target label is removed. If not specified, no action will be taken on unlabeling.' required: false + issue-number: + description: 'The issue number to use. Useful for triggering on PRs' + required: false skip-if-not-in-project: description: 'If set to "true", skip moving the issue if it is not already in the project.' required: false diff --git a/dist/index.js b/dist/index.js index b12dc22..1b63aea 100644 --- a/dist/index.js +++ b/dist/index.js @@ -34913,67 +34913,77 @@ const run = async () => { const targetColumn = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput("target-column"); const ignoredColumns = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput("ignored-columns"); const defaultColumn = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput("default-column", { required: false }); + const issueNumberParam = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput("issue-number", { required: false }); const TARGET_COLUMN = targetColumn.trim(); const TARGET_LABELS = parseCommaSeparatedInput(targetLabels); const IGNORED_COLUMNS = parseCommaSeparatedInput(ignoredColumns); const DEFAULT_COLUMN = defaultColumn ? defaultColumn.trim() : null; + const ISSUE_NUMBER_PARAM = issueNumberParam ? issueNumberParam.trim() : null; const SKIP_IF_NOT_IN_PROJECT = _actions_core__WEBPACK_IMPORTED_MODULE_0__.getInput("skip-if-not-in-project") === "true"; const octokit = _actions_github__WEBPACK_IMPORTED_MODULE_1__.getOctokit(token); - let issue = _actions_github__WEBPACK_IMPORTED_MODULE_1__.context.payload.issue; - if (!issue || !issue.node_id) { - throw new Error("Invalid or missing issue object"); - } + _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Determing issue number..."); + const issueNumber = ISSUE_NUMBER_PARAM ? ISSUE_NUMBER_PARAM : _actions_github__WEBPACK_IMPORTED_MODULE_1__.context.issue.number; + _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Issue number: " + issueNumber); - const issueNumber = _actions_github__WEBPACK_IMPORTED_MODULE_1__.context.issue.number; - const { owner, repo } = _actions_github__WEBPACK_IMPORTED_MODULE_1__.context.repo; // The issue might have been updated by a previous GitHub action; therefore, we refetch the issue data + const { owner, repo } = _actions_github__WEBPACK_IMPORTED_MODULE_1__.context.repo; + _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("owner: " + owner + " repo: " + repo); const { data: updatedIssue } = await octokit.rest.issues.get({ owner, repo, issue_number: issueNumber, }); - issue = updatedIssue; + _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Udpated issue " + updatedIssue); + const issue = updatedIssue; + _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Issue " + issue); + + if (!issue || !issue.node_id) { + throw new Error("Invalid or missing issue object"); + } const eventName = _actions_github__WEBPACK_IMPORTED_MODULE_1__.context.eventName; const action = _actions_github__WEBPACK_IMPORTED_MODULE_1__.context.payload.action; const projectData = await getProjectData(octokit, projectUrl); - if (eventName === "issue_comment") { - if (action === "created") { - // a comment was created on an issue - const hasTargetLabel = issue.labels.some((label) => - TARGET_LABELS.includes(label.name) + _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Event: " + eventName); + + if ((eventName === "issue_comment") || (eventName === "pull_request") || (eventName === "pull_request_target")) { + _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Hit issue or PR"); + + const hasTargetLabel = issue.labels.some((label) => + TARGET_LABELS.includes(label.name) + ); + if (hasTargetLabel) { + // Proceed as if the label was added to the issue + await processIssueItem( + octokit, + projectData, + issue, + TARGET_COLUMN, + IGNORED_COLUMNS, + SKIP_IF_NOT_IN_PROJECT + ); + } else { + // Proceed as if the label was removed from the issue + await moveIssueToDefaultColumn( + octokit, + projectData, + issue, + DEFAULT_COLUMN, + IGNORED_COLUMNS ); - if (hasTargetLabel) { - // Proceed as if the label was added to the issue - await processIssueItem( - octokit, - projectData, - issue, - TARGET_COLUMN, - IGNORED_COLUMNS, - SKIP_IF_NOT_IN_PROJECT - ); - } else { - // Proceed as if the label was removed from the issue - await moveIssueToDefaultColumn( - octokit, - projectData, - issue, - DEFAULT_COLUMN, - IGNORED_COLUMNS - ); - } - return; } + return; } if (action === "labeled") { + _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Hit labeled"); + await handleLabeledEvent( octokit, issue, @@ -34987,6 +34997,8 @@ const run = async () => { } if (action === "unlabeled" && DEFAULT_COLUMN) { + _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Hit unlabeled"); + await handleUnlabeledEvent( octokit, issue, diff --git a/index.js b/index.js index ff5e539..64de602 100644 --- a/index.js +++ b/index.js @@ -391,67 +391,77 @@ const run = async () => { const targetColumn = core.getInput("target-column"); const ignoredColumns = core.getInput("ignored-columns"); const defaultColumn = core.getInput("default-column", { required: false }); + const issueNumberParam = core.getInput("issue-number", { required: false }); const TARGET_COLUMN = targetColumn.trim(); const TARGET_LABELS = parseCommaSeparatedInput(targetLabels); const IGNORED_COLUMNS = parseCommaSeparatedInput(ignoredColumns); const DEFAULT_COLUMN = defaultColumn ? defaultColumn.trim() : null; + const ISSUE_NUMBER_PARAM = issueNumberParam ? issueNumberParam.trim() : null; const SKIP_IF_NOT_IN_PROJECT = core.getInput("skip-if-not-in-project") === "true"; const octokit = github.getOctokit(token); - let issue = github.context.payload.issue; - if (!issue || !issue.node_id) { - throw new Error("Invalid or missing issue object"); - } + core.debug("Determing issue number..."); + const issueNumber = ISSUE_NUMBER_PARAM ? ISSUE_NUMBER_PARAM : github.context.issue.number; + core.debug("Issue number: " + issueNumber); - const issueNumber = github.context.issue.number; - const { owner, repo } = github.context.repo; // The issue might have been updated by a previous GitHub action; therefore, we refetch the issue data + const { owner, repo } = github.context.repo; + core.debug("owner: " + owner + " repo: " + repo); const { data: updatedIssue } = await octokit.rest.issues.get({ owner, repo, issue_number: issueNumber, }); - issue = updatedIssue; + core.debug("Udpated issue " + updatedIssue); + const issue = updatedIssue; + core.debug("Issue " + issue); + + if (!issue || !issue.node_id) { + throw new Error("Invalid or missing issue object"); + } const eventName = github.context.eventName; const action = github.context.payload.action; const projectData = await getProjectData(octokit, projectUrl); - if (eventName === "issue_comment") { - if (action === "created") { - // a comment was created on an issue - const hasTargetLabel = issue.labels.some((label) => - TARGET_LABELS.includes(label.name) + core.debug("Event: " + eventName); + + if ((eventName === "issue_comment") || (eventName === "pull_request") || (eventName === "pull_request_target")) { + core.debug("Hit issue or PR"); + + const hasTargetLabel = issue.labels.some((label) => + TARGET_LABELS.includes(label.name) + ); + if (hasTargetLabel) { + // Proceed as if the label was added to the issue + await processIssueItem( + octokit, + projectData, + issue, + TARGET_COLUMN, + IGNORED_COLUMNS, + SKIP_IF_NOT_IN_PROJECT + ); + } else { + // Proceed as if the label was removed from the issue + await moveIssueToDefaultColumn( + octokit, + projectData, + issue, + DEFAULT_COLUMN, + IGNORED_COLUMNS ); - if (hasTargetLabel) { - // Proceed as if the label was added to the issue - await processIssueItem( - octokit, - projectData, - issue, - TARGET_COLUMN, - IGNORED_COLUMNS, - SKIP_IF_NOT_IN_PROJECT - ); - } else { - // Proceed as if the label was removed from the issue - await moveIssueToDefaultColumn( - octokit, - projectData, - issue, - DEFAULT_COLUMN, - IGNORED_COLUMNS - ); - } - return; } + return; } if (action === "labeled") { + core.debug("Hit labeled"); + await handleLabeledEvent( octokit, issue, @@ -465,6 +475,8 @@ const run = async () => { } if (action === "unlabeled" && DEFAULT_COLUMN) { + core.debug("Hit unlabeled"); + await handleUnlabeledEvent( octokit, issue, From 4438dbe2fe60de3deaff1b96e0fbc9ca1df3288e Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Mon, 17 Mar 2025 15:14:46 +0100 Subject: [PATCH 2/2] If issue number is set, do if it was an issue --- dist/index.js | 2 +- index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/index.js b/dist/index.js index 1b63aea..8dc2064 100644 --- a/dist/index.js +++ b/dist/index.js @@ -34952,7 +34952,7 @@ const run = async () => { _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Event: " + eventName); - if ((eventName === "issue_comment") || (eventName === "pull_request") || (eventName === "pull_request_target")) { + if ((eventName === "issue_comment") || (eventName === "pull_request") || (eventName === "pull_request_target") || ISSUE_NUMBER_PARAM) { _actions_core__WEBPACK_IMPORTED_MODULE_0__.debug("Hit issue or PR"); const hasTargetLabel = issue.labels.some((label) => diff --git a/index.js b/index.js index 64de602..fead95e 100644 --- a/index.js +++ b/index.js @@ -430,7 +430,7 @@ const run = async () => { core.debug("Event: " + eventName); - if ((eventName === "issue_comment") || (eventName === "pull_request") || (eventName === "pull_request_target")) { + if ((eventName === "issue_comment") || (eventName === "pull_request") || (eventName === "pull_request_target") || ISSUE_NUMBER_PARAM) { core.debug("Hit issue or PR"); const hasTargetLabel = issue.labels.some((label) =>