Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit56d0dd4

Browse files
authored
Merge branch 'main' into main
2 parents29f7978 +e95d8ee commit56d0dd4

File tree

1 file changed

+55
-167
lines changed

1 file changed

+55
-167
lines changed

‎pkg/github/projects.go‎

Lines changed: 55 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,11 @@ import (
66
"fmt"
77
"io"
88
"net/http"
9-
"net/url"
10-
"reflect"
119
"strings"
1210

1311
ghErrors"github.com/github/github-mcp-server/pkg/errors"
1412
"github.com/github/github-mcp-server/pkg/translations"
1513
"github.com/google/go-github/v79/github"
16-
"github.com/google/go-querystring/query"
1714
"github.com/mark3labs/mcp-go/mcp"
1815
"github.com/mark3labs/mcp-go/server"
1916
)
@@ -256,30 +253,19 @@ func ListProjectFields(getClient GetClientFn, t translations.TranslationHelperFu
256253
returnmcp.NewToolResultError(err.Error()),nil
257254
}
258255

256+
varresp*github.Response
257+
varprojectFields []*github.ProjectV2Field
258+
259259
opts:=&github.ListProjectsOptions{
260260
ListProjectsPaginationOptions:pagination,
261261
}
262262

263-
varurlstring
264263
ifownerType=="org" {
265-
url=fmt.Sprintf("orgs/%s/projectsV2/%d/fields",owner,projectNumber)
264+
projectFields,resp,err=client.Projects.ListOrganizationProjectFields(ctx,owner,projectNumber,opts)
266265
}else {
267-
url=fmt.Sprintf("users/%s/projectsV2/%d/fields",owner,projectNumber)
268-
}
269-
270-
url,err=addOptions(url,opts)
271-
iferr!=nil {
272-
returnmcp.NewToolResultError(err.Error()),nil
266+
projectFields,resp,err=client.Projects.ListUserProjectFields(ctx,owner,projectNumber,opts)
273267
}
274268

