Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "issue-number" as parameter #38

Merged
merged 2 commits into from
Mar 20, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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: '^#(?<ticketNumber>\d+)'
branchRegex: '^(?<ticketNumber>\d+)'
bodyRegex: '#(?<ticketNumber>\d+)'
bodyURLRegex: 'http(s?):\/\/(github.com)(\/:owner)(\/:repo)(\/issues)\/(?<ticketNumber>\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 }}
```
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -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
78 changes: 45 additions & 33 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -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") || ISSUE_NUMBER_PARAM) {
_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,
78 changes: 45 additions & 33 deletions index.js
Original file line number Diff line number Diff line change
@@ -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") || ISSUE_NUMBER_PARAM) {
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,