This is an automated email from the ASF dual-hosted git repository.
liuhongyu 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 72a89c0b05 feat(ci): replace prow action with local issue-manager
script (#6211)
72a89c0b05 is described below
commit 72a89c0b05a3477f7a950f18ecf8e629ea57a12c
Author: shown <[email protected]>
AuthorDate: Wed Oct 22 08:48:54 2025 +0800
feat(ci): replace prow action with local issue-manager script (#6211)
* feat(ci): replace prow action with local issue-manager script
* infra: fix issue manager ci
Signed-off-by: yuluo-yx <[email protected]>
* chore: add license header and comment
Signed-off-by: yuluo-yx <[email protected]>
---------
Signed-off-by: yuluo-yx <[email protected]>
---
.github/workflows/issue-label.yml | 26 ++--
actions/scripts/issue-manager.sh | 281 ++++++++++++++++++++++++++++++++++++++
2 files changed, 290 insertions(+), 17 deletions(-)
diff --git a/.github/workflows/issue-label.yml
b/.github/workflows/issue-label.yml
index 9dea11f695..2b00d3fcd4 100644
--- a/.github/workflows/issue-label.yml
+++ b/.github/workflows/issue-label.yml
@@ -30,20 +30,12 @@ jobs:
issues: write
pull-requests: write
steps:
- - uses:
jpmcb/prow-github-actions@c44ac3a57d67639e39e4a4988b52049ef45b80dd # v2.0.0
- with:
- prow-commands: '/assign
- /unassign
- /lgtm
- /approve
- /area
- /priority
- /remove
- /close
- /reopen
- /lock
- /milestone
- /hold
- /cc
- /uncc'
- github-token: "${{ secrets.GITHUB_TOKEN }}"
+ - uses: actions/checkout@v3
+ - name: Run issue manager script
+ run: |
+ echo "Running issue manager script"
+ bash actions/scripts/issue-manager.sh
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_EVENT_PATH: ${{ github.event_path }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
diff --git a/actions/scripts/issue-manager.sh b/actions/scripts/issue-manager.sh
new file mode 100644
index 0000000000..401d635a80
--- /dev/null
+++ b/actions/scripts/issue-manager.sh
@@ -0,0 +1,281 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# 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.
+
+# 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)
+#
+# Supported Commands:
+# -------------------
+# Command | Function | Example
| Status
+# --------------- | --------------------------- | ----------------------------
| ------
+# /assign | Assign issue to users | /assign or /assign @user
| Normal
+# /unassign | Unassign users | /unassign or /unassign @user
| Normal
+# /lgtm | Add lgtm label | /lgtm
| Normal
+# /approve | Add approved label | /approve
| Normal
+# /area | Add area label | /area plugin
| Normal
+# /priority | Add priority label | /priority high
| Normal
+# /remove | Remove label | /remove bug
| Normal
+# /hold | Add hold label | /hold
| Normal
+# /unhold | Remove hold label | /unhold
| Normal
+# /close | Close issue | /close
| Normal
+# /reopen | Reopen issue | /reopen
| Normal
+# /lock | Lock issue | /lock
| Normal
+# /unlock | Unlock issue | /unlock
| Normal
+# /milestone | Set milestone | /milestone 5
| Normal
+# /cc | Mention users (comment) | /cc @user1 @user2
| Normal
+# /uncc | Unmention users (comment) | /uncc @user1
| Normal
+
+set -euo pipefail
+
+GITHUB_API=${GITHUB_API:-https://api.github.com}
+
+if [ -z "${GITHUB_TOKEN:-}" ]; then
+ echo "GITHUB_TOKEN is required" >&2
+ exit 1
+fi
+
+if [ -z "${GITHUB_EVENT_PATH:-}" ] || [ ! -f "${GITHUB_EVENT_PATH}" ]; then
+ echo "GITHUB_EVENT_PATH not set or file missing: ${GITHUB_EVENT_PATH}" >&2
+ exit 1
+fi
+
+if [ -z "${GITHUB_REPOSITORY:-}" ]; then
+ echo "GITHUB_REPOSITORY is required (owner/repo)" >&2
+ exit 1
+fi
+
+read_event() {
+ jq -r "$1" "${GITHUB_EVENT_PATH}"
+}
+
+COMMENT_BODY=$(read_event '.comment.body')
+ISSUE_NUMBER=$(read_event '.issue.number')
+COMMENT_USER=$(read_event '.comment.user.login')
+
+OWNER=$(echo "${GITHUB_REPOSITORY}" | cut -d/ -f1)
+REPO=$(echo "${GITHUB_REPOSITORY}" | cut -d/ -f2)
+
+auth_header() {
+ echo "Authorization: token ${GITHUB_TOKEN}"
+}
+
+api() {
+ local method=$1 path=$2 data=${3:-}
+ if [ -n "${data}" ]; then
+ curl -sS -X "${method}" -H "$(auth_header)" -H "Accept:
application/vnd.github+json" \
+ -H "Content-Type: application/json" --data "${data}"
"${GITHUB_API}${path}"
+ else
+ curl -sS -X "${method}" -H "$(auth_header)" -H "Accept:
application/vnd.github+json" "${GITHUB_API}${path}"
+ fi
+}
+
+users_json_from_bash_array() {
+ # read users from args and output compact JSON array like ["user1","user2"]
+ if [ $# -eq 0 ]; then
+ echo '[]'
+ return
+ fi
+ printf "%s\n" "$@" | sed 's/^@//' | jq -R -s -c 'split("\n") |
map(select(length>0))'
+}
+
+add_label() {
+ local label=$1
+ api POST "/repos/${OWNER}/${REPO}/issues/${ISSUE_NUMBER}/labels" "$(jq -nc
--arg l "$label" '{labels:[$l]}')" >/dev/null || true
+}
+
+remove_label() {
+ local label=$1
+ encoded=$(printf "%s" "$label" | jq -s -R -r @uri)
+ api DELETE
"/repos/${OWNER}/${REPO}/issues/${ISSUE_NUMBER}/labels/${encoded}" >/dev/null
|| true
+}
+
+assign() {
+ local users_json
+ users_json=$(users_json_from_bash_array "$@")
+ api POST "/repos/${OWNER}/${REPO}/issues/${ISSUE_NUMBER}/assignees" "$(jq
-nc --argjson a "$users_json" '{assignees:$a}')" >/dev/null || true
+}
+
+unassign() {
+ local users_json
+ users_json=$(users_json_from_bash_array "$@")
+ api DELETE "/repos/${OWNER}/${REPO}/issues/${ISSUE_NUMBER}/assignees" "$(jq
-nc --argjson a "$users_json" '{assignees:$a}')" >/dev/null || true
+}
+
+close_issue() {
+ api PATCH "/repos/${OWNER}/${REPO}/issues/${ISSUE_NUMBER}"
'{"state":"closed"}' >/dev/null || true
+}
+
+reopen_issue() {
+ api PATCH "/repos/${OWNER}/${REPO}/issues/${ISSUE_NUMBER}"
'{"state":"open"}' >/dev/null || true
+}
+
+lock_issue() {
+ api PUT "/repos/${OWNER}/${REPO}/issues/${ISSUE_NUMBER}/lock"
'{"lock_reason":"resolved"}' >/dev/null || true
+}
+
+unlock_issue() {
+ api DELETE "/repos/${OWNER}/${REPO}/issues/${ISSUE_NUMBER}/lock" >/dev/null
|| true
+}
+
+set_milestone() {
+ local ms=$1
+ if [ -z "$ms" ]; then
+ echo "No milestone number provided to /milestone" >&2
+ return
+ fi
+ api PATCH "/repos/${OWNER}/${REPO}/issues/${ISSUE_NUMBER}" "$(jq -nc --arg m
"$ms" '{milestone:($m|tonumber)}')" >/dev/null || true
+}
+
+comment() {
+ local body=$1
+ api POST "/repos/${OWNER}/${REPO}/issues/${ISSUE_NUMBER}/comments" "$(jq -nc
--arg b "$body" '{body:$b}')" >/dev/null || true
+}
+
+normalize_user() {
+ local u=$1
+ echo "${u#@}"
+}
+
+process_command() {
+ local line="$1"
+ line="$(echo "$line" | sed -e 's/^\s*//' -e 's/\s*$//')"
+ case "$line" in
+ \/assign*)
+ args="${line#\/assign}"
+ args="$(echo "$args" | sed -e 's/^\s*//' -e 's/\s*$//')"
+ if [ -z "$args" ]; then
+ # If no users specified, assign to the commenter
+ assign "$COMMENT_USER"
+ else
+ read -ra users <<<"$args"
+ for i in "${!users[@]}"; do
+ users[$i]=$(normalize_user "${users[$i]}")
+ done
+ assign "${users[@]}"
+ fi
+ ;;
+ \/unassign*)
+ args="${line#\/unassign}"
+ args="$(echo "$args" | sed -e 's/^\s*//' -e 's/\s*$//')"
+ if [ -z "$args" ]; then
+ # If no users specified, unassign the commenter
+ unassign "$COMMENT_USER"
+ else
+ read -ra users <<<"$args"
+ for i in "${!users[@]}"; do
+ users[$i]=$(normalize_user "${users[$i]}")
+ done
+ unassign "${users[@]}"
+ fi
+ ;;
+ \/lgtm)
+ add_label "lgtm"
+ ;;
+ \/approve)
+ add_label "approved"
+ ;;
+ \/area*)
+ lbl="${line#\/area}"
+ lbl="$(echo "$lbl" | sed -e 's/^\s*//' -e 's/\s*$//')"
+ if [ -n "$lbl" ]; then
+ add_label "area/$lbl"
+ else
+ echo "Error: /area requires an area name (e.g., /area plugin)" >&2
+ fi
+ ;;
+ \/priority*)
+ lbl="${line#\/priority}"
+ lbl="$(echo "$lbl" | sed -e 's/^\s*//' -e 's/\s*$//')"
+ if [ -n "$lbl" ]; then
+ add_label "priority/$lbl"
+ else
+ echo "Error: /priority requires a priority level (e.g., /priority
high)" >&2
+ fi
+ ;;
+ \/remove*)
+ lbl="${line#\/remove}"
+ lbl="$(echo "$lbl" | sed -e 's/^\s*//' -e 's/\s*$//')"
+ if [ -n "$lbl" ]; then
+ remove_label "$lbl"
+ else
+ echo "Error: /remove requires a label name (e.g., /remove bug)" >&2
+ fi
+ ;;
+ \/close)
+ close_issue
+ ;;
+ \/reopen)
+ reopen_issue
+ ;;
+ \/lock)
+ lock_issue
+ ;;
+ \/unlock)
+ unlock_issue
+ ;;
+ \/milestone*)
+ ms="${line#\/milestone}"
+ ms="$(echo "$ms" | sed -e 's/^\s*//' -e 's/\s*$//')"
+ if [ -n "$ms" ] && [[ "$ms" =~ ^[0-9]+$ ]]; then
+ set_milestone "$ms"
+ else
+ echo "Error: /milestone requires a valid milestone number (e.g.,
/milestone 5)" >&2
+ fi
+ ;;
+ \/hold)
+ add_label "hold"
+ ;;
+ \/unhold)
+ remove_label "hold"
+ ;;
+ \/cc*)
+ users_str="${line#\/cc}"
+ users_str="$(echo "$users_str" | sed -e 's/^\s*//' -e 's/\s*$//')"
+ if [ -n "$users_str" ]; then
+ comment "cc: $users_str"
+ else
+ echo "Warning: /cc requires usernames (e.g., /cc @user1 @user2)" >&2
+ fi
+ ;;
+ \/uncc*)
+ users_str="${line#\/uncc}"
+ users_str="$(echo "$users_str" | sed -e 's/^\s*//' -e 's/\s*$//')"
+ if [ -n "$users_str" ]; then
+ comment "uncc: $users_str"
+ else
+ echo "Warning: /uncc requires usernames (e.g., /uncc @user1 @user2)"
>&2
+ fi
+ ;;
+ *)
+ echo "No recognized command: $line" >&2
+ ;;
+ esac
+}
+
+main() {
+ while IFS= read -r line; do
+ if [[ "$line" =~ ^/ ]]; then
+ echo "Processing command: $line"
+ process_command "$line"
+ fi
+ done <<<"$COMMENT_BODY"
+}
+
+main