This is an automated email from the ASF dual-hosted git repository.

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new b2bc43376a infra: add PR comment commands for assign, close, and lgtm 
(#7770)
b2bc43376a is described below

commit b2bc43376a0146684faf6d45a6832d201fc61f45
Author: shown <[email protected]>
AuthorDate: Sat Oct 17 22:22:42 2026 +0800

    infra: add PR comment commands for assign, close, and lgtm (#7770)
---
 .github/workflows/assign.yml     | 79 ++++++++++++++++++++++++++++++++++++++++
 .github/workflows/close.yml      | 71 ++++++++++++++++++++++++++++++++++++
 .github/workflows/lgtm.yml       | 66 +++++++++++++++++++++++++++++++++
 actions/scripts/issue-manager.sh |  8 ++++
 4 files changed, 224 insertions(+)

diff --git a/.github/workflows/assign.yml b/.github/workflows/assign.yml
new file mode 100644
index 0000000000..a84af41f2d
--- /dev/null
+++ b/.github/workflows/assign.yml
@@ -0,0 +1,79 @@
+# 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.
+
+name: Assign
+
+# Post /assign or /assign @user1 @user2 as the entire comment on an open PR.
+# With no arguments, assign the commenter. A rocket confirms success.
+on:
+  issue_comment:
+    types: [created]
+
+permissions: {}
+
+jobs:
+  assign:
+    if: github.event.issue.pull_request && contains(github.event.comment.body, 
'/assign')
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    permissions:
+      pull-requests: write
+    concurrency:
+      group: assign-${{ github.event.issue.number }}
+      cancel-in-progress: false
+    steps:
+      # Use the default-branch script without checking out or executing PR 
code.
+      - name: Assign pull request
+        uses: actions/github-script@v7
+        with:
+          script: |
+            const {issue, comment, action} = context.payload;
+            const command = comment?.body?.trim().match(/^\/assign(?:[ 
\t]+(@?[a-zA-Z0-9-]+(?:[ \t]+@?[a-zA-Z0-9-]+)*))?$/);
+            if (action !== 'created' || !issue?.pull_request || !command) {
+                return;
+            }
+
+            const repo = context.repo;
+            const {data: pr} = await github.rest.pulls.get({...repo, 
pull_number: issue.number});
+            if (pr.state !== 'open') {
+                core.info('Skipping a closed pull request.');
+                return;
+            }
+
+            const users = command[1] ? command[1].split(/[ \t]+/) : 
[comment.user.login];
+            const assignees = [...new Set(users.map(user => user.replace(/^@/, 
'').toLowerCase()))];
+            if (assignees.length > 10) {
+                core.setFailed('A pull request can have at most 10 
assignees.');
+                return;
+            }
+
+            const {data: updated} = await github.rest.issues.addAssignees({
+                ...repo,
+                issue_number: issue.number,
+                assignees,
+            });
+            // GitHub silently ignores users who cannot be assigned; report 
partial failures.
+            const assigned = new Set(updated.assignees.map(user => 
user.login.toLowerCase()));
+            const missing = assignees.filter(user => !assigned.has(user));
+            if (missing.length) {
+                core.setFailed(`Could not assign: ${missing.join(', ')}.`);
+                return;
+            }
+
+            await github.rest.reactions.createForIssueComment({
+                ...repo,
+                comment_id: comment.id,
+                content: 'rocket',
+            });
diff --git a/.github/workflows/close.yml b/.github/workflows/close.yml
new file mode 100644
index 0000000000..b906597a1a
--- /dev/null
+++ b/.github/workflows/close.yml
@@ -0,0 +1,71 @@
+# 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.
+
+name: Close
+
+# Post /close as the entire comment on an open PR. The PR author and users
+# with write, maintain, or admin access may close it. A rocket confirms 
success.
+on:
+  issue_comment:
+    types: [created]
+
+permissions: {}
+
+jobs:
+  close:
+    if: github.event.issue.pull_request && contains(github.event.comment.body, 
'/close')
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    permissions:
+      pull-requests: write
+    concurrency:
+      group: close-${{ github.event.issue.number }}
+      cancel-in-progress: false
+    steps:
+      # Use the default-branch script without checking out or executing PR 
code.
+      - name: Close pull request
+        uses: actions/github-script@v7
+        with:
+          script: |
+            const {issue, comment, action} = context.payload;
+            if (action !== 'created' || !issue?.pull_request || 
comment?.body?.trim() !== '/close') {
+                return;
+            }
+
+            const repo = context.repo;
+            const pullRequest = {...repo, pull_number: issue.number};
+            const {data: pr} = await github.rest.pulls.get(pullRequest);
+            if (pr.state !== 'open') {
+                core.info('Skipping a closed pull request.');
+                return;
+            }
+
+            if (comment.user.login.toLowerCase() !== 
pr.user.login.toLowerCase()) {
+                const {data: access} = await 
github.rest.repos.getCollaboratorPermissionLevel({
+                    ...repo,
+                    username: comment.user.login,
+                });
+                if (!['write', 'maintain', 
'admin'].includes(access.permission)) {
+                    core.info('Only the pull request author or a user with 
write access can close it.');
+                    return;
+                }
+            }
+
+            await github.rest.pulls.update({...pullRequest, state: 'closed'});
+            await github.rest.reactions.createForIssueComment({
+                ...repo,
+                comment_id: comment.id,
+                content: 'rocket',
+            });
diff --git a/.github/workflows/lgtm.yml b/.github/workflows/lgtm.yml
new file mode 100644
index 0000000000..5e92727f74
--- /dev/null
+++ b/.github/workflows/lgtm.yml
@@ -0,0 +1,66 @@
+# 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.
+
+name: LGTM
+
+# Post /lgtm as the entire comment on an open PR to submit an approving review.
+# The Actions bot reviews the current head commit. A rocket confirms success.
+# Repository settings must allow GitHub Actions to create and approve pull 
requests.
+on:
+  issue_comment:
+    types: [created]
+
+permissions: {}
+
+jobs:
+  lgtm:
+    if: github.event.issue.pull_request && contains(github.event.comment.body, 
'/lgtm')
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    permissions:
+      pull-requests: write
+    concurrency:
+      group: lgtm-${{ github.event.issue.number }}
+      cancel-in-progress: false
+    steps:
+      # Use the default-branch script without checking out or executing PR 
code.
+      - name: Approve pull request
+        uses: actions/github-script@v7
+        with:
+          script: |
+            const {issue, comment, action} = context.payload;
+            if (action !== 'created' || !issue?.pull_request || 
comment?.body?.trim() !== '/lgtm') {
+                return;
+            }
+
+            const repo = context.repo;
+            const {data: pr} = await github.rest.pulls.get({...repo, 
pull_number: issue.number});
+            if (pr.state !== 'open') {
+                core.info('Skipping a closed pull request.');
+                return;
+            }
+
+            await github.rest.pulls.createReview({
+                ...repo,
+                pull_number: issue.number,
+                commit_id: pr.head.sha,
+                event: 'APPROVE',
+                body: `Approved via /lgtm by @${comment.user.login}.`,
+            });
+            await github.rest.reactions.createForIssueComment({
+                ...repo,
+                comment_id: comment.id,
+                content: 'rocket',
+            });
diff --git a/actions/scripts/issue-manager.sh b/actions/scripts/issue-manager.sh
index 401d635a80..9edc78dcd1 100644
--- a/actions/scripts/issue-manager.sh
+++ b/actions/scripts/issue-manager.sh
@@ -20,6 +20,7 @@
 # Minimal issue manager script to handle a subset of prow-style commands
 # Reads the GitHub issue_comment event JSON pointed to by GITHUB_EVENT_PATH
 # Requires GITHUB_TOKEN env and GITHUB_REPOSITORY env (owner/repo)
+# PR /assign, /close, and /lgtm commands are handled by dedicated workflows.
 #
 # Supported Commands:
 # -------------------
@@ -68,6 +69,7 @@ read_event() {
 COMMENT_BODY=$(read_event '.comment.body')
 ISSUE_NUMBER=$(read_event '.issue.number')
 COMMENT_USER=$(read_event '.comment.user.login')
+IS_PULL_REQUEST=$(read_event '.issue.pull_request != null')
 
 OWNER=$(echo "${GITHUB_REPOSITORY}" | cut -d/ -f1)
 REPO=$(echo "${GITHUB_REPOSITORY}" | cut -d/ -f2)
@@ -156,6 +158,12 @@ normalize_user() {
 process_command() {
   local line="$1"
   line="$(echo "$line" | sed -e 's/^\s*//' -e 's/\s*$//')"
+  # Do not replay PR commands owned by the dedicated created-comment workflows.
+  if [ "$IS_PULL_REQUEST" = true ]; then
+    case "$line" in
+      \/assign*|\/close|\/lgtm) return ;;
+    esac
+  fi
   case "$line" in
     \/assign*)
       args="${line#\/assign}"

Reply via email to