From f52a01083361d4d5894b3dec014d86beec5380e9 Mon Sep 17 00:00:00 2001 From: Michaela Robosova Date: Mon, 23 Feb 2026 15:31:13 +0100 Subject: [PATCH 1/3] Do not consider rtibblesbot as contributor - Don't send replies on its PR - Don't track its PR in contributions spreadsheet --- scripts/constants.js | 10 ++++++++-- scripts/utils.js | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/constants.js b/scripts/constants.js index 2e5f3b4..2298ba7 100644 --- a/scripts/constants.js +++ b/scripts/constants.js @@ -3,6 +3,13 @@ const LE_BOT_USERNAME = 'learning-equality-bot[bot]'; const SENTRY_BOT_USERNAME = 'sentry-io[bot]'; const DEPENDABOT_USERNAME = 'dependabot[bot]'; +const RTIBBLESBOT_USERNAME = 'rtibblesbot'; +const BOT_USERNAMES = [ + LE_BOT_USERNAME, + SENTRY_BOT_USERNAME, + DEPENDABOT_USERNAME, + RTIBBLESBOT_USERNAME, +]; // close contributors are treated a bit special in some workflows, // for example, we receive a high priority notification about their @@ -103,8 +110,7 @@ const COMMUNITY_REPOS = [...PR_STATS_REPOS]; module.exports = { LE_BOT_USERNAME, - SENTRY_BOT_USERNAME, - DEPENDABOT_USERNAME, + BOT_USERNAMES, CLOSE_CONTRIBUTORS, KEYWORDS_DETECT_ASSIGNMENT_REQUEST, ISSUE_LABEL_HELP_WANTED, diff --git a/scripts/utils.js b/scripts/utils.js index 907c5f6..c9e4510 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -1,4 +1,4 @@ -const { LE_BOT_USERNAME, SENTRY_BOT_USERNAME, DEPENDABOT_USERNAME } = require('./constants'); +const { BOT_USERNAMES } = require('./constants'); // const { CLOSE_CONTRIBUTORS, TEAMS_WITH_CLOSE_CONTRIBUTORS } = require('./constants'); const { CLOSE_CONTRIBUTORS } = require('./constants'); @@ -10,7 +10,7 @@ async function isBot(username, { core }) { core.setFailed('Missing username'); return false; } - return [LE_BOT_USERNAME, SENTRY_BOT_USERNAME, DEPENDABOT_USERNAME].includes(username); + return BOT_USERNAMES.includes(username); } /** From 8620cb596614b46361a9019505d38ad17a71f1d3 Mon Sep 17 00:00:00 2001 From: Michaela Robosova Date: Mon, 23 Feb 2026 16:22:22 +0100 Subject: [PATCH 2/3] Add workflow to send info message about rtibblesbot review. --- .../workflows/call-pull-request-target.yml | 11 ++++ .github/workflows/pull-request-target.yml | 18 +++++++ .github/workflows/review-requested.yml | 52 +++++++++++++++++++ scripts/constants.js | 4 ++ scripts/review-requested.js | 17 ++++++ 5 files changed, 102 insertions(+) create mode 100644 .github/workflows/call-pull-request-target.yml create mode 100644 .github/workflows/pull-request-target.yml create mode 100644 .github/workflows/review-requested.yml create mode 100644 scripts/review-requested.js diff --git a/.github/workflows/call-pull-request-target.yml b/.github/workflows/call-pull-request-target.yml new file mode 100644 index 0000000..f2b0ae5 --- /dev/null +++ b/.github/workflows/call-pull-request-target.yml @@ -0,0 +1,11 @@ +name: Handle pull request events +on: + pull_request_target: + types: [review_requested] +jobs: + call-workflow: + name: Call shared workflow + uses: learningequality/.github/.github/workflows/pull-request-target.yml@main + secrets: + LE_BOT_APP_ID: ${{ secrets.LE_BOT_APP_ID }} + LE_BOT_PRIVATE_KEY: ${{ secrets.LE_BOT_PRIVATE_KEY }} diff --git a/.github/workflows/pull-request-target.yml b/.github/workflows/pull-request-target.yml new file mode 100644 index 0000000..a476a52 --- /dev/null +++ b/.github/workflows/pull-request-target.yml @@ -0,0 +1,18 @@ +name: Handle pull request events +on: + workflow_call: + secrets: + LE_BOT_APP_ID: + description: 'GitHub App ID for authentication' + required: true + LE_BOT_PRIVATE_KEY: + description: 'GitHub App Private Key for authentication' + required: true +jobs: + review-requested: + name: Handle review requested + if: ${{ github.event.action == 'review_requested' }} + uses: learningequality/.github/.github/workflows/review-requested.yml@main + secrets: + LE_BOT_APP_ID: ${{ secrets.LE_BOT_APP_ID }} + LE_BOT_PRIVATE_KEY: ${{ secrets.LE_BOT_PRIVATE_KEY }} diff --git a/.github/workflows/review-requested.yml b/.github/workflows/review-requested.yml new file mode 100644 index 0000000..ae819f3 --- /dev/null +++ b/.github/workflows/review-requested.yml @@ -0,0 +1,52 @@ +name: Handle review requested on community pull request +on: + workflow_call: + secrets: + LE_BOT_APP_ID: + description: 'GitHub App ID for authentication' + required: true + LE_BOT_PRIVATE_KEY: + description: 'GitHub App Private Key for authentication' + required: true +jobs: + check-if-contributor: + name: Check if author is contributor + uses: learningequality/.github/.github/workflows/is-contributor.yml@main + secrets: + LE_BOT_APP_ID: ${{ secrets.LE_BOT_APP_ID }} + LE_BOT_PRIVATE_KEY: ${{ secrets.LE_BOT_PRIVATE_KEY }} + with: + username: ${{ github.event.pull_request.user.login }} + author_association: ${{ github.event.pull_request.author_association }} + handle-review-requested: + name: Handle review requested + needs: [check-if-contributor] + if: ${{ needs.check-if-contributor.outputs.is_contributor == 'true' }} + runs-on: ubuntu-latest + steps: + - name: Generate App Token + id: generate-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.LE_BOT_APP_ID }} + private-key: ${{ secrets.LE_BOT_PRIVATE_KEY }} + - name: Checkout .github repository + uses: actions/checkout@v4 + with: + repository: learningequality/.github + ref: main + token: ${{ steps.generate-token.outputs.token }} + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: Install dependencies + run: yarn install --frozen-lockfile + - name: Run script + id: script + uses: actions/github-script@v7 + with: + github-token: ${{ steps.generate-token.outputs.token }} + script: | + const script = require('./scripts/review-requested.js'); + return await script({ github, context, core }); diff --git a/scripts/constants.js b/scripts/constants.js index 2298ba7..4e54b74 100644 --- a/scripts/constants.js +++ b/scripts/constants.js @@ -95,6 +95,8 @@ const BOT_MESSAGE_PULL_REQUEST = `👋 Thanks for contributing! \n\n We will ass const HOLIDAY_MESSAGE = `Season's greetings! 👋 \n\n We'd like to thank everyone for another year of fruitful collaborations, engaging discussions, and for the continued support of our work. **Learning Equality will be on holidays from December 22 to January 5.** We look forward to much more in the new year and wish you a very happy holiday season!${GSOC_NOTE}`; +const BOT_MESSAGE_RTIBBLESBOT_REVIEW = `📢✨ **Before we assign a reviewer, we'll turn on \`@rtibblesbot\` to pre-review. Its comments are generated by an LLM, and should be evaluated accordingly.**`; + // Repositories to include in PR statistics reports const PR_STATS_REPOS = [ 'kolibri', @@ -117,6 +119,8 @@ module.exports = { BOT_MESSAGE_ISSUE_NOT_OPEN, BOT_MESSAGE_ALREADY_ASSIGNED, BOT_MESSAGE_PULL_REQUEST, + BOT_MESSAGE_RTIBBLESBOT_REVIEW, + RTIBBLESBOT_USERNAME, TEAMS_WITH_CLOSE_CONTRIBUTORS, HOLIDAY_MESSAGE, PR_STATS_REPOS, diff --git a/scripts/review-requested.js b/scripts/review-requested.js new file mode 100644 index 0000000..e3c63a4 --- /dev/null +++ b/scripts/review-requested.js @@ -0,0 +1,17 @@ +// Send info message about rtibblesbot review + +const { BOT_MESSAGE_RTIBBLESBOT_REVIEW, RTIBBLESBOT_USERNAME } = require('./constants'); +const { sendBotMessage } = require('./utils'); + +module.exports = async ({ github, context, core }) => { + try { + const reviewer = context.payload.requested_reviewer?.login; + if (reviewer !== RTIBBLESBOT_USERNAME) { + return; + } + const prNumber = context.payload.pull_request.number; + await sendBotMessage(prNumber, BOT_MESSAGE_RTIBBLESBOT_REVIEW, { github, context }); + } catch (error) { + core.setFailed(`Action failed with error: ${error.message}`); + } +}; From 5ab682361af8a124a1752f1650ea0720fe0410fe Mon Sep 17 00:00:00 2001 From: Michaela Robosova Date: Mon, 23 Feb 2026 16:42:44 +0100 Subject: [PATCH 3/3] Add workflow to send info message when community review invited. --- .../workflows/call-pull-request-target.yml | 2 +- .github/workflows/pull-request-label.yml | 52 +++++++++++++++++++ .github/workflows/pull-request-target.yml | 7 +++ docs/community-review.md | 21 ++++++++ scripts/constants.js | 5 ++ scripts/pull-request-label.js | 17 ++++++ 6 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/pull-request-label.yml create mode 100644 docs/community-review.md create mode 100644 scripts/pull-request-label.js diff --git a/.github/workflows/call-pull-request-target.yml b/.github/workflows/call-pull-request-target.yml index f2b0ae5..d2e556f 100644 --- a/.github/workflows/call-pull-request-target.yml +++ b/.github/workflows/call-pull-request-target.yml @@ -1,7 +1,7 @@ name: Handle pull request events on: pull_request_target: - types: [review_requested] + types: [review_requested,labeled] jobs: call-workflow: name: Call shared workflow diff --git a/.github/workflows/pull-request-label.yml b/.github/workflows/pull-request-label.yml new file mode 100644 index 0000000..0ec12d2 --- /dev/null +++ b/.github/workflows/pull-request-label.yml @@ -0,0 +1,52 @@ +name: Handle label added on community pull request +on: + workflow_call: + secrets: + LE_BOT_APP_ID: + description: 'GitHub App ID for authentication' + required: true + LE_BOT_PRIVATE_KEY: + description: 'GitHub App Private Key for authentication' + required: true +jobs: + check-if-contributor: + name: Check if author is contributor + uses: learningequality/.github/.github/workflows/is-contributor.yml@main + secrets: + LE_BOT_APP_ID: ${{ secrets.LE_BOT_APP_ID }} + LE_BOT_PRIVATE_KEY: ${{ secrets.LE_BOT_PRIVATE_KEY }} + with: + username: ${{ github.event.pull_request.user.login }} + author_association: ${{ github.event.pull_request.author_association }} + handle-label: + name: Handle label + needs: [check-if-contributor] + if: ${{ needs.check-if-contributor.outputs.is_contributor == 'true' }} + runs-on: ubuntu-latest + steps: + - name: Generate App Token + id: generate-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.LE_BOT_APP_ID }} + private-key: ${{ secrets.LE_BOT_PRIVATE_KEY }} + - name: Checkout .github repository + uses: actions/checkout@v4 + with: + repository: learningequality/.github + ref: main + token: ${{ steps.generate-token.outputs.token }} + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: Install dependencies + run: yarn install --frozen-lockfile + - name: Run script + id: script + uses: actions/github-script@v7 + with: + github-token: ${{ steps.generate-token.outputs.token }} + script: | + const script = require('./scripts/pull-request-label.js'); + return await script({ github, context, core }); diff --git a/.github/workflows/pull-request-target.yml b/.github/workflows/pull-request-target.yml index a476a52..8ef404c 100644 --- a/.github/workflows/pull-request-target.yml +++ b/.github/workflows/pull-request-target.yml @@ -16,3 +16,10 @@ jobs: secrets: LE_BOT_APP_ID: ${{ secrets.LE_BOT_APP_ID }} LE_BOT_PRIVATE_KEY: ${{ secrets.LE_BOT_PRIVATE_KEY }} + pull-request-label: + name: Handle pull request label + if: ${{ github.event.action == 'labeled' }} + uses: learningequality/.github/.github/workflows/pull-request-label.yml@main + secrets: + LE_BOT_APP_ID: ${{ secrets.LE_BOT_APP_ID }} + LE_BOT_PRIVATE_KEY: ${{ secrets.LE_BOT_PRIVATE_KEY }} diff --git a/docs/community-review.md b/docs/community-review.md new file mode 100644 index 0000000..6e95c77 --- /dev/null +++ b/docs/community-review.md @@ -0,0 +1,21 @@ +# Community Review + +## Authors + +🎉 _Thank you for your contribution! Before we assign a maintainer, we invite the open-source community to pre-review your pull request. The focus of this round is community collaboration. Be kind with each other & have fun!_ :relieved: + +- Always engage with the community **respectfully and patiently**, and in line with our [Contributing guidelines](https://learningequality.org/contributing-to-our-open-code-base). Pay extra attention to [Using generative AI](https://learningequality.org/contributing-to-our-open-code-base/#using-generative-ai)—this is an opportunity to practice your own communication and collaboration skills. +- Experience levels in the community vary. **You don’t need to treat all feedback as final—discuss and clarify together. If something is unclear, just wait for a maintainer review.** +- If you notice any inappropriate behavior, contact us at [contributors@learningequality.org](mailto:contributors@learningequality.org). + +## Reviewers + +🙌 _Thank you for joining the review! Based on your interest and experience, you may choose to do some or all of the following: compare the implementation with the issue requirements, run the pull request locally and confirm it works as expected, report bugs, or ask questions. If you didn’t spot any problems, give the authors a pat on the back! Be kind with each other & have fun!_ :relieved: + +- Always keep in mind: **Respectful, Concise, Relevant** +- Follow our [Contributing guidelines](https://learningequality.org/contributing-to-our-open-code-base). **Pay extra attention to [Using generative AI](https://learningequality.org/contributing-to-our-open-code-base/#using-generative-ai). Avoid generic & long or otherwise AI-generated comments—they aren’t helpful and feel disrespectful to both authors and maintainers.** This is an opportunity to practice your own communication and collaboration skills. +- You may want to briefly introduce yourself and mention your experience level +- Before posting your first review, **see the following resources**: + - [What makes a code review good or bad?](https://github.blog/developer-skills/github/how-to-review-code-effectively-a-github-staff-engineers-philosophy/#what-makes-a-code-review-good-or-bad) + - [How to give a good code review](https://github.blog/developer-skills/github/how-to-review-code-effectively-a-github-staff-engineers-philosophy/#how-to-give-a-good-code-review) +* If you notice any inappropriate behavior, contact us at [contributors@learningequality.org](mailto:contributors@learningequality.org). diff --git a/scripts/constants.js b/scripts/constants.js index 4e54b74..5af3464 100644 --- a/scripts/constants.js +++ b/scripts/constants.js @@ -82,6 +82,7 @@ const KEYWORDS_DETECT_ASSIGNMENT_REQUEST = [ ]; const ISSUE_LABEL_HELP_WANTED = 'help wanted'; +const LABEL_COMMUNITY_REVIEW = 'community-review'; // Will be attached to bot messages when not empty // const GSOC_NOTE = ''; @@ -97,6 +98,8 @@ const HOLIDAY_MESSAGE = `Season's greetings! 👋 \n\n We'd like to thank everyo const BOT_MESSAGE_RTIBBLESBOT_REVIEW = `📢✨ **Before we assign a reviewer, we'll turn on \`@rtibblesbot\` to pre-review. Its comments are generated by an LLM, and should be evaluated accordingly.**`; +const BOT_MESSAGE_COMMUNITY_REVIEW = `📢✨ **Before we assign a reviewer, we'll invite community pre-review. See the [community review guidance](https://github.com/learningequality/.github/blob/main/docs/community-review.md) for both authors and reviewers.**`; + // Repositories to include in PR statistics reports const PR_STATS_REPOS = [ 'kolibri', @@ -121,6 +124,8 @@ module.exports = { BOT_MESSAGE_PULL_REQUEST, BOT_MESSAGE_RTIBBLESBOT_REVIEW, RTIBBLESBOT_USERNAME, + LABEL_COMMUNITY_REVIEW, + BOT_MESSAGE_COMMUNITY_REVIEW, TEAMS_WITH_CLOSE_CONTRIBUTORS, HOLIDAY_MESSAGE, PR_STATS_REPOS, diff --git a/scripts/pull-request-label.js b/scripts/pull-request-label.js new file mode 100644 index 0000000..bcf9fe7 --- /dev/null +++ b/scripts/pull-request-label.js @@ -0,0 +1,17 @@ +// Send info message when community-review label is added + +const { BOT_MESSAGE_COMMUNITY_REVIEW, LABEL_COMMUNITY_REVIEW } = require('./constants'); +const { sendBotMessage } = require('./utils'); + +module.exports = async ({ github, context, core }) => { + try { + const label = context.payload.label?.name; + if (label !== LABEL_COMMUNITY_REVIEW) { + return; + } + const prNumber = context.payload.pull_request.number; + await sendBotMessage(prNumber, BOT_MESSAGE_COMMUNITY_REVIEW, { github, context }); + } catch (error) { + core.setFailed(`Action failed with error: ${error.message}`); + } +};