From 96d4d75b9fdeebc74d477df67a95bd11d56209df Mon Sep 17 00:00:00 2001 From: Tim van Mourik <6152205+TimVanMourik@users.noreply.github.com> Date: Tue, 14 May 2024 14:41:21 +0200 Subject: [PATCH] archive tickets --- README.md | 71 ++++++++---------------- dist/index.js | 146 ++++++++++++++++++++++++-------------------------- index.js | 55 ++++++++++--------- 3 files changed, 119 insertions(+), 153 deletions(-) diff --git a/README.md b/README.md index 91075ab..bf21ca8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Move to next iteration +# Archive tickets from a certain column for an iteration -Automatically move issues and pull requests to the next iteration of your [GitHub project](https://docs.github.com/en/issues/planning-and-tracking-with-projects/learning-about-projects/about-projects) with this [Github Action](https://github.com/features/actions). +Automatically archive issues for a given iteration of your [GitHub project](https://docs.github.com/en/issues/planning-and-tracking-with-projects/learning-about-projects/about-projects) with this [Github Action](https://github.com/features/actions). ## Example @@ -8,79 +8,50 @@ Automatically move issues and pull requests to the next iteration of your [GitHu on: schedule: # Runs "at 05:00, only on Monday" (see https://crontab.guru) - - cron: '0 5 * * 1' + - cron: "0 5 * * 1" jobs: - move-to-next-iteration: - name: Move to next iteration + archive-done-tickets: + name: Archive done tickets runs-on: ubuntu-latest steps: - - uses: blombard/move-to-next-iteration@master - with: - owner: OrgName - number: 1 - token: ${{ secrets.PROJECT_PAT }} - iteration-field: Iteration - iteration: last - new-iteration: current - statuses: 'Todo,In Progress,In Review' -``` - -Alternatively, you may specify `excluded-statuses`. In this case, all items that _don’t_ have these statuses will be moved to the new iteration. (Note that if `excluded-statuses` is used, `statuses` will be ignored.) - -```yaml -on: - schedule: - # Runs "at 05:00, only on Monday" (see https://crontab.guru) - - cron: '0 5 * * 1' - -jobs: - move-to-next-iteration: - name: Move to next iteration - runs-on: ubuntu-latest - - steps: - - uses: blombard/move-to-next-iteration@master - with: - owner: OrgName - number: 1 - token: ${{ secrets.PROJECT_PAT }} - iteration-field: Iteration - iteration: last - new-iteration: current - excluded-statuses: "Done,Won't Fix" + - uses: TimVanMourik/gha-archive-tickets-from-sprint@v0.1.0 + with: + owner: OrgName + number: 1 + token: ${{ secrets.PROJECT_PAT }} + iteration-field: Iteration + iteration: last + statuses: "Done" ``` ## Inputs + #### owner + The account name of the GitHub organization. #### number + Project number as you see it in the URL of the project. #### token + Personal access token or an OAuth token. the `project` scope is required. #### iteration-field + The name of your iteration field. #### iteration -Should be `last` or `current`. -#### new-iteration -Should be `current` or `next`. +Should be `last` or `current`. #### statuses -Statuses of the issues to move to the next iteration. - -⚠️ _This setting is ignored if `excluded-statuses` is provided. See below._ ⚠️ - -#### excluded-statuses -Statuses of the issues that should _not_ be moved. -⚠️ _This setting takes precedence over `statuses`._ ⚠️ +Statuses of the issues to archive ## Sources -This action was made possible thanks to https://github.com/gr2m/github-project. +This action was made possible thanks to https://github.com/gr2m/github-project. This was an adaption from https://github.com/blombard/move-to-next-iteration. diff --git a/dist/index.js b/dist/index.js index 9bd76bd..a538284 100644 --- a/dist/index.js +++ b/dist/index.js @@ -8489,8 +8489,6 @@ function projectFieldsNodesToFieldsMap(state, project, nodes) { // If the field is of type "Iteration", then the `configuration` property will be set. if (node.configuration) { - acc[userInternalFieldName].configuration = node.configuration; - acc[userInternalFieldName].optionsById = node.configuration.iterations.concat(node.configuration.completedIterations).reduce( (acc, option) => { return { @@ -8585,52 +8583,52 @@ function projectFieldValueNodeToValue(projectField, node) { function projectItemNodeToGitHubProjectItem(state, itemNode) { const fields = itemFieldsNodesToFieldsMap(state, itemNode.fieldValues.nodes); - // const common = { - // type: itemNode.type, - // id: itemNode.id, - // isArchived: itemNode.isArchived, - // fields, - // }; - - // if (itemNode.type === "DRAFT_ISSUE") { - // return { - // ...common, - // content: { - // id: itemNode.content.id, - // title: itemNode.content.title, - // createdAt: itemNode.content.createdAt, - // assignees: itemNode.content.assignees.nodes.map((node) => node.login), - // }, - // }; - // } - - // if (itemNode.type === "ISSUE" || itemNode.type === "PULL_REQUEST") { - // // item is issue or pull request - // const issue = { - // id: itemNode.content.id, - // number: itemNode.content.number, - // createdAt: itemNode.content.createdAt, - // closed: itemNode.content.closed, - // closedAt: itemNode.content.closedAt, - // assignees: itemNode.content.assignees.nodes.map((node) => node.login), - // labels: itemNode.content.labels.nodes.map((node) => node.name), - // repository: itemNode.content.repository.name, - // milestone: itemNode.content.milestone, - // title: itemNode.content.title, - // url: itemNode.content.url, - // databaseId: itemNode.content.databaseId, - // }; - - // const content = - // itemNode.type === "ISSUE" - // ? issue - // : { ...issue, merged: itemNode.content.merged }; - - // return { - // ...common, - // content, - // }; - // } + const common = { + type: itemNode.type, + id: itemNode.id, + isArchived: itemNode.isArchived, + fields, + }; + + if (itemNode.type === "DRAFT_ISSUE") { + return { + ...common, + content: { + id: itemNode.content.id, + title: itemNode.content.title, + createdAt: itemNode.content.createdAt, + assignees: itemNode.content.assignees.nodes.map((node) => node.login), + }, + }; + } + + if (itemNode.type === "ISSUE" || itemNode.type === "PULL_REQUEST") { + // item is issue or pull request + const issue = { + id: itemNode.content.id, + number: itemNode.content.number, + createdAt: itemNode.content.createdAt, + closed: itemNode.content.closed, + closedAt: itemNode.content.closedAt, + assignees: itemNode.content.assignees.nodes.map((node) => node.login), + labels: itemNode.content.labels.nodes.map((node) => node.name), + repository: itemNode.content.repository.name, + milestone: itemNode.content.milestone, + title: itemNode.content.title, + url: itemNode.content.url, + databaseId: itemNode.content.databaseId, + }; + + const content = + itemNode.type === "ISSUE" + ? issue + : { ...issue, merged: itemNode.content.merged }; + + return { + ...common, + content, + }; + } /* c8 ignore next 9 */ // fallback: no content properties are set. Currently that's in case of "REDACTED" @@ -9671,7 +9669,6 @@ function projectNodeToProperties(state) { id: state.id, title: state.title, url: state.url, - fields: state.fields, }; } @@ -9817,43 +9814,42 @@ class GitHubProject { const run = async () => { try { - const owner = core.getInput('owner'); - const number = Number(core.getInput('number')); - const token = core.getInput('token'); - const iterationField = core.getInput('iteration-field'); // name of the iteration field - const iterationType = core.getInput('iteration'); // last or current - const newiterationType = core.getInput('new-iteration'); // current or next - const statuses = core.getInput('statuses').split(','); - const coreExclusedStatuses = core.getInput('excluded-statuses'); - const excludedStatuses = coreExclusedStatuses ? coreExclusedStatuses.split(',') : []; - - const project = new GitHubProject({ owner, number, token, fields: { iteration: iterationField } }); + const owner = core.getInput("owner"); + const number = Number(core.getInput("number")); + const token = core.getInput("token"); + const iterationField = core.getInput("iteration-field"); // name of the iteration field + const iterationType = core.getInput("iteration"); // last or current + const statuses = core.getInput("statuses").split(","); + + const project = new GitHubProject({ + owner, + number, + token, + fields: { iteration: iterationField }, + }); const projectData = await project.getProperties(); - const lastIteration = projectData.fields.iteration.configuration.completedIterations[0]; - const currentIteration = projectData.fields.iteration.configuration.iterations[0]; - const nextIteration = projectData.fields.iteration.configuration.iterations[1]; + const lastIteration = + projectData.fields.iteration.configuration.completedIterations[0]; + const currentIteration = + projectData.fields.iteration.configuration.iterations[0]; - const iteration = iterationType === 'last' ? lastIteration : currentIteration; - const newIteration = newiterationType === 'current' ? currentIteration : nextIteration; + const iteration = + iterationType === "last" ? lastIteration : currentIteration; const items = await project.items.list(); - const filteredItems = items.filter(item => { + const filteredItems = items.filter((item) => { // If item is not in the old iteration, return false. if (item.fields.iteration !== iteration.title) return false; - // If excludedStatuses are supplied, use that. Otherwise, use statuses. - if (excludedStatuses?.length) { - // Move item only if its status _is not_ in the excluded statuses list. - return !excludedStatuses.includes(item.fields.status); - } else { - // Move item only if its status _is_ in the statuses list. - return statuses.includes(item.fields.status); - } + // Move item only if its status _is_ in the statuses list. + return statuses.includes(item.fields.status); }); - await Promise.all(filteredItems.map(item => project.items.update(item.id, { iteration: newIteration.title }))); + await Promise.all( + filteredItems.map((item) => project.items.archive(item.id)) + ); } catch (error) { core.setFailed(error.message); } diff --git a/index.js b/index.js index c81823e..8139f0f 100644 --- a/index.js +++ b/index.js @@ -1,45 +1,44 @@ -import core from '@actions/core'; -import GitHubProject from 'github-project'; +import core from "@actions/core"; +import GitHubProject from "github-project"; const run = async () => { try { - const owner = core.getInput('owner'); - const number = Number(core.getInput('number')); - const token = core.getInput('token'); - const iterationField = core.getInput('iteration-field'); // name of the iteration field - const iterationType = core.getInput('iteration'); // last or current - const newiterationType = core.getInput('new-iteration'); // current or next - const statuses = core.getInput('statuses').split(','); - const coreExclusedStatuses = core.getInput('excluded-statuses'); - const excludedStatuses = coreExclusedStatuses ? coreExclusedStatuses.split(',') : []; - - const project = new GitHubProject({ owner, number, token, fields: { iteration: iterationField } }); + const owner = core.getInput("owner"); + const number = Number(core.getInput("number")); + const token = core.getInput("token"); + const iterationField = core.getInput("iteration-field"); // name of the iteration field + const iterationType = core.getInput("iteration"); // last or current + const statuses = core.getInput("statuses").split(","); + + const project = new GitHubProject({ + owner, + number, + token, + fields: { iteration: iterationField }, + }); const projectData = await project.getProperties(); - const lastIteration = projectData.fields.iteration.configuration.completedIterations[0]; - const currentIteration = projectData.fields.iteration.configuration.iterations[0]; - const nextIteration = projectData.fields.iteration.configuration.iterations[1]; + const lastIteration = + projectData.fields.iteration.configuration.completedIterations[0]; + const currentIteration = + projectData.fields.iteration.configuration.iterations[0]; - const iteration = iterationType === 'last' ? lastIteration : currentIteration; - const newIteration = newiterationType === 'current' ? currentIteration : nextIteration; + const iteration = + iterationType === "last" ? lastIteration : currentIteration; const items = await project.items.list(); - const filteredItems = items.filter(item => { + const filteredItems = items.filter((item) => { // If item is not in the old iteration, return false. if (item.fields.iteration !== iteration.title) return false; - // If excludedStatuses are supplied, use that. Otherwise, use statuses. - if (excludedStatuses?.length) { - // Move item only if its status _is not_ in the excluded statuses list. - return !excludedStatuses.includes(item.fields.status); - } else { - // Move item only if its status _is_ in the statuses list. - return statuses.includes(item.fields.status); - } + // Move item only if its status _is_ in the statuses list. + return statuses.includes(item.fields.status); }); - await Promise.all(filteredItems.map(item => project.items.update(item.id, { iteration: newIteration.title }))); + await Promise.all( + filteredItems.map((item) => project.items.archive(item.id)) + ); } catch (error) { core.setFailed(error.message); }