├── .editorconfig ├── .github └── workflows │ ├── add-to-triage.yml │ ├── ci.yml │ └── deploy.yml ├── .gitignore ├── .npmrc ├── CONTRIBUTING.md ├── LICENSE ├── Procfile ├── README.md ├── docs ├── commit-message-check.md └── edit-pr-title-explanation.png ├── eslint.config.js ├── package-lock.json ├── package.json ├── src ├── app.js ├── constants.js └── plugins │ ├── auto-assign │ └── index.js │ ├── commit-message │ ├── createMessage.js │ ├── index.js │ └── util.js │ ├── index.js │ ├── needs-info │ └── index.js │ ├── recurring-issues │ └── index.js │ ├── release-monitor │ └── index.js │ └── wip │ └── index.js └── tests ├── __mocks__ └── probot-scheduler.js └── plugins ├── auto-assign └── index.js ├── commit-message ├── __snapshots__ │ └── index.js.snap └── index.js ├── needs-info └── index.js ├── recurring-issues └── index.js ├── release-monitor └── index.js └── wip └── index.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | trim_trailing_whitespace = true 7 | end_of_line = lf 8 | insert_final_newline = true 9 | 10 | [package.json] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.github/workflows/add-to-triage.yml: -------------------------------------------------------------------------------- 1 | name: Add to Triage 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | 8 | jobs: 9 | add-to-project: 10 | name: Add issue to project 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/add-to-project@v0.4.0 14 | with: 15 | project-url: https://github.com/orgs/eslint/projects/3 16 | github-token: ${{ secrets.PROJECT_BOT_TOKEN }} 17 | labeled: "triage:no" 18 | label-operator: NOT 19 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | jobs: 10 | lint: 11 | name: Lint 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Setup Node.js 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: 22.x 19 | - name: Install dependencies 20 | run: npm install 21 | - name: Lint files 22 | run: npm run lint 23 | test: 24 | name: Test 25 | strategy: 26 | matrix: 27 | os: [ubuntu-latest] 28 | node: [22.x] 29 | runs-on: ${{ matrix.os }} 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: actions/setup-node@v4 33 | with: 34 | node-version: ${{ matrix.node }} 35 | - name: Install dependencies 36 | run: npm install 37 | - name: Run tests 38 | run: npm test 39 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'deploy' 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Cloning repo 14 | uses: actions/checkout@v3 15 | with: 16 | fetch-depth: 0 17 | 18 | - name: Push to dokku 19 | uses: dokku/github-action@master 20 | with: 21 | branch: main 22 | git_remote_url: 'ssh://dokku@github-bot.eslint.org/eslint-github-bot' 23 | ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | test.js 3 | coverage/ 4 | build/ 5 | npm-debug.log 6 | .DS_Store 7 | tmp/ 8 | .idea 9 | jsdoc/ 10 | versions.json 11 | *.iml 12 | .eslintcache 13 | .cache 14 | /packages/**/node_modules 15 | /.vscode 16 | *.code-workspace 17 | .cursor 18 | .sublimelinterrc 19 | .svn 20 | /credentials.json 21 | *.pem 22 | .env 23 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock = true 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please be sure to read the contribution guidelines before making or requesting a change. 4 | 5 | ## Code of Conduct 6 | 7 | This project adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct). We kindly request that you read over our code of conduct before contributing. 8 | 9 | ## Filing Issues 10 | 11 | * To report a security vulnerability in `eslint-github-bot`, please use our [HackerOne program](https://hackerone.com/eslint). 12 | * To report an issue that does not have security impact, please [create an issue on GitHub](https://github.com/eslint/eslint-github-bot/issues/new). 13 | * To create a feature request, [create an issue on GitHub](https://github.com/eslint/eslint-github-bot/issues/new). 14 | 15 | Please keep in mind that `eslint-github-bot` is primarily intended for the ESLint team's use cases. You're welcome to use the code for your own purposes, but we are unlikely to accept a feature request unless we would use the feature for the ESLint team's repositories. 16 | 17 | ## Contributing Code 18 | 19 | Please sign our [Contributor License Agreement](https://cla.js.foundation/eslint/eslint) and read over the [Pull Request Guidelines](https://eslint.org/docs/developer-guide/contributing/pull-requests). 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm start 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://github.com/eslint/eslint-github-bot/workflows/CI/badge.svg)](https://github.com/eslint/eslint-github-bot/actions) 2 | 3 | # ESLint GitHub bot 4 | 5 | `eslint-github-bot` is a bot created with [probot](https://github.com/probot/probot) which automates some common tasks for repositories run by the ESLint team. 6 | 7 | ## Environment Variables: 8 | 9 | * `APP_ID` (required): The numeric GitHub app ID 10 | * `PRIVATE_KEY` (required): the contents of the private key you downloaded after creating the app. 11 | * `WEBHOOK_SECRET` (required): Secret setup for GitHub webhook or you generated when you created the app. 12 | * `PORT`: Port for web server _(optional, defaults to 8000)_. 13 | 14 | ## :wrench: Setup 15 | 16 | * Clone this repo 17 | * `npm install` 18 | * `npm test` 19 | 20 | To start the server locally, you'll need: 21 | 22 | * A PEM file 23 | * A `.env` file that specifies the required environment variables 24 | 25 | The `APP_ID` and `WEBHOOK_SECRET` need to be present but need not be the registered application ID or webhook secret to start the server. `PRIVATE_KEY` must be a valid PEM private key. 26 | 27 | #### Adding plugins 28 | 29 | To add a plugin: 30 | 31 | 1. Create the plugin as a new file in `src/plugins`. 32 | 1. Add the plugin to the list in `src/plugins/index.js`. 33 | 1. Add the plugin to the list in `src/app.js` to enable it by default. 34 | 35 | ## Deployment 36 | 37 | The bot is deployed to a [Dokku](https://dokku.com) instance named and is installed as a GitHub Application at the organization level. 38 | 39 | The URL to receive webhooks is the default for Probot, which is `/api/github/webhooks`. This must be configured for the app on the ESLint organization. 40 | 41 | ### Health Check 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/commit-message-check.md: -------------------------------------------------------------------------------- 1 | # commit-message status check 2 | 3 | ## Background 4 | 5 | `eslint-github-bot`'s commit message check ensures that all pull requests which get merged into `main` have a valid commit message, based on [ESLint's commit message guidelines](https://eslint.org/docs/developer-guide/contributing/pull-requests#step-2-make-your-changes). 6 | 7 | The ESLint team uses GitHub's "Squash and Merge" feature to merge pull requests. When using this feature, the default commit message for the squashed commit is the title of the pull request. To minimize the risk of an incorrect commit message getting merged into `main`, `eslint-github-bot` checks the title. 8 | 9 | ## How do I fix it? 10 | 11 | If this status check is failing on your pull request, you should fix your pull request title on github.com to conform to [ESLint's commit message guidelines](https://eslint.org/docs/developer-guide/contributing/pull-requests#step-2-make-your-changes). 12 | 13 | ![](./edit-pr-title-explanation.png) 14 | -------------------------------------------------------------------------------- /docs/edit-pr-title-explanation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eslint/eslint-github-bot/b8b950e73d1fd05f114cabf1722366d6dc7934a0/docs/edit-pr-title-explanation.png -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const { defineConfig, globalIgnores } = require("eslint/config"); 4 | const eslintConfigESLint = require("eslint-config-eslint/cjs"); 5 | const globals = require("globals"); 6 | 7 | module.exports = defineConfig([ 8 | globalIgnores(["coverage/"]), 9 | eslintConfigESLint, 10 | { 11 | rules: { 12 | camelcase: ["error", { properties: "never" }], 13 | } 14 | }, 15 | { 16 | files: ["eslint.config.js"], 17 | rules: { 18 | "n/no-unpublished-require": "off" 19 | } 20 | }, 21 | { 22 | files: ["tests/**/*.js"], 23 | languageOptions: { 24 | globals: { 25 | ...globals.jest 26 | } 27 | }, 28 | rules: { 29 | "n/no-unpublished-require": "off" 30 | } 31 | } 32 | ]); 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-github-bot", 3 | "version": "0.1.0", 4 | "description": "Plugin based Github bot for ESLint", 5 | "main": "./src/app.js", 6 | "scripts": { 7 | "lint": "eslint .", 8 | "lint:fix": "npm run lint -- --fix", 9 | "start": "node ./src/app.js", 10 | "test": "jest --colors --verbose --coverage" 11 | }, 12 | "author": "Gyandeep Singh ", 13 | "license": "MIT", 14 | "homepage": "https://github.com/eslint/eslint-github-bot", 15 | "repository": "eslint/eslint-github-bot", 16 | "bugs": "https://github.com/eslint/eslint-github-bot/issues/", 17 | "funding": "https://opencollective.com/eslint", 18 | "gitHooks": { 19 | "pre-commit": "lint-staged" 20 | }, 21 | "lint-staged": { 22 | "*.js": "eslint --fix" 23 | }, 24 | "dependencies": { 25 | "moment": "^2.30.1", 26 | "moment-timezone": "^0.5.46", 27 | "probot": "^13.4.1" 28 | }, 29 | "devDependencies": { 30 | "eslint": "^9.28.0", 31 | "eslint-config-eslint": "^11.0.0", 32 | "fetch-mock": "^12.2.0", 33 | "globals": "^16.2.0", 34 | "jest": "^29.7.0", 35 | "lint-staged": "^13.2.1", 36 | "yorkie": "^2.0.0" 37 | }, 38 | "keywords": [ 39 | "bot", 40 | "github", 41 | "events", 42 | "eslint" 43 | ], 44 | "jest": { 45 | "testMatch": [ 46 | "/tests/**/*.js" 47 | ], 48 | "testPathIgnorePatterns": [ 49 | "/tests/.eslintrc.js", 50 | "/tests/__mocks__" 51 | ], 52 | "coverageDirectory": "./coverage", 53 | "collectCoverage": false, 54 | "testEnvironment": "node" 55 | }, 56 | "engines": { 57 | "node": "22.x", 58 | "npm": "10.x" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Main file which starts the probot server and loads the plugins 3 | * @author Gyandeep Singh 4 | */ 5 | 6 | "use strict"; 7 | 8 | //----------------------------------------------------------------------------- 9 | // Requirements 10 | //----------------------------------------------------------------------------- 11 | 12 | const { run } = require("probot"); 13 | const plugins = require("./plugins"); 14 | 15 | //----------------------------------------------------------------------------- 16 | // Type Definitions 17 | //----------------------------------------------------------------------------- 18 | 19 | /** @typedef {import("probot").Probot} Probot */ 20 | 21 | //----------------------------------------------------------------------------- 22 | // Main 23 | //----------------------------------------------------------------------------- 24 | 25 | const enabledPlugins = new Set([ 26 | "autoAssign", 27 | "commitMessage", 28 | "needsInfo", 29 | "recurringIssues", 30 | "releaseMonitor", 31 | "wip" 32 | ]); 33 | 34 | /** 35 | * Assign the plugins to the robot. 36 | * @param {Probot} robot The Probot instance. 37 | * @returns {void} 38 | */ 39 | function appFn(robot) { 40 | Object.keys(plugins) 41 | .filter(pluginId => enabledPlugins.has(pluginId)) 42 | .forEach(pluginId => plugins[pluginId](robot)); 43 | } 44 | 45 | // start the server 46 | run(appFn); 47 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Shared constants for the bot 3 | * @author Nicholas C. Zakas 4 | */ 5 | 6 | "use strict"; 7 | 8 | module.exports = { 9 | }; 10 | -------------------------------------------------------------------------------- /src/plugins/auto-assign/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Automatically assigns issues to users who have indicated they're willing to submit a PR 3 | * @author xbinaryx 4 | */ 5 | 6 | "use strict"; 7 | 8 | //----------------------------------------------------------------------------- 9 | // Type Definitions 10 | //----------------------------------------------------------------------------- 11 | 12 | /** @typedef {import("probot").Context} ProbotContext */ 13 | 14 | //----------------------------------------------------------------------------- 15 | // Helpers 16 | //----------------------------------------------------------------------------- 17 | 18 | /** 19 | * Checks if the issue body contains text indicating the user is willing to submit a PR 20 | * @param {string} body The issue body text 21 | * @returns {boolean} True if the user indicated they're willing to submit a PR 22 | * @private 23 | */ 24 | function isWillingToSubmitPR(body) { 25 | return body 26 | .toLowerCase() 27 | .includes( 28 | "- [x] i am willing to submit a pull request" 29 | ); 30 | } 31 | 32 | /** 33 | * Handler for issue opened event 34 | * @param {ProbotContext} context probot context object 35 | * @returns {Promise} promise 36 | * @private 37 | */ 38 | async function issueOpenedHandler(context) { 39 | const { payload } = context; 40 | 41 | if (!isWillingToSubmitPR(payload.issue.body)) { 42 | return; 43 | } 44 | 45 | await context.octokit.issues.addAssignees( 46 | context.issue({ 47 | assignees: [payload.issue.user.login], 48 | }) 49 | ); 50 | } 51 | 52 | module.exports = (robot) => { 53 | robot.on("issues.opened", issueOpenedHandler); 54 | }; 55 | -------------------------------------------------------------------------------- /src/plugins/commit-message/createMessage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Create the message that needs to be commented in the Pull Request. 3 | * @author Aniketh Saha 4 | */ 5 | 6 | "use strict"; 7 | 8 | const MESSAGE_LENGTH_LIMIT = 72; 9 | 10 | const ERROR_MESSAGES = { 11 | SPACE_AFTER_TAG_COLON: "- There should be a space following the initial tag and colon, for example 'feat: Message'.", 12 | NON_LOWERCASE_FIRST_LETTER_TAG: "- The first letter of the tag should be in lowercase", 13 | NON_MATCHED_TAG: "- The commit message tag wasn't recognized. Did you mean \"docs\", \"fix\", or \"feat\"?", 14 | LONG_MESSAGE: `- The length of the commit message must be less than or equal to ${MESSAGE_LENGTH_LIMIT}` 15 | }; 16 | 17 | /** 18 | * Create a comment message body with the error details 19 | * @param {Array} errors list of the error codes 20 | * @param {string} username username of the PR author 21 | * @returns {string} the message to comment 22 | * @private 23 | */ 24 | module.exports = function commentMessage(errors, username) { 25 | const errorMessages = []; 26 | 27 | errors.forEach(err => { 28 | if (ERROR_MESSAGES[err]) { 29 | errorMessages.push(ERROR_MESSAGES[err]); 30 | } 31 | }); 32 | 33 | return `Hi @${username}!, thanks for the Pull Request 34 | 35 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 36 | 37 | ${errorMessages.join("\n")} 38 | 39 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 40 | 41 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 42 | `; 43 | 44 | }; 45 | -------------------------------------------------------------------------------- /src/plugins/commit-message/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Validates that commit messages are formatted according 3 | * to the guidelines. 4 | * @author Gyandeep Singh 5 | */ 6 | 7 | "use strict"; 8 | 9 | //----------------------------------------------------------------------------- 10 | // Requirements 11 | //----------------------------------------------------------------------------- 12 | 13 | const commentMessage = require("./createMessage"); 14 | const { TAG_LABELS } = require("./util"); 15 | 16 | //----------------------------------------------------------------------------- 17 | // Type Definitions 18 | //----------------------------------------------------------------------------- 19 | 20 | /** @typedef {import("probot").Context} ProbotContext */ 21 | 22 | //----------------------------------------------------------------------------- 23 | // Helpers 24 | //----------------------------------------------------------------------------- 25 | 26 | const TAG_REGEX = /^(?:feat|build|chore|docs|fix|refactor|test|ci|perf)!?: /u; 27 | 28 | const TAG_SPACE_REGEX = /^(?:[a-z]+!?: )/u; 29 | 30 | const LOWERCASE_TAG_REGEX = /^[a-z]/u; 31 | 32 | const MESSAGE_LENGTH_LIMIT = 72; 33 | 34 | const EXCLUDED_REPOSITORY_NAMES = new Set([ 35 | "eslint.github.io", 36 | "tsc-meetings" 37 | ]); 38 | 39 | //----------------------------------------------------------------------------- 40 | // Functions 41 | //----------------------------------------------------------------------------- 42 | 43 | /** 44 | * Apply different checks on the commit message 45 | * @param {string} message commit message 46 | * @returns {boolean} `true` if the commit message is valid 47 | * @private 48 | */ 49 | function getCommitMessageErrors(message) { 50 | const commitTitle = message.split(/\r?\n/u)[0]; 51 | const errors = []; 52 | 53 | if (message.startsWith("Revert \"")) { 54 | return errors; 55 | } 56 | 57 | // First, check tag and summary length 58 | if (!TAG_REGEX.test(commitTitle)) { 59 | errors.push("NON_MATCHED_TAG"); 60 | } 61 | 62 | // Check if there is any whitespace after the : 63 | if (!TAG_SPACE_REGEX.test(commitTitle)) { 64 | errors.push("SPACE_AFTER_TAG_COLON"); 65 | } 66 | 67 | if (!LOWERCASE_TAG_REGEX.test(commitTitle)) { 68 | errors.push("NON_LOWERCASE_FIRST_LETTER_TAG"); 69 | } 70 | 71 | if (!(commitTitle.length <= MESSAGE_LENGTH_LIMIT)) { 72 | errors.push("LONG_MESSAGE"); 73 | } 74 | 75 | return errors; 76 | } 77 | 78 | /** 79 | * Apply different checks on the commit message 80 | * @param {string} message commit message 81 | * @returns {Array} The labels to add to the PR. 82 | * @private 83 | */ 84 | function getCommitMessageLabels(message) { 85 | const commitTitle = message.split(/\r?\n/u)[0]; 86 | const [tag] = commitTitle.match(TAG_REGEX) || [""]; 87 | 88 | return TAG_LABELS.get(tag.trim()); 89 | } 90 | 91 | /** 92 | * If the first commit message is not legal then it adds a comment 93 | * @param {ProbotContext} context context given by the probot 94 | * @returns {Promise} promise 95 | * @private 96 | */ 97 | async function processCommitMessage(context) { 98 | 99 | /* 100 | * We care about the default commit message that will appear when the 101 | * PR is merged. If the PR has exactly one commit, this is the commit 102 | * message of that commit. If the PR has more than one commit, this 103 | * is the title of the PR. 104 | */ 105 | const { payload, octokit } = context; 106 | 107 | if (EXCLUDED_REPOSITORY_NAMES.has(payload.repository.name)) { 108 | return; 109 | } 110 | 111 | const allCommits = await octokit.pulls.listCommits(context.pullRequest()); 112 | const messageToCheck = payload.pull_request.title; 113 | const errors = getCommitMessageErrors(messageToCheck); 114 | let description; 115 | let state; 116 | 117 | if (errors.length === 0) { 118 | state = "success"; 119 | description = "PR title follows commit message guidelines"; 120 | 121 | const labels = getCommitMessageLabels(messageToCheck); 122 | 123 | if (labels) { 124 | await context.octokit.issues.addLabels(context.issue({ labels })); 125 | } 126 | 127 | } else { 128 | state = "failure"; 129 | description = "PR title doesn't follow commit message guidelines"; 130 | } 131 | 132 | // create status on the last commit 133 | await octokit.repos.createCommitStatus( 134 | context.repo({ 135 | sha: allCommits.data.at(-1).sha, 136 | state, 137 | target_url: "https://github.com/eslint/eslint-github-bot/blob/main/docs/commit-message-check.md", 138 | description, 139 | context: "commit-message" 140 | }) 141 | ); 142 | 143 | if (state === "failure") { 144 | await octokit.issues.createComment(context.issue({ 145 | body: commentMessage(errors, payload.pull_request.user.login) 146 | })); 147 | } 148 | 149 | } 150 | 151 | /** 152 | * check commit message 153 | */ 154 | 155 | module.exports = robot => { 156 | robot.on("pull_request.opened", processCommitMessage); 157 | robot.on("pull_request.reopened", processCommitMessage); 158 | robot.on("pull_request.synchronize", processCommitMessage); 159 | robot.on("pull_request.edited", processCommitMessage); 160 | }; 161 | -------------------------------------------------------------------------------- /src/plugins/commit-message/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Shared data for plugin and tests of commit-message 3 | * @author Nicholas C. Zakas 4 | */ 5 | 6 | "use strict"; 7 | 8 | exports.TAG_LABELS = new Map([ 9 | ["feat:", ["feature"]], 10 | ["feat!:", ["feature", "breaking"]], 11 | ["build:", ["build"]], 12 | ["chore:", ["chore"]], 13 | ["docs:", ["documentation"]], 14 | ["fix:", ["bug"]], 15 | ["fix!:", ["bug", "breaking"]], 16 | ["refactor:", ["chore"]], 17 | ["test:", ["chore"]], 18 | ["ci:", ["build"]], 19 | ["perf:", ["chore"]] 20 | ]); 21 | -------------------------------------------------------------------------------- /src/plugins/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Exports all plugins for easy inclusion elsewhere. 3 | * @author Gyandeep Singh 4 | */ 5 | 6 | "use strict"; 7 | 8 | /** 9 | * All the exposed plugins 10 | * 11 | * Note that exported plugins are not automatically loaded into 12 | * the bot. You need to also update app.js. 13 | */ 14 | 15 | module.exports = { 16 | autoAssign: require("./auto-assign"), 17 | commitMessage: require("./commit-message"), 18 | needsInfo: require("./needs-info"), 19 | recurringIssues: require("./recurring-issues"), 20 | releaseMonitor: require("./release-monitor"), 21 | wip: require("./wip") 22 | }; 23 | -------------------------------------------------------------------------------- /src/plugins/needs-info/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview It add a comment on issue when needs info label is added to it. 3 | * @author Gyandeep Singh 4 | */ 5 | 6 | "use strict"; 7 | 8 | const needInfoLabel = "needs info"; 9 | 10 | /** 11 | * Create the comment for the need info 12 | * @returns {string} comment message 13 | * @private 14 | */ 15 | function commentMessage() { 16 | return ` 17 | It looks like there wasn't enough information for us to know how to help you, so we're closing the issue. 18 | 19 | Thanks for your understanding. 20 | 21 | [//]: # (needs-info) 22 | `; 23 | } 24 | 25 | /** 26 | * Check if the needs info label is present or not 27 | * @param {Object} label added label object 28 | * @returns {boolean} True if it does contain needs info label 29 | * @private 30 | */ 31 | function hasNeedInfoLabel(label) { 32 | return label.name === needInfoLabel; 33 | } 34 | 35 | /** 36 | * If the label is need info then add the comment 37 | * @param {Object} context event payload from github 38 | * @returns {undefined} 39 | * @private 40 | */ 41 | async function check(context) { 42 | const { payload, octokit } = context; 43 | 44 | if (payload.issue.labels.some(hasNeedInfoLabel)) { 45 | await octokit.issues.createComment(context.issue({ 46 | body: commentMessage() 47 | })); 48 | } 49 | } 50 | 51 | /** 52 | * If the label is need info then add the comment when issue is labeled 53 | */ 54 | 55 | module.exports = robot => { 56 | robot.on("issues.closed", check); 57 | }; 58 | -------------------------------------------------------------------------------- /src/plugins/recurring-issues/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Creates new issues after specified old issues are closed 3 | * @author Teddy Katz 4 | */ 5 | 6 | "use strict"; 7 | 8 | //----------------------------------------------------------------------------- 9 | // Requirements 10 | //----------------------------------------------------------------------------- 11 | 12 | const moment = require("moment-timezone"); 13 | 14 | //----------------------------------------------------------------------------- 15 | // Type Definitions 16 | //----------------------------------------------------------------------------- 17 | 18 | /** @typedef {import("probot").Context} ProbotContext */ 19 | /** @typedef {import("probot").ProbotOctokit} ProbotOctokit */ 20 | 21 | //----------------------------------------------------------------------------- 22 | // Helpers 23 | //----------------------------------------------------------------------------- 24 | 25 | /** 26 | * Gets the desired issue body for a release issue, given the date of the release. 27 | * @param {Moment} releaseDate The date of the release, as Moment UTC date 28 | * @returns {Promise} The text of the issue 29 | */ 30 | async function getReleaseIssueBody(releaseDate) { 31 | return ` 32 | 33 | The next scheduled release will occur on ${releaseDate.format("dddd, MMMM Do, YYYY")}. 34 | 35 | ## Release Day Checklist 36 | 37 | - [ ] Remove the 'tsc agenda' label on this issue 38 | - [ ] Review open pull requests and merge any that are [ready](https://eslint.org/docs/maintainer-guide/pullrequests#when-to-merge-a-pull-request) 39 | - [ ] Verify if there are other packages (i.e., \`espree\`, \`eslint-scope\`, \`eslint-visitor-keys\`, \`@eslint/eslintrc\`) that need to be released first 40 | - [ ] Release \`@eslint/js\` to match the upcoming \`eslint\` version in [Jenkins](https://jenkins2.eslint.org) 41 | - [ ] Update \`package.json\` in the \`eslint\` repo with new versions from the preceding steps (create and merge a pull request) 42 | - [ ] Start the release on [Jenkins](https://jenkins2.eslint.org) 43 | - [ ] Update the release blog post: 44 | - [ ] Add a "Highlights" section for any noteworthy changes. 45 | - [ ] In the \`authors\` frontmatter, replace \`eslintbot\` with your GitHub username. 46 | - [ ] Remove the \`draft: true\` line in frontmatter. 47 | - [ ] Make a release announcement on Twitter 48 | - [ ] Make a release announcement in the Discord '#announcements' channel 49 | - [ ] Add a comment to this issue saying the release is out 50 | - [ ] Add the 'patch release pending' label to this issue 51 | 52 | ## Two Days After Release Day Checklist 53 | 54 | Typically Monday for regular releases; two days after patch releases. 55 | 56 | - [ ] Check the issues list for any regression issues 57 | 58 | ## No Regressions Checklist 59 | 60 | - [ ] Remove the 'patch release pending' label from this issue 61 | - [ ] Close this issue 62 | 63 | ## Patch Release Checklist 64 | 65 | - [ ] Resolve the regression by merging any necessary fixes 66 | - [ ] Start the release on [Jenkins](https://jenkins2.eslint.org) 67 | - [ ] Update the release blog post: 68 | - [ ] Add a "Highlights" section for any noteworthy changes. 69 | - [ ] In the \`authors\` frontmatter, replace \`eslintbot\` with your GitHub username. 70 | - [ ] Remove the \`draft: true\` line in frontmatter. 71 | - [ ] Make a release announcement on Twitter 72 | - [ ] Make a release announcement in the Discord '#announcements' channel 73 | - [ ] Add a comment to this issue saying the release is out 74 | - [ ] Wait two days and repeat the Two Days After a Release checklist 75 | - [ ] Close this issue 76 | 77 | ## Followup 78 | 79 | Please use this issue to document how the release went, any problems during the release, and anything the team might want to know about the release process. This issue should be closed after all patch releases have been completed (or there was no patch release needed). 80 | 81 | Resources: 82 | 83 | * [Release guidelines](https://eslint.org/docs/maintainer-guide/releases) 84 | 85 | `.trim(); 86 | } 87 | 88 | /** 89 | * Gets the members of a particular team on GitHub. 90 | * @param {Object} options The options to use for this function. 91 | * @param {ProbotOctokit} options.octokit A GitHub API client. 92 | * @param {string} options.organizationName The name of the organization that owns the team. 93 | * @param {string} options.teamName The name of the team. 94 | * @returns {{login: string, name: (string|null)}} A list of team member login names and full names 95 | */ 96 | async function getTeamMembers({ octokit, organizationName, teamName }) { 97 | 98 | /* 99 | * NOTE: This will fail if the organization contains more than 100 teams. This isn't 100 | * close to being a problem right now, so it hasn't been worth figuring out a good 101 | * way to paginate yet, but that would be a good enhancement in the future. 102 | */ 103 | const teams = await octokit.teams.list({ org: organizationName, per_page: 100 }).then(res => res.data); 104 | const desiredTeam = teams.find(team => team.slug === teamName); 105 | 106 | if (!desiredTeam) { 107 | throw new Error(`No team with name ${teamName} found`); 108 | } 109 | 110 | const teamMembers = await octokit.teams.listMembersInOrg({ team_slug: desiredTeam.slug, org: organizationName, per_page: 100 }).then(res => res.data); 111 | 112 | return Promise.all(teamMembers.map(async member => ({ 113 | login: member.login, 114 | name: await octokit.users.getByUsername({ username: member.login }).then(res => res.data.name) 115 | }))); 116 | } 117 | 118 | /** 119 | * Formats a list of team members' names and GitHub usernames into a bulleted Markdown list 120 | * @param {{name: string, login: string}[]} teamMembers Information about team members 121 | * @returns {string} Markdown text containing a bulleted list of names 122 | */ 123 | function formatTeamMembers(teamMembers) { 124 | return teamMembers.map(({ login, name }) => `- ${name || login} (@${login}) - TSC`).join("\n"); 125 | } 126 | 127 | /** 128 | * Gets the desired issue body for a release issue, given the date and of the meeting 129 | * @param {Object} options Configure the issue body 130 | * @param {Moment} options.meetingDate The date and time when the meeting will take place, as a Moment date 131 | * @param {GitHub} options.octokit A GitHub API client for fetching TSC team members 132 | * @param {string} options.organizationName The name of the organization that owns the TSC team 133 | * @param {string} options.tscTeamName The name of the TSC team 134 | * @returns {Promise} The text of the issue 135 | */ 136 | async function getTscMeetingIssueBody({ meetingDate, octokit, organizationName, tscTeamName }) { 137 | const timeFormatString = "ddd DD-MMM-YYYY HH:mm"; 138 | 139 | return ` 140 | 141 | # Time 142 | 143 | UTC ${moment.utc(meetingDate).format(timeFormatString)}: 144 | - Los Angeles: ${moment.tz(meetingDate, "America/Los_Angeles").format(timeFormatString)} 145 | - Chicago: ${moment.tz(meetingDate, "America/Chicago").format(timeFormatString)} 146 | - New York: ${moment.tz(meetingDate, "America/New_York").format(timeFormatString)} 147 | - Madrid: ${moment.tz(meetingDate, "Europe/Madrid").format(timeFormatString)} 148 | - Moscow: ${moment.tz(meetingDate, "Europe/Moscow").format(timeFormatString)} 149 | - Tokyo: ${moment.tz(meetingDate, "Asia/Tokyo").format(timeFormatString)} 150 | - Sydney: ${moment.tz(meetingDate, "Australia/Sydney").format(timeFormatString)} 151 | 152 | # Location 153 | 154 | https://eslint.org/chat/tsc-meetings 155 | 156 | # Agenda 157 | 158 | Extracted from: 159 | 160 | * Issues and pull requests from the ESLint organization with the ["tsc agenda" label](https://github.com/issues?utf8=%E2%9C%93&q=org%3Aeslint+label%3A%22tsc+agenda%22) 161 | * Comments on this issue 162 | 163 | # Invited 164 | 165 | ${await getTeamMembers({ octokit, organizationName, teamName: tscTeamName }).then(formatTeamMembers)} 166 | 167 | # Public participation 168 | 169 | Anyone is welcome to attend the meeting as observers. We ask that you refrain from interrupting the meeting once it begins and only participate if invited to do so. 170 | 171 | `.trim(); 172 | } 173 | 174 | /* eslint-disable camelcase -- issue_number is part of the GitHub API response */ 175 | /** 176 | * A function that determines whether an issue on GitHub was closed multiple times in the past. 177 | * @param {ProbotOctokit} octokit A GitHub API client 178 | * @param {Object} issueInfo information about the issue 179 | * @param {string} issueInfo.owner The owner of the repository 180 | * @param {string} issueInfo.repo The repo name 181 | * @param {number} issueInfo.issue_number The issue number on GitHub 182 | * @returns {Promise} A Promise that fulfills with `true` if the issue was closed multiple times 183 | */ 184 | async function issueWasClosedMultipleTimes(octokit, { owner, repo, issue_number }) { 185 | const issueEvents = await octokit.issues.listEvents({ 186 | owner, 187 | repo, 188 | issue_number, 189 | per_page: 100 190 | }).then(res => res.data); 191 | 192 | return issueEvents.filter(eventObj => eventObj.event === "closed").length > 1; 193 | } 194 | /* eslint-enable camelcase -- issue_number is part of the GitHub API response */ 195 | 196 | /** 197 | * Creates a webhook handler that responds when an issue is closed for the first time 198 | * by creating a new issue. 199 | * @param {Object} options Configure the webhook handler 200 | * @param {string} options.labelTrigger A label that the closed issue must have for this webhook 201 | * to run 202 | * @param {string[]} options.newLabels The labels that the newly-created issue should be given 203 | * @param {Function} options.shouldCreateNewIssue A function that accepts an object with `title` and 204 | * `body` properties as an argument, and returns a Promise for a boolean indicating whether 205 | * a new issue should be created. If the Promise fulfills with `false`, creating a new issue 206 | * will be cancelled. 207 | * @param {Function} options.getNewIssueInfo A function to get the title and body of the new issue. 208 | * Accepts a single parameter with `title` and `body` properties for the old issue, as well as 209 | * a `github` property containing a GitHub API client and an `organizationName` property containing 210 | * the name of the organization that owns the repo where the issue was filed. Returns a promise 211 | * for an object with `title` and `body` properties for the new issue. 212 | * @returns {function(probot.Context): Promise} A Probot event listener 213 | */ 214 | function createIssueHandler({ labelTrigger, newLabels, shouldCreateNewIssue, getNewIssueInfo }) { 215 | 216 | /** 217 | * A Probot event listener that creates a new issue when an old issue is closed. 218 | * @param {ProbotContext} context A Probot context object 219 | * @returns {Promise} A Promise that fulfills when the new issue is created. 220 | */ 221 | return async context => { 222 | const { title: oldTitle, body: oldBody, labels: oldLabels } = context.payload.issue; 223 | 224 | // If the issue does not have the correct label, skip it. 225 | if (!oldLabels.some(label => label.name === labelTrigger)) { 226 | return; 227 | } 228 | 229 | // If the issue was previously closed and then reopened, skip it. 230 | if (await issueWasClosedMultipleTimes(context.octokit, context.issue())) { 231 | return; 232 | } 233 | 234 | if (!await shouldCreateNewIssue({ title: oldTitle, body: oldBody })) { 235 | return; 236 | } 237 | 238 | const { title: newTitle, body: newBody } = await getNewIssueInfo({ 239 | title: oldTitle, 240 | body: oldBody, 241 | octokit: context.octokit, 242 | organizationName: context.repo().owner 243 | }); 244 | 245 | // Create a new issue. 246 | await context.octokit.issues.create( 247 | context.repo({ 248 | title: newTitle, 249 | body: newBody, 250 | labels: newLabels 251 | }) 252 | ); 253 | }; 254 | } 255 | 256 | const RELEASE_ISSUE_TITLE_FORMAT = "[Scheduled release for ]MMMM Do, YYYY"; 257 | const releaseIssueHandler = createIssueHandler({ 258 | labelTrigger: "release", 259 | newLabels: ["release", "tsc agenda", "triage:no"], 260 | async shouldCreateNewIssue({ title }) { 261 | return moment.utc(title, RELEASE_ISSUE_TITLE_FORMAT, true).isValid(); 262 | }, 263 | async getNewIssueInfo({ title }) { 264 | const oldReleaseDate = moment.utc(title, RELEASE_ISSUE_TITLE_FORMAT, true); 265 | const newReleaseDate = oldReleaseDate.clone().add({ weeks: 2 }); 266 | 267 | return { 268 | title: newReleaseDate.format(RELEASE_ISSUE_TITLE_FORMAT), 269 | body: await getReleaseIssueBody(newReleaseDate) 270 | }; 271 | } 272 | }); 273 | 274 | const TSC_MEETING_TITLE_FORMAT = "[TSC meeting ]DD-MMMM-YYYY"; 275 | const tscMeetingIssueHandler = createIssueHandler({ 276 | labelTrigger: "tsc meeting", 277 | newLabels: ["tsc meeting", "triage:no"], 278 | async shouldCreateNewIssue({ title }) { 279 | return moment.utc(title, TSC_MEETING_TITLE_FORMAT, true).isValid(); 280 | }, 281 | async getNewIssueInfo({ title, octokit, organizationName }) { 282 | const meetingDate = moment.tz(title, TSC_MEETING_TITLE_FORMAT, "America/New_York") 283 | .hour(16) 284 | .add({ weeks: 2 }); 285 | 286 | 287 | const newTitle = meetingDate.format(TSC_MEETING_TITLE_FORMAT); 288 | const newBody = await getTscMeetingIssueBody({ 289 | meetingDate, 290 | octokit, 291 | organizationName, 292 | tscTeamName: "eslint-tsc" 293 | }); 294 | 295 | return { title: newTitle, body: newBody }; 296 | } 297 | }); 298 | 299 | module.exports = robot => { 300 | robot.on("issues.closed", releaseIssueHandler); 301 | robot.on("issues.closed", tscMeetingIssueHandler); 302 | }; 303 | -------------------------------------------------------------------------------- /src/plugins/release-monitor/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Handle PR status after the release and when the release is complete 3 | * @author Gyandeep Singh 4 | */ 5 | 6 | "use strict"; 7 | 8 | //----------------------------------------------------------------------------- 9 | // Type Definitions 10 | //----------------------------------------------------------------------------- 11 | 12 | /** @typedef {import("probot").Context} ProbotContext */ 13 | 14 | //----------------------------------------------------------------------------- 15 | // Helpers 16 | //----------------------------------------------------------------------------- 17 | 18 | const PATCH_COMMIT_MESSAGE_REGEX = /^(?:Build|Chore|Docs|Fix|Upgrade):/u; 19 | const POST_RELEASE_LABEL = "patch release pending"; 20 | const RELEASE_LABEL = "release"; 21 | 22 | /** 23 | * Apply different checks on the commit message to see if its ok for a patch release 24 | * @param {string} message commit message 25 | * @returns {boolean} `true` if the commit message is valid for patch release 26 | * @private 27 | */ 28 | function isMessageValidForPatchRelease(message) { 29 | return PATCH_COMMIT_MESSAGE_REGEX.test(message); 30 | } 31 | 32 | /** 33 | * Get the sha value from the latest commit 34 | * @param {Object[]} allCommits A list of commit objects from GitHub's API 35 | * @returns {string} latest commit sha 36 | * @private 37 | */ 38 | function pluckLatestCommitSha(allCommits) { 39 | return allCommits.at(-1).sha; 40 | } 41 | 42 | /** 43 | * Gets all the open PR 44 | * @param {ProbotContext} context context object 45 | * @returns {Promise} collection of pr objects 46 | * @private 47 | */ 48 | function getAllOpenPRs(context) { 49 | return context.octokit.paginate( 50 | context.octokit.pulls.list, 51 | context.repo({ 52 | state: "open" 53 | }) 54 | ); 55 | } 56 | 57 | /** 58 | * Create status on the PR 59 | * @param {Object} options Configure the status 60 | * @param {Object} options.context probot context object 61 | * @param {string} options.state state can be either success or failure 62 | * @param {string} options.sha sha for the commit 63 | * @param {string} options.description description for the status 64 | * @param {string} options.targetUrl The URL that the status should link to 65 | * @returns {Promise} Resolves when the status is created on the PR 66 | * @private 67 | */ 68 | function createStatusOnPR({ context, state, sha, description, targetUrl }) { 69 | return context.octokit.repos.createCommitStatus( 70 | context.repo({ 71 | sha, 72 | state, 73 | target_url: targetUrl || "", 74 | description, 75 | context: "release-monitor" 76 | }) 77 | ); 78 | } 79 | 80 | /** 81 | * Get all the commits for a PR 82 | * @param {Object} options Configure the request 83 | * @param {Object} options.context Probot context object 84 | * @param {Object} options.pr pull request object from GitHub's API 85 | * @returns {Promise} A Promise that fulfills with a list of commit objects from GitHub's API 86 | * @private 87 | */ 88 | async function getAllCommitsForPR({ context, pr }) { 89 | const commits = await context.octokit.pulls.listCommits( 90 | context.repo({ pull_number: pr.number }) 91 | ); 92 | 93 | return commits.data; 94 | } 95 | 96 | /** 97 | * Creates an appropriate status on a PR, based on the current patch release state and the PR type. 98 | * * If there is no pending patch release, creates a success status with the message "No patch release is pending". 99 | * * If there is a pending patch release and this PR is semver-patch, creates a success status with the message 100 | * "This change is semver-patch" and a link to the release issue. 101 | * * If there is a pending patch release and this PR is not semver-patch, creates a pending status with the message 102 | * "A patch release is pending" and a link to the release issue. 103 | * @param {Object} options Configure the status 104 | * @param {Object} options.context Probot context object 105 | * @param {Object} options.pr pull request object from GitHub's API 106 | * @param {string|null} options.pendingReleaseIssueUrl If a patch release is pending, this is the HTML URL of the 107 | * release issue. Otherwise, this is null. 108 | * @returns {Promise} A Promise that fulfills when the status check has been created 109 | */ 110 | async function createAppropriateStatusForPR({ context, pr, pendingReleaseIssueUrl }) { 111 | const allCommits = await getAllCommitsForPR({ context, pr }); 112 | const sha = pluckLatestCommitSha(allCommits); 113 | 114 | if (pendingReleaseIssueUrl === null) { 115 | await createStatusOnPR({ 116 | context, 117 | sha, 118 | state: "success", 119 | description: "No patch release is pending" 120 | }); 121 | } else if (isMessageValidForPatchRelease(pr.title)) { 122 | await createStatusOnPR({ 123 | context, 124 | sha, 125 | state: "success", 126 | description: "This change is semver-patch", 127 | targetUrl: pendingReleaseIssueUrl 128 | }); 129 | } else { 130 | await createStatusOnPR({ 131 | context, 132 | sha, 133 | state: "pending", 134 | description: "A patch release is pending", 135 | targetUrl: pendingReleaseIssueUrl 136 | }); 137 | } 138 | } 139 | 140 | /** 141 | * Get all the commits for a PR 142 | * @param {Object} options Configure the status 143 | * @param {Object} options.context probot context object 144 | * @param {string|null} options.pendingReleaseIssueUrl A link to the pending release issue, if it exists 145 | * @returns {Promise} Resolves when the status is created on the PR 146 | * @private 147 | */ 148 | async function createStatusOnAllPRs({ context, pendingReleaseIssueUrl }) { 149 | const allOpenPrs = await getAllOpenPRs(context); 150 | 151 | return Promise.all(allOpenPrs.map(pr => 152 | createAppropriateStatusForPR({ 153 | context, 154 | pr, 155 | pendingReleaseIssueUrl 156 | }))); 157 | } 158 | 159 | /** 160 | * Release label is present 161 | * @param {Array} labels collection of label objects 162 | * @returns {boolean} True if release label is present 163 | * @private 164 | */ 165 | function hasReleaseLabel(labels) { 166 | return labels.some(({ name }) => name === RELEASE_LABEL); 167 | } 168 | 169 | /** 170 | * Check if it is Post Release label 171 | * @param {Object} label label options 172 | * @param {string} label.name label name 173 | * @returns {boolean} True if its post release label 174 | * @private 175 | */ 176 | function isPostReleaseLabel({ name }) { 177 | return name === POST_RELEASE_LABEL; 178 | } 179 | 180 | /** 181 | * Handler for issue label event 182 | * @param {ProbotContext} context probot context object 183 | * @returns {Promise} promise 184 | * @private 185 | */ 186 | async function issueLabeledHandler(context) { 187 | 188 | // check if the label is post-release and the same issue has release label 189 | if (isPostReleaseLabel(context.payload.label) && hasReleaseLabel(context.payload.issue.labels)) { 190 | await createStatusOnAllPRs({ 191 | context, 192 | pendingReleaseIssueUrl: context.payload.issue.html_url 193 | }); 194 | } 195 | } 196 | 197 | /** 198 | * Handler for issue close event 199 | * @param {ProbotContext} context probot context object 200 | * @returns {Promise} promise 201 | * @private 202 | */ 203 | async function issueCloseHandler(context) { 204 | 205 | // check if the closed issue is a release issue 206 | if (hasReleaseLabel(context.payload.issue.labels)) { 207 | await createStatusOnAllPRs({ 208 | context, 209 | pendingReleaseIssueUrl: null 210 | }); 211 | } 212 | } 213 | 214 | /** 215 | * Handler for pull request open and reopen event 216 | * @param {ProbotContext} context probot context object 217 | * @returns {Promise} promise 218 | * @private 219 | */ 220 | async function prOpenHandler(context) { 221 | 222 | /** 223 | * check if the release issue has the label for no semver minor merge please 224 | * false: add success status to pr 225 | * true: add failure message if its not a fix or doc pr else success 226 | */ 227 | const { data: releaseIssues } = await context.octokit.issues.listForRepo( 228 | context.repo({ 229 | labels: `${RELEASE_LABEL},${POST_RELEASE_LABEL}` 230 | }) 231 | ); 232 | 233 | await createAppropriateStatusForPR({ 234 | context, 235 | pr: context.payload.pull_request, 236 | pendingReleaseIssueUrl: releaseIssues.length ? releaseIssues[0].html_url : null 237 | }); 238 | } 239 | 240 | module.exports = robot => { 241 | robot.on("issues.labeled", issueLabeledHandler); 242 | robot.on("issues.closed", issueCloseHandler); 243 | robot.on( 244 | [ 245 | "pull_request.opened", 246 | "pull_request.reopened", 247 | "pull_request.synchronize", 248 | "pull_request.edited" 249 | ], 250 | prOpenHandler 251 | ); 252 | }; 253 | -------------------------------------------------------------------------------- /src/plugins/wip/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Handle PR status for works in progress, using either "WIP" in title or "do not merge" label 3 | * @author Kevin Partington 4 | */ 5 | 6 | "use strict"; 7 | 8 | //----------------------------------------------------------------------------- 9 | // Type Definitions 10 | //----------------------------------------------------------------------------- 11 | 12 | /** @typedef {import("probot").Context} ProbotContext */ 13 | 14 | //----------------------------------------------------------------------------- 15 | // Helpers 16 | //----------------------------------------------------------------------------- 17 | 18 | const WIP_IN_TITLE_REGEX = /^WIP:|\(WIP\)/iu; 19 | const DO_NOT_MERGE_LABEL = "do not merge"; 20 | 21 | /** 22 | * Create status on the PR 23 | * @param {Object} options Configure the status 24 | * @param {ProbotContext} options.context probot context object 25 | * @param {string} options.state state can be either success or failure 26 | * @param {string} options.sha sha for the commit 27 | * @param {string} options.description description for the status 28 | * @param {string} options.targetUrl The URL that the status should link to 29 | * @returns {Promise} Resolves when the status is created on the PR 30 | * @private 31 | */ 32 | function createStatusOnPR({ context, state, sha, description, targetUrl }) { 33 | return context.octokit.repos.createCommitStatus( 34 | context.repo({ 35 | sha, 36 | state, 37 | target_url: targetUrl || "", 38 | description, 39 | context: "wip" 40 | }) 41 | ); 42 | } 43 | 44 | /** 45 | * Creates a pending status on the PR to indicate it is a WIP. 46 | * @param {ProbotContext} context Probot context object 47 | * @param {string} sha The SHA hash representing the latest commit to the PR. 48 | * @returns {Promise} A Promise that will fulfill when the status check is created 49 | */ 50 | function createPendingWipStatusOnPR(context, sha) { 51 | return createStatusOnPR({ 52 | context, 53 | sha, 54 | state: "pending", 55 | description: "This PR appears to be a work in progress" 56 | }); 57 | } 58 | 59 | /** 60 | * Creates a pending status on the PR to indicate it is WIP. 61 | * @param {ProbotContext} context Probot context object 62 | * @param {string} sha The SHA hash representing the latest commit to the PR. 63 | * @returns {Promise} A Promise that will fulfill when the status check is created 64 | */ 65 | function createSuccessWipStatusOnPR(context, sha) { 66 | return createStatusOnPR({ 67 | context, 68 | sha, 69 | state: "success", 70 | description: "This PR is no longer a work in progress" 71 | }); 72 | } 73 | 74 | /** 75 | * Check to see if there is an existing pending wip status check on the PR. 76 | * If so, create a success wip status check. 77 | * @param {ProbotContext} context Probot context object 78 | * @param {string} sha Commit SHA hash associated with the status check 79 | * @returns {Promise} A Promise which will resolve when a success status check 80 | * is created on the PR, or an immediately-resolved Promise if no status check 81 | * is needed. 82 | */ 83 | async function maybeResolveWipStatusOnPR(context, sha) { 84 | const repoAndRef = context.repo({ 85 | ref: sha 86 | }); 87 | 88 | const { octokit } = context; 89 | const statuses = await octokit.paginate(octokit.repos.getCombinedStatusForRef, repoAndRef); 90 | const statusCheckExists = statuses.some(status => status.context === "wip"); 91 | 92 | if (statusCheckExists) { 93 | return createSuccessWipStatusOnPR(context, sha); 94 | } 95 | 96 | return null; 97 | } 98 | 99 | /** 100 | * Get all the commits for a PR 101 | * @param {Object} options Configure the request 102 | * @param {ProbotContext} options.context Probot context object 103 | * @param {Object} options.pr pull request object from GitHub's API 104 | * @returns {Promise} A Promise that fulfills with a list of commit objects from GitHub's API 105 | * @private 106 | */ 107 | async function getAllCommitsForPR({ context, pr }) { 108 | const { data: commitList } = await context.octokit.pulls.listCommits( 109 | context.repo({ pull_number: pr.number }) 110 | ); 111 | 112 | return commitList; 113 | } 114 | 115 | /** 116 | * Checks to see if a PR has the "do not merge" label. 117 | * @param {Array} labels collection of label objects 118 | * @returns {boolean} True if release label is present 119 | * @private 120 | */ 121 | function hasDoNotMergeLabel(labels) { 122 | return labels.some(({ name }) => name === DO_NOT_MERGE_LABEL); 123 | } 124 | 125 | /** 126 | * Get the sha value from the latest commit 127 | * @param {Object[]} allCommits A list of commit objects from GitHub's API 128 | * @returns {string} latest commit sha 129 | * @private 130 | */ 131 | function pluckLatestCommitSha(allCommits) { 132 | return allCommits.at(-1).sha; 133 | } 134 | 135 | /** 136 | * Checks to see if a PR's title has a WIP indication. 137 | * @param {Object} pr Pull request object 138 | * @returns {boolean} True if the PR title indicates WIP 139 | * @private 140 | */ 141 | function prHasWipTitle(pr) { 142 | return WIP_IN_TITLE_REGEX.test(pr.title); 143 | } 144 | 145 | /** 146 | * Handler for PR events (opened, reopened, synchronize, edited, labeled, 147 | * unlabeled). 148 | * @param {ProbotContext} context probot context object 149 | * @returns {Promise} promise 150 | * @private 151 | */ 152 | async function prChangedHandler(context) { 153 | const pr = context.payload.pull_request; 154 | 155 | const allCommits = await getAllCommitsForPR({ 156 | context, 157 | pr 158 | }); 159 | 160 | const sha = pluckLatestCommitSha(allCommits); 161 | 162 | const isWip = prHasWipTitle(pr) || hasDoNotMergeLabel(pr.labels); 163 | 164 | if (isWip) { 165 | return createPendingWipStatusOnPR(context, sha); 166 | } 167 | 168 | return maybeResolveWipStatusOnPR(context, sha); 169 | } 170 | 171 | //----------------------------------------------------------------------------- 172 | // Robot 173 | //----------------------------------------------------------------------------- 174 | 175 | module.exports = robot => { 176 | robot.on( 177 | [ 178 | "pull_request.opened", 179 | "pull_request.reopened", 180 | "pull_request.edited", 181 | "pull_request.labeled", 182 | "pull_request.unlabeled", 183 | "pull_request.synchronize" 184 | ], 185 | prChangedHandler 186 | ); 187 | }; 188 | -------------------------------------------------------------------------------- /tests/__mocks__/probot-scheduler.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = () => { }; 3 | -------------------------------------------------------------------------------- /tests/plugins/auto-assign/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Tests for the auto-assign plugin 3 | */ 4 | 5 | "use strict"; 6 | 7 | //----------------------------------------------------------------------------- 8 | // Requirements 9 | //----------------------------------------------------------------------------- 10 | 11 | const { Probot, ProbotOctokit } = require("probot"); 12 | const { default: fetchMock } = require("fetch-mock"); 13 | const autoAssign = require("../../../src/plugins/auto-assign"); 14 | 15 | //----------------------------------------------------------------------------- 16 | // Helpers 17 | //----------------------------------------------------------------------------- 18 | 19 | const API_URL = "https://api.github.com/repos/test/repo-test/issues/1/assignees"; 20 | 21 | /** 22 | * Returns an array of strings representing the issue body. 23 | * @param {'x' | ''} checkMark Check mark to use in the issue body. 24 | * @returns {string[]} Array of strings representing the issue body. 25 | */ 26 | function issueBodies(checkMark) { 27 | return [ 28 | `- [${checkMark}] I am willing to submit a pull request for this issue.`, 29 | `- [${checkMark}] I am willing to submit a pull request for this change.`, 30 | `- [${checkMark}] I am willing to submit a pull request to implement this rule.`, 31 | `- [${checkMark}] I am willing to submit a pull request to implement this change.` 32 | ] 33 | } 34 | 35 | //----------------------------------------------------------------------------- 36 | // Tests 37 | //----------------------------------------------------------------------------- 38 | 39 | describe("auto-assign", () => { 40 | let bot = null; 41 | 42 | beforeEach(() => { 43 | bot = new Probot({ 44 | appId: 1, 45 | githubToken: "test", 46 | Octokit: ProbotOctokit.defaults(instanceOptions => ({ 47 | ...instanceOptions, 48 | throttle: { enabled: false }, 49 | retry: { enabled: false } 50 | })) 51 | }); 52 | 53 | autoAssign(bot); 54 | 55 | fetchMock.mockGlobal().post( 56 | API_URL, 57 | { status: 200 } 58 | ); 59 | }); 60 | 61 | afterEach(() => { 62 | fetchMock.unmockGlobal(); 63 | fetchMock.removeRoutes(); 64 | fetchMock.clearHistory(); 65 | }); 66 | 67 | describe("issue opened", () => { 68 | test("assigns issue to author when they indicate willingness to submit PR", async () => { 69 | for (const body of issueBodies("x")) { 70 | await bot.receive({ 71 | name: "issues", 72 | payload: { 73 | action: "opened", 74 | installation: { 75 | id: 1 76 | }, 77 | issue: { 78 | number: 1, 79 | body, 80 | user: { 81 | login: "user-a" 82 | } 83 | }, 84 | repository: { 85 | name: "repo-test", 86 | owner: { 87 | login: "test" 88 | } 89 | } 90 | } 91 | }); 92 | 93 | expect(fetchMock.callHistory.called(API_URL)).toBeTruthy(); 94 | } 95 | }); 96 | 97 | test("does not assign issue when author does not indicate willingness to submit PR", async () => { 98 | for (const body of issueBodies("")) { 99 | await bot.receive({ 100 | name: "issues", 101 | payload: { 102 | action: "opened", 103 | installation: { 104 | id: 1 105 | }, 106 | issue: { 107 | number: 1, 108 | body, 109 | user: { 110 | login: "user-a" 111 | } 112 | }, 113 | repository: { 114 | name: "repo-test", 115 | owner: { 116 | login: "test" 117 | } 118 | } 119 | } 120 | }); 121 | 122 | expect(fetchMock.callHistory.called(API_URL)).toBe(false); 123 | } 124 | }); 125 | }); 126 | }); 127 | -------------------------------------------------------------------------------- /tests/plugins/commit-message/__snapshots__/index.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`commit-message pull request edited Posts failure status if PR title is not correct 1`] = ` 4 | "Hi @user-a!, thanks for the Pull Request 5 | 6 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 7 | 8 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 9 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 10 | 11 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 12 | 13 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 14 | " 15 | `; 16 | 17 | exports[`commit-message pull request edited Posts failure status if PR title is not correct even when the first commit message is correct 1`] = ` 18 | "Hi @user-a!, thanks for the Pull Request 19 | 20 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 21 | 22 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 23 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 24 | 25 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 26 | 27 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 28 | " 29 | `; 30 | 31 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: " New: " 1`] = ` 32 | "Hi @user-a!, thanks for the Pull Request 33 | 34 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 35 | 36 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 37 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 38 | - The first letter of the tag should be in lowercase 39 | 40 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 41 | 42 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 43 | " 44 | `; 45 | 46 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: ": " 1`] = ` 47 | "Hi @user-a!, thanks for the Pull Request 48 | 49 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 50 | 51 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 52 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 53 | - The first letter of the tag should be in lowercase 54 | 55 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 56 | 57 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 58 | " 59 | `; 60 | 61 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Foo: " 1`] = ` 62 | "Hi @user-a!, thanks for the Pull Request 63 | 64 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 65 | 66 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 67 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 68 | - The first letter of the tag should be in lowercase 69 | 70 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 71 | 72 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 73 | " 74 | `; 75 | 76 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New " 1`] = ` 77 | "Hi @user-a!, thanks for the Pull Request 78 | 79 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 80 | 81 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 82 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 83 | - The first letter of the tag should be in lowercase 84 | 85 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 86 | 87 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 88 | " 89 | `; 90 | 91 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New : " 1`] = ` 92 | "Hi @user-a!, thanks for the Pull Request 93 | 94 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 95 | 96 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 97 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 98 | - The first letter of the tag should be in lowercase 99 | 100 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 101 | 102 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 103 | " 104 | `; 105 | 106 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New:" 1`] = ` 107 | "Hi @user-a!, thanks for the Pull Request 108 | 109 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 110 | 111 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 112 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 113 | - The first letter of the tag should be in lowercase 114 | 115 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 116 | 117 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 118 | " 119 | `; 120 | 121 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Neww: " 1`] = ` 122 | "Hi @user-a!, thanks for the Pull Request 123 | 124 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 125 | 126 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 127 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 128 | - The first letter of the tag should be in lowercase 129 | 130 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 131 | 132 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 133 | " 134 | `; 135 | 136 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Revert: " 1`] = ` 137 | "Hi @user-a!, thanks for the Pull Request 138 | 139 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 140 | 141 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 142 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 143 | - The first letter of the tag should be in lowercase 144 | 145 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 146 | 147 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 148 | " 149 | `; 150 | 151 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: "feat" 1`] = ` 152 | "Hi @user-a!, thanks for the Pull Request 153 | 154 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 155 | 156 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 157 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 158 | 159 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 160 | 161 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 162 | " 163 | `; 164 | 165 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: "nNew: " 1`] = ` 166 | "Hi @user-a!, thanks for the Pull Request 167 | 168 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 169 | 170 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 171 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 172 | 173 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 174 | 175 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 176 | " 177 | `; 178 | 179 | exports[`commit-message pull request edited Posts failure status if PR with multiple commits has invalid tag prefix in the title: "new: " 1`] = ` 180 | "Hi @user-a!, thanks for the Pull Request 181 | 182 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 183 | 184 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 185 | 186 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 187 | 188 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 189 | " 190 | `; 191 | 192 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: " New: " 1`] = ` 193 | "Hi @user-a!, thanks for the Pull Request 194 | 195 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 196 | 197 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 198 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 199 | - The first letter of the tag should be in lowercase 200 | 201 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 202 | 203 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 204 | " 205 | `; 206 | 207 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: ": " 1`] = ` 208 | "Hi @user-a!, thanks for the Pull Request 209 | 210 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 211 | 212 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 213 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 214 | - The first letter of the tag should be in lowercase 215 | 216 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 217 | 218 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 219 | " 220 | `; 221 | 222 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: "Foo: " 1`] = ` 223 | "Hi @user-a!, thanks for the Pull Request 224 | 225 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 226 | 227 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 228 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 229 | - The first letter of the tag should be in lowercase 230 | 231 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 232 | 233 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 234 | " 235 | `; 236 | 237 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: "New " 1`] = ` 238 | "Hi @user-a!, thanks for the Pull Request 239 | 240 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 241 | 242 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 243 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 244 | - The first letter of the tag should be in lowercase 245 | 246 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 247 | 248 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 249 | " 250 | `; 251 | 252 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: "New : " 1`] = ` 253 | "Hi @user-a!, thanks for the Pull Request 254 | 255 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 256 | 257 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 258 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 259 | - The first letter of the tag should be in lowercase 260 | 261 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 262 | 263 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 264 | " 265 | `; 266 | 267 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: "New:" 1`] = ` 268 | "Hi @user-a!, thanks for the Pull Request 269 | 270 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 271 | 272 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 273 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 274 | - The first letter of the tag should be in lowercase 275 | 276 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 277 | 278 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 279 | " 280 | `; 281 | 282 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: "Neww: " 1`] = ` 283 | "Hi @user-a!, thanks for the Pull Request 284 | 285 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 286 | 287 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 288 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 289 | - The first letter of the tag should be in lowercase 290 | 291 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 292 | 293 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 294 | " 295 | `; 296 | 297 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: "Revert: " 1`] = ` 298 | "Hi @user-a!, thanks for the Pull Request 299 | 300 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 301 | 302 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 303 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 304 | - The first letter of the tag should be in lowercase 305 | 306 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 307 | 308 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 309 | " 310 | `; 311 | 312 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: "feat" 1`] = ` 313 | "Hi @user-a!, thanks for the Pull Request 314 | 315 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 316 | 317 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 318 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 319 | 320 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 321 | 322 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 323 | " 324 | `; 325 | 326 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: "nNew: " 1`] = ` 327 | "Hi @user-a!, thanks for the Pull Request 328 | 329 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 330 | 331 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 332 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 333 | 334 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 335 | 336 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 337 | " 338 | `; 339 | 340 | exports[`commit-message pull request edited Posts failure status if the PR title has invalid tag prefix: "new: " 1`] = ` 341 | "Hi @user-a!, thanks for the Pull Request 342 | 343 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 344 | 345 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 346 | 347 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 348 | 349 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 350 | " 351 | `; 352 | 353 | exports[`commit-message pull request edited Posts failure status if the PR title is longer than 72 chars and don't set labels 1`] = ` 354 | "Hi @user-a!, thanks for the Pull Request 355 | 356 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 357 | 358 | - The length of the commit message must be less than or equal to 72 359 | 360 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 361 | 362 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 363 | " 364 | `; 365 | 366 | exports[`commit-message pull request edited Posts failure status if there are multiple commit messages and the title is invalid 1`] = ` 367 | "Hi @user-a!, thanks for the Pull Request 368 | 369 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 370 | 371 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 372 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 373 | 374 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 375 | 376 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 377 | " 378 | `; 379 | 380 | exports[`commit-message pull request edited Posts failure status if there are multiple commit messages and the title is too long 1`] = ` 381 | "Hi @user-a!, thanks for the Pull Request 382 | 383 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 384 | 385 | - The length of the commit message must be less than or equal to 72 386 | 387 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 388 | 389 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 390 | " 391 | `; 392 | 393 | exports[`commit-message pull request opened Posts failure status if PR title is not correct 1`] = ` 394 | "Hi @user-a!, thanks for the Pull Request 395 | 396 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 397 | 398 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 399 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 400 | 401 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 402 | 403 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 404 | " 405 | `; 406 | 407 | exports[`commit-message pull request opened Posts failure status if PR title is not correct even when the first commit message is correct 1`] = ` 408 | "Hi @user-a!, thanks for the Pull Request 409 | 410 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 411 | 412 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 413 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 414 | 415 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 416 | 417 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 418 | " 419 | `; 420 | 421 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: " New: " 1`] = ` 422 | "Hi @user-a!, thanks for the Pull Request 423 | 424 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 425 | 426 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 427 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 428 | - The first letter of the tag should be in lowercase 429 | 430 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 431 | 432 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 433 | " 434 | `; 435 | 436 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: ": " 1`] = ` 437 | "Hi @user-a!, thanks for the Pull Request 438 | 439 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 440 | 441 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 442 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 443 | - The first letter of the tag should be in lowercase 444 | 445 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 446 | 447 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 448 | " 449 | `; 450 | 451 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Foo: " 1`] = ` 452 | "Hi @user-a!, thanks for the Pull Request 453 | 454 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 455 | 456 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 457 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 458 | - The first letter of the tag should be in lowercase 459 | 460 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 461 | 462 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 463 | " 464 | `; 465 | 466 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New " 1`] = ` 467 | "Hi @user-a!, thanks for the Pull Request 468 | 469 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 470 | 471 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 472 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 473 | - The first letter of the tag should be in lowercase 474 | 475 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 476 | 477 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 478 | " 479 | `; 480 | 481 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New : " 1`] = ` 482 | "Hi @user-a!, thanks for the Pull Request 483 | 484 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 485 | 486 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 487 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 488 | - The first letter of the tag should be in lowercase 489 | 490 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 491 | 492 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 493 | " 494 | `; 495 | 496 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New:" 1`] = ` 497 | "Hi @user-a!, thanks for the Pull Request 498 | 499 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 500 | 501 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 502 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 503 | - The first letter of the tag should be in lowercase 504 | 505 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 506 | 507 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 508 | " 509 | `; 510 | 511 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Neww: " 1`] = ` 512 | "Hi @user-a!, thanks for the Pull Request 513 | 514 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 515 | 516 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 517 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 518 | - The first letter of the tag should be in lowercase 519 | 520 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 521 | 522 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 523 | " 524 | `; 525 | 526 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Revert: " 1`] = ` 527 | "Hi @user-a!, thanks for the Pull Request 528 | 529 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 530 | 531 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 532 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 533 | - The first letter of the tag should be in lowercase 534 | 535 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 536 | 537 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 538 | " 539 | `; 540 | 541 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "feat" 1`] = ` 542 | "Hi @user-a!, thanks for the Pull Request 543 | 544 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 545 | 546 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 547 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 548 | 549 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 550 | 551 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 552 | " 553 | `; 554 | 555 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "nNew: " 1`] = ` 556 | "Hi @user-a!, thanks for the Pull Request 557 | 558 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 559 | 560 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 561 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 562 | 563 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 564 | 565 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 566 | " 567 | `; 568 | 569 | exports[`commit-message pull request opened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "new: " 1`] = ` 570 | "Hi @user-a!, thanks for the Pull Request 571 | 572 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 573 | 574 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 575 | 576 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 577 | 578 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 579 | " 580 | `; 581 | 582 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: " New: " 1`] = ` 583 | "Hi @user-a!, thanks for the Pull Request 584 | 585 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 586 | 587 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 588 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 589 | - The first letter of the tag should be in lowercase 590 | 591 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 592 | 593 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 594 | " 595 | `; 596 | 597 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: ": " 1`] = ` 598 | "Hi @user-a!, thanks for the Pull Request 599 | 600 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 601 | 602 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 603 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 604 | - The first letter of the tag should be in lowercase 605 | 606 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 607 | 608 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 609 | " 610 | `; 611 | 612 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: "Foo: " 1`] = ` 613 | "Hi @user-a!, thanks for the Pull Request 614 | 615 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 616 | 617 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 618 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 619 | - The first letter of the tag should be in lowercase 620 | 621 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 622 | 623 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 624 | " 625 | `; 626 | 627 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: "New " 1`] = ` 628 | "Hi @user-a!, thanks for the Pull Request 629 | 630 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 631 | 632 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 633 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 634 | - The first letter of the tag should be in lowercase 635 | 636 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 637 | 638 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 639 | " 640 | `; 641 | 642 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: "New : " 1`] = ` 643 | "Hi @user-a!, thanks for the Pull Request 644 | 645 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 646 | 647 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 648 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 649 | - The first letter of the tag should be in lowercase 650 | 651 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 652 | 653 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 654 | " 655 | `; 656 | 657 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: "New:" 1`] = ` 658 | "Hi @user-a!, thanks for the Pull Request 659 | 660 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 661 | 662 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 663 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 664 | - The first letter of the tag should be in lowercase 665 | 666 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 667 | 668 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 669 | " 670 | `; 671 | 672 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: "Neww: " 1`] = ` 673 | "Hi @user-a!, thanks for the Pull Request 674 | 675 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 676 | 677 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 678 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 679 | - The first letter of the tag should be in lowercase 680 | 681 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 682 | 683 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 684 | " 685 | `; 686 | 687 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: "Revert: " 1`] = ` 688 | "Hi @user-a!, thanks for the Pull Request 689 | 690 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 691 | 692 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 693 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 694 | - The first letter of the tag should be in lowercase 695 | 696 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 697 | 698 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 699 | " 700 | `; 701 | 702 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: "feat" 1`] = ` 703 | "Hi @user-a!, thanks for the Pull Request 704 | 705 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 706 | 707 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 708 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 709 | 710 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 711 | 712 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 713 | " 714 | `; 715 | 716 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: "nNew: " 1`] = ` 717 | "Hi @user-a!, thanks for the Pull Request 718 | 719 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 720 | 721 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 722 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 723 | 724 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 725 | 726 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 727 | " 728 | `; 729 | 730 | exports[`commit-message pull request opened Posts failure status if the PR title has invalid tag prefix: "new: " 1`] = ` 731 | "Hi @user-a!, thanks for the Pull Request 732 | 733 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 734 | 735 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 736 | 737 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 738 | 739 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 740 | " 741 | `; 742 | 743 | exports[`commit-message pull request opened Posts failure status if the PR title is longer than 72 chars and don't set labels 1`] = ` 744 | "Hi @user-a!, thanks for the Pull Request 745 | 746 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 747 | 748 | - The length of the commit message must be less than or equal to 72 749 | 750 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 751 | 752 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 753 | " 754 | `; 755 | 756 | exports[`commit-message pull request opened Posts failure status if there are multiple commit messages and the title is invalid 1`] = ` 757 | "Hi @user-a!, thanks for the Pull Request 758 | 759 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 760 | 761 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 762 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 763 | 764 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 765 | 766 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 767 | " 768 | `; 769 | 770 | exports[`commit-message pull request opened Posts failure status if there are multiple commit messages and the title is too long 1`] = ` 771 | "Hi @user-a!, thanks for the Pull Request 772 | 773 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 774 | 775 | - The length of the commit message must be less than or equal to 72 776 | 777 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 778 | 779 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 780 | " 781 | `; 782 | 783 | exports[`commit-message pull request reopened Posts failure status if PR title is not correct 1`] = ` 784 | "Hi @user-a!, thanks for the Pull Request 785 | 786 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 787 | 788 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 789 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 790 | 791 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 792 | 793 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 794 | " 795 | `; 796 | 797 | exports[`commit-message pull request reopened Posts failure status if PR title is not correct even when the first commit message is correct 1`] = ` 798 | "Hi @user-a!, thanks for the Pull Request 799 | 800 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 801 | 802 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 803 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 804 | 805 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 806 | 807 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 808 | " 809 | `; 810 | 811 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: " New: " 1`] = ` 812 | "Hi @user-a!, thanks for the Pull Request 813 | 814 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 815 | 816 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 817 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 818 | - The first letter of the tag should be in lowercase 819 | 820 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 821 | 822 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 823 | " 824 | `; 825 | 826 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: ": " 1`] = ` 827 | "Hi @user-a!, thanks for the Pull Request 828 | 829 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 830 | 831 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 832 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 833 | - The first letter of the tag should be in lowercase 834 | 835 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 836 | 837 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 838 | " 839 | `; 840 | 841 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Foo: " 1`] = ` 842 | "Hi @user-a!, thanks for the Pull Request 843 | 844 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 845 | 846 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 847 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 848 | - The first letter of the tag should be in lowercase 849 | 850 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 851 | 852 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 853 | " 854 | `; 855 | 856 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New " 1`] = ` 857 | "Hi @user-a!, thanks for the Pull Request 858 | 859 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 860 | 861 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 862 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 863 | - The first letter of the tag should be in lowercase 864 | 865 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 866 | 867 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 868 | " 869 | `; 870 | 871 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New : " 1`] = ` 872 | "Hi @user-a!, thanks for the Pull Request 873 | 874 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 875 | 876 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 877 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 878 | - The first letter of the tag should be in lowercase 879 | 880 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 881 | 882 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 883 | " 884 | `; 885 | 886 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New:" 1`] = ` 887 | "Hi @user-a!, thanks for the Pull Request 888 | 889 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 890 | 891 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 892 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 893 | - The first letter of the tag should be in lowercase 894 | 895 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 896 | 897 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 898 | " 899 | `; 900 | 901 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Neww: " 1`] = ` 902 | "Hi @user-a!, thanks for the Pull Request 903 | 904 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 905 | 906 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 907 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 908 | - The first letter of the tag should be in lowercase 909 | 910 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 911 | 912 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 913 | " 914 | `; 915 | 916 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Revert: " 1`] = ` 917 | "Hi @user-a!, thanks for the Pull Request 918 | 919 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 920 | 921 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 922 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 923 | - The first letter of the tag should be in lowercase 924 | 925 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 926 | 927 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 928 | " 929 | `; 930 | 931 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "feat" 1`] = ` 932 | "Hi @user-a!, thanks for the Pull Request 933 | 934 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 935 | 936 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 937 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 938 | 939 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 940 | 941 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 942 | " 943 | `; 944 | 945 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "nNew: " 1`] = ` 946 | "Hi @user-a!, thanks for the Pull Request 947 | 948 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 949 | 950 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 951 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 952 | 953 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 954 | 955 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 956 | " 957 | `; 958 | 959 | exports[`commit-message pull request reopened Posts failure status if PR with multiple commits has invalid tag prefix in the title: "new: " 1`] = ` 960 | "Hi @user-a!, thanks for the Pull Request 961 | 962 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 963 | 964 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 965 | 966 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 967 | 968 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 969 | " 970 | `; 971 | 972 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: " New: " 1`] = ` 973 | "Hi @user-a!, thanks for the Pull Request 974 | 975 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 976 | 977 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 978 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 979 | - The first letter of the tag should be in lowercase 980 | 981 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 982 | 983 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 984 | " 985 | `; 986 | 987 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: ": " 1`] = ` 988 | "Hi @user-a!, thanks for the Pull Request 989 | 990 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 991 | 992 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 993 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 994 | - The first letter of the tag should be in lowercase 995 | 996 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 997 | 998 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 999 | " 1000 | `; 1001 | 1002 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: "Foo: " 1`] = ` 1003 | "Hi @user-a!, thanks for the Pull Request 1004 | 1005 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1006 | 1007 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1008 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1009 | - The first letter of the tag should be in lowercase 1010 | 1011 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1012 | 1013 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1014 | " 1015 | `; 1016 | 1017 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: "New " 1`] = ` 1018 | "Hi @user-a!, thanks for the Pull Request 1019 | 1020 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1021 | 1022 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1023 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1024 | - The first letter of the tag should be in lowercase 1025 | 1026 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1027 | 1028 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1029 | " 1030 | `; 1031 | 1032 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: "New : " 1`] = ` 1033 | "Hi @user-a!, thanks for the Pull Request 1034 | 1035 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1036 | 1037 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1038 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1039 | - The first letter of the tag should be in lowercase 1040 | 1041 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1042 | 1043 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1044 | " 1045 | `; 1046 | 1047 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: "New:" 1`] = ` 1048 | "Hi @user-a!, thanks for the Pull Request 1049 | 1050 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1051 | 1052 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1053 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1054 | - The first letter of the tag should be in lowercase 1055 | 1056 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1057 | 1058 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1059 | " 1060 | `; 1061 | 1062 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: "Neww: " 1`] = ` 1063 | "Hi @user-a!, thanks for the Pull Request 1064 | 1065 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1066 | 1067 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1068 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1069 | - The first letter of the tag should be in lowercase 1070 | 1071 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1072 | 1073 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1074 | " 1075 | `; 1076 | 1077 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: "Revert: " 1`] = ` 1078 | "Hi @user-a!, thanks for the Pull Request 1079 | 1080 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1081 | 1082 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1083 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1084 | - The first letter of the tag should be in lowercase 1085 | 1086 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1087 | 1088 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1089 | " 1090 | `; 1091 | 1092 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: "feat" 1`] = ` 1093 | "Hi @user-a!, thanks for the Pull Request 1094 | 1095 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1096 | 1097 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1098 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1099 | 1100 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1101 | 1102 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1103 | " 1104 | `; 1105 | 1106 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: "nNew: " 1`] = ` 1107 | "Hi @user-a!, thanks for the Pull Request 1108 | 1109 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1110 | 1111 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1112 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1113 | 1114 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1115 | 1116 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1117 | " 1118 | `; 1119 | 1120 | exports[`commit-message pull request reopened Posts failure status if the PR title has invalid tag prefix: "new: " 1`] = ` 1121 | "Hi @user-a!, thanks for the Pull Request 1122 | 1123 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1124 | 1125 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1126 | 1127 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1128 | 1129 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1130 | " 1131 | `; 1132 | 1133 | exports[`commit-message pull request reopened Posts failure status if the PR title is longer than 72 chars and don't set labels 1`] = ` 1134 | "Hi @user-a!, thanks for the Pull Request 1135 | 1136 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1137 | 1138 | - The length of the commit message must be less than or equal to 72 1139 | 1140 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1141 | 1142 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1143 | " 1144 | `; 1145 | 1146 | exports[`commit-message pull request reopened Posts failure status if there are multiple commit messages and the title is invalid 1`] = ` 1147 | "Hi @user-a!, thanks for the Pull Request 1148 | 1149 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1150 | 1151 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1152 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1153 | 1154 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1155 | 1156 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1157 | " 1158 | `; 1159 | 1160 | exports[`commit-message pull request reopened Posts failure status if there are multiple commit messages and the title is too long 1`] = ` 1161 | "Hi @user-a!, thanks for the Pull Request 1162 | 1163 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1164 | 1165 | - The length of the commit message must be less than or equal to 72 1166 | 1167 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1168 | 1169 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1170 | " 1171 | `; 1172 | 1173 | exports[`commit-message pull request synchronize Posts failure status if PR title is not correct 1`] = ` 1174 | "Hi @user-a!, thanks for the Pull Request 1175 | 1176 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1177 | 1178 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1179 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1180 | 1181 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1182 | 1183 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1184 | " 1185 | `; 1186 | 1187 | exports[`commit-message pull request synchronize Posts failure status if PR title is not correct even when the first commit message is correct 1`] = ` 1188 | "Hi @user-a!, thanks for the Pull Request 1189 | 1190 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1191 | 1192 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1193 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1194 | 1195 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1196 | 1197 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1198 | " 1199 | `; 1200 | 1201 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: " New: " 1`] = ` 1202 | "Hi @user-a!, thanks for the Pull Request 1203 | 1204 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1205 | 1206 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1207 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1208 | - The first letter of the tag should be in lowercase 1209 | 1210 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1211 | 1212 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1213 | " 1214 | `; 1215 | 1216 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: ": " 1`] = ` 1217 | "Hi @user-a!, thanks for the Pull Request 1218 | 1219 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1220 | 1221 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1222 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1223 | - The first letter of the tag should be in lowercase 1224 | 1225 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1226 | 1227 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1228 | " 1229 | `; 1230 | 1231 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Foo: " 1`] = ` 1232 | "Hi @user-a!, thanks for the Pull Request 1233 | 1234 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1235 | 1236 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1237 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1238 | - The first letter of the tag should be in lowercase 1239 | 1240 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1241 | 1242 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1243 | " 1244 | `; 1245 | 1246 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New " 1`] = ` 1247 | "Hi @user-a!, thanks for the Pull Request 1248 | 1249 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1250 | 1251 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1252 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1253 | - The first letter of the tag should be in lowercase 1254 | 1255 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1256 | 1257 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1258 | " 1259 | `; 1260 | 1261 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New : " 1`] = ` 1262 | "Hi @user-a!, thanks for the Pull Request 1263 | 1264 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1265 | 1266 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1267 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1268 | - The first letter of the tag should be in lowercase 1269 | 1270 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1271 | 1272 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1273 | " 1274 | `; 1275 | 1276 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: "New:" 1`] = ` 1277 | "Hi @user-a!, thanks for the Pull Request 1278 | 1279 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1280 | 1281 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1282 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1283 | - The first letter of the tag should be in lowercase 1284 | 1285 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1286 | 1287 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1288 | " 1289 | `; 1290 | 1291 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Neww: " 1`] = ` 1292 | "Hi @user-a!, thanks for the Pull Request 1293 | 1294 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1295 | 1296 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1297 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1298 | - The first letter of the tag should be in lowercase 1299 | 1300 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1301 | 1302 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1303 | " 1304 | `; 1305 | 1306 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: "Revert: " 1`] = ` 1307 | "Hi @user-a!, thanks for the Pull Request 1308 | 1309 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1310 | 1311 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1312 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1313 | - The first letter of the tag should be in lowercase 1314 | 1315 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1316 | 1317 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1318 | " 1319 | `; 1320 | 1321 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: "feat" 1`] = ` 1322 | "Hi @user-a!, thanks for the Pull Request 1323 | 1324 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1325 | 1326 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1327 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1328 | 1329 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1330 | 1331 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1332 | " 1333 | `; 1334 | 1335 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: "nNew: " 1`] = ` 1336 | "Hi @user-a!, thanks for the Pull Request 1337 | 1338 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1339 | 1340 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1341 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1342 | 1343 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1344 | 1345 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1346 | " 1347 | `; 1348 | 1349 | exports[`commit-message pull request synchronize Posts failure status if PR with multiple commits has invalid tag prefix in the title: "new: " 1`] = ` 1350 | "Hi @user-a!, thanks for the Pull Request 1351 | 1352 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1353 | 1354 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1355 | 1356 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1357 | 1358 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1359 | " 1360 | `; 1361 | 1362 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: " New: " 1`] = ` 1363 | "Hi @user-a!, thanks for the Pull Request 1364 | 1365 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1366 | 1367 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1368 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1369 | - The first letter of the tag should be in lowercase 1370 | 1371 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1372 | 1373 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1374 | " 1375 | `; 1376 | 1377 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: ": " 1`] = ` 1378 | "Hi @user-a!, thanks for the Pull Request 1379 | 1380 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1381 | 1382 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1383 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1384 | - The first letter of the tag should be in lowercase 1385 | 1386 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1387 | 1388 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1389 | " 1390 | `; 1391 | 1392 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: "Foo: " 1`] = ` 1393 | "Hi @user-a!, thanks for the Pull Request 1394 | 1395 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1396 | 1397 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1398 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1399 | - The first letter of the tag should be in lowercase 1400 | 1401 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1402 | 1403 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1404 | " 1405 | `; 1406 | 1407 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: "New " 1`] = ` 1408 | "Hi @user-a!, thanks for the Pull Request 1409 | 1410 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1411 | 1412 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1413 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1414 | - The first letter of the tag should be in lowercase 1415 | 1416 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1417 | 1418 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1419 | " 1420 | `; 1421 | 1422 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: "New : " 1`] = ` 1423 | "Hi @user-a!, thanks for the Pull Request 1424 | 1425 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1426 | 1427 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1428 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1429 | - The first letter of the tag should be in lowercase 1430 | 1431 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1432 | 1433 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1434 | " 1435 | `; 1436 | 1437 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: "New:" 1`] = ` 1438 | "Hi @user-a!, thanks for the Pull Request 1439 | 1440 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1441 | 1442 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1443 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1444 | - The first letter of the tag should be in lowercase 1445 | 1446 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1447 | 1448 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1449 | " 1450 | `; 1451 | 1452 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: "Neww: " 1`] = ` 1453 | "Hi @user-a!, thanks for the Pull Request 1454 | 1455 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1456 | 1457 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1458 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1459 | - The first letter of the tag should be in lowercase 1460 | 1461 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1462 | 1463 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1464 | " 1465 | `; 1466 | 1467 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: "Revert: " 1`] = ` 1468 | "Hi @user-a!, thanks for the Pull Request 1469 | 1470 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1471 | 1472 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1473 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1474 | - The first letter of the tag should be in lowercase 1475 | 1476 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1477 | 1478 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1479 | " 1480 | `; 1481 | 1482 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: "feat" 1`] = ` 1483 | "Hi @user-a!, thanks for the Pull Request 1484 | 1485 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1486 | 1487 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1488 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1489 | 1490 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1491 | 1492 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1493 | " 1494 | `; 1495 | 1496 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: "nNew: " 1`] = ` 1497 | "Hi @user-a!, thanks for the Pull Request 1498 | 1499 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1500 | 1501 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1502 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1503 | 1504 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1505 | 1506 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1507 | " 1508 | `; 1509 | 1510 | exports[`commit-message pull request synchronize Posts failure status if the PR title has invalid tag prefix: "new: " 1`] = ` 1511 | "Hi @user-a!, thanks for the Pull Request 1512 | 1513 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1514 | 1515 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1516 | 1517 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1518 | 1519 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1520 | " 1521 | `; 1522 | 1523 | exports[`commit-message pull request synchronize Posts failure status if the PR title is longer than 72 chars and don't set labels 1`] = ` 1524 | "Hi @user-a!, thanks for the Pull Request 1525 | 1526 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1527 | 1528 | - The length of the commit message must be less than or equal to 72 1529 | 1530 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1531 | 1532 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1533 | " 1534 | `; 1535 | 1536 | exports[`commit-message pull request synchronize Posts failure status if there are multiple commit messages and the title is invalid 1`] = ` 1537 | "Hi @user-a!, thanks for the Pull Request 1538 | 1539 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1540 | 1541 | - The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"? 1542 | - There should be a space following the initial tag and colon, for example 'feat: Message'. 1543 | 1544 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1545 | 1546 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1547 | " 1548 | `; 1549 | 1550 | exports[`commit-message pull request synchronize Posts failure status if there are multiple commit messages and the title is too long 1`] = ` 1551 | "Hi @user-a!, thanks for the Pull Request 1552 | 1553 | The **pull request title** isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases. 1554 | 1555 | - The length of the commit message must be less than or equal to 72 1556 | 1557 | **To Fix:** You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page. 1558 | 1559 | Read more about contributing to ESLint [here](https://eslint.org/docs/developer-guide/contributing/) 1560 | " 1561 | `; 1562 | -------------------------------------------------------------------------------- /tests/plugins/commit-message/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const { commitMessage } = require("../../../src/plugins/index"); 4 | const { TAG_LABELS } = require("../../../src/plugins/commit-message/util"); 5 | const { Probot, ProbotOctokit } = require("probot"); 6 | const { default: fetchMock } = require("fetch-mock"); 7 | 8 | const API_ROOT = "https://api.github.com"; 9 | 10 | /** 11 | * Mocks a given commit on a PR with the specified message 12 | * @param {string} message The commit message 13 | * @returns {void} 14 | */ 15 | // function mockSingleCommitWithMessage(message) { 16 | // nock("https://api.github.com") 17 | // .get("/repos/test/repo-test/pulls/1/commits") 18 | // .reply(200, [ 19 | // { 20 | // commit: { 21 | // message 22 | // }, 23 | // sha: "first-sha" 24 | // } 25 | // ]); 26 | // } 27 | 28 | /** 29 | * Mocks a labels request. 30 | * @param {Array} labels The labels to check for on the PR. 31 | * @returns {Nock} The mock for the labels request. 32 | */ 33 | // function mockLabels(labels) { 34 | // return nock("https://api.github.com") 35 | // .post("/repos/test/repo-test/issues/1/labels", body => { 36 | // expect(body).toEqual({ labels }); 37 | // return true; 38 | // }) 39 | // .reply(200); 40 | // } 41 | 42 | /** 43 | * Mocks multiple commits on a PR 44 | * @returns {void} 45 | */ 46 | // function mockMultipleCommits() { 47 | // nock("https://api.github.com") 48 | // .get("/repos/test/repo-test/pulls/1/commits") 49 | // .reply(200, [ 50 | // { 51 | // commit: { 52 | // message: "foo" 53 | // }, 54 | // sha: "first-sha" 55 | // }, 56 | // { 57 | // commit: { 58 | // message: "bar" 59 | // }, 60 | // sha: "second-sha" 61 | // } 62 | // ]); 63 | // } 64 | 65 | /** 66 | * Mocks a given commit on a PR with the specified message using fetchMock 67 | * @param {string} message The commit message 68 | * @returns {void} 69 | */ 70 | function mockSingleCommitWithMessage(message) { 71 | fetchMock.mockGlobal().get(`${API_ROOT}/repos/test/repo-test/pulls/1/commits`, [ 72 | { 73 | commit: { 74 | message 75 | }, 76 | sha: "first-sha" 77 | } 78 | ]); 79 | } 80 | 81 | /** 82 | * Mocks a labels request using fetchMock. 83 | * @param {Array} labels The labels to check for on the PR. 84 | * @returns {void} 85 | */ 86 | function mockLabels(labels) { 87 | fetchMock.mockGlobal().post({ 88 | url: `${API_ROOT}/repos/test/repo-test/issues/1/labels`, 89 | body: { labels }, 90 | matchPartialBody: true 91 | }, 200); 92 | } 93 | 94 | /** 95 | * Mocks multiple commits on a PR using fetchMock 96 | * @returns {void} 97 | */ 98 | function mockMultipleCommits() { 99 | fetchMock.mockGlobal().get(`${API_ROOT}/repos/test/repo-test/pulls/1/commits`, [ 100 | { 101 | commit: { 102 | message: "foo" 103 | }, 104 | sha: "first-sha" 105 | }, 106 | { 107 | commit: { 108 | message: "bar" 109 | }, 110 | sha: "second-sha" 111 | } 112 | ]); 113 | } 114 | 115 | /** 116 | * Emits a bot event for this plugin 117 | * @param {probot.Robot} bot A probot instance 118 | * @param {Object} payload The payload from the webhook 119 | * @returns {Promise} A Promise that fulfills when the action is complete 120 | */ 121 | function emitBotEvent(bot, payload = {}) { 122 | return bot.receive({ 123 | name: "pull_request", 124 | payload: Object.assign({ 125 | installation: { 126 | id: 1 127 | }, 128 | pull_request: { 129 | number: 1, 130 | user: { 131 | login: "user-a" 132 | } 133 | }, 134 | sender: { 135 | login: "user-a" 136 | }, 137 | repository: { 138 | name: "repo-test", 139 | owner: { 140 | login: "test" 141 | } 142 | } 143 | }, payload) 144 | }); 145 | } 146 | 147 | describe("commit-message", () => { 148 | let bot = null; 149 | 150 | beforeAll(() => { 151 | bot = new Probot({ 152 | 153 | appId: 1, 154 | githubToken: "test", 155 | 156 | Octokit: ProbotOctokit.defaults(instanceOptions => ({ 157 | ...instanceOptions, 158 | throttle: { enabled: false }, 159 | retry: { enabled: false } 160 | })) 161 | }); 162 | commitMessage(bot); 163 | }); 164 | 165 | afterEach(() => { 166 | fetchMock.unmockGlobal(); 167 | fetchMock.removeRoutes(); 168 | fetchMock.clearHistory(); 169 | }); 170 | 171 | ["opened", "reopened", "synchronize", "edited"].forEach(action => { 172 | describe(`pull request ${action}`, () => { 173 | test("Posts failure status if PR title is not correct", async () => { 174 | mockSingleCommitWithMessage("non standard commit message"); 175 | 176 | fetchMock.mockGlobal().post({ 177 | url: `${API_ROOT}/repos/test/repo-test/statuses/first-sha`, 178 | body: { 179 | state: "failure" 180 | }, 181 | matchPartialBody: true 182 | }, 201); 183 | 184 | fetchMock.mockGlobal().post(({ args: [url, opts] }) => { 185 | if (url !== `${API_ROOT}/repos/test/repo-test/issues/1/comments`) { 186 | return false; 187 | } 188 | const body = JSON.parse(opts.body).body; 189 | 190 | expect(body).toMatchSnapshot(); 191 | 192 | return true; 193 | }, 200); 194 | 195 | await emitBotEvent(bot, { 196 | action, 197 | pull_request: { 198 | number: 1, 199 | title: "non standard commit message", 200 | user: { login: "user-a" } 201 | } 202 | }); 203 | 204 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/first-sha`)).toBeTruthy(); 205 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/comments`)).toBeTruthy(); 206 | }); 207 | 208 | test("Posts failure status if PR title is not correct even when the first commit message is correct", async () => { 209 | mockSingleCommitWithMessage("feat: standard commit message"); 210 | 211 | fetchMock.mockGlobal().post({ 212 | url: `${API_ROOT}/repos/test/repo-test/statuses/first-sha`, 213 | body: { 214 | state: "failure" 215 | }, 216 | matchPartialBody: true 217 | }, 201); 218 | 219 | fetchMock.mockGlobal().post(({ args: [url, opts] }) => { 220 | if (url !== `${API_ROOT}/repos/test/repo-test/issues/1/comments`) { 221 | return false; 222 | } 223 | const body = JSON.parse(opts.body).body; 224 | 225 | expect(body).toMatchSnapshot(); 226 | 227 | return true; 228 | }, 200); 229 | 230 | await emitBotEvent(bot, { 231 | action, 232 | pull_request: { 233 | number: 1, 234 | title: "non standard commit message", 235 | user: { login: "user-a" } 236 | } 237 | }); 238 | }); 239 | 240 | test("Posts success status if PR title is correct", async () => { 241 | mockSingleCommitWithMessage("feat: standard commit message"); 242 | mockLabels(["feature"]); 243 | 244 | fetchMock.mockGlobal().post({ 245 | url: `${API_ROOT}/repos/test/repo-test/statuses/first-sha`, 246 | body: { 247 | state: "success" 248 | }, 249 | matchPartialBody: true 250 | }, 201); 251 | 252 | await emitBotEvent(bot, { 253 | action, 254 | pull_request: { 255 | number: 1, 256 | title: "feat: standard commit message", 257 | user: { login: "user-a" } 258 | } 259 | }); 260 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/first-sha`)).toBeTruthy(); 261 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/labels`)).toBeTruthy(); 262 | }); 263 | 264 | test("Posts success status if PR title is correct even when the first commit message is not correct", async () => { 265 | mockSingleCommitWithMessage("non standard commit message"); 266 | mockLabels(["feature"]); 267 | 268 | fetchMock.mockGlobal().post({ 269 | url: `${API_ROOT}/repos/test/repo-test/statuses/first-sha`, 270 | body: { 271 | state: "success" 272 | }, 273 | matchPartialBody: true 274 | }, 201); 275 | 276 | await emitBotEvent(bot, { 277 | action, 278 | pull_request: { 279 | number: 1, 280 | title: "feat: standard commit message", 281 | user: { login: "user-a" } 282 | } 283 | }); 284 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/first-sha`)).toBeTruthy(); 285 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/labels`)).toBeTruthy(); 286 | }); 287 | 288 | test("Posts success status if PR title begins with `Revert`", async () => { 289 | mockSingleCommitWithMessage("Revert \"chore: add test for commit tag Revert\""); 290 | 291 | fetchMock.mockGlobal().post({ 292 | url: `${API_ROOT}/repos/test/repo-test/statuses/first-sha`, 293 | body: { 294 | state: "success" 295 | }, 296 | matchPartialBody: true 297 | }, 201); 298 | 299 | await emitBotEvent(bot, { 300 | action, 301 | pull_request: { 302 | number: 1, 303 | title: "Revert \"chore: add test for commit tag Revert\"", 304 | user: { login: "user-a" } 305 | } 306 | }); 307 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/first-sha`)).toBeTruthy(); 308 | }); 309 | 310 | test("Posts failure status if the PR title is longer than 72 chars and don't set labels", async () => { 311 | mockSingleCommitWithMessage("feat!: standard commit message very very very long message and its beyond 72"); 312 | 313 | fetchMock.mockGlobal().post({ 314 | url: `${API_ROOT}/repos/test/repo-test/statuses/first-sha`, 315 | body: { 316 | state: "failure" 317 | }, 318 | matchPartialBody: true 319 | }, 201); 320 | 321 | fetchMock.mockGlobal().post(({ args: [url, opts] }) => { 322 | if (url !== `${API_ROOT}/repos/test/repo-test/issues/1/comments`) { 323 | return false; 324 | } 325 | const body = JSON.parse(opts.body).body; 326 | 327 | expect(body).toMatchSnapshot(); 328 | 329 | return true; 330 | }, 200); 331 | 332 | await emitBotEvent(bot, { 333 | action, 334 | pull_request: { 335 | number: 1, 336 | title: "feat!: standard commit message very very very long message and its beyond 72", 337 | user: { login: "user-a" } 338 | } 339 | }); 340 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/first-sha`)).toBeTruthy(); 341 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/comments`)).toBeTruthy(); 342 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/labels`)).toBeFalsy(); 343 | }); 344 | 345 | test("Posts success status if there are multiple commit messages and the title is valid", async () => { 346 | mockMultipleCommits(); 347 | 348 | fetchMock.mockGlobal().post({ 349 | url: `${API_ROOT}/repos/test/repo-test/statuses/second-sha`, 350 | body: { 351 | state: "success" 352 | }, 353 | matchPartialBody: true 354 | }, 201); 355 | 356 | mockLabels(["feature"]); 357 | 358 | await emitBotEvent(bot, { action, pull_request: { number: 1, title: "feat: foo" } }); 359 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/second-sha`)).toBeTruthy(); 360 | }); 361 | 362 | test("Posts failure status if there are multiple commit messages and the title is invalid", async () => { 363 | mockMultipleCommits(); 364 | 365 | fetchMock.mockGlobal().post({ 366 | url: `${API_ROOT}/repos/test/repo-test/statuses/second-sha`, 367 | body: { 368 | state: "failure" 369 | }, 370 | matchPartialBody: true 371 | }, 201); 372 | 373 | fetchMock.mockGlobal().post(({ args: [url, opts] }) => { 374 | if (url !== `${API_ROOT}/repos/test/repo-test/issues/1/comments`) { 375 | return false; 376 | } 377 | const body = JSON.parse(opts.body).body; 378 | 379 | expect(body).toMatchSnapshot(); 380 | 381 | return true; 382 | }, 200); 383 | 384 | await emitBotEvent(bot, { action, pull_request: { number: 1, title: "foo", user: { login: "user-a" } } }); 385 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/second-sha`)).toBeTruthy(); 386 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/comments`)).toBeTruthy(); 387 | }); 388 | 389 | test("Posts failure status if there are multiple commit messages and the title is too long", async () => { 390 | mockMultipleCommits(); 391 | 392 | fetchMock.mockGlobal().post({ 393 | url: `${API_ROOT}/repos/test/repo-test/statuses/second-sha`, 394 | body: { 395 | state: "failure" 396 | }, 397 | matchPartialBody: true 398 | }, 201); 399 | 400 | fetchMock.mockGlobal().post(({ args: [url, opts] }) => { 401 | if (url !== `${API_ROOT}/repos/test/repo-test/issues/1/comments`) { 402 | return false; 403 | } 404 | const body = JSON.parse(opts.body).body; 405 | 406 | expect(body).toMatchSnapshot(); 407 | 408 | return true; 409 | }, 200); 410 | 411 | await emitBotEvent(bot, { action, pull_request: { number: 1, title: `feat: ${"A".repeat(72)}`, user: { login: "user-a" } } }); 412 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/second-sha`)).toBeTruthy(); 413 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/comments`)).toBeTruthy(); 414 | }); 415 | 416 | // Tests for invalid or malformed tag prefixes 417 | [ 418 | ": ", 419 | "Foo: ", 420 | "Revert: ", 421 | "Neww: ", 422 | "nNew: ", 423 | " New: ", 424 | "new: ", 425 | "New:", 426 | "New : ", 427 | "New ", 428 | "feat" 429 | ].forEach(prefix => { 430 | const message = `${prefix}foo`; 431 | 432 | test(`Posts failure status if the PR title has invalid tag prefix: "${prefix}"`, async () => { 433 | mockSingleCommitWithMessage(message); 434 | 435 | fetchMock.mockGlobal().post({ 436 | url: `${API_ROOT}/repos/test/repo-test/statuses/first-sha`, 437 | body: { 438 | state: "failure" 439 | }, 440 | matchPartialBody: true 441 | }, 201); 442 | 443 | fetchMock.mockGlobal().post(({ args: [url, opts] }) => { 444 | if (url !== `${API_ROOT}/repos/test/repo-test/issues/1/comments`) { 445 | return false; 446 | } 447 | const body = JSON.parse(opts.body).body; 448 | 449 | expect(body).toMatchSnapshot(); 450 | 451 | return true; 452 | }, 200); 453 | 454 | await emitBotEvent(bot, { action, pull_request: { number: 1, title: message, user: { login: "user-a" } } }); 455 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/first-sha`)).toBeTruthy(); 456 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/comments`)).toBeTruthy(); 457 | }); 458 | 459 | test(`Posts failure status if PR with multiple commits has invalid tag prefix in the title: "${prefix}"`, async () => { 460 | mockMultipleCommits(); 461 | 462 | fetchMock.mockGlobal().post({ 463 | url: `${API_ROOT}/repos/test/repo-test/statuses/second-sha`, 464 | body: { 465 | state: "failure" 466 | }, 467 | matchPartialBody: true 468 | }, 201); 469 | 470 | fetchMock.mockGlobal().post(({ args: [url, opts] }) => { 471 | if (url !== `${API_ROOT}/repos/test/repo-test/issues/1/comments`) { 472 | return false; 473 | } 474 | const body = JSON.parse(opts.body).body; 475 | 476 | expect(body).toMatchSnapshot(); 477 | 478 | return true; 479 | }, 200); 480 | 481 | await emitBotEvent(bot, { action, pull_request: { number: 1, title: message, user: { login: "user-a" } } }); 482 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/second-sha`)).toBeTruthy(); 483 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/comments`)).toBeTruthy(); 484 | }); 485 | }); 486 | 487 | // Tests for valid tag prefixes 488 | TAG_LABELS.forEach((labels, prefix) => { 489 | const message = `${prefix} foo`; 490 | 491 | test(`Posts success status if the PR title has valid tag prefix: "${prefix}"`, async () => { 492 | mockSingleCommitWithMessage(message); 493 | 494 | mockLabels(labels); 495 | fetchMock.mockGlobal().post({ 496 | url: `${API_ROOT}/repos/test/repo-test/statuses/first-sha`, 497 | body: { 498 | state: "success" 499 | }, 500 | matchPartialBody: true 501 | }, 201); 502 | 503 | await emitBotEvent(bot, { action, pull_request: { number: 1, title: message, user: { login: "user-a" } } }); 504 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/first-sha`)).toBeTruthy(); 505 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/labels`)).toBeTruthy(); 506 | }); 507 | 508 | test(`Posts success status if PR with multiple commits has valid tag prefix in the title: "${prefix}"`, async () => { 509 | mockMultipleCommits(); 510 | 511 | fetchMock.mockGlobal().post({ 512 | url: `${API_ROOT}/repos/test/repo-test/statuses/second-sha`, 513 | body: { 514 | state: "success" 515 | }, 516 | matchPartialBody: true 517 | }, 201); 518 | 519 | mockLabels(labels); 520 | 521 | await emitBotEvent(bot, { action, pull_request: { number: 1, title: message } }); 522 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/second-sha`)).toBeTruthy(); 523 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/labels`)).toBeTruthy(); 524 | }); 525 | }); 526 | 527 | test("Does not post a status if the repository is excluded", async () => { 528 | await emitBotEvent(bot, { 529 | action: "opened", 530 | repository: { 531 | name: "tsc-meetings", 532 | owner: { 533 | login: "test" 534 | } 535 | } 536 | }); 537 | }); 538 | 539 | // Tests for commit messages starting with 'Revert "' 540 | [ 541 | "Revert \"feat: do something (#123)\"", 542 | "Revert \"Very long commit message with lots and lots of characters (more than 72!)\"", 543 | "Revert \"blah\"\n\nbaz" 544 | ].forEach(message => { 545 | test("Posts a success status", async () => { 546 | mockSingleCommitWithMessage(message); 547 | 548 | fetchMock.mockGlobal().post({ 549 | url: `${API_ROOT}/repos/test/repo-test/statuses/first-sha`, 550 | body: { 551 | state: "success" 552 | }, 553 | matchPartialBody: true 554 | }, 201); 555 | 556 | await emitBotEvent(bot, { action, pull_request: { number: 1, title: message.replace(/\n[\s\S]*/u, "") } }); 557 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/first-sha`)).toBeTruthy(); 558 | }); 559 | }); 560 | }); 561 | }); 562 | }); 563 | -------------------------------------------------------------------------------- /tests/plugins/needs-info/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const { needsInfo } = require("../../../src/plugins/index"); 4 | const { Probot, ProbotOctokit } = require("probot"); 5 | const { default: fetchMock } = require("fetch-mock"); 6 | 7 | const API_ROOT = "https://api.github.com"; 8 | 9 | describe("needs-info", () => { 10 | let bot = null; 11 | 12 | beforeEach(() => { 13 | bot = new Probot({ 14 | appId: 1, 15 | githubToken: "test", 16 | Octokit: ProbotOctokit.defaults(instanceOptions => ({ 17 | ...instanceOptions, 18 | throttle: { enabled: false }, 19 | retry: { enabled: false } 20 | })) 21 | }); 22 | needsInfo(bot); 23 | }); 24 | 25 | afterEach(() => { 26 | fetchMock.unmockGlobal(); 27 | fetchMock.removeRoutes(); 28 | fetchMock.clearHistory(); 29 | }); 30 | 31 | describe("issue labeled", () => { 32 | test("Adds the comment if there needs info is added", async () => { 33 | fetchMock.mockGlobal().post( 34 | `${API_ROOT}/repos/test/repo-test/issues/1/comments`, 35 | { status: 200 } 36 | ); 37 | 38 | await bot.receive({ 39 | name: "issues", 40 | payload: { 41 | action: "closed", 42 | installation: { 43 | id: 1 44 | }, 45 | issue: { 46 | labels: [ 47 | { 48 | name: "needs info" 49 | } 50 | ], 51 | user: { 52 | login: "user-a" 53 | }, 54 | number: 1 55 | }, 56 | repository: { 57 | name: "repo-test", 58 | owner: { 59 | login: "test" 60 | } 61 | } 62 | } 63 | }); 64 | 65 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/comments`)).toBeTruthy(); 66 | }); 67 | 68 | test("Do not add the comment if needs label label is not present", async () => { 69 | await bot.receive({ 70 | name: "issues", 71 | payload: { 72 | action: "closed", 73 | installation: { 74 | id: 1 75 | }, 76 | issue: { 77 | labels: [ 78 | { 79 | name: "triage" 80 | } 81 | ], 82 | user: { 83 | login: "user-a" 84 | }, 85 | number: 1 86 | }, 87 | repository: { 88 | name: "repo-test", 89 | owner: { 90 | login: "test" 91 | } 92 | } 93 | } 94 | }); 95 | 96 | expect(fetchMock.callHistory.called()).toBe(false); 97 | }); 98 | }); 99 | }); 100 | -------------------------------------------------------------------------------- /tests/plugins/recurring-issues/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Tests for recurring-issues plugin. 3 | * @author Nicholas C. Zakas 4 | */ 5 | "use strict"; 6 | 7 | //----------------------------------------------------------------------------- 8 | // Requirements 9 | //----------------------------------------------------------------------------- 10 | 11 | const { recurringIssues } = require("../../../src/plugins/index"); 12 | const { Probot, ProbotOctokit } = require("probot"); 13 | const { default: fetchMock } = require("fetch-mock"); 14 | 15 | //----------------------------------------------------------------------------- 16 | // Helpers 17 | //----------------------------------------------------------------------------- 18 | 19 | const API_ROOT = "https://api.github.com"; 20 | 21 | //----------------------------------------------------------------------------- 22 | // Tests 23 | //----------------------------------------------------------------------------- 24 | 25 | describe("recurring-issues", () => { 26 | let issueWasCreated; 27 | let issue; 28 | 29 | /** 30 | * Runs the bot with the given arguments, setting up fixtures and running the webhook listener 31 | * @param {Object} options Configure API responses the bot will see 32 | * @param {string} options.issueTitle The title of the existing issue which was closed 33 | * @param {string[]} options.labelNames The labels of the issue which was closed 34 | * @param {string[]} options.eventTypes The events that have occurred for the issue 35 | * @returns {Promise} A Promise that fulfills after the webhook action is complete 36 | */ 37 | function runBot({ issueTitle, labelNames, eventTypes }) { 38 | issueWasCreated = false; 39 | 40 | const bot = new Probot({ 41 | appId: 1, 42 | githubToken: "test", 43 | Octokit: ProbotOctokit.defaults(instanceOptions => ({ 44 | ...instanceOptions, 45 | throttle: { enabled: false }, 46 | retry: { enabled: false } 47 | })) 48 | }); 49 | 50 | recurringIssues(bot); 51 | 52 | const ORGANIZATION_NAME = "test"; 53 | const TEAM_ID = 55; 54 | const TEAM_SLUG = "eslint-tsc"; 55 | 56 | fetchMock.mockGlobal().get(`${API_ROOT}/repos/${ORGANIZATION_NAME}/repo-test/issues/1/events?per_page=100`, eventTypes.map(type => ({ event: type }))); 57 | 58 | fetchMock.mockGlobal().post(`${API_ROOT}/repos/${ORGANIZATION_NAME}/repo-test/issues`, ({ options }) => { 59 | issueWasCreated = true; 60 | issue = JSON.parse(options.body); 61 | return { 62 | status: 200, 63 | body: { 64 | issue_number: 2 65 | } 66 | }; 67 | }); 68 | 69 | fetchMock.mockGlobal().get(`${API_ROOT}/orgs/${ORGANIZATION_NAME}/teams?per_page=100`, [ 70 | { 71 | id: TEAM_ID, 72 | slug: "eslint-tsc" 73 | } 74 | ]); 75 | 76 | fetchMock.mockGlobal().get(`${API_ROOT}/orgs/${ORGANIZATION_NAME}/teams/${TEAM_SLUG}/members?per_page=100`, [ 77 | { 78 | id: 1, 79 | login: "user1" 80 | }, 81 | { 82 | id: 2, 83 | login: "user2" 84 | } 85 | ]); 86 | 87 | fetchMock.mockGlobal().get(`${API_ROOT}/users/user1`, { 88 | login: "user1", 89 | name: "User One" 90 | }); 91 | 92 | fetchMock.mockGlobal().get(`${API_ROOT}/users/user2`, { 93 | login: "user2", 94 | name: "User Two" 95 | }); 96 | 97 | return bot.receive({ 98 | name: "issues", 99 | payload: { 100 | installation: { 101 | id: 1 102 | }, 103 | action: "closed", 104 | issue: { 105 | number: 1, 106 | title: issueTitle, 107 | labels: labelNames.map(name => ({ name })) 108 | }, 109 | repository: { 110 | owner: { 111 | login: "test" 112 | }, 113 | name: "repo-test" 114 | } 115 | } 116 | }); 117 | } 118 | 119 | afterEach(() => { 120 | fetchMock.unmockGlobal(); 121 | fetchMock.removeRoutes(); 122 | fetchMock.clearHistory(); 123 | }); 124 | 125 | describe("when an issue does not have the release label", () => { 126 | test("ignores the issue", async () => { 127 | await runBot({ 128 | issueTitle: "Scheduled release for October 27th, 2017", 129 | labelNames: ["foo"], 130 | eventTypes: ["closed"] 131 | }); 132 | 133 | expect(issueWasCreated).toBe(false); 134 | }); 135 | }); 136 | 137 | describe("when an issue has already been closed and reopened", () => { 138 | test("ignores the issue", async () => { 139 | await runBot({ 140 | issueTitle: "Scheduled release for October 27th, 2017", 141 | labelNames: ["release"], 142 | eventTypes: ["foo", "closed", "reopened", "closed"] 143 | }); 144 | 145 | expect(issueWasCreated).toBe(false); 146 | }); 147 | }); 148 | 149 | describe("when an issue has an invalid title", () => { 150 | test("ignores the issue", async () => { 151 | await runBot({ 152 | issueTitle: "Foo bar!", 153 | labelNames: ["release"], 154 | eventTypes: ["closed"] 155 | }); 156 | 157 | expect(issueWasCreated).toBe(false); 158 | }); 159 | }); 160 | 161 | describe("when an issue has a parseable title, has the release label, and has never been closed", () => { 162 | test("creates a new issue", async () => { 163 | await runBot({ 164 | issueTitle: "Scheduled release for October 27th, 2017", 165 | labelNames: ["release"], 166 | eventTypes: ["closed"] 167 | }); 168 | 169 | expect(issueWasCreated).toBe(true); 170 | expect(issue.title).toBe("Scheduled release for November 10th, 2017"); 171 | expect(issue.body.startsWith("The next scheduled release will occur on Friday, November 10th, 2017")).toBe(true); 172 | }); 173 | }); 174 | 175 | describe("when an issue has a parseable title, has the tsc meeting label, and has never been closed", () => { 176 | test("creates a new issue", async () => { 177 | await runBot({ 178 | issueTitle: "TSC meeting 26-October-2017", 179 | labelNames: ["tsc meeting"], 180 | eventTypes: ["closed"] 181 | }); 182 | 183 | expect(issueWasCreated).toBe(true); 184 | expect(issue.title).toBe("TSC meeting 09-November-2017"); 185 | expect(issue.body).toBe([ 186 | "# Time", 187 | "", 188 | "UTC Thu 09-Nov-2017 21:00:", 189 | "- Los Angeles: Thu 09-Nov-2017 13:00", 190 | "- Chicago: Thu 09-Nov-2017 15:00", 191 | "- New York: Thu 09-Nov-2017 16:00", 192 | "- Madrid: Thu 09-Nov-2017 22:00", 193 | "- Moscow: Fri 10-Nov-2017 00:00", 194 | "- Tokyo: Fri 10-Nov-2017 06:00", 195 | "- Sydney: Fri 10-Nov-2017 08:00", 196 | "", 197 | "# Location", 198 | "", 199 | "https://eslint.org/chat/tsc-meetings", 200 | "", 201 | "# Agenda", 202 | "", 203 | "Extracted from:", 204 | "", 205 | "* Issues and pull requests from the ESLint organization with the [\"tsc agenda\" label](https://github.com/issues?utf8=%E2%9C%93&q=org%3Aeslint+label%3A%22tsc+agenda%22)", 206 | "* Comments on this issue", 207 | "", 208 | "# Invited", 209 | "", 210 | "- User One (@user1) - TSC", 211 | "- User Two (@user2) - TSC", 212 | "", 213 | "# Public participation", 214 | "", 215 | "Anyone is welcome to attend the meeting as observers. We ask that you refrain from interrupting the meeting once it begins and only participate if invited to do so." 216 | ].join("\n")); 217 | }); 218 | }); 219 | }); 220 | -------------------------------------------------------------------------------- /tests/plugins/release-monitor/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Tests for release-monitor plugin 3 | */ 4 | 5 | "use strict"; 6 | 7 | //----------------------------------------------------------------------------- 8 | // Requirements 9 | //----------------------------------------------------------------------------- 10 | 11 | const { releaseMonitor } = require("../../../src/plugins/index"); 12 | const { Probot, ProbotOctokit } = require("probot"); 13 | const { default: fetchMock } = require("fetch-mock"); 14 | 15 | //----------------------------------------------------------------------------- 16 | // Helpers 17 | //----------------------------------------------------------------------------- 18 | 19 | const POST_RELEASE_LABEL = "patch release pending"; 20 | const RELEASE_LABEL = "release"; 21 | const API_ROOT = "https://api.github.com"; 22 | 23 | /** 24 | * Creates mock PR with commits 25 | * @example 26 | * mockData = [ 27 | * { 28 | * number: 1, 29 | * title: "hi", 30 | * commits: [ 31 | * { 32 | * sha: "111", 33 | * commit: { 34 | * message: "asf" 35 | * } 36 | * } 37 | * ] 38 | * } 39 | * ]; 40 | * 41 | * @param {Array} mockData data for PR 42 | * @returns {void} 43 | * @private 44 | */ 45 | function mockAllOpenPrWithCommits(mockData = []) { 46 | mockData.forEach((pullRequest, index) => { 47 | const apiPath = `/repos/test/repo-test/pulls?state=open${index === 0 ? "" : `&page=${index + 1}`}`; 48 | const linkHeaders = []; 49 | 50 | if (index !== mockData.length - 1) { 51 | linkHeaders.push(`<${API_ROOT}/repos/test/repo-test/pulls?state=open&page=${index + 2}>; rel="next"`); 52 | linkHeaders.push(`<${API_ROOT}/repos/test/repo-test/pulls?state=open&page=${mockData.length}>; rel="last"`); 53 | } 54 | 55 | if (index !== 0) { 56 | linkHeaders.push(`<${API_ROOT}/repos/test/repo-test/pulls?state=open&page=${index}>; rel="prev"`); 57 | linkHeaders.push(`<${API_ROOT}/repos/test/repo-test/pulls?state=open&page=1>; rel="first"`); 58 | } 59 | 60 | fetchMock.mockGlobal().get(`${API_ROOT}${apiPath}`, { 61 | status: 200, 62 | body: [pullRequest], 63 | headers: linkHeaders.length ? { Link: linkHeaders.join(", ") } : {} 64 | }); 65 | 66 | fetchMock.mockGlobal().get( 67 | `${API_ROOT}/repos/test/repo-test/pulls/${pullRequest.number}/commits`, 68 | pullRequest.commits 69 | ); 70 | }); 71 | } 72 | 73 | /** 74 | * Mocks a pending status for a given status ID. 75 | * @param {string} statusId The ID of the status to mock. 76 | * @returns {void} 77 | */ 78 | function mockStatusPending(statusId) { 79 | fetchMock.mockGlobal().post({ 80 | url: `${API_ROOT}/repos/test/repo-test/statuses/${statusId}`, 81 | body: { 82 | state: "pending", 83 | description: "A patch release is pending", 84 | target_url: "https://github.com/test/repo-test/issues/1" 85 | }, 86 | matchPartialBody: true 87 | }, 200); 88 | } 89 | 90 | /** 91 | * Mocks a successful status update for a given status ID with a patch release message. 92 | * @param {string} statusId The ID of the status to update. 93 | * @returns {void} 94 | */ 95 | function mockStatusSuccessWithPatch(statusId) { 96 | fetchMock.mockGlobal().post({ 97 | url: `${API_ROOT}/repos/test/repo-test/statuses/${statusId}`, 98 | body: { 99 | state: "success", 100 | description: "This change is semver-patch" 101 | }, 102 | matchPartialBody: true 103 | }, 200); 104 | } 105 | 106 | /** 107 | * Mocks a successful status update for a given status ID with no patch release message. 108 | * @param {string} statusId The ID of the status to update. 109 | * @returns {void} 110 | */ 111 | function mockStatusSuccessNoPending(statusId) { 112 | fetchMock.mockGlobal().post({ 113 | url: `${API_ROOT}/repos/test/repo-test/statuses/${statusId}`, 114 | body: { 115 | state: "success", 116 | description: "No patch release is pending" 117 | }, 118 | matchPartialBody: true 119 | }, 200); 120 | } 121 | 122 | describe("release-monitor", () => { 123 | let bot = null; 124 | 125 | beforeEach(() => { 126 | bot = new Probot({ 127 | appId: 1, 128 | githubToken: "test", 129 | Octokit: ProbotOctokit.defaults(instanceOptions => ({ 130 | ...instanceOptions, 131 | throttle: { enabled: false }, 132 | retry: { enabled: false } 133 | })) 134 | }); 135 | releaseMonitor(bot); 136 | }); 137 | 138 | afterEach(() => { 139 | fetchMock.unmockGlobal(); 140 | fetchMock.removeRoutes(); 141 | fetchMock.clearHistory(); 142 | }); 143 | 144 | describe("issue labeled", () => { 145 | test("in post release phase then add appropriate status check to all PRs", async () => { 146 | mockAllOpenPrWithCommits([ 147 | { 148 | number: 1, 149 | title: "New: add 1", 150 | commits: [ 151 | { 152 | sha: "111", 153 | commit: { 154 | message: "New: add 1" 155 | } 156 | } 157 | ] 158 | }, 159 | { 160 | number: 2, 161 | title: "Fix: fix 2", 162 | commits: [ 163 | { 164 | sha: "222", 165 | commit: { 166 | message: "Fix: fix 2" 167 | } 168 | } 169 | ] 170 | }, 171 | { 172 | number: 3, 173 | title: "Update: add 3", 174 | commits: [ 175 | { 176 | sha: "333", 177 | commit: { 178 | message: "Update: add 3" 179 | } 180 | } 181 | ] 182 | }, 183 | { 184 | number: 4, 185 | title: "Breaking: add 4", 186 | commits: [ 187 | { 188 | sha: "444", 189 | commit: { 190 | message: "Breaking: add 4" 191 | } 192 | } 193 | ] 194 | }, 195 | { 196 | number: 5, 197 | title: "random message", 198 | commits: [ 199 | { 200 | sha: "555", 201 | commit: { 202 | message: "random message" 203 | } 204 | } 205 | ] 206 | }, 207 | { 208 | number: 6, 209 | title: "Docs: message", 210 | commits: [ 211 | { 212 | sha: "666", 213 | commit: { 214 | message: "Docs: message" 215 | } 216 | } 217 | ] 218 | }, 219 | { 220 | number: 7, 221 | title: "Upgrade: message", 222 | commits: [ 223 | { 224 | sha: "777", 225 | commit: { 226 | message: "Upgrade: message" 227 | } 228 | } 229 | ] 230 | } 231 | ]); 232 | 233 | // Mock status API calls with fetchMock 234 | mockStatusPending(111); 235 | mockStatusSuccessWithPatch(222); 236 | mockStatusPending(333); 237 | mockStatusPending(444); 238 | mockStatusPending(555); 239 | mockStatusSuccessWithPatch(666); 240 | mockStatusSuccessWithPatch(777); 241 | 242 | await bot.receive({ 243 | name: "issues", 244 | payload: { 245 | action: "labeled", 246 | installation: { 247 | id: 1 248 | }, 249 | issue: { 250 | labels: [ 251 | { 252 | name: RELEASE_LABEL 253 | }, 254 | { 255 | name: POST_RELEASE_LABEL 256 | } 257 | ], 258 | number: 1, 259 | html_url: "https://github.com/test/repo-test/issues/1" 260 | }, 261 | label: { 262 | name: POST_RELEASE_LABEL 263 | }, 264 | repository: { 265 | name: "repo-test", 266 | owner: { 267 | login: "test" 268 | } 269 | } 270 | } 271 | }); 272 | 273 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/111`)).toBeTruthy(); 274 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/222`)).toBeTruthy(); 275 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/333`)).toBeTruthy(); 276 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/444`)).toBeTruthy(); 277 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/555`)).toBeTruthy(); 278 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/666`)).toBeTruthy(); 279 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/777`)).toBeTruthy(); 280 | }, 10000); 281 | 282 | test("with no post release label nothing happens", async () => { 283 | mockAllOpenPrWithCommits([ 284 | { 285 | number: 1, 286 | title: "New: add 1", 287 | commits: [ 288 | { 289 | sha: "111", 290 | commit: { 291 | message: "New: add 1" 292 | } 293 | } 294 | ] 295 | }, 296 | { 297 | number: 2, 298 | title: "Fix: fix 2", 299 | commits: [ 300 | { 301 | sha: "222", 302 | commit: { 303 | message: "Fix: fix 2" 304 | } 305 | } 306 | ] 307 | } 308 | ]); 309 | 310 | await bot.receive({ 311 | name: "issues", 312 | payload: { 313 | action: "labeled", 314 | installation: { 315 | id: 1 316 | }, 317 | issue: { 318 | labels: [ 319 | { 320 | name: RELEASE_LABEL 321 | } 322 | ], 323 | number: 5 324 | }, 325 | label: { 326 | name: "something" 327 | }, 328 | repository: { 329 | name: "repo-test", 330 | owner: { 331 | login: "test" 332 | } 333 | } 334 | } 335 | }); 336 | 337 | expect(fetchMock.callHistory.called()).toBe(false); 338 | }); 339 | 340 | test("with post release label on non release issue, nothing happens", async () => { 341 | mockAllOpenPrWithCommits([ 342 | { 343 | number: 1, 344 | title: "New: add 1", 345 | commits: [ 346 | { 347 | sha: "111", 348 | commit: { 349 | message: "New: add 1" 350 | } 351 | } 352 | ] 353 | }, 354 | { 355 | number: 2, 356 | title: "Fix: fix 2", 357 | commits: [ 358 | { 359 | sha: "222", 360 | commit: { 361 | message: "Fix: fix 2" 362 | } 363 | } 364 | ] 365 | } 366 | ]); 367 | 368 | await bot.receive({ 369 | name: "issues", 370 | payload: { 371 | action: "labeled", 372 | installation: { 373 | id: 1 374 | }, 375 | issue: { 376 | labels: [ 377 | { 378 | name: POST_RELEASE_LABEL 379 | }, 380 | { 381 | name: "bug" 382 | } 383 | ], 384 | number: 5 385 | }, 386 | label: { 387 | name: POST_RELEASE_LABEL 388 | }, 389 | repository: { 390 | name: "repo-test", 391 | owner: { 392 | login: "test" 393 | } 394 | } 395 | } 396 | }); 397 | 398 | expect(fetchMock.callHistory.called()).toBe(false); 399 | }); 400 | }); 401 | 402 | describe("issue closed", () => { 403 | test("is release then update status on all PR", async () => { 404 | mockAllOpenPrWithCommits([ 405 | { 406 | number: 1, 407 | title: "New: add 1", 408 | commits: [ 409 | { 410 | sha: "111", 411 | commit: { 412 | message: "New: add 1" 413 | } 414 | } 415 | ] 416 | }, 417 | { 418 | number: 2, 419 | title: "Fix: fix 2", 420 | commits: [ 421 | { 422 | sha: "222", 423 | commit: { 424 | message: "Fix: fix 2" 425 | } 426 | } 427 | ] 428 | }, 429 | { 430 | number: 3, 431 | title: "Update: add 3", 432 | commits: [ 433 | { 434 | sha: "333", 435 | commit: { 436 | message: "Update: add 3" 437 | } 438 | } 439 | ] 440 | }, 441 | { 442 | number: 4, 443 | title: "Breaking: add 4", 444 | commits: [ 445 | { 446 | sha: "444", 447 | commit: { 448 | message: "Breaking: add 4" 449 | } 450 | } 451 | ] 452 | }, 453 | { 454 | number: 5, 455 | title: "random message", 456 | commits: [ 457 | { 458 | sha: "555", 459 | commit: { 460 | message: "random message" 461 | } 462 | } 463 | ] 464 | }, 465 | { 466 | number: 6, 467 | title: "Docs: message", 468 | commits: [ 469 | { 470 | sha: "666", 471 | commit: { 472 | message: "Docs: message" 473 | } 474 | } 475 | ] 476 | }, 477 | { 478 | number: 7, 479 | title: "Upgrade: message", 480 | commits: [ 481 | { 482 | sha: "777", 483 | commit: { 484 | message: "Upgrade: message" 485 | } 486 | } 487 | ] 488 | } 489 | ]); 490 | 491 | mockStatusSuccessNoPending(111); 492 | mockStatusSuccessNoPending(222); 493 | mockStatusSuccessNoPending(333); 494 | mockStatusSuccessNoPending(444); 495 | mockStatusSuccessNoPending(555); 496 | mockStatusSuccessNoPending(666); 497 | mockStatusSuccessNoPending(777); 498 | 499 | await bot.receive({ 500 | name: "issues", 501 | payload: { 502 | action: "closed", 503 | installation: { 504 | id: 1 505 | }, 506 | issue: { 507 | labels: [ 508 | { 509 | name: RELEASE_LABEL 510 | } 511 | ], 512 | number: 5, 513 | html_url: "https://github.com/test/repo-test/issues/1" 514 | }, 515 | repository: { 516 | name: "repo-test", 517 | owner: { 518 | login: "test" 519 | } 520 | } 521 | } 522 | }); 523 | 524 | expect(fetchMock.callHistory.called()).toBe(true); 525 | }, 10000); 526 | 527 | test("is not a release issue", async () => { 528 | mockAllOpenPrWithCommits([ 529 | { 530 | number: 1, 531 | title: "New: add 1", 532 | commits: [ 533 | { 534 | sha: "111", 535 | commit: { 536 | message: "New: add 1" 537 | } 538 | } 539 | ] 540 | }, 541 | { 542 | number: 2, 543 | title: "Fix: fix 2", 544 | commits: [ 545 | { 546 | sha: "222", 547 | commit: { 548 | message: "Fix: fix 2" 549 | } 550 | } 551 | ] 552 | } 553 | ]); 554 | 555 | await bot.receive({ 556 | name: "issues", 557 | payload: { 558 | action: "closed", 559 | installation: { 560 | id: 1 561 | }, 562 | issue: { 563 | labels: [ 564 | { 565 | name: "test" 566 | } 567 | ], 568 | number: 5, 569 | html_url: "https://github.com/test/repo-test/issues/5" 570 | }, 571 | repository: { 572 | name: "repo-test", 573 | owner: { 574 | login: "test" 575 | } 576 | } 577 | } 578 | }); 579 | 580 | expect(fetchMock.callHistory.called()).toBe(false); 581 | }); 582 | }); 583 | 584 | ["opened", "reopened", "synchronize", "edited"].forEach(action => { 585 | describe(`pull request ${action}`, () => { 586 | test("put pending for non semver patch PR under post release phase", async () => { 587 | mockAllOpenPrWithCommits([ 588 | { 589 | number: 1, 590 | title: "New: add 1", 591 | commits: [ 592 | { 593 | sha: "111old", 594 | commit: { 595 | message: "New: add 1" 596 | } 597 | }, 598 | { 599 | sha: "111", 600 | commit: { 601 | message: "New: add 1" 602 | } 603 | } 604 | ] 605 | } 606 | ]); 607 | 608 | fetchMock.mockGlobal().get( 609 | `${API_ROOT}/repos/test/repo-test/issues?labels=release%2C${encodeURIComponent(POST_RELEASE_LABEL)}`, 610 | [ 611 | { 612 | html_url: "https://github.com/test/repo-test/issues/1" 613 | } 614 | ] 615 | ); 616 | 617 | mockStatusPending(111); 618 | 619 | await bot.receive({ 620 | name: "pull_request", 621 | payload: { 622 | action: "opened", 623 | installation: { 624 | id: 1 625 | }, 626 | pull_request: { 627 | number: 1, 628 | title: "New: add 1" 629 | }, 630 | repository: { 631 | name: "repo-test", 632 | owner: { 633 | login: "test" 634 | } 635 | } 636 | } 637 | }); 638 | 639 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/111`)).toBe(true); 640 | }); 641 | 642 | test("put success for semver patch PR under post release phase", async () => { 643 | mockAllOpenPrWithCommits([ 644 | { 645 | number: 1, 646 | title: "Fix: add 1", 647 | commits: [ 648 | { 649 | sha: "111", 650 | commit: { 651 | message: "Fix: add 1" 652 | } 653 | } 654 | ] 655 | } 656 | ]); 657 | 658 | fetchMock.mockGlobal().get( 659 | `${API_ROOT}/repos/test/repo-test/issues?labels=release%2C${encodeURIComponent(POST_RELEASE_LABEL)}`, 660 | [ 661 | { 662 | html_url: "https://github.com/test/repo-test/issues/1" 663 | } 664 | ] 665 | ); 666 | 667 | mockStatusSuccessWithPatch(111); 668 | 669 | await bot.receive({ 670 | name: "pull_request", 671 | payload: { 672 | action: "opened", 673 | installation: { 674 | id: 1 675 | }, 676 | pull_request: { 677 | number: 1, 678 | title: "Fix: add 1" 679 | }, 680 | repository: { 681 | name: "repo-test", 682 | owner: { 683 | login: "test" 684 | } 685 | } 686 | } 687 | }); 688 | 689 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/111`)).toBe(true); 690 | }); 691 | 692 | test("put success for all PR under outside release phase", async () => { 693 | mockAllOpenPrWithCommits([ 694 | { 695 | number: 1, 696 | title: "New: add 1", 697 | commits: [ 698 | { 699 | sha: "111", 700 | commit: { 701 | message: "New: add 1" 702 | } 703 | } 704 | ] 705 | } 706 | ]); 707 | 708 | fetchMock.mockGlobal().get( 709 | `${API_ROOT}/repos/test/repo-test/issues?labels=release%2C${encodeURIComponent(POST_RELEASE_LABEL)}`, 710 | [] 711 | ); 712 | 713 | mockStatusSuccessNoPending(111); 714 | 715 | await bot.receive({ 716 | name: "pull_request", 717 | payload: { 718 | action: "opened", 719 | installation: { 720 | id: 1 721 | }, 722 | pull_request: { 723 | number: 1, 724 | title: "New: add 1" 725 | }, 726 | repository: { 727 | name: "repo-test", 728 | owner: { 729 | login: "test" 730 | } 731 | } 732 | } 733 | }); 734 | 735 | expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/statuses/111`)).toBe(true); 736 | }); 737 | }); 738 | }); 739 | }); 740 | -------------------------------------------------------------------------------- /tests/plugins/wip/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Tests for the WIP plugin. 3 | */ 4 | 5 | "use strict"; 6 | 7 | //----------------------------------------------------------------------------- 8 | // Requirements 9 | //----------------------------------------------------------------------------- 10 | 11 | const { wip } = require("../../../src/plugins"); 12 | const { Probot, ProbotOctokit } = require("probot"); 13 | const { default: fetchMock } = require("fetch-mock"); 14 | 15 | //----------------------------------------------------------------------------- 16 | // Helpers 17 | //----------------------------------------------------------------------------- 18 | 19 | const DO_NOT_MERGE_LABEL = "do not merge"; 20 | const API_ROOT = "https://api.github.com"; 21 | 22 | // Add debugging for unmocked requests 23 | 24 | /** 25 | * Mocks a response for the "get all commits for PR" API. 26 | * @param {Object} options Options for the request. 27 | * @param {number} options.number The pull request number. 28 | * @param {Array} options.commits The pull request commits to be returned. 29 | * @returns {void} 30 | * @private 31 | */ 32 | function mockGetAllCommitsForPR({ number, commits }) { 33 | 34 | const url = `${API_ROOT}/repos/test/repo-test/pulls/${number}/commits`; 35 | 36 | fetchMock.mockGlobal().get( 37 | url, 38 | { 39 | status: 200, 40 | headers: { 41 | "content-type": "application/json" 42 | }, 43 | body: JSON.stringify(commits) 44 | } 45 | ); 46 | } 47 | 48 | /** 49 | * Mocks a response for the "get combined status checks for commit" API. 50 | * @param {Object} options Options for the request. 51 | * @param {string} options.sha The SHA for the commit for which to retrieve statuses. 52 | * @param {Array} options.statuses The status response that should be used. 53 | * @returns {void} 54 | * @private 55 | */ 56 | function mockStatusChecksForCommit({ sha, statuses }) { 57 | 58 | const url = `${API_ROOT}/repos/test/repo-test/commits/${sha}/status`; 59 | 60 | fetchMock.mockGlobal().get( 61 | url, 62 | { 63 | status: 200, 64 | headers: { 65 | "content-type": "application/json" 66 | }, 67 | body: JSON.stringify({ 68 | sha, 69 | statuses 70 | }) 71 | } 72 | ); 73 | 74 | } 75 | 76 | /** 77 | * Mocks a response for the "create status check on PR" API. 78 | * Sets the status to pending. 79 | * @returns {void} 80 | */ 81 | function mockPendingStatusForWip() { 82 | 83 | fetchMock.mockGlobal().post( 84 | { 85 | url: `${API_ROOT}/repos/test/repo-test/statuses/111`, 86 | body: { 87 | context: "wip", 88 | state: "pending" 89 | }, 90 | matchPartialBody: true 91 | }, 92 | { 93 | status: 200, 94 | body: JSON.stringify({}) 95 | } 96 | ); 97 | } 98 | 99 | /** 100 | * Mocks a response for the "create status check on PR" API. 101 | * Sets the status to success. 102 | * @returns {void} 103 | */ 104 | function mockSuccessStatusForWip() { 105 | fetchMock.mockGlobal().post( 106 | { 107 | url: `${API_ROOT}/repos/test/repo-test/statuses/111`, 108 | body: { 109 | context: "wip", 110 | state: "success" 111 | }, 112 | matchPartialBody: true 113 | }, 114 | { 115 | status: 200, 116 | body: JSON.stringify({}) 117 | } 118 | ); 119 | } 120 | 121 | /** 122 | * Asserts that no status checks were created. 123 | * @returns {void} 124 | */ 125 | function assertNoStatusChecksCreated() { 126 | expect(fetchMock.callHistory.calls(`${API_ROOT}/repos/test/repo-test/statuses/111`)).toHaveLength(0); 127 | } 128 | 129 | //----------------------------------------------------------------------------- 130 | // Tests 131 | //----------------------------------------------------------------------------- 132 | 133 | describe("wip", () => { 134 | let bot = null; 135 | 136 | beforeEach(() => { 137 | bot = new Probot({ 138 | 139 | appId: 1, 140 | githubToken: "test", 141 | 142 | Octokit: ProbotOctokit.defaults(instanceOptions => ({ 143 | ...instanceOptions, 144 | throttle: { enabled: false }, 145 | retry: { enabled: false } 146 | })) 147 | }); 148 | wip(bot); 149 | }); 150 | 151 | afterEach(() => { 152 | fetchMock.unmockGlobal(); 153 | fetchMock.removeRoutes(); 154 | fetchMock.clearHistory(); 155 | }); 156 | 157 | ["opened", "reopened", "edited", "labeled", "unlabeled", "synchronize"].forEach(action => { 158 | describe(`pull request ${action}`, () => { 159 | test("create pending status if PR title starts with 'WIP:'", async () => { 160 | mockGetAllCommitsForPR({ 161 | number: 1, 162 | commits: [ 163 | { 164 | sha: "111", 165 | commit: { 166 | message: "New: add 1" 167 | } 168 | } 169 | ] 170 | }); 171 | 172 | mockPendingStatusForWip(); 173 | 174 | await bot.receive({ 175 | name: "pull_request", 176 | payload: { 177 | action, 178 | installation: { 179 | id: 1 180 | }, 181 | pull_request: { 182 | number: 1, 183 | title: "WIP: Some title", 184 | labels: [] 185 | }, 186 | repository: { 187 | name: "repo-test", 188 | owner: { 189 | login: "test" 190 | } 191 | } 192 | } 193 | }); 194 | 195 | }); 196 | 197 | test("create pending status if PR title contains '(WIP)'", async () => { 198 | mockGetAllCommitsForPR({ 199 | number: 1, 200 | commits: [ 201 | { 202 | sha: "111", 203 | commit: { 204 | message: "New: add 1" 205 | } 206 | } 207 | ] 208 | }); 209 | 210 | mockPendingStatusForWip(); 211 | 212 | await bot.receive({ 213 | name: "pull_request", 214 | payload: { 215 | action, 216 | installation: { 217 | id: 1 218 | }, 219 | pull_request: { 220 | number: 1, 221 | title: "Some title (WIP)", 222 | labels: [] 223 | }, 224 | repository: { 225 | name: "repo-test", 226 | owner: { 227 | login: "test" 228 | } 229 | } 230 | } 231 | }); 232 | 233 | }); 234 | 235 | test("create pending status if labels contain 'do not merge'", async () => { 236 | mockGetAllCommitsForPR({ 237 | number: 1, 238 | commits: [ 239 | { 240 | sha: "111", 241 | commit: { 242 | message: "New: add 1" 243 | } 244 | } 245 | ] 246 | }); 247 | 248 | mockPendingStatusForWip(); 249 | 250 | await bot.receive({ 251 | name: "pull_request", 252 | payload: { 253 | action, 254 | installation: { 255 | id: 1 256 | }, 257 | pull_request: { 258 | number: 1, 259 | title: "Some title", 260 | labels: [{ name: DO_NOT_MERGE_LABEL }] 261 | }, 262 | repository: { 263 | name: "repo-test", 264 | owner: { 265 | login: "test" 266 | } 267 | } 268 | } 269 | }); 270 | 271 | }); 272 | 273 | test("does not create status check if PR is not WIP and no wip status exists", async () => { 274 | mockGetAllCommitsForPR({ 275 | number: 1, 276 | commits: [ 277 | { 278 | sha: "111", 279 | commit: { 280 | message: "New: add 1" 281 | } 282 | } 283 | ] 284 | }); 285 | 286 | mockStatusChecksForCommit({ 287 | sha: "111", 288 | statuses: [] 289 | }); 290 | 291 | await bot.receive({ 292 | name: "pull_request", 293 | payload: { 294 | action, 295 | installation: { 296 | id: 1 297 | }, 298 | pull_request: { 299 | number: 1, 300 | title: "Some title", 301 | labels: [] 302 | }, 303 | repository: { 304 | name: "repo-test", 305 | owner: { 306 | login: "test" 307 | } 308 | } 309 | } 310 | }); 311 | 312 | assertNoStatusChecksCreated(); 313 | 314 | }); 315 | 316 | test("creates success status check if PR is not WIP and wip status exists", async () => { 317 | mockGetAllCommitsForPR({ 318 | number: 1, 319 | commits: [ 320 | { 321 | sha: "111", 322 | commit: { 323 | message: "New: add 1" 324 | } 325 | } 326 | ] 327 | }); 328 | 329 | mockStatusChecksForCommit({ 330 | sha: "111", 331 | statuses: [{ 332 | state: "pending", 333 | context: "wip" 334 | }] 335 | }); 336 | 337 | mockSuccessStatusForWip(); 338 | 339 | await bot.receive({ 340 | name: "pull_request", 341 | payload: { 342 | action, 343 | installation: { 344 | id: 1 345 | }, 346 | pull_request: { 347 | number: 1, 348 | title: "Some title", 349 | labels: [] 350 | }, 351 | repository: { 352 | name: "repo-test", 353 | owner: { 354 | login: "test" 355 | } 356 | } 357 | } 358 | }); 359 | 360 | }); 361 | }); 362 | }); 363 | }); 364 | --------------------------------------------------------------------------------