fix(issue): preserve metadata during updates

This commit is contained in:
fsafasff 2026-05-26 17:31:29 +08:00
parent 42bc83295a
commit 3f844dbcab
2 changed files with 95 additions and 0 deletions

View File

@ -18,6 +18,9 @@ func v1RepoPath(ctx *common.RuntimeContext) string {
type existingIssue struct {
Subject string
Description string
StatusID interface{}
PriorityID interface{}
TagIDs []interface{}
}
func Shortcuts() []*common.Shortcut {
@ -134,6 +137,8 @@ func Shortcuts() []*common.Shortcut {
"description": current.Description,
"status_id": 5, // 5 = closed
}
preserveIssueMetadata(body, current)
body["status_id"] = 5
env, err := ctx.CallAPI("PATCH", fmt.Sprintf("%s/issues/%s", v1RepoPath(ctx), number), body)
if err != nil {
return err
@ -174,6 +179,7 @@ func Shortcuts() []*common.Shortcut {
"subject": current.Subject,
"description": current.Description,
}
preserveIssueMetadata(body, current)
if t := ctx.Arg("title"); t != "" {
body["subject"] = t
}
@ -273,9 +279,50 @@ func fetchExistingIssue(ctx *common.RuntimeContext, number string) (*existingIss
return &existingIssue{
Subject: subject,
Description: description,
StatusID: nestedID(issueData, "status"),
PriorityID: nestedID(issueData, "priority"),
TagIDs: issueTagIDs(issueData),
}, nil
}
func preserveIssueMetadata(body map[string]interface{}, issue *existingIssue) {
if issue.StatusID != nil {
body["status_id"] = issue.StatusID
}
if issue.PriorityID != nil {
body["priority_id"] = issue.PriorityID
}
if len(issue.TagIDs) > 0 {
body["issue_tag_ids"] = issue.TagIDs
}
}
func nestedID(data map[string]interface{}, key string) interface{} {
item, ok := data[key].(map[string]interface{})
if !ok {
return nil
}
return item["id"]
}
func issueTagIDs(data map[string]interface{}) []interface{} {
tags, ok := data["tags"].([]interface{})
if !ok {
return nil
}
ids := make([]interface{}, 0, len(tags))
for _, item := range tags {
tag, ok := item.(map[string]interface{})
if !ok {
continue
}
if id, ok := tag["id"]; ok {
ids = append(ids, id)
}
}
return ids
}
func normalizeIssueStatus(state string) (interface{}, error) {
switch strings.ToLower(strings.TrimSpace(state)) {
case "open":

View File

@ -100,6 +100,54 @@ func TestIssueUpdatePreservesCurrentSubjectWhenChangingDescription(t *testing.T)
assertEqual(t, updatePayload["description"], "New description")
}
func TestIssueUpdatePreservesCurrentMetadata(t *testing.T) {
var updatePayload map[string]interface{}
server := newIssueTestServer(t, func(w http.ResponseWriter, r *http.Request) {
switch {
case r.Method == "GET" && r.URL.Path == "/v1/owner/repo/issues/42.json":
writeJSON(t, w, map[string]interface{}{
"subject": "Existing title",
"description": "Existing description",
"status": map[string]interface{}{
"id": float64(1),
},
"priority": map[string]interface{}{
"id": float64(2),
},
"tags": []interface{}{
map[string]interface{}{"id": float64(7)},
map[string]interface{}{"id": float64(8)},
},
})
case r.Method == "PATCH" && r.URL.Path == "/v1/owner/repo/issues/42.json":
updatePayload = decodeJSON(t, r)
writeJSON(t, w, updatePayload)
default:
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.Path)
}
})
defer server.Close()
err := runIssueShortcut(t, server, "update", map[string]string{
"number": "42",
"title": "New title",
})
if err != nil {
t.Fatalf("update shortcut failed: %v", err)
}
assertEqual(t, updatePayload["subject"], "New title")
assertEqual(t, updatePayload["description"], "Existing description")
assertEqual(t, updatePayload["status_id"], float64(1))
assertEqual(t, updatePayload["priority_id"], float64(2))
tagIDs, ok := updatePayload["issue_tag_ids"].([]interface{})
if !ok {
t.Fatalf("issue_tag_ids missing or wrong type: %T", updatePayload["issue_tag_ids"])
}
assertEqual(t, tagIDs[0], float64(7))
assertEqual(t, tagIDs[1], float64(8))
}
func TestBatchClosePreservesCurrentDescription(t *testing.T) {
var updatePayload map[string]interface{}
server := newIssueTestServer(t, func(w http.ResponseWriter, r *http.Request) {