Skip to content

Commit 0c986e9

Browse files
authored
Revert "add support for fields in issues write"
This reverts commit 2fcbc88.
1 parent 93180e8 commit 0c986e9

3 files changed

Lines changed: 9 additions & 365 deletions

File tree

pkg/github/__toolsnaps__/issue_write.snap

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,6 @@
2929
"description": "Issue number that this issue is a duplicate of. Only used when state_reason is 'duplicate'.",
3030
"type": "number"
3131
},
32-
"issue_fields": {
33-
"description": "Issue field values to set. Each item requires field_name and either value or field_option_name. field_option_name is for single-select fields and is resolved to the corresponding option ID automatically.",
34-
"items": {
35-
"properties": {
36-
"field_name": {
37-
"description": "Issue field name",
38-
"type": "string"
39-
},
40-
"field_option_name": {
41-
"description": "Single-select option name to resolve and set for the field",
42-
"type": "string"
43-
},
44-
"value": {
45-
"description": "Value for text/number/date/single-select fields. For single-select, you can use field_option_name instead."
46-
}
47-
},
48-
"required": [
49-
"field_name"
50-
],
51-
"type": "object"
52-
},
53-
"type": "array"
54-
},
5532
"issue_number": {
5633
"description": "Issue number to update",
5734
"type": "number"

pkg/github/issues.go

Lines changed: 8 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -34,36 +34,6 @@ type CloseIssueInput struct {
3434
// Used to extend the functionality of the githubv4 library to support closing issues as duplicates.
3535
type IssueClosedStateReason string
3636

37-
// IssueWriteFieldInput is a user-friendly issue field input for issue_write.
38-
// Field IDs and option IDs are resolved internally before calling the REST API.
39-
type IssueWriteFieldInput struct {
40-
FieldName string
41-
Value any
42-
FieldOptionName string
43-
}
44-
45-
type issueFieldMetadataOption struct {
46-
DatabaseID githubv4.Int `graphql:"databaseId"`
47-
Name githubv4.String
48-
}
49-
50-
type issueFieldMetadataNode struct {
51-
DatabaseID githubv4.Int `graphql:"databaseId"`
52-
Name githubv4.String
53-
DataType githubv4.String
54-
SingleSelectField struct {
55-
Options []issueFieldMetadataOption `graphql:"options"`
56-
} `graphql:"... on IssueFieldSingleSelect"`
57-
}
58-
59-
type issueFieldMetadataQuery struct {
60-
Repository struct {
61-
IssueFields struct {
62-
Nodes []issueFieldMetadataNode
63-
} `graphql:"issueFields(first: 100)"`
64-
} `graphql:"repository(owner: $owner, name: $repo)"`
65-
}
66-
6737
const (
6838
IssueClosedStateReasonCompleted IssueClosedStateReason = "COMPLETED"
6939
IssueClosedStateReasonDuplicate IssueClosedStateReason = "DUPLICATE"
@@ -132,127 +102,6 @@ func getCloseStateReason(stateReason string) IssueClosedStateReason {
132102
}
133103
}
134104

135-
func optionalIssueWriteFields(args map[string]any) ([]IssueWriteFieldInput, error) {
136-
issueFieldsRaw, exists := args["issue_fields"]
137-
if !exists {
138-
return nil, nil
139-
}
140-
141-
var inputMaps []map[string]any
142-
switch v := issueFieldsRaw.(type) {
143-
case []any:
144-
for _, item := range v {
145-
itemMap, ok := item.(map[string]any)
146-
if !ok {
147-
return nil, fmt.Errorf("each issue_fields item must be an object")
148-
}
149-
inputMaps = append(inputMaps, itemMap)
150-
}
151-
case []map[string]any:
152-
inputMaps = v
153-
default:
154-
return nil, fmt.Errorf("issue_fields must be an array")
155-
}
156-
157-
issueFields := make([]IssueWriteFieldInput, 0, len(inputMaps))
158-
for _, itemMap := range inputMaps {
159-
fieldName, err := RequiredParam[string](itemMap, "field_name")
160-
if err != nil || strings.TrimSpace(fieldName) == "" {
161-
return nil, fmt.Errorf("field_name is required for each issue_fields item")
162-
}
163-
164-
fieldOptionName, err := OptionalParam[string](itemMap, "field_option_name")
165-
if err != nil {
166-
return nil, err
167-
}
168-
169-
value, hasValue := itemMap["value"]
170-
if hasValue && value == nil {
171-
return nil, fmt.Errorf("value cannot be null for field %q", fieldName)
172-
}
173-
174-
if hasValue && fieldOptionName != "" {
175-
return nil, fmt.Errorf("issue field %q cannot specify both value and field_option_name", fieldName)
176-
}
177-
178-
if !hasValue && fieldOptionName == "" {
179-
return nil, fmt.Errorf("issue field %q must specify either value or field_option_name", fieldName)
180-
}
181-
182-
issueFields = append(issueFields, IssueWriteFieldInput{
183-
FieldName: fieldName,
184-
Value: value,
185-
FieldOptionName: fieldOptionName,
186-
})
187-
}
188-
189-
return issueFields, nil
190-
}
191-
192-
func resolveIssueRequestFieldValues(ctx context.Context, gqlClient *githubv4.Client, owner, repo string, issueFields []IssueWriteFieldInput) ([]*github.IssueRequestFieldValue, error) {
193-
if len(issueFields) == 0 {
194-
return nil, nil
195-
}
196-
197-
query := issueFieldMetadataQuery{}
198-
vars := map[string]any{
199-
"owner": githubv4.String(owner),
200-
"repo": githubv4.String(repo),
201-
}
202-
if err := gqlClient.Query(ctx, &query, vars); err != nil {
203-
return nil, fmt.Errorf("failed to query issue fields metadata: %w", err)
204-
}
205-
206-
fieldByName := make(map[string]issueFieldMetadataNode, len(query.Repository.IssueFields.Nodes))
207-
for _, field := range query.Repository.IssueFields.Nodes {
208-
fieldByName[strings.ToLower(strings.TrimSpace(string(field.Name)))] = field
209-
}
210-
211-
resolved := make([]*github.IssueRequestFieldValue, 0, len(issueFields))
212-
for _, fieldInput := range issueFields {
213-
field, ok := fieldByName[strings.ToLower(strings.TrimSpace(fieldInput.FieldName))]
214-
if !ok {
215-
return nil, fmt.Errorf("issue field %q was not found in %s/%s", fieldInput.FieldName, owner, repo)
216-
}
217-
218-
fieldID := int64(field.DatabaseID)
219-
if fieldID == 0 {
220-
return nil, fmt.Errorf("issue field %q is missing databaseId", fieldInput.FieldName)
221-
}
222-
223-
resolvedValue := fieldInput.Value
224-
if fieldInput.FieldOptionName != "" {
225-
if !strings.EqualFold(string(field.DataType), "single_select") {
226-
return nil, fmt.Errorf("issue field %q is %q, so field_option_name cannot be used", fieldInput.FieldName, field.DataType)
227-
}
228-
229-
optionFound := false
230-
for _, option := range field.SingleSelectField.Options {
231-
if strings.EqualFold(strings.TrimSpace(string(option.Name)), strings.TrimSpace(fieldInput.FieldOptionName)) {
232-
optionID := int64(option.DatabaseID)
233-
if optionID == 0 {
234-
return nil, fmt.Errorf("issue field option %q on field %q is missing databaseId", fieldInput.FieldOptionName, fieldInput.FieldName)
235-
}
236-
resolvedValue = optionID
237-
optionFound = true
238-
break
239-
}
240-
}
241-
242-
if !optionFound {
243-
return nil, fmt.Errorf("issue field option %q was not found for field %q", fieldInput.FieldOptionName, fieldInput.FieldName)
244-
}
245-
}
246-
247-
resolved = append(resolved, &github.IssueRequestFieldValue{
248-
FieldID: fieldID,
249-
Value: resolvedValue,
250-
})
251-
}
252-
253-
return resolved, nil
254-
}
255-
256105
// IssueFragment represents a fragment of an issue node in the GraphQL API.
257106
type IssueFragment struct {
258107
Number githubv4.Int
@@ -1204,27 +1053,6 @@ Options are:
12041053
Type: "number",
12051054
Description: "Issue number that this issue is a duplicate of. Only used when state_reason is 'duplicate'.",
12061055
},
1207-
"issue_fields": {
1208-
Type: "array",
1209-
Description: "Issue field values to set. Each item requires field_name and either value or field_option_name. field_option_name is for single-select fields and is resolved to the corresponding option ID automatically.",
1210-
Items: &jsonschema.Schema{
1211-
Type: "object",
1212-
Properties: map[string]*jsonschema.Schema{
1213-
"field_name": {
1214-
Type: "string",
1215-
Description: "Issue field name",
1216-
},
1217-
"value": {
1218-
Description: "Value for text/number/date/single-select fields. For single-select, you can use field_option_name instead.",
1219-
},
1220-
"field_option_name": {
1221-
Type: "string",
1222-
Description: "Single-select option name to resolve and set for the field",
1223-
},
1224-
},
1225-
Required: []string{"field_name"},
1226-
},
1227-
},
12281056
},
12291057
Required: []string{"method", "owner", "repo"},
12301058
},
@@ -1326,11 +1154,6 @@ Options are:
13261154
return utils.NewToolResultError("duplicate_of can only be used when state_reason is 'duplicate'"), nil, nil
13271155
}
13281156

