diff --git a/shortcuts/issue/batch_common.go b/shortcuts/issue/batch_common.go index 6917f68..94f177e 100644 --- a/shortcuts/issue/batch_common.go +++ b/shortcuts/issue/batch_common.go @@ -395,7 +395,7 @@ func ResolveUserID(ctx *common.RuntimeContext, name string) (int, error) { // ResolveLabelID 把 label 名称解析为数字 label ID。 // 若 name 本身是数字则直接返回;否则首次按当前仓库拉取全部 label -// (GET /v1/{owner}/{repo}/labels)并按仓库维度缓存,后续直接走缓存。 +// (GET /{owner}/{repo}/labels,v0 前缀)并按仓库维度缓存,后续直接走缓存。 func ResolveLabelID(ctx *common.RuntimeContext, name string) (int, error) { if id, err := strconv.Atoi(name); err == nil { return id, nil @@ -416,14 +416,24 @@ func ResolveLabelID(ctx *common.RuntimeContext, name string) (int, error) { resolverCacheMu.Unlock() // 缓存未命中,从 API 拉取该仓库的全部 label - env, err := ctx.CallAPI("GET", v1RepoPath(ctx)+"/labels", nil) + env, err := ctx.CallAPI("GET", fmt.Sprintf("/%s/%s/labels", ctx.Owner, ctx.Repo), nil) if err != nil { return 0, fmt.Errorf("resolve label: %w", err) } - items, err := parseDataArray(env.Data) + // API 返回 {"status":0, "issue_tags":[...], ...},client.Do 把整个响应包在 envelope 里, + // 所以 env.Data 是包含 issue_tags 键的 map,需要先提取 issue_tags 再解析数组。 + rawMap, ok := env.Data.(map[string]interface{}) + if !ok { + return 0, fmt.Errorf("resolve label: unexpected response type %T", env.Data) + } + itemsRaw, ok := rawMap["issue_tags"] + if !ok { + return 0, fmt.Errorf("resolve label: response missing issue_tags field") + } + items, err := parseDataArray(itemsRaw) if err != nil { - return 0, fmt.Errorf("resolve label: parse data: %w", err) + return 0, fmt.Errorf("resolve label: parse issue_tags: %w", err) } // 在锁内把当前仓库的 label 全量写入按 repoKey 隔离的缓存 diff --git a/shortcuts/issue/batch_create.go b/shortcuts/issue/batch_create.go index 70c403f..5943b44 100644 --- a/shortcuts/issue/batch_create.go +++ b/shortcuts/issue/batch_create.go @@ -138,7 +138,7 @@ func createIssueFromRow(ctx *common.RuntimeContext, row []string, titleCol, body if err != nil { return fmt.Errorf("label %q: %w", labels, err) } - body["label_ids"] = labelIDs + body["issue_tag_ids"] = labelIDs } if pri := getCell(row, priorityCol); pri != "" { pid, err := strconv.Atoi(pri) diff --git a/shortcuts/issue/batch_label.go b/shortcuts/issue/batch_label.go index fa8c0dc..349b772 100644 --- a/shortcuts/issue/batch_label.go +++ b/shortcuts/issue/batch_label.go @@ -94,7 +94,7 @@ func manageIssueLabels(ctx *common.RuntimeContext, number string, action string, body := map[string]interface{}{ "subject": current.Subject, "description": current.Description, - "label_ids": finalIDs, + "issue_tag_ids": finalIDs, } _, err = ctx.CallAPI("PATCH", fmt.Sprintf("%s/issues/%s", v1RepoPath(ctx), number), body) if err != nil { diff --git a/shortcuts/issue/batch_update.go b/shortcuts/issue/batch_update.go index 1e4c946..eaa3e59 100644 --- a/shortcuts/issue/batch_update.go +++ b/shortcuts/issue/batch_update.go @@ -15,7 +15,7 @@ var updateFieldMapping = map[string]string{ "state": "status_id", "assignee": "assigner_ids", "milestone": "fixed_version_id", - "label": "label_ids", + "label": "issue_tag_ids", "priority": "priority_id", } @@ -127,12 +127,12 @@ func applyIssueUpdates(ctx *common.RuntimeContext, number string, row []string, } body["fixed_version_id"] = id } - case "label_ids": + case "issue_tag_ids": labelIDs, err := resolveLabelArgs(ctx, val, "") if err != nil { return fmt.Errorf("issue #%s label %q: %w", number, val, err) } - body["label_ids"] = labelIDs + body["issue_tag_ids"] = labelIDs case "priority_id": pid, err := strconv.Atoi(val) if err != nil { diff --git a/shortcuts/issue/issue.go b/shortcuts/issue/issue.go index c845d6e..c67c3ff 100644 --- a/shortcuts/issue/issue.go +++ b/shortcuts/issue/issue.go @@ -265,7 +265,7 @@ func fetchIssueData(ctx *common.RuntimeContext, number string) (*IssueData, erro AssignedToID: getMapInt(issueMap, "assigned_to_id"), FixedVersionID: getMapInt(issueMap, "fixed_version_id"), PriorityID: getMapInt(issueMap, "priority_id"), - LabelIDs: getMapIntSlice(issueMap, "label_ids"), + LabelIDs: getTagIDs(issueMap, "tags"), } return data, nil } @@ -307,6 +307,26 @@ func getMapIntSlice(m map[string]interface{}, key string) []int { return ids } +// getTagIDs 从 map 中提取 tag 对象数组中每个对象的 id 字段。 +// API 返回 tags: [{id: 1, name: "bug"}, ...],需要遍历对象提取 id。 +// 类型不匹配或缺失时返回 nil。 +func getTagIDs(m map[string]interface{}, key string) []int { + raw, ok := m[key].([]interface{}) + if !ok { + return nil + } + ids := make([]int, 0, len(raw)) + for _, item := range raw { + if tag, ok := item.(map[string]interface{}); ok { + id := getMapInt(tag, "id") + if id > 0 { + ids = append(ids, id) + } + } + } + return ids +} + func normalizeIssueStatus(state string) (interface{}, error) { switch strings.ToLower(strings.TrimSpace(state)) { case "open":