From 811c9b51c6c1b37319c2532034a62eb1c10c61dd Mon Sep 17 00:00:00 2001 From: Javier Bullrich Date: Mon, 5 Jun 2023 12:53:16 +0200 Subject: [PATCH] Added label filter (#18) Added filter where a label is required for the issue to be considered. If the issue doesn't have the given label, it will filter it out. --------- Co-authored-by: Przemek Rzad --- README.md | 8 ++++++++ action.yml | 6 +++++- package.json | 2 +- src/filters.ts | 3 +++ src/github/issuesParser.ts | 22 +++++++++++++++++++++- src/index.ts | 13 +++++++++++-- src/types/global.d.ts | 9 +++++++++ 7 files changed, 58 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a6b9720..ed1dca0 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,14 @@ You can find all the inputs in [the action file](./action.yml) but let's walk th - It is **not** _case sensitive_. - It works great in conjuction with [`paritytech/list-team-members`](https://github.com/paritytech/list-team-members) - It can use the output directly to ignore any issues made by a member of a team. +- `requiredLabels`: Collections of labels separated by commas that should be required when searching for a PR. + - Only needs to have one of the included labels. + - If you have labels: `A,B` the issue will be taken into consideration if it has: `A`, `B` or both `A` and `B`. + - Short for `Only include issues with at least one of the required labels`. + - **optional** + - **Important**: If set be sure to connect the names by comma. + - Example: `feature,bug,good first issue` + - It is **not** _case sensitive_. #### Accessing other repositories diff --git a/action.yml b/action.yml index bffada4..02938f8 100644 --- a/action.yml +++ b/action.yml @@ -26,6 +26,10 @@ inputs: required: false description: Collections of usernames separated by commas that should be ignored if they are the author of the issue. type: string + requiredLabels: + required: false + description: Collections of labels separated by commas that should be required when searching for a issue. + type: string outputs: repo: description: 'The name of the repo in owner/repo pattern' @@ -38,4 +42,4 @@ outputs: runs: using: 'docker' - image: 'docker://ghcr.io/paritytech/stale-issues-finder/action:0.0.6' + image: 'docker://ghcr.io/paritytech/stale-issues-finder/action:0.1.0' diff --git a/package.json b/package.json index 37ed85e..4de6416 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stale-issues-finder", - "version": "0.0.6", + "version": "0.1.0", "description": "Find what issues have been stale for a given time", "main": "src/index.ts", "engines": { diff --git a/src/filters.ts b/src/filters.ts index dae677b..e4c22b6 100644 --- a/src/filters.ts +++ b/src/filters.ts @@ -7,3 +7,6 @@ export const byNoComments = (issue: IssueData): boolean => issue.comments === 0; export const isNotFromAuthor = ({ user }: IssueData, authors: string[]): boolean => !authors.some((author) => author.toLowerCase() === user?.login.toLowerCase()); + +export const byLabels = (issue: IssueData, requiredLabels: string[]): boolean => + issue.labels?.map((l) => l.name.toLowerCase()).some((l) => requiredLabels.map((lb) => lb.toLowerCase()).includes(l)); diff --git a/src/github/issuesParser.ts b/src/github/issuesParser.ts index 4d9ab77..aa2f76b 100644 --- a/src/github/issuesParser.ts +++ b/src/github/issuesParser.ts @@ -22,8 +22,28 @@ const getAllIssues = async (octokit: InstanceType, repo: Repo): P fullPage = data.length > 99; } + // parse the label data + const parsedIssues = issues.map((issue) => { + const labels: Label[] = []; + for (const label of issue.labels) { + let parsedLabel: Label; + if (typeof label === "string") { + parsedLabel = { id: 0, name: label, description: label, url: "" }; + } else { + parsedLabel = { + id: label.id ?? 0, + name: label.name ?? "", + description: label.description ?? "", + url: label.url ?? "", + }; + } + labels.push(parsedLabel); + } + return { ...issue, labels }; + }); + debug(`Found a total of ${issues.length} issues`); - return issues; + return parsedIssues; }; export const fetchIssues = async (octokit: InstanceType, repo: Repo): Promise => { diff --git a/src/index.ts b/src/index.ts index 9694ac7..663b214 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ import { context, getOctokit } from "@actions/github"; import { Context } from "@actions/github/lib/context"; import moment from "moment"; -import { byNoComments, isNotFromAuthor, olderThanDays } from "./filters"; +import { byLabels, byNoComments, isNotFromAuthor, olderThanDays } from "./filters"; import { fetchIssues } from "./github/issuesParser"; const daysSinceDate = (date: string): number => moment().diff(moment(date), "days"); @@ -20,7 +20,13 @@ const getFiltersFromInput = (): Filters => { ignoreAuthors = authorsToIgnore.split(","); } - return { daysStale, noComments, notFromAuthor: ignoreAuthors }; + let requiredLabels: string[] = []; + const labels = getInput("requiredLabels"); + if (labels) { + requiredLabels = labels.split(","); + } + + return { daysStale, noComments, notFromAuthor: ignoreAuthors, requiredLabels }; }; const generateMarkdownMessage = (issues: IssueData[], repo: { owner: string; repo: string }) => { @@ -59,6 +65,9 @@ const filterIssues = (issues: IssueData[] | undefined, filters: Filters) => { if (filters.notFromAuthor.length > 0) { filteredData = filteredData.filter((is) => isNotFromAuthor(is, filters.notFromAuthor)); } + if (filters.requiredLabels?.length > 0) { + filteredData = filteredData.filter((fd) => byLabels(fd, filters.requiredLabels)); + } return filteredData; }; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 1ab7ff4..8f7aca9 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -8,6 +8,7 @@ declare global { comments: number; /** If user was deleted it is going to be null */ user: { login: string } | null; + labels: Label[]; } interface Repo { @@ -19,6 +20,14 @@ declare global { noComments?: boolean; daysStale: number; notFromAuthor: string[]; + requiredLabels: string[]; + } + + interface Label { + id: number; + url: string; + name: string; + description: string; } }