1329-
issueFields, err := optionalIssueWriteFields(args)
1330-
if err != nil {
1331-
return utils.NewToolResultError(err.Error()), nil, nil
1332-
}
1333-
13341157
client, err := deps.GetClient(ctx)
13351158
if err != nil {
13361159
return utils.NewToolResultErrorFromErr("failed to get GitHub client", err), nil, nil
@@ -1341,21 +1164,16 @@ Options are:
13411164
return utils.NewToolResultErrorFromErr("failed to get GraphQL client", err), nil, nil
13421165
}
13431166

1344-
issueFieldValues, err := resolveIssueRequestFieldValues(ctx, gqlClient, owner, repo, issueFields)
1345-
if err != nil {
1346-
return utils.NewToolResultError(fmt.Sprintf("failed to resolve issue_fields: %v", err)), nil, nil
1347-
}
1348-
13491167
switch method {
13501168
case "create":
1351-
result, err := CreateIssue(ctx, client, owner, repo, title, body, assignees, labels, milestoneNum, issueType, issueFieldValues)
1169+
result, err := CreateIssue(ctx, client, owner, repo, title, body, assignees, labels, milestoneNum, issueType)
13521170
return result, nil, err
13531171
case "update":
13541172
issueNumber, err := RequiredInt(args, "issue_number")
13551173
if err != nil {
13561174
return utils.NewToolResultError(err.Error()), nil, nil
13571175
}
1358-
result, err := UpdateIssue(ctx, client, gqlClient, owner, repo, issueNumber, title, body, assignees, labels, milestoneNum, issueType, issueFieldValues, state, stateReason, duplicateOf)
1176+
result, err := UpdateIssue(ctx, client, gqlClient, owner, repo, issueNumber, title, body, assignees, labels, milestoneNum, issueType, state, stateReason, duplicateOf)
13591177
return result, nil, err
13601178
default:
13611179
return utils.NewToolResultError("invalid method, must be either 'create' or 'update'"), nil, nil
@@ -1365,18 +1183,17 @@ Options are:
13651183
return st
13661184
}
13671185

