diff --git a/.gitignore b/.gitignore index dc12c03..8543b70 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ versions.json .svn /credentials.json *.pem +.env diff --git a/README.md b/README.md index cd02a4b..eee7a73 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,28 @@ [![Build Status](https://github.com/eslint/eslint-github-bot/workflows/CI/badge.svg)](https://github.com/eslint/eslint-github-bot/actions) -ESLint GitHub bot -========================== +# ESLint GitHub bot `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. -The bot can perform the following tasks: - -* **Triage** - adds the "triage" label to newly-created issues which don't have labels. -* **Commit message check** - adds a status check to pull requests to verify that they follow ESLint's [pull request guidelines](https://eslint.org/docs/developer-guide/contributing/pull-requests#step-2-make-your-changes) -* **Needs info** - adds a comment to issues requesting more information when a maintainer adds the `needs info` label. -* **Release/TSC meeting issues** - creates a new issue with the `release`/`tsc meeting` label scheduled two weeks later, after another release/TSC meeting issue is closed. -* **Release monitor** - searches the repository for an issue with the `release` and `patch release pending` labels, indicating that a patch release might soon be created from `master`. If an issue is found, adds a pending status check to all PRs that would require a semver-minor release, to prevent anyone from accidentally merging them. -* **Issue Archiver** - Locks and adds a label to issues which have been closed for a while -* **Issue Closer** - Closes and adds a label to issues which have been inactive for a while -* **WIP Tracking** - adds pending status check for PRs with WIP in the title or with "do not merge" label, and marks the status check as successful once the WIP indicators are removed. -* **PR ready to merge** (experimental) - adds a label to all PRs which are "ready to merge", defined by the following criteria: - * At least one review is approved. - * Build status is `success`. -* **Check unit tests** (experimental) - makes sure a PR contains unit tests. This check will be ignored for PRs with `Build|Chore|Docs|Upgrade` in the commit message. -* **Duplicate comments** (inactive) - removes all the duplicates comments by this bot and leaves the last one of each type. +## Environment Variables: + +* `APP_ID` (required): The numeric GitHub app ID +* `PRIVATE_KEY` (required): the contents of the private key you downloaded after creating the app. +* `WEBHOOK_SECRET` (required): Secret setup for GitHub webhook or you generated when you created the app. +* `PORT`: Port for web server _(optional, defaults to 8000)_. ## :wrench: Setup -* Clone this repo. +* Clone this repo * `npm install` -* Start the app - * `npm start` to start it as a GitHub APP +* `npm test` -### ENV variables required: +To start the server locally, you'll need: -* `PORT`: Port for web server _(optional, defaults to 8000)_. -* `SECRET`: Secret setup for GitHub webhook or you generated when you created the app. -* `PRIVATE_KEY`: the contents of the private key you downloaded after creating the app. -* `APP_ID`: The numeric app ID +* A PEM file +* A `.env` file that specifies the required environment variables + +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. #### Adding plugins @@ -45,4 +34,8 @@ To add a plugin: ## Deployment -The bot is deployed to a [Dokku](https://dokku.com) instance named github-bot.eslint.org and is installed as a GitHub Application at the organization level. +The bot is deployed to a [Dokku](https://dokku.com) instance named and is installed as a GitHub Application at the organization level. + +### Health Check + + diff --git a/package.json b/package.json index f83cf91..b2043b0 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "testEnvironment": "node" }, "engines": { - "node": "22.x" + "node": "22.x", + "npm": "10.x" } } diff --git a/src/app.js b/src/app.js index 23bf3be..bbd3f3c 100644 --- a/src/app.js +++ b/src/app.js @@ -9,7 +9,7 @@ // Requirements //----------------------------------------------------------------------------- -const { Probot, run } = require("probot"); +const { run } = require("probot"); const plugins = require("./plugins"); //----------------------------------------------------------------------------- @@ -17,33 +17,11 @@ const plugins = require("./plugins"); //----------------------------------------------------------------------------- /** @typedef {import("probot").Probot} Probot */ -/** @typedef {import("probot").Context} ProbotContext */ -/** @typedef {import("probot").ProbotOctokit} ProbotOctokit */ //----------------------------------------------------------------------------- // Main //----------------------------------------------------------------------------- -if (!process.env.SECRET) { - throw new Error("Missing 'SECRET' environment variable"); -} - -if (!process.env.PRIVATE_KEY) { - throw new Error("Missing 'PRIVATE_KEY' environment variable"); -} - -if (!process.env.APP_ID) { - throw new Error("Missing 'APP_ID' environment variable"); -} - -const port = process.env.PORT || 8000; -const app = new Probot({ - privateKey: process.env.PRIVATE_KEY, - appId: process.env.APP_ID, - secret: process.env.SECRET, - port -}); - const enabledPlugins = new Set([ "commitMessage", "needsInfo", @@ -52,10 +30,16 @@ const enabledPlugins = new Set([ "wip" ]); -// load all the enabled plugins from inside plugins folder -Object.keys(plugins) - .filter(pluginId => enabledPlugins.has(pluginId)) - .forEach(pluginId => app.load(plugins[pluginId])); +/** + * Assign the plugins to the robot. + * @param {Probot} robot The Probot instance. + * @returns {void} + */ +function appFn(robot) { + Object.keys(plugins) + .filter(pluginId => enabledPlugins.has(pluginId)) + .forEach(pluginId => plugins[pluginId](robot)); +} // start the server -run(app); +run(appFn);