Repository: eslint/eslint-github-bot (js)

Issue:
Automatically assign an issue when checkbox is checked
When a new issue is opened and the author has checked "I'm willing to submit a pull request", we should automatically assign the issue to that user to avoid an extra step for the team.

Looking for a volunteer for this.

Pull request:
feat: automatically assign issues to users willing to submit PRs
This PR adds a new plugin that automatically assigns issues to users who have checked the "I am willing to submit a pull request to implement this change" checkbox in the issue template.

Closes #218

Patch:
diff --git a/src/app.js b/src/app.js
index bbd3f3c..9f01a60 100644
--- a/src/app.js
+++ b/src/app.js
@@ -23,6 +23,7 @@ const plugins = require("./plugins");
 //-----------------------------------------------------------------------------
 
 const enabledPlugins = new Set([
+    "autoAssign",
     "commitMessage",
     "needsInfo",
     "recurringIssues",
diff --git a/src/plugins/auto-assign/index.js b/src/plugins/auto-assign/index.js
new file mode 100644
index 0000000..caf137f
--- /dev/null
+++ b/src/plugins/auto-assign/index.js
@@ -0,0 +1,54 @@
+/**
+ * @fileoverview Automatically assigns issues to users who have indicated they're willing to submit a PR
+ * @author xbinaryx
+ */
+
+"use strict";
+
+//-----------------------------------------------------------------------------
+// Type Definitions
+//-----------------------------------------------------------------------------
+
+/** @typedef {import("probot").Context} ProbotContext */
+
+//-----------------------------------------------------------------------------
+// Helpers
+//-----------------------------------------------------------------------------
+
+/**
+ * Checks if the issue body contains text indicating the user is willing to submit a PR
+ * @param {string} body The issue body text
+ * @returns {boolean} True if the user indicated they're willing to submit a PR
+ * @private
+ */
+function isWillingToSubmitPR(body) {
+    return body
+        .toLowerCase()
+        .includes(
+            "- [x] i am willing to submit a pull request to implement this change."
+        );
+}
+
+/**
+ * Handler for issue opened event
+ * @param {ProbotContext} context probot context object
+ * @returns {Promise<void>} promise
+ * @private
+ */
+async function issueOpenedHandler(context) {
+    const { payload } = context;
+
+    if (!isWillingToSubmitPR(payload.issue.body)) {
+        return;
+    }
+
+    await context.octokit.issues.addAssignees(
+        context.issue({
+            assignees: [payload.issue.user.login],
+        })
+    );
+}
+
+module.exports = (robot) => {
+    robot.on("issues.opened", issueOpenedHandler);
+};
diff --git a/src/plugins/index.js b/src/plugins/index.js
index 8e8c003..7542af5 100644
--- a/src/plugins/index.js
+++ b/src/plugins/index.js
@@ -13,6 +13,7 @@
  */
 
 module.exports = {
+    autoAssign: require("./auto-assign"),
     commitMessage: require("./commit-message"),
     needsInfo: require("./needs-info"),
     recurringIssues: require("./recurring-issues"),


Test patch:
diff --git a/tests/plugins/auto-assign/index.js b/tests/plugins/auto-assign/index.js
new file mode 100644
index 0000000..61e37f4
--- /dev/null
+++ b/tests/plugins/auto-assign/index.js
@@ -0,0 +1,108 @@
+/**
+ * @fileoverview Tests for the auto-assign plugin
+ */
+
+"use strict";
+
+//-----------------------------------------------------------------------------
+// Requirements
+//-----------------------------------------------------------------------------
+
+const { Probot, ProbotOctokit } = require("probot");
+const { default: fetchMock } = require("fetch-mock");
+const autoAssign = require("../../../src/plugins/auto-assign");
+
+//-----------------------------------------------------------------------------
+// Helpers
+//-----------------------------------------------------------------------------
+
+const API_ROOT = "https://api.github.com";
+
+//-----------------------------------------------------------------------------
+// Tests
+//-----------------------------------------------------------------------------
+
+describe("auto-assign", () => {
+    let bot = null;
+
+    beforeEach(() => {
+        bot = new Probot({
+            appId: 1,
+            githubToken: "test",
+            Octokit: ProbotOctokit.defaults(instanceOptions => ({
+                ...instanceOptions,
+                throttle: { enabled: false },
+                retry: { enabled: false }
+            }))
+        });
+
+        autoAssign(bot);
+    });
+
+    afterEach(() => {
+        fetchMock.unmockGlobal();
+        fetchMock.removeRoutes();
+        fetchMock.clearHistory();
+    });
+
+    describe("issue opened", () => {
+        test("assigns issue to author when they indicate willingness to submit PR", async () => {
+            fetchMock.mockGlobal().post(
+                `${API_ROOT}/repos/test/repo-test/issues/1/assignees`,
+                { status: 200 }
+            );
+
+            await bot.receive({
+                name: "issues",
+                payload: {
+                    action: "opened",
+                    installation: {
+                        id: 1
+                    },
+                    issue: {
+                        number: 1,
+                        body: "- [x] I am willing to submit a pull request to implement this change.",
+                        user: {
+                            login: "user-a"
+                        }
+                    },
+                    repository: {
+                        name: "repo-test",
+                        owner: {
+                            login: "test"
+                        }
+                    }
+                }
+            });
+
+            expect(fetchMock.callHistory.called(`${API_ROOT}/repos/test/repo-test/issues/1/assignees`)).toBeTruthy();
+        });
+
+        test("does not assign issue when author does not indicate willingness to submit PR", async () => {
+            await bot.receive({
+                name: "issues",
+                payload: {
+                    action: "opened",
+                    installation: {
+                        id: 1
+                    },
+                    issue: {
+                        number: 1,
+                        body: "- [] I am willing to submit a pull request to implement this change.",
+                        user: {
+                            login: "user-a"
+                        }
+                    },
+                    repository: {
+                        name: "repo-test",
+                        owner: {
+                            login: "test"
+                        }
+                    }
+                }
+            });
+
+            expect(fetchMock.callHistory.called()).toBe(false);
+        });
+    });
+}); 
\ No newline at end of file