1368-
func CreateIssue(ctx context.Context, client *github.Client, owner string, repo string, title string, body string, assignees []string, labels []string, milestoneNum int, issueType string, issueFieldValues []*github.IssueRequestFieldValue) (*mcp.CallToolResult, error) {
1186+
func CreateIssue(ctx context.Context, client *github.Client, owner string, repo string, title string, body string, assignees []string, labels []string, milestoneNum int, issueType string) (*mcp.CallToolResult, error) {
13691187
if title == "" {
13701188
return utils.NewToolResultError("missing required parameter: title"), nil
13711189
}
13721190

13731191
// Create the issue request
13741192
issueRequest := &github.IssueRequest{
1375-
Title: github.Ptr(title),
1376-
Body: github.Ptr(body),
1377-
Assignees: &assignees,
1378-
Labels: &labels,
1379-
IssueFieldValues: issueFieldValues,
1193+
Title: github.Ptr(title),
1194+
Body: github.Ptr(body),
1195+
Assignees: &assignees,
1196+
Labels: &labels,
13801197
}
13811198

13821199
if milestoneNum != 0 {
@@ -1419,7 +1236,7 @@ func CreateIssue(ctx context.Context, client *github.Client, owner string, repo
14191236
return utils.NewToolResultText(string(r)), nil
14201237
}
14211238

1422-
func UpdateIssue(ctx context.Context, client *github.Client, gqlClient *githubv4.Client, owner string, repo string, issueNumber int, title string, body string, assignees []string, labels []string, milestoneNum int, issueType string, issueFieldValues []*github.IssueRequestFieldValue, state string, stateReason string, duplicateOf int) (*mcp.CallToolResult, error) {
1239+
func UpdateIssue(ctx context.Context, client *github.Client, gqlClient *githubv4.Client, owner string, repo string, issueNumber int, title string, body string, assignees []string, labels []string, milestoneNum int, issueType string, state string, stateReason string, duplicateOf int) (*mcp.CallToolResult, error) {
14231240
// Create the issue request with only provided fields
14241241
issueRequest := &github.IssueRequest{}
14251242

@@ -1448,10 +1265,6 @@ func UpdateIssue(ctx context.Context, client *github.Client, gqlClient *githubv4
14481265
issueRequest.Type = github.Ptr(issueType)
14491266
}
14501267

1451-
if len(issueFieldValues) > 0 {
1452-
issueRequest.IssueFieldValues = issueFieldValues
1453-
}
1454-
14551268
updatedIssue, resp, err := client.Issues.Edit(ctx, owner, repo, issueNumber, issueRequest)
14561269
if err != nil {
14571270
return ghErrors.NewGitHubAPIErrorResponse(ctx,

0 commit comments

Comments
 (0)