From 74f2a34943d1b8a62bedb6fe8690476decab2ee7 Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 15:50:59 +0530 Subject: [PATCH 01/12] ci: add PR Community Tested workflow skeleton Adds .github/workflows/pr-community-tested.yml with the issue_comment trigger (created only), PR-only job guard, and least-privilege permissions (issues: write, pull-requests: write). The script step is a placeholder for the counting and labeling logic added in subsequent commits. --- .github/workflows/pr-community-tested.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/pr-community-tested.yml diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml new file mode 100644 index 000000000..642a330ae --- /dev/null +++ b/.github/workflows/pr-community-tested.yml @@ -0,0 +1,22 @@ +name: PR Community Tested + +on: + issue_comment: + types: [created] + +permissions: + issues: write + pull-requests: write + +jobs: + community-tested: + if: | + github.event.issue.pull_request != null && + startsWith(github.event.comment.body, '/tested') + runs-on: ubuntu-latest + steps: + - name: Process /tested command + uses: actions/github-script@v7 + with: + script: | + core.info("Triggered by: " + context.actor); From 89872031507998a89f9ca269834ef18e96c1dfae Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 16:23:49 +0530 Subject: [PATCH 02/12] ci(community-tested): implement paginated tester counting and labeling Fetches the PR author and all conversation comments on each /tested trigger. Builds a deduplicated Set of non-author, non-bot logins whose comment body is exactly '/tested'. Applies the community-tested label once 2 unique testers are recorded; addLabels is idempotent so re-running never causes issues. --- .github/workflows/pr-community-tested.yml | 52 ++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index 642a330ae..2ce46f16c 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -19,4 +19,54 @@ jobs: uses: actions/github-script@v7 with: script: | - core.info("Triggered by: " + context.actor); + const issueNumber = context.issue.number; + const repo = context.repo; + + // Resolve the PR author so we can exclude them from the count + const { data: pr } = await github.rest.pulls.get({ + ...repo, + pull_number: issueNumber, + }); + const prAuthor = pr.user.login; + + // Paginate through every conversation comment on this PR + const allComments = await github.paginate( + github.rest.issues.listComments, + { ...repo, issue_number: issueNumber, per_page: 100 } + ); + + // Build a deduplicated set of qualifying testers: + // - trimmed body must be exactly "/tested" + // - must not be the PR author + // - must not be a bot account + const testers = new Set(); + for (const c of allComments) { + const login = c.user.login; + const body = (c.body ?? "").trim(); + if ( + body === "/tested" && + login !== prAuthor && + !login.endsWith("[bot]") + ) { + testers.add(login); + } + } + + core.info( + `Unique testers so far: ${testers.size} — [${[...testers].join(", ")}]` + ); + + // Apply the label once the threshold is reached + const LABEL_NAME = "community-tested"; + const THRESHOLD = 2; + + if (testers.size >= THRESHOLD) { + await github.rest.issues.addLabels({ + ...repo, + issue_number: issueNumber, + labels: [LABEL_NAME], + }); + core.info(`Label "${LABEL_NAME}" applied — ${testers.size} unique testers.`); + } else { + core.info(`${testers.size}/${THRESHOLD} testers. Label not applied yet.`); + } From e1580e99e32d6a493379074bed68c8057e3efad2 Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 16:26:33 +0530 Subject: [PATCH 03/12] =?UTF-8?q?ci(community-tested):=20add=20ephemeral?= =?UTF-8?q?=20feedback=20via=20reactions=20and=20step=20summary=20Reacts?= =?UTF-8?q?=20with=20+1=20(=F0=9F=91=8D)=20on=20a=20valid=20/tested=20comm?= =?UTF-8?q?ent=20and=20eyes=20(=F0=9F=91=80)=20when=20the=20comment=20is?= =?UTF-8?q?=20ignored=20(author=20self-test=20or=20not=20exact=20match).?= =?UTF-8?q?=20Writes=20a=20progress=20table=20to=20the=20Actions=20step=20?= =?UTF-8?q?summary=20so=20maintainers=20can=20see=20tester=20status=20with?= =?UTF-8?q?out=20any=20new=20PR=20thread=20noise.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pr-community-tested.yml | 41 +++++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index 2ce46f16c..454734674 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -35,6 +35,10 @@ jobs: { ...repo, issue_number: issueNumber, per_page: 100 } ); + // Constants — declared early so the summary and label steps share them + const LABEL_NAME = "community-tested"; + const THRESHOLD = 2; + // Build a deduplicated set of qualifying testers: // - trimmed body must be exactly "/tested" // - must not be the PR author @@ -56,10 +60,41 @@ jobs: `Unique testers so far: ${testers.size} — [${[...testers].join(", ")}]` ); - // Apply the label once the threshold is reached - const LABEL_NAME = "community-tested"; - const THRESHOLD = 2; + // ── Ephemeral feedback via reaction on the triggering comment ──── + // Reactions appear on the comment itself — no new thread noise. + // 👍 (+1) — comment was valid and counted + // 👀 (eyes) — comment was ignored (author self-test, or not exact match) + const triggerCommentId = context.payload.comment.id; + const commenter = context.actor; + const isValid = + commenter !== prAuthor && + !commenter.endsWith("[bot]") && + (context.payload.comment.body ?? "").trim() === "/tested"; + await github.rest.reactions.createForIssueComment({ + ...repo, + comment_id: triggerCommentId, + content: isValid ? "+1" : "eyes", + }); + + // ── Step summary (visible in Actions UI, not in the PR thread) ─── + await core.summary + .addHeading("Community Tested Progress", 3) + .addTable([ + [ + { data: "Testers", header: true }, + { data: "Required", header: true }, + { data: "Status", header: true }, + ], + [ + `${[...testers].join(", ") || "—"}`, + `${THRESHOLD}`, + testers.size >= THRESHOLD ? "✅ Label applied" : `⏳ ${testers.size}/${THRESHOLD} — waiting`, + ], + ]) + .write(); + + // Apply the label once the threshold is reached if (testers.size >= THRESHOLD) { await github.rest.issues.addLabels({ ...repo, From 449cc388307000a5d05c89e9f9602c9c78de0b7d Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 16:29:37 +0530 Subject: [PATCH 04/12] =?UTF-8?q?ci(community-tested):=20auto-create=20lab?= =?UTF-8?q?el=20and=20make=20workflow=20self-contained=20Before=20applying?= =?UTF-8?q?=20the=20community-tested=20label,=20the=20workflow=20now=20che?= =?UTF-8?q?cks=20whether=20it=20exists=20and=20creates=20it=20(color=20#00?= =?UTF-8?q?75ca,=20with=20description)=20if=20not.=20This=20removes=20any?= =?UTF-8?q?=20need=20for=20manual=20repo=20setup=20=E2=80=94=20the=20first?= =?UTF-8?q?=20qualifying=20PR=20triggers=20label=20creation=20automaticall?= =?UTF-8?q?y.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pr-community-tested.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index 454734674..cabf6c0f7 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -96,6 +96,24 @@ jobs: // Apply the label once the threshold is reached if (testers.size >= THRESHOLD) { + // Auto-create the label if it doesn't exist yet — no manual repo setup needed + try { + await github.rest.issues.getLabel({ ...repo, name: LABEL_NAME }); + } catch (err) { + if (err.status === 404) { + await github.rest.issues.createLabel({ + ...repo, + name: LABEL_NAME, + color: "0075ca", + description: "Tested by at least 2 independent community contributors", + }); + core.info(`Label "${LABEL_NAME}" created in this repository.`); + } else { + throw err; + } + } + + // addLabels is idempotent — safe to call even if the label is already on the PR await github.rest.issues.addLabels({ ...repo, issue_number: issueNumber, From 9d0e734f3afdcf53e430a1a5365221329b76aeae Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 16:40:22 +0530 Subject: [PATCH 05/12] ci(community-tested): skip labeling when PR is closed or merged --- .github/workflows/pr-community-tested.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index cabf6c0f7..6c19180da 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -29,6 +29,12 @@ jobs: }); const prAuthor = pr.user.login; + // Skip closed/merged PRs — no point labeling a finished PR + if (pr.state !== "open") { + core.info("PR is not open. Skipping."); + return; + } + // Paginate through every conversation comment on this PR const allComments = await github.paginate( github.rest.issues.listComments, From 8daca44de80f6d7f8d2c78c453bfe1236d3adbea Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 17:45:18 +0530 Subject: [PATCH 06/12] ci(community-tested): normalize /tested comparison with toLowerCase - Compare trimmed comment bodies case-insensitively when counting testers and when deciding +1 vs eyes reactions, so /Tested and /TESTED match the command once the workflow has started. --- .github/workflows/pr-community-tested.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index 6c19180da..61735aee4 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -52,7 +52,7 @@ jobs: const testers = new Set(); for (const c of allComments) { const login = c.user.login; - const body = (c.body ?? "").trim(); + const body = (c.body ?? "").trim().toLowerCase(); if ( body === "/tested" && login !== prAuthor && @@ -75,7 +75,7 @@ jobs: const isValid = commenter !== prAuthor && !commenter.endsWith("[bot]") && - (context.payload.comment.body ?? "").trim() === "/tested"; + (context.payload.comment.body ?? "").trim().toLowerCase() === "/tested"; await github.rest.reactions.createForIssueComment({ ...repo, From 7900f365162a909c9205fda80f86b32e0bb56778 Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 18:51:10 +0530 Subject: [PATCH 07/12] =?UTF-8?q?ci:=20gate=20/tested=20on=20commenter=20h?= =?UTF-8?q?aving=20=E2=89=A51=20merged=20PR=20in=20the=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pr-community-tested.yml | 88 ++++++++++++----------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index 61735aee4..f0e81ecf9 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -22,68 +22,80 @@ jobs: const issueNumber = context.issue.number; const repo = context.repo; - // Resolve the PR author so we can exclude them from the count const { data: pr } = await github.rest.pulls.get({ ...repo, pull_number: issueNumber, }); const prAuthor = pr.user.login; - // Skip closed/merged PRs — no point labeling a finished PR if (pr.state !== "open") { core.info("PR is not open. Skipping."); return; } - // Paginate through every conversation comment on this PR + const triggerCommentId = context.payload.comment.id; + const commenter = context.actor; + + // Eligibility: not the PR author, not a bot, has ≥1 merged PR in this repo + const isAuthor = commenter === prAuthor; + const isBot = commenter.endsWith("[bot]"); + + let hasMergedPR = false; + if (!isAuthor && !isBot) { + const { data: searchResult } = await github.rest.search.issuesAndPullRequests({ + q: `repo:${repo.owner}/${repo.repo} is:pr is:merged author:${commenter}`, + }); + hasMergedPR = searchResult.total_count > 0; + } + + const isEligible = + !isAuthor && + !isBot && + hasMergedPR && + (context.payload.comment.body ?? "").trim().toLowerCase() === "/tested"; + + await github.rest.reactions.createForIssueComment({ + ...repo, + comment_id: triggerCommentId, + content: isEligible ? "+1" : "eyes", + }); + + if (!isEligible) { + let reason; + if (isAuthor) reason = "you are the author of this PR"; + else if (isBot) reason = "bot accounts cannot run this command"; + else if (!hasMergedPR) reason = "only contributors with at least one merged PR in this repository can run `/tested`"; + else reason = "the comment must be exactly `/tested`"; + + await github.rest.issues.createComment({ + ...repo, + issue_number: issueNumber, + body: `@${commenter} Your \`/tested\` was not counted — ${reason}.`, + }); + core.info(`${commenter} not eligible: ${reason}`); + return; + } + const allComments = await github.paginate( github.rest.issues.listComments, { ...repo, issue_number: issueNumber, per_page: 100 } ); - // Constants — declared early so the summary and label steps share them const LABEL_NAME = "community-tested"; const THRESHOLD = 2; - // Build a deduplicated set of qualifying testers: - // - trimmed body must be exactly "/tested" - // - must not be the PR author - // - must not be a bot account + const testers = new Set(); for (const c of allComments) { const login = c.user.login; const body = (c.body ?? "").trim().toLowerCase(); - if ( - body === "/tested" && - login !== prAuthor && - !login.endsWith("[bot]") - ) { + if (body === "/tested" && login !== prAuthor && !login.endsWith("[bot]")) { testers.add(login); } } - core.info( - `Unique testers so far: ${testers.size} — [${[...testers].join(", ")}]` - ); - - // ── Ephemeral feedback via reaction on the triggering comment ──── - // Reactions appear on the comment itself — no new thread noise. - // 👍 (+1) — comment was valid and counted - // 👀 (eyes) — comment was ignored (author self-test, or not exact match) - const triggerCommentId = context.payload.comment.id; - const commenter = context.actor; - const isValid = - commenter !== prAuthor && - !commenter.endsWith("[bot]") && - (context.payload.comment.body ?? "").trim().toLowerCase() === "/tested"; - - await github.rest.reactions.createForIssueComment({ - ...repo, - comment_id: triggerCommentId, - content: isValid ? "+1" : "eyes", - }); + core.info(`Unique testers: ${testers.size} — [${[...testers].join(", ")}]`); - // ── Step summary (visible in Actions UI, not in the PR thread) ─── await core.summary .addHeading("Community Tested Progress", 3) .addTable([ @@ -100,9 +112,7 @@ jobs: ]) .write(); - // Apply the label once the threshold is reached if (testers.size >= THRESHOLD) { - // Auto-create the label if it doesn't exist yet — no manual repo setup needed try { await github.rest.issues.getLabel({ ...repo, name: LABEL_NAME }); } catch (err) { @@ -111,21 +121,19 @@ jobs: ...repo, name: LABEL_NAME, color: "0075ca", - description: "Tested by at least 2 independent community contributors", + description: "Tested by community contributors with ≥1 merged PR in this repo", }); - core.info(`Label "${LABEL_NAME}" created in this repository.`); } else { throw err; } } - // addLabels is idempotent — safe to call even if the label is already on the PR await github.rest.issues.addLabels({ ...repo, issue_number: issueNumber, labels: [LABEL_NAME], }); - core.info(`Label "${LABEL_NAME}" applied — ${testers.size} unique testers.`); + core.info(`Label "${LABEL_NAME}" applied — ${testers.size} testers.`); } else { core.info(`${testers.size}/${THRESHOLD} testers. Label not applied yet.`); } From ea4aeadee4f9438e233f4c881cc1504ec050adc0 Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 19:10:11 +0530 Subject: [PATCH 08/12] ci: apply label on first tester and prompt for demo video upload --- .github/workflows/pr-community-tested.yml | 26 ++++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index f0e81ecf9..3a5fa1052 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -62,7 +62,7 @@ jobs: if (!isEligible) { let reason; - if (isAuthor) reason = "you are the author of this PR"; + if (isAuthor) reason = "you are the author of this PR"; else if (isBot) reason = "bot accounts cannot run this command"; else if (!hasMergedPR) reason = "only contributors with at least one merged PR in this repository can run `/tested`"; else reason = "the comment must be exactly `/tested`"; @@ -82,7 +82,6 @@ jobs: ); const LABEL_NAME = "community-tested"; - const THRESHOLD = 2; const testers = new Set(); @@ -101,18 +100,17 @@ jobs: .addTable([ [ { data: "Testers", header: true }, - { data: "Required", header: true }, { data: "Status", header: true }, ], [ `${[...testers].join(", ") || "—"}`, - `${THRESHOLD}`, - testers.size >= THRESHOLD ? "✅ Label applied" : `⏳ ${testers.size}/${THRESHOLD} — waiting`, + testers.size >= 1 ? "✅ Label applied" : "⏳ Waiting for first tester", ], ]) .write(); - if (testers.size >= THRESHOLD) { + // Apply the label on the first eligible tester + if (testers.size >= 1) { try { await github.rest.issues.getLabel({ ...repo, name: LABEL_NAME }); } catch (err) { @@ -133,7 +131,19 @@ jobs: issue_number: issueNumber, labels: [LABEL_NAME], }); - core.info(`Label "${LABEL_NAME}" applied — ${testers.size} testers.`); + + // On the first tester, ask them to upload a demo video + if (testers.size === 1) { + await github.rest.issues.createComment({ + ...repo, + issue_number: issueNumber, + body: + `@${commenter} has marked this PR as community-tested!\n\n` + + `Please reply with a **demo video** showing your test so reviewers can verify the behaviour.`, + }); + } + + core.info(`Label "${LABEL_NAME}" applied — ${testers.size} tester(s).`); } else { - core.info(`${testers.size}/${THRESHOLD} testers. Label not applied yet.`); + core.info("No eligible testers yet. Label not applied."); } From f504c810c28ddfdf6e1387d84c6d5c002cde86de Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 19:34:27 +0530 Subject: [PATCH 09/12] ci: add running confidence score comment updated on each /tested --- .github/workflows/pr-community-tested.yml | 54 ++++++++++++++++++----- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index 3a5fa1052..b5cf56095 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -36,7 +36,7 @@ jobs: const triggerCommentId = context.payload.comment.id; const commenter = context.actor; - // Eligibility: not the PR author, not a bot, has ≥1 merged PR in this repo + // Eligibility: not the PR author, not a bot, has >=1 merged PR in this repo const isAuthor = commenter === prAuthor; const isBot = commenter.endsWith("[bot]"); @@ -63,14 +63,14 @@ jobs: if (!isEligible) { let reason; if (isAuthor) reason = "you are the author of this PR"; - else if (isBot) reason = "bot accounts cannot run this command"; + else if (isBot) reason = "bot accounts cannot run this command"; else if (!hasMergedPR) reason = "only contributors with at least one merged PR in this repository can run `/tested`"; - else reason = "the comment must be exactly `/tested`"; + else reason = "the comment must be exactly `/tested`"; await github.rest.issues.createComment({ ...repo, issue_number: issueNumber, - body: `@${commenter} Your \`/tested\` was not counted — ${reason}.`, + body: `@${commenter} Your \`/tested\` was not counted -- ${reason}.`, }); core.info(`${commenter} not eligible: ${reason}`); return; @@ -83,7 +83,7 @@ jobs: const LABEL_NAME = "community-tested"; - + // Deduplicated testers (author + bot filtered; merged-PR gate enforced live above) const testers = new Set(); for (const c of allComments) { const login = c.user.login; @@ -93,7 +93,7 @@ jobs: } } - core.info(`Unique testers: ${testers.size} — [${[...testers].join(", ")}]`); + core.info(`Unique testers: ${testers.size} -- [${[...testers].join(", ")}]`); await core.summary .addHeading("Community Tested Progress", 3) @@ -103,8 +103,8 @@ jobs: { data: "Status", header: true }, ], [ - `${[...testers].join(", ") || "—"}`, - testers.size >= 1 ? "✅ Label applied" : "⏳ Waiting for first tester", + `${[...testers].join(", ") || "-"}`, + testers.size >= 1 ? "Label applied" : "Waiting for first tester", ], ]) .write(); @@ -119,7 +119,7 @@ jobs: ...repo, name: LABEL_NAME, color: "0075ca", - description: "Tested by community contributors with ≥1 merged PR in this repo", + description: "Tested by community contributors with >=1 merged PR in this repo", }); } else { throw err; @@ -143,7 +143,41 @@ jobs: }); } - core.info(`Label "${LABEL_NAME}" applied — ${testers.size} tester(s).`); + core.info(`Label "${LABEL_NAME}" applied -- ${testers.size} tester(s).`); } else { core.info("No eligible testers yet. Label not applied."); } + + // Confidence score: find-or-update a single bot comment tracking progress + const MARKER = ""; + const confidence = + testers.size >= 4 ? "High (4+ testers)" : + testers.size >= 2 ? "Medium (2-3 testers)" : + testers.size >= 1 ? "Low (1 tester)" : "None"; + + const scoreBody = + `${MARKER}\n` + + `### Community Testing Confidence\n` + + `| Testers | Confidence |\n` + + `|---------|------------|\n` + + `| ${[...testers].join(", ") || "-"} | ${confidence} |`; + + const existing = allComments.find( + (c) => c.body?.includes(MARKER) && c.user.type === "Bot" + ); + + if (existing) { + await github.rest.issues.updateComment({ + ...repo, + comment_id: existing.id, + body: scoreBody, + }); + core.info("Confidence score comment updated."); + } else { + await github.rest.issues.createComment({ + ...repo, + issue_number: issueNumber, + body: scoreBody, + }); + core.info("Confidence score comment created."); + } From 04b109376a853e88308c3bd3c97b31411c2dd035 Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 20:01:25 +0530 Subject: [PATCH 10/12] ci: use verified-testers list in score comment as source of truth --- .github/workflows/pr-community-tested.yml | 72 +++++++++++------------ 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index b5cf56095..f935200d4 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -76,38 +76,34 @@ jobs: return; } + const SCORE_MARKER = ""; + const VERIFIED_MARKER = "/s); + if (match) { + match[1].split(",").map((s) => s.trim()).filter(Boolean).forEach((l) => testers.add(l)); } } - core.info(`Unique testers: ${testers.size} -- [${[...testers].join(", ")}]`); + // Register the current commenter (Set deduplicates repeat /tested calls) + const isFirstTester = testers.size === 0; + testers.add(commenter); - await core.summary - .addHeading("Community Tested Progress", 3) - .addTable([ - [ - { data: "Testers", header: true }, - { data: "Status", header: true }, - ], - [ - `${[...testers].join(", ") || "-"}`, - testers.size >= 1 ? "Label applied" : "Waiting for first tester", - ], - ]) - .write(); + core.info(`Verified testers: ${testers.size} -- [${[...testers].join(", ")}]`); + + const LABEL_NAME = "community-tested"; // Apply the label on the first eligible tester if (testers.size >= 1) { @@ -132,8 +128,8 @@ jobs: labels: [LABEL_NAME], }); - // On the first tester, ask them to upload a demo video - if (testers.size === 1) { + // On the first verified tester, ask them to upload a demo video + if (isFirstTester) { await github.rest.issues.createComment({ ...repo, issue_number: issueNumber, @@ -144,32 +140,34 @@ jobs: } core.info(`Label "${LABEL_NAME}" applied -- ${testers.size} tester(s).`); - } else { - core.info("No eligible testers yet. Label not applied."); } - // Confidence score: find-or-update a single bot comment tracking progress - const MARKER = ""; + // Build and persist the score comment (embeds the verified list for future runs) const confidence = - testers.size >= 4 ? "High (4+ testers)" : - testers.size >= 2 ? "Medium (2-3 testers)" : - testers.size >= 1 ? "Low (1 tester)" : "None"; + testers.size >= 4 ? "High (4+ testers)" : + testers.size >= 2 ? "Medium (2-3 testers)" : + "Low (1 tester)"; const scoreBody = - `${MARKER}\n` + + `${SCORE_MARKER}\n` + + `${VERIFIED_MARKER} ${[...testers].join(", ")} -->\n` + `### Community Testing Confidence\n` + `| Testers | Confidence |\n` + `|---------|------------|\n` + - `| ${[...testers].join(", ") || "-"} | ${confidence} |`; + `| ${[...testers].join(", ")} | ${confidence} |`; - const existing = allComments.find( - (c) => c.body?.includes(MARKER) && c.user.type === "Bot" - ); + await core.summary + .addHeading("Community Tested Progress", 3) + .addTable([ + [{ data: "Testers", header: true }, { data: "Confidence", header: true }], + [[...testers].join(", "), confidence], + ]) + .write(); - if (existing) { + if (scoreComment) { await github.rest.issues.updateComment({ ...repo, - comment_id: existing.id, + comment_id: scoreComment.id, body: scoreBody, }); core.info("Confidence score comment updated."); From a8f87e283cbf1511aac6635520d5af07d592248e Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 20:13:52 +0530 Subject: [PATCH 11/12] ci: short-circuit early when commenter has already been counted --- .github/workflows/pr-community-tested.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index f935200d4..59a5cfa1f 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -97,7 +97,12 @@ jobs: } } - // Register the current commenter (Set deduplicates repeat /tested calls) + // Short-circuit if this person has already been counted + if (testers.has(commenter)) { + core.info(`${commenter} already verified. Skipping.`); + return; + } + const isFirstTester = testers.size === 0; testers.add(commenter); From 8e2c2766f8bd337955b5452aa77292d93e0df9b1 Mon Sep 17 00:00:00 2001 From: Rishabh Negi Date: Sat, 21 Mar 2026 20:14:53 +0530 Subject: [PATCH 12/12] ci: tighten verified-testers regex, drop unnecessary dotAll flag --- .github/workflows/pr-community-tested.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-community-tested.yml b/.github/workflows/pr-community-tested.yml index 59a5cfa1f..3952dcc13 100644 --- a/.github/workflows/pr-community-tested.yml +++ b/.github/workflows/pr-community-tested.yml @@ -91,7 +91,7 @@ jobs: // Parse the persisted verified-testers list, or start fresh const testers = new Set(); if (scoreComment) { - const match = scoreComment.body.match(//s); + const match = scoreComment.body.match(//); if (match) { match[1].split(",").map((s) => s.trim()).filter(Boolean).forEach((l) => testers.add(l)); }