Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .github/workflows/robot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -325,11 +325,14 @@ jobs:
repository: ${{ github.repository }} # 获取执行该作业的仓库名 形如: matrixorigin/CI
issue_number: ${{ github.event.issue.number }} # 获取当前操作的issue number
assignees: "sukki37" #issue指定分配对象
LABELS: "no-pr-linked" #相关自定义label配置 形如 label1,label2
LABELS_NEED: "kind/bug,Bug fix,bug_fix,bug/ut" # 指定需要排查的标签 label1,label2,...
labels: "no-pr-linked" #相关自定义label配置 形如 label1,label2
labels_need: "kind/bug,Bug fix,bug_fix,bug/ut" # 指定需要排查的标签 label1,label2,...
uses: matrixorigin/CI/actions/reopen-without-PR@main
- name: WeChat Work notification
if: ${{ failure() || cancelled() || steps.step1.outputs.send == 'yes' }}
# Only notify when the action confirms no linked PR (send=yes).
# Do NOT notify on failure/cancelled — runner/action errors were
# falsely alerting "Close Issue Without PR" for issues that already have PRs.
if: ${{ steps.step1.outputs.send == 'yes' }}
id: notification
uses: chf007/action-wechat-work@master
env:
Expand Down
39 changes: 34 additions & 5 deletions actions/reopen-without-PR/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,47 @@ inputs:
required: false
default: "sukki77,fengttt,aressu1985"
issue_owner:
require: true
required: true
description: issue owner
close_user:
description: close issue user
require: true
required: true
base_url:
description: GitHub API base URL
required: false
default: 'https://api.github.com'
outputs:
send:
description: Whether to send a notification
value: ${{ steps.run.outputs.send }}

runs:
using: docker
image: Dockerfile
using: composite
steps:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: ${{ github.action_path }}/go.mod
cache: false

- name: Run reopen-without-PR
id: run
shell: bash
working-directory: ${{ github.action_path }}
env:
INPUT_BASE_URL: ${{ inputs.base_url }}
INPUT_REPOSITORY: ${{ inputs.repository }}
INPUT_ISSUE_NUMBER: ${{ inputs.issue_number }}
INPUT_GITHUB_TOKEN: ${{ inputs.github_token }}
INPUT_ASSIGNEES: ${{ inputs.assignees }}
INPUT_LABELS: ${{ inputs.labels }}
INPUT_LABELS_NEED: ${{ inputs.labels_need }}
INPUT_WHITELIST: ${{ inputs.whitelist }}
INPUT_ISSUE_OWNER: ${{ inputs.issue_owner }}
INPUT_CLOSE_USER: ${{ inputs.close_user }}
run: |
set -euo pipefail
CGO_ENABLED=0 go run .
branding:
icon: arrow-up
color: blue
color: blue
52 changes: 39 additions & 13 deletions actions/reopen-without-PR/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ func task() {

// 转交给sukki37
assigneeURL := fmt.Sprintf("%s/repos/%s/issues/%d/assignees", baseURL, repo, issueNumber)
assigneeData := map[string]string{"assignees": assignees}
assigneeList := strings.Split(assignees, ",")
for i := range assigneeList {
assigneeList[i] = strings.TrimSpace(assigneeList[i])
}
assigneeData := map[string][]string{"assignees": assigneeList}
jsonData, err = json.Marshal(assigneeData)
if err != nil {
panic("json.Marshal assigneeData failed")
Expand All @@ -77,7 +81,9 @@ func task() {
panic(fmt.Sprintf("Error creating assignee request:%v", err))
}
if assigneeResp.StatusCode != 201 {
panic(fmt.Sprintf("Failed to assign a problem to a specified person,assigneeStatusCode:%d", assigneeResp.StatusCode))
body, _ := io.ReadAll(assigneeResp.Body)
assigneeResp.Body.Close()
panic(fmt.Sprintf("Failed to assign a problem to a specified person,assigneeStatusCode:%d body:%s", assigneeResp.StatusCode, string(body)))
}
defer assigneeResp.Body.Close()
fmt.Printf("Issue labeled and assigned to %s successfully.\n", assignees)
Expand Down Expand Up @@ -201,14 +207,15 @@ func main() {
panic(fmt.Sprintf("issueUrl http.Request failed,err:%v", err))
}
if issueResp.StatusCode != http.StatusOK {
panic(fmt.Sprintf("connect issueUrl failed,resp.statusCode:%d", issueResp.StatusCode))
body, _ := io.ReadAll(issueResp.Body)
issueResp.Body.Close()
panic(fmt.Sprintf("connect issueUrl failed,resp.statusCode:%d body:%s", issueResp.StatusCode, string(body)))
}
defer issueResp.Body.Close()
fmt.Printf("get issue %d info successfully.\n", issueNumber)

// 解析响应内容(这里省略了具体的解析过程,你可以根据需要自行处理)
// 检查issue是否有关联的pull request
body, err := io.ReadAll(issueResp.Body)
issueResp.Body.Close()
if err != nil {
panic(fmt.Sprintf("Error reading issue response body:%v", err))
}
Expand All @@ -224,16 +231,35 @@ func main() {
}

for _, data := range issueData {
dataMap := data.(map[string]interface{})
typeEvent := dataMap["event"]
if typeEvent == "cross-referenced" {
sourceMap := dataMap["source"].(map[string]interface{})
issueMap := sourceMap["issue"].(map[string]interface{})
_, ok := issueMap["pull_request"]
if ok {
dataMap, ok := data.(map[string]interface{})
if !ok {
continue
}
switch dataMap["event"] {
case "cross-referenced":
// PR/issue that mentioned this issue in body or commit.
sourceMap, _ := dataMap["source"].(map[string]interface{})
issueMap, _ := sourceMap["issue"].(map[string]interface{})
if _, ok := issueMap["pull_request"]; ok {
hasRelatedPR = true
break
}
case "connected":
// Linked via Development sidebar (Fixes/Closes) or manual link.
// subject may be an issue or a PR; only count PRs.
if subject, ok := dataMap["subject"].(map[string]interface{}); ok {
if _, isPR := subject["pull_request"]; isPR {
hasRelatedPR = true
}
} else if source, ok := dataMap["source"].(map[string]interface{}); ok {
if issueMap, ok := source["issue"].(map[string]interface{}); ok {
if _, isPR := issueMap["pull_request"]; isPR {
hasRelatedPR = true
}
}
}
}
if hasRelatedPR {
break
}
}
if hasRelatedPR {
Expand Down
2 changes: 2 additions & 0 deletions actions/reopen-without-PR/pkg/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ func Request(method, url, token string, data io.Reader, contentType string) (res
return nil, err
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
req.Header.Set("Accept", "application/vnd.github+json")
req.Header.Set("X-GitHub-Api-Version", "2022-11-28")
if contentType != "" {
req.Header.Set("Content-Type", contentType)
}
Expand Down