275-
httpRequest,err:=client.NewRequest("GET",url,nil)
276-
iferr!=nil {
277-
returnnil,fmt.Errorf("failed to create request: %w",err)
278-
}
279-
280-
varprojectFields []projectV2Field
281-
resp,err:=client.Do(ctx,httpRequest,&projectFields)
282-
283269
iferr!=nil {
284270
returnghErrors.NewGitHubAPIErrorResponse(ctx,
285271
"failed to list project fields",
@@ -452,7 +438,7 @@ func ListProjectItems(getClient GetClientFn, t translations.TranslationHelperFun
452438
}
453439

454440
varresp*github.Response
455-
varprojectItems []projectV2Item
441+
varprojectItems []*github.ProjectV2Item
456442
varqueryPtr*string
457443

458444
ifqueryStr!="" {
@@ -467,25 +453,12 @@ func ListProjectItems(getClient GetClientFn, t translations.TranslationHelperFun
467453
},
468454
}
469455

470-
varurlstring
471456
ifownerType=="org" {
472-
url=fmt.Sprintf("orgs/%s/projectsV2/%d/items",owner,projectNumber)
457+
projectItems,resp,err=client.Projects.ListOrganizationProjectItems(ctx,owner,projectNumber,opts)
473458
}else {
474-
url=fmt.Sprintf("users/%s/projectsV2/%d/items",owner,projectNumber)
459+
projectItems,resp,err=client.Projects.ListUserProjectItems(ctx,owner,projectNumber,opts)
475460
}
476461

477-
url,err=addOptions(url,opts)
478-
iferr!=nil {
479-
returnmcp.NewToolResultError(err.Error()),nil
480-
}
481-
482-
httpRequest,err:=client.NewRequest("GET",url,nil)
483-
iferr!=nil {
484-
returnnil,fmt.Errorf("failed to create request: %w",err)
485-
}
486-
487-
resp,err=client.Do(ctx,httpRequest,&projectItems)
488-
489462
iferr!=nil {
490463
returnghErrors.NewGitHubAPIErrorResponse(ctx,
491464
ProjectListFailedError,
@@ -566,32 +539,22 @@ func GetProjectItem(getClient GetClientFn, t translations.TranslationHelperFunc)
566539
returnmcp.NewToolResultError(err.Error()),nil
567540
}
568541

569-
varurlstring
570-
ifownerType=="org" {
571-
url=fmt.Sprintf("orgs/%s/projectsV2/%d/items/%d",owner,projectNumber,itemID)
572-
}else {
573-
url=fmt.Sprintf("users/%s/projectsV2/%d/items/%d",owner,projectNumber,itemID)
574-
}
575-
576-
opts:=fieldSelectionOptions{}
542+
varresp*github.Response
543+
varprojectItem*github.ProjectV2Item
544+
varopts*github.GetProjectItemOptions
577545

578546
iflen(fields)>0 {
579-
opts.Fields=fields
580-
}
581-
582-
url,err=addOptions(url,opts)
583-
iferr!=nil {
584-
returnmcp.NewToolResultError(err.Error()),nil
547+
opts=&github.GetProjectItemOptions{
548+
Fields:fields,
549+
}
585550
}
586551

587-
projectItem:=projectV2Item{}
588-
589-
httpRequest,err:=client.NewRequest("GET",url,nil)
590-
iferr!=nil {
591-
returnnil,fmt.Errorf("failed to create request: %w",err)
552+
ifownerType=="org" {
553+
projectItem,resp,err=client.Projects.GetOrganizationProjectItem(ctx,owner,projectNumber,itemID,opts)
554+
}else {
555+
projectItem,resp,err=client.Projects.GetUserProjectItem(ctx,owner,projectNumber,itemID,opts)
592556
}
593557

594-
resp,err:=client.Do(ctx,httpRequest,&projectItem)
595558
iferr!=nil {
596559
returnghErrors.NewGitHubAPIErrorResponse(ctx,
597560
"failed to get project item",
@@ -748,7 +711,7 @@ func UpdateProjectItem(getClient GetClientFn, t translations.TranslationHelperFu
748711
iferr!=nil {
749712
returnmcp.NewToolResultError(err.Error()),nil
750713
}
751-
itemID,err:=RequiredInt(req,"item_id")
714+
itemID,err:=RequiredBigInt(req,"item_id")
752715
iferr!=nil {
753716
returnmcp.NewToolResultError(err.Error()),nil
754717
}
@@ -773,21 +736,15 @@ func UpdateProjectItem(getClient GetClientFn, t translations.TranslationHelperFu
773736
returnmcp.NewToolResultError(err.Error()),nil
774737
}
775738

776-
varprojectsURLstring
739+
varresp*github.Response
740+
varupdatedItem*github.ProjectV2Item
741+
777742
ifownerType=="org" {
778-
projectsURL=fmt.Sprintf("orgs/%s/projectsV2/%d/items/%d",owner,projectNumber,itemID)
743+
updatedItem,resp,err=client.Projects.UpdateOrganizationProjectItem(ctx,owner,projectNumber,itemID,updatePayload)
779744
}else {
780-
projectsURL=fmt.Sprintf("users/%s/projectsV2/%d/items/%d",owner,projectNumber,itemID)
781-
}
782-
httpRequest,err:=client.NewRequest("PATCH",projectsURL,updateProjectItemPayload{
783-
Fields: []updateProjectItem{*updatePayload},
784-
})
785-
iferr!=nil {
786-
returnnil,fmt.Errorf("failed to create request: %w",err)
745+
updatedItem,resp,err=client.Projects.UpdateUserProjectItem(ctx,owner,projectNumber,itemID,updatePayload)
787746
}
788-
updatedItem:=projectV2Item{}
789747

790-
resp,err:=client.Do(ctx,httpRequest,&updatedItem)
791748
iferr!=nil {
792749
returnghErrors.NewGitHubAPIErrorResponse(ctx,
793750
ProjectUpdateFailedError,
@@ -886,76 +843,13 @@ func DeleteProjectItem(getClient GetClientFn, t translations.TranslationHelperFu
886843
}
887844
}
888845

889-
typefieldSelectionOptionsstruct {
890-
// Specific list of field IDs to include in the response. If not provided, only the title field is included.
891-
// The comma tag encodes the slice as comma-separated values: fields=102589,985201,169875
892-
Fields []int64`url:"fields,omitempty,comma"`
893-
}
894-
895-
typeupdateProjectItemPayloadstruct {
896-
Fields []updateProjectItem`json:"fields"`
897-
}
898-
899-
typeupdateProjectItemstruct {
900-
IDint`json:"id"`
901-
Valueany`json:"value"`
902-
}
903-
904-
typeprojectV2ItemFieldValuestruct {
905-
ID*int64`json:"id,omitempty"`
906-
Namestring`json:"name,omitempty"`
907-
DataTypestring`json:"data_type,omitempty"`
908-
Valueany`json:"value,omitempty"`
909-
}
910-
911-
typeprojectV2Itemstruct {
912-
ArchivedAt*github.Timestamp`json:"archived_at,omitempty"`
913-
Content*projectV2ItemContent`json:"content,omitempty"`
914-
ContentType*string`json:"content_type,omitempty"`
915-
CreatedAt*github.Timestamp`json:"created_at,omitempty"`
916-
Creator*github.User`json:"creator,omitempty"`
917-
Description*string`json:"description,omitempty"`
918-
Fields []*projectV2ItemFieldValue`json:"fields,omitempty"`
919-
ID*int64`json:"id,omitempty"`
920-
ItemURL*string`json:"item_url,omitempty"`
921-
NodeID*string`json:"node_id,omitempty"`
922-
ProjectURL*string`json:"project_url,omitempty"`
923-
Title*string`json:"title,omitempty"`
924-
UpdatedAt*github.Timestamp`json:"updated_at,omitempty"`
925-
}
926-
927-
typeprojectV2ItemContentstruct {
928-
Body*string`json:"body,omitempty"`
929-
ClosedAt*github.Timestamp`json:"closed_at,omitempty"`
930-
CreatedAt*github.Timestamp`json:"created_at,omitempty"`
931-
ID*int64`json:"id,omitempty"`
932-
Number*int`json:"number,omitempty"`
933-
State*string`json:"state,omitempty"`
934-
StateReason*string`json:"stateReason,omitempty"`
935-
Title*string`json:"title,omitempty"`
936-
UpdatedAt*github.Timestamp`json:"updated_at,omitempty"`
937-
URL*string`json:"url,omitempty"`
938-
}
939-
940846
typepageInfostruct {
941847
HasNextPagebool`json:"hasNextPage"`
942848
HasPreviousPagebool`json:"hasPreviousPage"`
943849
NextCursorstring`json:"nextCursor,omitempty"`
944850
PrevCursorstring`json:"prevCursor,omitempty"`
945851
}
946852

947-
typeprojectV2Fieldstruct {
948-
ID*int64`json:"id,omitempty"`
949-
NodeID*string`json:"node_id,omitempty"`
950-
Name*string`json:"name,omitempty"`
951-
DataType*string`json:"data_type,omitempty"`
952-
ProjectURL*string`json:"project_url,omitempty"`
953-
Options []any`json:"options,omitempty"`
954-
Configurationany`json:"configuration,omitempty"`
955-
CreatedAt*github.Timestamp`json:"created_at,omitempty"`
956-
UpdatedAt*github.Timestamp`json:"updated_at,omitempty"`
957-
}
958-
959853
functoNewProjectType(projTypestring)string {
960854
switchstrings.ToLower(projType) {
961855
case"issue":
@@ -967,7 +861,27 @@ func toNewProjectType(projType string) string {
967861
}
968862
}
969863

970-
funcbuildUpdateProjectItem(inputmap[string]any) (*updateProjectItem,error) {
864+
// validateAndConvertToInt64 ensures the value is a number and converts it to int64.
865+
funcvalidateAndConvertToInt64(valueany) (int64,error) {
866+
switchv:=value.(type) {
867+
casefloat64:
868+
// Validate that the float64 can be safely converted to int64
869+
intVal:=int64(v)
870+
iffloat64(intVal)!=v {
871+
return0,fmt.Errorf("value must be a valid integer (got %v)",v)
872+
}
873+
returnintVal,nil
874+
caseint64:
875+
returnv,nil
876+
caseint:
877+
returnint64(v),nil
878+
default:
879+
return0,fmt.Errorf("value must be a number (got %T)",v)
880+
}
881+
}
882+
883+
// buildUpdateProjectItem constructs UpdateProjectItemOptions from the input map.
884+
funcbuildUpdateProjectItem(inputmap[string]any) (*github.UpdateProjectItemOptions,error) {
971885
ifinput==nil {
972886
returnnil,fmt.Errorf("updated_field must be an object")
973887
}
@@ -977,16 +891,22 @@ func buildUpdateProjectItem(input map[string]any) (*updateProjectItem, error) {
977891
returnnil,fmt.Errorf("updated_field.id is required")
978892
}
979893

980-
idFieldAsFloat64,ok:=idField.(float64)// JSON numbers are float64
981-
if!ok {
982-
returnnil,fmt.Errorf("updated_field.id must be a number")
894+
fieldID,err:=validateAndConvertToInt64(idField)
895+
iferr!=nil {
896+
returnnil,fmt.Errorf("updated_field.id: %w",err)
983897
}
984898

985899
valueField,ok:=input["value"]
986900
if!ok {
987901
returnnil,fmt.Errorf("updated_field.value is required")
988902
}
989-
payload:=&updateProjectItem{ID:int(idFieldAsFloat64),Value:valueField}
903+
904+
payload:=&github.UpdateProjectItemOptions{
905+
Fields: []*github.UpdateProjectV2Field{{
906+
ID:fieldID,
907+
Value:valueField,
908+
}},
909+
}
990910

991911
returnpayload,nil
992912
}
@@ -1034,35 +954,3 @@ func extractPaginationOptions(request mcp.CallToolRequest) (github.ListProjectsP
1034954

1035955
returnopts,nil
1036956
}
1037-
1038-
// addOptions adds the parameters in opts as URL query parameters to s. opts
1039-
// must be a struct whose fields may contain "url" tags.
1040-
funcaddOptions(sstring,optsany) (string,error) {
1041-
v:=reflect.ValueOf(opts)
1042-
ifv.Kind()==reflect.Ptr&&v.IsNil() {
1043-
returns,nil
1044-
}
1045-
1046-
origURL,err:=url.Parse(s)
1047-
iferr!=nil {
1048-
returns,err
1049-
}
1050-
1051-
origValues:=origURL.Query()
1052-
1053-
// Use the github.com/google/go-querystring library to parse the struct
1054-
newValues,err:=query.Values(opts)
1055-
iferr!=nil {
1056-
returns,err
1057-
}
1058-
1059-
// Merge the values
1060-
forkey,values:=rangenewValues {
1061-
for_,value:=rangevalues {
1062-
origValues.Add(key,value)
1063-
}
1064-
}
1065-
1066-
origURL.RawQuery=origValues.Encode()
1067-
returnorigURL.String(),nil
1068-
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp