From 235dbebdd22dad6eb12519b2eb40c03e89d65e2c Mon Sep 17 00:00:00 2001 From: kamesh-09 Date: Wed, 28 Feb 2024 00:09:32 +0530 Subject: [PATCH 1/2] Modified to support multiple project keys --- __tests__/index.test.ts | 68 ++++++++++++++++++++++++++++++++--------- src/main.ts | 61 +++++++++++++++++++++++------------- 2 files changed, 94 insertions(+), 35 deletions(-) diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 31702ac..cba8b49 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -2,7 +2,7 @@ import * as github from "@actions/github"; import { readFileSync } from "fs"; import { getPullRequestTitle, getRegex } from "../src/main"; -const projectKeyInputName = "projectKey"; +const projectKeyInputName = "projectKeys"; const separatorKeyInputName = "separator"; const keyAnywhereInTitle = "keyAnywhereInTitle"; @@ -51,21 +51,23 @@ describe("index", () => { process.env[ `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` ] = ""; - const regex = getRegex(); + const regexes = getRegex(); const defaultRegex = // eslint-disable-next-line no-useless-escape /(?<=^|[a-z]-|[\s\p{Punct}&[^\-]])([A-Z][A-Z0-9_]*-\d+)(?![^\W_])(\s)+(.)+/; - expect(regex).toEqual(defaultRegex); - expect(regex.test("PR-4 this is valid")).toBe(true); + expect(regexes.length).toEqual(1); + expect(regexes[0]).toEqual(defaultRegex); + expect(regexes[0].test("PR-4 this is valid")).toBe(true); }); it("uses a project key if it exists", () => { process.env[ `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` ] = "AB"; - const regex = getRegex(); - expect(regex).toEqual(new RegExp(`(^AB-){1}(\\d)+(\\s)+(.)+`)); - expect(regex.test("AB-43 stuff and things")).toBe(true); + const regexes = getRegex(); + expect(regexes.length).toEqual(1); + expect(regexes[0]).toEqual(new RegExp(`(^AB-){1}(\\d)+(\\s)+(.)+`)); + expect(regexes[0].test("AB-43 stuff and things")).toBe(true); }); it("throws an exception if the provided project key is not valid", () => { @@ -75,6 +77,13 @@ describe("index", () => { expect(getRegex).toThrow('Project Key "aB" is invalid'); }); + it("throws an exception if one of the provided project key is not valid", () => { + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB/naB/nCD"; + expect(getRegex).toThrow('Project Key "aB" is invalid'); + }); + it("uses a project key and a colon separator if they exist", () => { process.env[ `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` @@ -85,7 +94,9 @@ describe("index", () => { process.env[ `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` ] = "false"; - const regex = getRegex(); + const regexes = getRegex(); + expect(regexes.length).toEqual(1); + const regex = regexes[0]; expect(regex).toEqual(new RegExp(`(^AB-){1}(\\d)+(:)+(\\S)+(.)+`)); expect(regex.test("AB-43: stuff and things")).toBe(false); expect(regex.test("AB-123: PR Title")).toBe(false); @@ -103,22 +114,28 @@ describe("index", () => { process.env[ `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` ] = "false"; - const regex = getRegex(); + const regexes = getRegex(); + expect(regexes.length).toEqual(1); + const regex = regexes[0]; expect(regex).toEqual(new RegExp(`(^AB-){1}(\\d)+(_)+(\\S)+(.)+`)); expect(regex.test("AB-43_stuff and things")).toBe(true); expect(regex.test("AB-123_PR Title")).toBe(true); }); it("uses a project key if it exists anywhere in the title", () => { + const projectNames: string[] = ["AB", "CD", "EF"]; process.env[ `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = "AB"; + ] = "AB/nCD/nEF"; process.env[ `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` ] = "true"; - const regex = getRegex(); - expect(regex).toEqual(new RegExp(`(.)*(AB-){1}(\\d)+(\\s)+(.)+`)); - expect(regex.test("other words AB-43 stuff and things")).toBe(true); + const regexes = getRegex(); + expect(regexes.length).not.toEqual(1); + regexes.forEach((regex: RegExp, index: number) => { + expect(regex).toEqual(new RegExp(`(.)*(${projectNames[index]}-){1}(\\d)+(\\s)+(.)+`)); + expect(regex.test(`other words ${projectNames[index]}-43 stuff and things`)).toBe(true); + }) }); it("uses a project key and a colon separator if they exist anywhere in the title", () => { @@ -131,7 +148,9 @@ describe("index", () => { process.env[ `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` ] = "true"; - const regex = getRegex(); + const regexes = getRegex(); + expect(regexes.length).toEqual(1); + const regex = regexes[0]; expect(regex).toEqual(new RegExp(`(.)*(AB-){1}(\\d)+(:)+(\\S)+(.)+`)); expect(regex.test("other words AB-43: stuff and things")).toBe(false); expect(regex.test("other words AB-123: PR Title")).toBe(false); @@ -140,5 +159,26 @@ describe("index", () => { expect(regex.test("AB-43:stuff and things")).toBe(true); expect(regex.test("AB-123:PR Title")).toBe(true); }); + + it("uses a project key and a colon separator if they exist", () => { + const projectNames: string[] = ["AB", "CD", "EF", "GH"]; + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB/nCD/nEF/nGH"; + process.env[ + `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = ":"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "false"; + const regexCollection = getRegex(); + regexCollection.forEach((regex: RegExp, index: number) => { + expect(regex).toEqual(new RegExp(`(^${projectNames[index]}-){1}(\\d)+(:)+(\\S)+(.)+`)); + expect(regex.test(`${projectNames[index]}-43: stuff and things`)).toBe(false); + expect(regex.test(`${projectNames[index]}-123: PR Title`)).toBe(false); + expect(regex.test(`${projectNames[index]}-43:stuff and things`)).toBe(true); + expect(regex.test(`${projectNames[index]}-123:PR Title`)).toBe(true); + }) + }); }); }); diff --git a/src/main.ts b/src/main.ts index 8dd0999..a0ccf39 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,47 +5,66 @@ export const run = async () => { try { core.debug("Starting PR Title check for Jira Issue Key"); const title = getPullRequestTitle(); - const regex = getRegex(); + const allPossibleRegex = getRegex(); core.debug(title); - core.debug(regex.toString()); + core.debug(allPossibleRegex.toString()); - if (!regex.test(title)) { - core.debug(`Regex ${regex} failed with title ${title}`); - core.info("Title Failed"); - core.setFailed("PullRequest title does not start with a Jira Issue key."); - return; + for (const regex of allPossibleRegex) { + if (regex.test(title)) { + core.info("Title Passed"); + return; + } } - core.info("Title Passed"); + core.debug(`Regex ${allPossibleRegex} failed with title ${title}`); + core.info("Title Failed"); + core.setFailed("PullRequest title does not start with any Jira Issue key."); + return; // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { core.setFailed(error.message); } }; -export const getRegex = () => { - const projectKey = core.getInput("projectKey", { required: false }); +export const getRegex = (): RegExp[] => { + const projectKeysInput = core.getInput("projectKeys", { required: false }); const separator = core.getInput("separator", { required: false }); const keyAnywhereInTitle = core.getBooleanInput("keyAnywhereInTitle", { required: false, }); - core.debug(`Project Key ${projectKey}`); + core.debug(`Project Keys ${projectKeysInput}`); core.debug(`Separator ${separator}`); core.debug(`Key Anywhere In Title ${keyAnywhereInTitle}`); - if (!projectKey || projectKey === "") return getDefaultJiraIssueRegex(); + if (!projectKeysInput || projectKeysInput === "") return [getDefaultJiraIssueRegex()]; - if (!isValidProjectKey(projectKey)) - throw new Error(`Project Key "${projectKey}" is invalid`); + const projectKeys: string[] = []; + // input separated by multiple lines: split and consume. + projectKeysInput.split('/n').forEach((project: string) => { + projectKeys.push(project.trim()); + }); + projectKeys.forEach((projectName: string) => { + if (!isValidProjectKey(projectName)) + throw new Error(`Project Key "${projectName}" is invalid`); + }); - if (!separator || separator === "") - return getRegexWithProjectKey(projectKey, keyAnywhereInTitle); + const allPossibleRegex: RegExp[] = []; - return getRegexWithProjectKeyAndSeparator( - projectKey, - separator, - keyAnywhereInTitle, - ); + if (!separator || separator === "") { + projectKeys.forEach((projectName: string) => { + allPossibleRegex.push(getRegexWithProjectKey(projectName, keyAnywhereInTitle)); + }); + return allPossibleRegex; + } + + projectKeys.forEach((projectName: string) => { + allPossibleRegex.push(getRegexWithProjectKeyAndSeparator( + projectName, + separator, + keyAnywhereInTitle, + )); + }); + return allPossibleRegex; }; export const getPullRequestTitle = () => { const pull_request = github.context.payload.pull_request; From 20113cb209e38adfd306f1f4029e1f83cf9a14e1 Mon Sep 17 00:00:00 2001 From: kamesh-09 Date: Mon, 4 Mar 2024 21:51:47 +0530 Subject: [PATCH 2/2] Reverted breaking changes + Updated Readme --- README.md | 19 ++ __tests__/index.test.ts | 384 +++++++++++++++++++++++++++------------- src/main.ts | 20 ++- 3 files changed, 294 insertions(+), 129 deletions(-) diff --git a/README.md b/README.md index c967471..1d77dde 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,10 @@ By default, this action will allow any valid Issue Key so long as it *could* be A specific Project Key to always check for +### `projectKeys` + +Multiple Project Keys to always check for + ### `separator` A specific separator to use. Defaults to a space character. @@ -65,6 +69,9 @@ A specific separator to use. Defaults to a space character. Allows the Jira Project Key, Issue # and separator to be anywhere in the title. Defaults to false. + +Note that `projectKey` and `projectKeys` works same under the hood. You can pass either one of them depending on the usecase. + ## Example Usage ``` @@ -81,6 +88,18 @@ Allows the Jira Project Key, Issue # and separator to be anywhere in the title. projectKey: 'AB' ``` +## Example Usage with a multiple Project Keys + +``` +- name: Enforce Jira Issue Key in Pull Request Title + uses: ryanvade/enforce-pr-title-style-action@v2 + with: + projectKeys: | + 'AB' + 'CD' + 'EF' +``` + ## Example Usage with a specific Project Key and a separator ``` diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index cba8b49..6d569e4 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -2,13 +2,16 @@ import * as github from "@actions/github"; import { readFileSync } from "fs"; import { getPullRequestTitle, getRegex } from "../src/main"; -const projectKeyInputName = "projectKeys"; +const projectKeyInputName = "projectKey"; +const projectKeysInputName = 'projectKeys'; const separatorKeyInputName = "separator"; const keyAnywhereInTitle = "keyAnywhereInTitle"; const resetEnvironmentVariables = () => { process.env[`INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}`] = ""; + process.env[`INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}`] = + ""; process.env[ `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` ] = ""; @@ -47,138 +50,271 @@ describe("index", () => { describe("getRegex", () => { beforeEach(() => resetEnvironmentVariables()); - it("gets the default when no project key is provided", () => { - process.env[ - `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = ""; - const regexes = getRegex(); - const defaultRegex = - // eslint-disable-next-line no-useless-escape - /(?<=^|[a-z]-|[\s\p{Punct}&[^\-]])([A-Z][A-Z0-9_]*-\d+)(?![^\W_])(\s)+(.)+/; - expect(regexes.length).toEqual(1); - expect(regexes[0]).toEqual(defaultRegex); - expect(regexes[0].test("PR-4 this is valid")).toBe(true); - }); + describe("when projectKey is provided", () => { + it("uses a project key if it exists", () => { + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB"; + const regex = getRegex(); + expect(regex.length).toEqual(1); + expect(regex[0]).toEqual(new RegExp(`(^AB-){1}(\\d)+(\\s)+(.)+`)); + expect(regex[0].test("AB-43 stuff and things")).toBe(true); + }); - it("uses a project key if it exists", () => { - process.env[ - `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = "AB"; - const regexes = getRegex(); - expect(regexes.length).toEqual(1); - expect(regexes[0]).toEqual(new RegExp(`(^AB-){1}(\\d)+(\\s)+(.)+`)); - expect(regexes[0].test("AB-43 stuff and things")).toBe(true); - }); + it("throws an exception if the provided project key is not valid", () => { + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "aB"; + expect(getRegex).toThrow('Project Key "aB" is invalid'); + }); - it("throws an exception if the provided project key is not valid", () => { - process.env[ - `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = "aB"; - expect(getRegex).toThrow('Project Key "aB" is invalid'); - }); + it("uses a project key and a colon separator if they exist", () => { + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB"; + process.env[ + `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = ":"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "false"; + const regex = getRegex(); + expect(regex.length).toEqual(1); + expect(regex[0]).toEqual(new RegExp(`(^AB-){1}(\\d)+(:)+(\\S)+(.)+`)); + expect(regex[0].test("AB-43: stuff and things")).toBe(false); + expect(regex[0].test("AB-123: PR Title")).toBe(false); + expect(regex[0].test("AB-43:stuff and things")).toBe(true); + expect(regex[0].test("AB-123:PR Title")).toBe(true); + }); - it("throws an exception if one of the provided project key is not valid", () => { - process.env[ - `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = "AB/naB/nCD"; - expect(getRegex).toThrow('Project Key "aB" is invalid'); - }); + it("uses a project key and an underscore separator if they exist", () => { + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB"; + process.env[ + `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "_"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "false"; + const regex = getRegex(); + expect(regex.length).toEqual(1); + expect(regex[0]).toEqual(new RegExp(`(^AB-){1}(\\d)+(_)+(\\S)+(.)+`)); + expect(regex[0].test("AB-43_stuff and things")).toBe(true); + expect(regex[0].test("AB-123_PR Title")).toBe(true); + }); - it("uses a project key and a colon separator if they exist", () => { - process.env[ - `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = "AB"; - process.env[ - `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = ":"; - process.env[ - `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` - ] = "false"; - const regexes = getRegex(); - expect(regexes.length).toEqual(1); - const regex = regexes[0]; - expect(regex).toEqual(new RegExp(`(^AB-){1}(\\d)+(:)+(\\S)+(.)+`)); - expect(regex.test("AB-43: stuff and things")).toBe(false); - expect(regex.test("AB-123: PR Title")).toBe(false); - expect(regex.test("AB-43:stuff and things")).toBe(true); - expect(regex.test("AB-123:PR Title")).toBe(true); - }); + it("uses a project key if it exists anywhere in the title", () => { + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "true"; + const regex = getRegex(); + expect(regex.length).toEqual(1); + expect(regex[0]).toEqual(new RegExp(`(.)*(AB-){1}(\\d)+(\\s)+(.)+`)); + expect(regex[0].test("other words AB-43 stuff and things")).toBe(true); + }); - it("uses a project key and an underscore separator if they exist", () => { - process.env[ - `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = "AB"; - process.env[ - `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = "_"; - process.env[ - `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` - ] = "false"; - const regexes = getRegex(); - expect(regexes.length).toEqual(1); - const regex = regexes[0]; - expect(regex).toEqual(new RegExp(`(^AB-){1}(\\d)+(_)+(\\S)+(.)+`)); - expect(regex.test("AB-43_stuff and things")).toBe(true); - expect(regex.test("AB-123_PR Title")).toBe(true); + it("uses a project key and a colon separator if they exist anywhere in the title", () => { + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB"; + process.env[ + `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = ":"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "true"; + const regex = getRegex(); + expect(regex.length).toEqual(1); + expect(regex[0]).toEqual(new RegExp(`(.)*(AB-){1}(\\d)+(:)+(\\S)+(.)+`)); + expect(regex[0].test("other words AB-43: stuff and things")).toBe(false); + expect(regex[0].test("other words AB-123: PR Title")).toBe(false); + expect(regex[0].test("other words AB-43:stuff and things")).toBe(true); + expect(regex[0].test("other words AB-123:PR Title")).toBe(true); + expect(regex[0].test("AB-43:stuff and things")).toBe(true); + expect(regex[0].test("AB-123:PR Title")).toBe(true); + }); }); - it("uses a project key if it exists anywhere in the title", () => { - const projectNames: string[] = ["AB", "CD", "EF"]; - process.env[ - `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = "AB/nCD/nEF"; - process.env[ - `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` - ] = "true"; - const regexes = getRegex(); - expect(regexes.length).not.toEqual(1); - regexes.forEach((regex: RegExp, index: number) => { - expect(regex).toEqual(new RegExp(`(.)*(${projectNames[index]}-){1}(\\d)+(\\s)+(.)+`)); - expect(regex.test(`other words ${projectNames[index]}-43 stuff and things`)).toBe(true); - }) + describe("when projectKeys are provided", () => { + it("uses a project key if it exists in projectKeys", () => { + process.env[ + `INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB"; + const regexes = getRegex(); + expect(regexes.length).toEqual(1); + expect(regexes[0]).toEqual(new RegExp(`(^AB-){1}(\\d)+(\\s)+(.)+`)); + expect(regexes[0].test("AB-43 stuff and things")).toBe(true); + }); + + it("throws an exception if the provided project key is not valid", () => { + process.env[ + `INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}` + ] = "aB"; + expect(getRegex).toThrow('Project Key "aB" is invalid'); + }); + + it("throws an exception if one of the provided project key is not valid", () => { + process.env[ + `INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB\naB\nCD"; + expect(getRegex).toThrow('Project Key "aB" is invalid'); + }); + + it("uses a project key and a colon separator if they exist", () => { + process.env[ + `INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB"; + process.env[ + `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = ":"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "false"; + const regexes = getRegex(); + expect(regexes.length).toEqual(1); + const regex = regexes[0]; + expect(regex).toEqual(new RegExp(`(^AB-){1}(\\d)+(:)+(\\S)+(.)+`)); + expect(regex.test("AB-43: stuff and things")).toBe(false); + expect(regex.test("AB-123: PR Title")).toBe(false); + expect(regex.test("AB-43:stuff and things")).toBe(true); + expect(regex.test("AB-123:PR Title")).toBe(true); + }); + + it("uses a project key and an underscore separator if they exist", () => { + process.env[ + `INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB"; + process.env[ + `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "_"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "false"; + const regexes = getRegex(); + expect(regexes.length).toEqual(1); + const regex = regexes[0]; + expect(regex).toEqual(new RegExp(`(^AB-){1}(\\d)+(_)+(\\S)+(.)+`)); + expect(regex.test("AB-43_stuff and things")).toBe(true); + expect(regex.test("AB-123_PR Title")).toBe(true); + }); + + it("uses a project key if it exists anywhere in the title", () => { + const projectNames: string[] = ["AB", "CD", "EF"]; + process.env[ + `INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB\nCD\nEF"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "true"; + const regexes = getRegex(); + expect(regexes.length).not.toEqual(1); + regexes.forEach((regex: RegExp, index: number) => { + expect(regex).toEqual(new RegExp(`(.)*(${projectNames[index]}-){1}(\\d)+(\\s)+(.)+`)); + expect(regex.test(`other words ${projectNames[index]}-43 stuff and things`)).toBe(true); + }) + }); + + it("uses a project key and a colon separator if they exist anywhere in the title", () => { + process.env[ + `INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB"; + process.env[ + `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = ":"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "true"; + const regexes = getRegex(); + expect(regexes.length).toEqual(1); + const regex = regexes[0]; + expect(regex).toEqual(new RegExp(`(.)*(AB-){1}(\\d)+(:)+(\\S)+(.)+`)); + expect(regex.test("other words AB-43: stuff and things")).toBe(false); + expect(regex.test("other words AB-123: PR Title")).toBe(false); + expect(regex.test("other words AB-43:stuff and things")).toBe(true); + expect(regex.test("other words AB-123:PR Title")).toBe(true); + expect(regex.test("AB-43:stuff and things")).toBe(true); + expect(regex.test("AB-123:PR Title")).toBe(true); + }); + + it("uses a project key and a colon separator if they exist", () => { + const projectNames: string[] = ["AB", "CD", "EF", "GH"]; + process.env[ + `INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB\nCD\nEF\nGH"; + process.env[ + `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = ":"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "false"; + const regexCollection = getRegex(); + regexCollection.forEach((regex: RegExp, index: number) => { + expect(regex).toEqual(new RegExp(`(^${projectNames[index]}-){1}(\\d)+(:)+(\\S)+(.)+`)); + expect(regex.test(`${projectNames[index]}-43: stuff and things`)).toBe(false); + expect(regex.test(`${projectNames[index]}-123: PR Title`)).toBe(false); + expect(regex.test(`${projectNames[index]}-43:stuff and things`)).toBe(true); + expect(regex.test(`${projectNames[index]}-123:PR Title`)).toBe(true); + }) + }); }); - it("uses a project key and a colon separator if they exist anywhere in the title", () => { - process.env[ - `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = "AB"; - process.env[ - `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = ":"; - process.env[ - `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` - ] = "true"; - const regexes = getRegex(); - expect(regexes.length).toEqual(1); - const regex = regexes[0]; - expect(regex).toEqual(new RegExp(`(.)*(AB-){1}(\\d)+(:)+(\\S)+(.)+`)); - expect(regex.test("other words AB-43: stuff and things")).toBe(false); - expect(regex.test("other words AB-123: PR Title")).toBe(false); - expect(regex.test("other words AB-43:stuff and things")).toBe(true); - expect(regex.test("other words AB-123:PR Title")).toBe(true); - expect(regex.test("AB-43:stuff and things")).toBe(true); - expect(regex.test("AB-123:PR Title")).toBe(true); - }); + describe("when projectKey and projectKeys both are provided", () => { - it("uses a project key and a colon separator if they exist", () => { - const projectNames: string[] = ["AB", "CD", "EF", "GH"]; - process.env[ - `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = "AB/nCD/nEF/nGH"; - process.env[ - `INPUT_${separatorKeyInputName.replace(/ /g, "_").toUpperCase()}` - ] = ":"; - process.env[ - `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` - ] = "false"; - const regexCollection = getRegex(); - regexCollection.forEach((regex: RegExp, index: number) => { - expect(regex).toEqual(new RegExp(`(^${projectNames[index]}-){1}(\\d)+(:)+(\\S)+(.)+`)); - expect(regex.test(`${projectNames[index]}-43: stuff and things`)).toBe(false); - expect(regex.test(`${projectNames[index]}-123: PR Title`)).toBe(false); - expect(regex.test(`${projectNames[index]}-43:stuff and things`)).toBe(true); - expect(regex.test(`${projectNames[index]}-123:PR Title`)).toBe(true); - }) - }); + it("gets the default when no project key is provided", () => { + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = ""; + const regex = getRegex(); + const defaultRegex = + // eslint-disable-next-line no-useless-escape + /(?<=^|[a-z]-|[\s\p{Punct}&[^\-]])([A-Z][A-Z0-9_]*-\d+)(?![^\W_])(\s)+(.)+/; + expect(regex.length).toEqual(1); + expect(regex[0]).toEqual(defaultRegex); + expect(regex[0].test("PR-4 this is valid")).toBe(true); + }); + + it("uses project key if it exists anywhere in the title", () => { + const projectNames: string[] = ["AB", "CD", "EF", "GH"]; + process.env[ + `INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB\nCD\nEF"; + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "GH"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "true"; + const regexes = getRegex(); + expect(regexes.length).not.toEqual(1); + regexes.forEach((regex: RegExp, index: number) => { + expect(regex).toEqual(new RegExp(`(.)*(${projectNames[index]}-){1}(\\d)+(\\s)+(.)+`)); + expect(regex.test(`other words ${projectNames[index]}-43 stuff and things`)).toBe(true); + }) + }); + + it("multiple project keys are present", () => { + const projectNames: string[] = ["AB", "CD"]; + process.env[ + `INPUT_${projectKeysInputName.replace(/ /g, "_").toUpperCase()}` + ] = "AB\n"; + process.env[ + `INPUT_${projectKeyInputName.replace(/ /g, "_").toUpperCase()}` + ] = "CD"; + process.env[ + `INPUT_${keyAnywhereInTitle.replace(/ /g, "_").toUpperCase()}` + ] = "true"; + const regexes = getRegex(); + expect(regexes.length).not.toEqual(1); + regexes.forEach((regex: RegExp, index: number) => { + expect(regex).toEqual(new RegExp(`(.)*(${projectNames[index]}-){1}(\\d)+(\\s)+(.)+`)); + expect(regex.test(`other words ${projectNames[index]}-43 CD-43 stuff and things`)).toBe(true); + expect(regex.test(`other words CD-43 ${projectNames[index]}-43 stuff and things`)).toBe(true); + }) + }); + }) }); }); diff --git a/src/main.ts b/src/main.ts index a0ccf39..fa1fa12 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,23 +26,33 @@ export const run = async () => { } }; export const getRegex = (): RegExp[] => { - const projectKeysInput = core.getInput("projectKeys", { required: false }); + const projectKeyInput = core.getInput("projectKey", { required: false }); + let projectKeysInput = core.getInput("projectKeys", { required: false }); const separator = core.getInput("separator", { required: false }); const keyAnywhereInTitle = core.getBooleanInput("keyAnywhereInTitle", { required: false, }); + core.debug(`Project Key ${projectKeyInput}`); core.debug(`Project Keys ${projectKeysInput}`); core.debug(`Separator ${separator}`); core.debug(`Key Anywhere In Title ${keyAnywhereInTitle}`); - if (!projectKeysInput || projectKeysInput === "") return [getDefaultJiraIssueRegex()]; + if ((!projectKeysInput || projectKeysInput === "") && (!projectKeyInput || projectKeyInput === "")) return [getDefaultJiraIssueRegex()]; const projectKeys: string[] = []; + // if there is any input in projectKeys. // input separated by multiple lines: split and consume. - projectKeysInput.split('/n').forEach((project: string) => { - projectKeys.push(project.trim()); - }); + projectKeysInput = projectKeysInput.trim(); // remove extra spaces. + if (projectKeysInput.length > 0) { + projectKeysInput.split('\n').forEach((project: string) => { + projectKeys.push(project.trim()); + }); + } + if (projectKeyInput) { + projectKeys.push(projectKeyInput); + } + projectKeys.forEach((projectName: string) => { if (!isValidProjectKey(projectName)) throw new Error(`Project Key "${projectName}" is invalid`);