This is an automated email from the ASF dual-hosted git repository.
Abacn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git
The following commit(s) were added to refs/heads/master by this push:
new bce7e07a9df Introduce LABEL_NOTICE for PR bot (#40002)
bce7e07a9df is described below
commit bce7e07a9df478893ee209cd02432888101a9af2
Author: Yi Hu <[email protected]>
AuthorDate: Tue Sep 8 16:59:39 2026 -0400
Introduce LABEL_NOTICE for PR bot (#40002)
---
.agent/skills/contributing/SKILL.md | 7 ++++-
.github/autolabeler.yml | 21 ++++++++++++-
scripts/ci/pr-bot/findPrsNeedingAttention.ts | 4 ++-
scripts/ci/pr-bot/processNewPrs.ts | 4 ++-
scripts/ci/pr-bot/shared/commentStrings.ts | 47 +++++++++++++++++++++++++---
scripts/ci/pr-bot/shared/userCommand.ts | 12 ++++---
scripts/ci/pr-bot/test/commentStringsTest.ts | 45 ++++++++++++++++++++++++++
7 files changed, 128 insertions(+), 12 deletions(-)
diff --git a/.agent/skills/contributing/SKILL.md
b/.agent/skills/contributing/SKILL.md
index 2a60c5a3cd9..bf4d00f86a0 100644
--- a/.agent/skills/contributing/SKILL.md
+++ b/.agent/skills/contributing/SKILL.md
@@ -17,7 +17,7 @@
# under the License.
name: contributing
-description: Guides the contribution workflow for Apache Beam, including
creating PRs, issue management, code review process, and release cycles. Use
when contributing code, creating PRs, or understanding the contribution process.
+description: Guides the contribution workflow for Apache Beam, including
creating PRs, issue management, code review process, release cycles, and
rigorous evaluation rules for high-risk core component changes. Use when
contributing code, creating PRs, or modifying core Beam components.
---
# Contributing to Apache Beam
@@ -71,6 +71,10 @@ description: Guides the contribution workflow for Apache
Beam, including creatin
- Implementation details belong in inline code comments.
- Use descriptive commit messages
+#### Working on Core Components (High Risk — Heightened Scrutiny)
+
+> **AGENT DIRECTIVE**: modification to **Core Components** carries an
inherently elevated risk of silent regression across distributed runners. Refer
to `.github/autolabeler.yml` under the `"core"` label for the authoritative
list of core component paths (including `sdks/java/core`, `runners/core-*`,
`model`, `sdks/python/apache_beam/transforms|coders`, `sdks/go/pkg/beam/core`,
`FileIO`, and `GCS`). If you are an AI agent modifying files matched by these
paths, **evaluate your changes wi [...]
+
### 5. Create Pull Request
- Link to the issue in PR description
- Pre-commit tests run automatically
@@ -91,6 +95,7 @@ description: Guides the contribution workflow for Apache
Beam, including creatin
### For Reviewers
- PRs can only be merged by [Beam
committers](https://home.apache.org/phonebook.html?pmc=beam)
+- PRs with the `core` label touch foundational Beam semantics or common code
paths; review with extra scrutiny for non-obvious failure modes, edge case, and
performance regressions
## Testing Workflows
diff --git a/.github/autolabeler.yml b/.github/autolabeler.yml
index 0b2cdf7dc28..24ab2ca9a60 100644
--- a/.github/autolabeler.yml
+++ b/.github/autolabeler.yml
@@ -17,6 +17,26 @@
# Please keep the entries sorted lexicographically in each category.
+# All core components
+"core": # This label instructs review with scrutiny
+ - "model/**/*"
+ - "runners/core-java/**/*"
+ - "runners/java-fn-execution/**/*"
+ - "sdks/go/pkg/beam/*.go"
+ - "sdks/go/pkg/beam/core/**/*"
+ - "sdks/go/pkg/beam/io/fileio/**/*"
+ - "sdks/go/pkg/beam/io/filesystem/**/*"
+ - "sdks/go/pkg/beam/transforms/**/*"
+ - "sdks/java/core/**/*"
+ - "sdks/java/extensions/google-cloud-platform-core/**/*"
+ - "sdks/java/harness/**/*"
+ - "sdks/python/apache_beam/*.py"
+ - "sdks/python/apache_beam/coders/**/*"
+ - "sdks/python/apache_beam/io/file*"
+ - "sdks/python/apache_beam/io/gcp/gcs*"
+ - "sdks/python/apache_beam/transforms/**/*"
+ - "sdks/python/apache_beam/typehints/**/*"
+
# General
build: ["assembly.xml", "buildSrc/**/*", ".gitattributes",
".github/workflows/*", ".gitignore", "gradle/**/*", ".mailmap", "release/**/*",
"sdks/java/build-tools/**/*"]
docker: ["runners/flink/job-server-container/**/*",
"runners/spark/job-server/container/**/*", "sdks/go/container/**/*",
"sdks/java/container/**/*", "sdks/python/container/**/*"]
@@ -80,7 +100,6 @@ io: ["sdks/go/pkg/beam/io/**/*", "sdks/java/io/**/*",
"sdks/python/apache_beam/
# Runners
"runners": ["runners/**/*", "sdks/go/pkg/beam/runners/**/*",
"sdks/python/apache_beam/runners/**/*",
"sdks/typescript/src/apache_beam/runners/**/*"]
-"core": ["runners/core-java/**/*"]
"dataflow": ["runners/google-cloud-dataflow-java/**/*",
"sdks/go/pkg/beam/runners/dataflow/**/*", "sdks/python/runners/dataflow/**/*"]
"direct": ["runners/direct-java/**/*", "sdks/go/pkg/beam/runners/direct/**/*",
"sdks/python/runners/direct/**/*"]
"flink": ["runners/flink/**/*", "sdks/go/pkg/beam/runners/flink/**/*"]
diff --git a/scripts/ci/pr-bot/findPrsNeedingAttention.ts
b/scripts/ci/pr-bot/findPrsNeedingAttention.ts
index ca868ad783f..ebca0deba83 100644
--- a/scripts/ci/pr-bot/findPrsNeedingAttention.ts
+++ b/scripts/ci/pr-bot/findPrsNeedingAttention.ts
@@ -128,7 +128,9 @@ async function assignToNewReviewers(
console.log(`Assigning new reviewers for pr ${pull.number}`);
await github.addPrComment(
pull.number,
- commentStrings.assignNewReviewer(prState.reviewersAssignedForLabels)
+ commentStrings.assignNewReviewer(prState.reviewersAssignedForLabels, {
+ labels: pull.labels,
+ })
);
await stateClient.writePrState(pull.number, prState);
diff --git a/scripts/ci/pr-bot/processNewPrs.ts
b/scripts/ci/pr-bot/processNewPrs.ts
index dd20d4a98c2..9f0ed52a116 100644
--- a/scripts/ci/pr-bot/processNewPrs.ts
+++ b/scripts/ci/pr-bot/processNewPrs.ts
@@ -341,7 +341,9 @@ async function processPull(
console.log(`Assigning reviewers for PR ${pull.number}`);
await github.addPrComment(
pull.number,
- commentStrings.assignReviewer(prState.reviewersAssignedForLabels)
+ commentStrings.assignReviewer(prState.reviewersAssignedForLabels, {
+ labels: pull.labels,
+ })
);
github.nextActionReviewers(pull.number, pull.labels);
diff --git a/scripts/ci/pr-bot/shared/commentStrings.ts
b/scripts/ci/pr-bot/shared/commentStrings.ts
index b556deea4f7..272f185d4ec 100644
--- a/scripts/ci/pr-bot/shared/commentStrings.ts
+++ b/scripts/ci/pr-bot/shared/commentStrings.ts
@@ -16,8 +16,37 @@
* limitations under the License.
*/
+import { Label } from "./githubUtils";
const { NO_MATCHING_LABEL } = require("./constants");
+export interface AssignReviewerOptions {
+ labels?: (string | Label)[];
+ notices?: string[];
+}
+
+// Custom notices for specific labels
+const LABEL_NOTICES: Record<string, string> = {
+ core: "This pull request likely touches a core component (\"core\" label).
Please review with scrutiny.",
+};
+
+function formatNotices(
+ labelToReviewerMapping: any,
+ options?: AssignReviewerOptions
+): string {
+ const notices = [...(options?.notices || [])];
+ const labels = [
+ ...(options?.labels || []),
+ ...Object.keys(labelToReviewerMapping),
+ ];
+ for (const label of labels) {
+ const name = (typeof label === "string" ? label :
label.name).toLowerCase();
+ if (LABEL_NOTICES[name] && !notices.includes(LABEL_NOTICES[name])) {
+ notices.push(LABEL_NOTICES[name]);
+ }
+ }
+ return notices.length ? `\n${notices.join("\n\n")}\n` : "";
+}
+
export function allChecksPassed(reviewersToNotify: string[]): string {
return `All checks have passed: @${reviewersToNotify.join(" ")}`;
}
@@ -26,7 +55,10 @@ export function assignCommitter(committer: string): string {
return `R: @${committer} for final approval`;
}
-export function assignReviewer(labelToReviewerMapping: any): string {
+export function assignReviewer(
+ labelToReviewerMapping: any,
+ options?: AssignReviewerOptions
+): string {
let commentString =
"Assigning reviewers:\n\n";
@@ -39,6 +71,8 @@ export function assignReviewer(labelToReviewerMapping: any):
string {
}
}
+ commentString += formatNotices(labelToReviewerMapping, options);
+
commentString += `
Note: If you would like to opt out of this review, comment \`assign to next
reviewer\`.
@@ -114,9 +148,12 @@ Users are removed if they haven't reviewed or completed a
PR in the last 3 month
return commentString;
}
-export function assignNewReviewer(labelToReviewerMapping: {
- [label: string]: string;
-}): string {
+export function assignNewReviewer(
+ labelToReviewerMapping: {
+ [label: string]: string;
+ },
+ options?: AssignReviewerOptions
+): string {
let commentString =
"Assigning new set of reviewers because Pr has gone too long without
review. If you would like to opt out of this review, comment `assign to next
reviewer`:\n\n";
@@ -129,6 +166,8 @@ export function assignNewReviewer(labelToReviewerMapping: {
}
}
+ commentString += formatNotices(labelToReviewerMapping, options);
+
commentString += `
Available commands:
- \`stop reviewer notifications\` - opt out of the automated review tooling
diff --git a/scripts/ci/pr-bot/shared/userCommand.ts
b/scripts/ci/pr-bot/shared/userCommand.ts
index 6980468c3b1..1c545f36dfd 100644
--- a/scripts/ci/pr-bot/shared/userCommand.ts
+++ b/scripts/ci/pr-bot/shared/userCommand.ts
@@ -101,14 +101,16 @@ async function assignToNextReviewer(
// Comment assigning reviewer
console.log(`Assigning ${chosenReviewer}`);
+ const existingLabels =
+ payload.issue?.labels || payload.pull_request?.labels;
await github.addPrComment(
pullNumber,
- commentStrings.assignReviewer(prState.reviewersAssignedForLabels)
+ commentStrings.assignReviewer(prState.reviewersAssignedForLabels, {
+ labels: existingLabels,
+ })
);
// Set next action to reviewer
- const existingLabels =
- payload.issue?.labels || payload.pull_request?.labels;
await github.nextActionReviewers(pullNumber, existingLabels);
prState.nextAction = "Reviewers";
@@ -227,7 +229,9 @@ async function assignReviewerSet(
console.log(`Assigning reviewers for pr ${pullNumber}`);
await github.addPrComment(
pullNumber,
- commentStrings.assignReviewer(prState.reviewersAssignedForLabels)
+ commentStrings.assignReviewer(prState.reviewersAssignedForLabels, {
+ labels: existingLabels,
+ })
);
github.nextActionReviewers(pullNumber, existingLabels);
diff --git a/scripts/ci/pr-bot/test/commentStringsTest.ts
b/scripts/ci/pr-bot/test/commentStringsTest.ts
new file mode 100644
index 00000000000..f2a16ca1c63
--- /dev/null
+++ b/scripts/ci/pr-bot/test/commentStringsTest.ts
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var assert = require("assert");
+const commentStrings = require("../shared/commentStrings");
+
+describe("commentStrings", function () {
+ describe("assignReviewer()", function () {
+ it("should not include scrutiny statement when core label is not present",
function () {
+ const comment = commentStrings.assignReviewer(
+ { Java: "reviewer1" },
+ { labels: [{ name: "Java" }] }
+ );
+ assert(!comment.includes("review with scrutiny"));
+ });
+
+ it("should include scrutiny statement when core label is present in
options.labels", function () {
+ const comment = commentStrings.assignReviewer(
+ { Java: "reviewer1" },
+ { labels: [{ name: "core" }] }
+ );
+ assert(comment.includes("review with scrutiny"));
+ });
+
+ it("should include scrutiny statement when core label is in mapping keys",
function () {
+ const comment = commentStrings.assignReviewer({ core: "reviewer1" });
+ assert(comment.includes("review with scrutiny"));
+ });
+ });
+});