diff --git a/README.md b/README.md index d9193d2..e9019ea 100755 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ steps: #### Description -When a PR passes the above check, `jira-lint` will also add the issue details to the top of the PR description. It will pick details such as the Issue summary, type, estimation points and labels and add them to the PR description. +When a PR passes the above check, `jira-lint` will also add the issue details to the top of the PR description. It will pick details such as the Issue summary, type, estimation points, status and labels and add them to the PR description. #### Labels @@ -96,6 +96,35 @@ When a PR passes the above check, `jira-lint` will also add the issue details to +#### Issue Status Validation +Issue status is shown in the [Description](#description). +**Why validate issue status?** +In some cases, one may be pushing changes for a story that is set to `Done`/`Completed` or it may not have been pulled into working backlog or current sprint. + + This option allows discouraging pushing to branches for stories that are set to statuses other than the ones allowed in the project; for example - you may want to only allow PRs for stories that are in `To Do`/`Planning`/`In Progress` states. + +The following flags can be used to validate issue status: +- `validate_issue_status` + - If set to `true`, `jira-lint` will validate the issue status based on `allowed_issue_statuses` +- `allowed_issue_statuses` + - This will only be used when `validate_issue_status` is `true`. This should be a comma separated list of statuses. If the detected issue's status is not in one of the `allowed_issue_statuses` then `jira-lint` will fail the status check. + +**Example of invalid status** +
:broken_heart: The detected issue is not in one of the allowed statuses :broken_heart:
+Detected Status | +${issueStatus} | +:x: | +
---|---|---|
Allowed Statuses | +${allowedStatuses} | +:heavy_check_mark: | +
Please ensure your jira story is in one of the allowed statuses
+ #### Soft-validations via comments `jira-lint` will add comments to a PR to encourage better PR practices: @@ -140,11 +169,14 @@ When a PR passes the above check, `jira-lint` will also add the issue details to | `skip-branches` | A regex to ignore running `jira-lint` on certain branches, like production etc. | false | ' ' | | `skip-comments` | A `Boolean` if set to `true` then `jira-lint` will skip adding lint comments for PR title. | false | false | | `pr-threshold` | An `Integer` based on which `jira-lint` will add a comment discouraging huge PRs. | false | 800 | +| `validate_issue_status` | A `Boolean` based on which `jira-lint` will validate the status of the detected jira issue | false | false | +| `allowed_issue_statuses` | A comma separated list of allowed statuses. The detected jira issue's status will be compared against this list and if a match is not found then the status check will fail. *Note*: Requires `validate_issue_status` to be set to `true`. | false | `"In Progress"` | -Since tokens are private, we suggest adding them as [GitHub secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets). ### `jira-token` +Since tokens are private, we suggest adding them as [GitHub secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets). + The Jira token is used to fetch issue information via the Jira REST API. To get the token:- 1. Generate an [API token via JIRA](https://confluence.atlassian.com/cloud/api-tokens-938839638.html) 2. Create the encoded token in the format of `base64Encode(\n Knock Knock! 🔍\n
\n\n Just thought I'd let you know that your PR title and story title look quite different. PR titles\n that closely resemble the story title make it easier for reviewers to understand the context of the PR.\n
\n\n An easy-to-understand PR title a day makes the reviewer review away! 😛⚡️\n\n
Story Title | \n${e} | \n
---|---|
PR Title | \n${t} | \n
\n Check out this guide to learn more about PR best-practices.\n
\n `}else if(r>=.2&&r<=.4){return`\n Let's make that PR title a 💯 shall we? 💪\n
\n\n Your PR title and story title look slightly different. Just checking in to know if it was intentional!\n
\nStory Title | \n${e} | \n
---|---|
PR Title | \n${t} | \n
\n Check out this guide to learn more about PR best-practices.\n
\n `}return`I'm a bot and I 👍 this PR title. 🤖
\n\n `});t.shouldSkipBranchLint=((e,t)=>{if(p.BOT_BRANCH_PATTERNS.some(t=>t.test(e))){console.log(`You look like a bot 🤖 so we're letting you off the hook!`);return true}if(p.DEFAULT_BRANCH_PATTERNS.some(t=>t.test(e))){console.log(`Ignoring check for default branch ${e}`);return true}const r=new RegExp(t||"");if(!!t&&r.test(e)){console.log(`branch '${e}' ignored as it matches the ignore pattern '${t}' provided in skip-branches`);return true}console.log(`branch '${e}' does not match ignore pattern provided in 'skip-branches' option:`,r);return false});t.shouldUpdatePRDescription=(e=>typeof e==="string"&&!p.MARKER_REGEX.test(e));t.getLabelsForDisplay=(e=>{if(!e||!e.length){return"-"}const t=e.map(e=>`${e.name}`).join(", ");return t.replace(/\s+/," ")});t.getPRDescription=((e="",r)=>{const n=r.key.toUpperCase();return`\nSummary | \n${r.summary} | \n
---|---|
Type | \n\n \n ${r.type.name}\n | \n
Points | \n${r.estimate||"N/A"} | \n
Labels | \n${t.getLabelsForDisplay(r.labels)} | \n
This PR is too huge for one to review :broken_heart:
\n \nAdditions | \n${e} :no_good_woman: | \n
---|---|
Expected | \n:arrow_down: ${t} | \n
\n Consider breaking it down into multiple small PRs.\n
\n\n Check out this guide to learn more about PR best-practices.\n
\n `);t.getNoIdComment=(e=>{return`A JIRA Issue ID is missing from your branch name! 🦄
\nYour branch: ${e}
\nIf this is your first time contributing to this repository - welcome!
\nPlease refer to jira-lint to get started.\n
Without the JIRA Issue ID in your branch name you would lose out on automatic updates to JIRA via SCM; some GitHub status checks might fail.
\nValid sample branch names:\n\n ‣ feature/shiny-new-feature--mojo-10'\n ‣ 'chore/changelogUpdate_mojo-123'\n ‣ 'bugfix/fix-some-strange-bug_GAL-2345'\n`})},168:function(e){"use strict";const t=["stdin","stdout","stderr"];const r=e=>t.some(t=>Boolean(e[t]));e.exports=(e=>{if(!e){return null}if(e.stdio&&r(e)){throw new Error(`It's not possible to provide \`stdio\` in combination with one of ${t.map(e=>`\`${e}\``).join(", ")}`)}if(typeof e.stdio==="string"){return e.stdio}const n=e.stdio||[];if(!Array.isArray(n)){throw new TypeError(`Expected \`stdio\` to be of type \`string\` or \`Array\`, got \`${typeof n}\``)}const i=[];const s=Math.max(n.length,t.length);for(let r=0;r\n Knock Knock! 🔍\n
\n\n Just thought I'd let you know that your PR title and story title look quite different. PR titles\n that closely resemble the story title make it easier for reviewers to understand the context of the PR.\n
\n\n An easy-to-understand PR title a day makes the reviewer review away! 😛⚡️\n\n
Story Title | \n${e} | \n
---|---|
PR Title | \n${t} | \n
\n Check out this guide to learn more about PR best-practices.\n
\n `}else if(r>=.2&&r<=.4){return`\n Let's make that PR title a 💯 shall we? 💪\n
\n\n Your PR title and story title look slightly different. Just checking in to know if it was intentional!\n
\nStory Title | \n${e} | \n
---|---|
PR Title | \n${t} | \n
\n Check out this guide to learn more about PR best-practices.\n
\n `}return`I'm a bot and I 👍 this PR title. 🤖
\n\n `});t.shouldSkipBranchLint=((e,t)=>{if(p.BOT_BRANCH_PATTERNS.some(t=>t.test(e))){console.log(`You look like a bot 🤖 so we're letting you off the hook!`);return true}if(p.DEFAULT_BRANCH_PATTERNS.some(t=>t.test(e))){console.log(`Ignoring check for default branch ${e}`);return true}const r=new RegExp(t||"");if(!!t&&r.test(e)){console.log(`branch '${e}' ignored as it matches the ignore pattern '${t}' provided in skip-branches`);return true}console.log(`branch '${e}' does not match ignore pattern provided in 'skip-branches' option:`,r);return false});t.shouldUpdatePRDescription=(e=>typeof e==="string"&&!p.MARKER_REGEX.test(e));t.getLabelsForDisplay=(e=>{if(!e||!e.length){return"-"}const t=e.map(e=>`${e.name}`).join(", ");return t.replace(/\s+/," ")});t.getPRDescription=((e="",r)=>{const n=r.key.toUpperCase();return`\nSummary | \n${r.summary} | \n
---|---|
Type | \n\n \n ${r.type.name}\n | \n
Status | \n${r.status} | \n
Points | \n${r.estimate||"N/A"} | \n
Labels | \n${t.getLabelsForDisplay(r.labels)} | \n
This PR is too huge for one to review :broken_heart:
\n \nAdditions | \n${e} :no_good_woman: | \n
---|---|
Expected | \n:arrow_down: ${t} | \n
\n Consider breaking it down into multiple small PRs.\n
\n\n Check out this guide to learn more about PR best-practices.\n
\n `);t.getNoIdComment=(e=>{return`A JIRA Issue ID is missing from your branch name! 🦄
\nYour branch: ${e}
\nIf this is your first time contributing to this repository - welcome!
\nPlease refer to jira-lint to get started.\n
Without the JIRA Issue ID in your branch name you would lose out on automatic updates to JIRA via SCM; some GitHub status checks might fail.
\nValid sample branch names:\n\n ‣ feature/shiny-new-feature--mojo-10'\n ‣ 'chore/changelogUpdate_mojo-123'\n ‣ 'bugfix/fix-some-strange-bug_GAL-2345'\n`});t.isIssueStatusValid=((e,t,r)=>{if(!e){a.info("Skipping Jira issue status validation as shouldValidate is false");return true}return t.includes(r.status)});t.getInvalidIssueStatusComment=((e,t)=>`:broken_heart: The detected issue is not in one of the allowed statuses :broken_heart:
\nDetected Status | \n${e} | \n:x: | \n
---|---|---|
Allowed Statuses | \n${t} | \n:heavy_check_mark: | \n
Please ensure your jira story is in one of the allowed statuses
\n `)},168:function(e){"use strict";const t=["stdin","stdout","stderr"];const r=e=>t.some(t=>Boolean(e[t]));e.exports=(e=>{if(!e){return null}if(e.stdio&&r(e)){throw new Error(`It's not possible to provide \`stdio\` in combination with one of ${t.map(e=>`\`${e}\``).join(", ")}`)}if(typeof e.stdio==="string"){return e.stdio}const n=e.stdio||[];if(!Array.isArray(n)){throw new TypeError(`Expected \`stdio\` to be of type \`string\` or \`Array\`, got \`${typeof n}\``)}const i=[];const s=Math.max(n.length,t.length);for(let r=0;r:broken_heart: The detected issue is not in one of the allowed statuses :broken_heart:
+Detected Status | +${issueStatus} | +:x: | +
---|---|---|
Allowed Statuses | +${allowedStatuses} | +:heavy_check_mark: | +
Please ensure your jira story is in one of the allowed statuses
+ `;