Merge pull request #12757 from cli/12756-gh-project-edit-fails-variable-$query-used-but-not-declared-in-updateprojectv2
Fix project mutation query variable usage
This commit is contained in:
commit
cf862d65df
8 changed files with 122 additions and 13 deletions
|
|
@ -30,7 +30,7 @@ type closeConfig struct {
|
|||
// the close command relies on the updateProjectV2 mutation
|
||||
type updateProjectMutation struct {
|
||||
UpdateProjectV2 struct {
|
||||
ProjectV2 queries.Project `graphql:"projectV2"`
|
||||
ProjectV2 queries.ProjectMutationQuery `graphql:"projectV2"`
|
||||
} `graphql:"updateProjectV2(input:$input)"`
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ func closeArgs(config closeConfig) (*updateProjectMutation, map[string]interface
|
|||
}
|
||||
}
|
||||
|
||||
func printResults(config closeConfig, project queries.Project) error {
|
||||
func printResults(config closeConfig, project queries.ProjectMutationQuery) error {
|
||||
if !config.io.IsStdoutTTY() {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ type copyConfig struct {
|
|||
|
||||
type copyProjectMutation struct {
|
||||
CopyProjectV2 struct {
|
||||
ProjectV2 queries.Project `graphql:"projectV2"`
|
||||
ProjectV2 queries.ProjectMutationQuery `graphql:"projectV2"`
|
||||
} `graphql:"copyProjectV2(input:$input)"`
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ func copyArgs(config copyConfig) (*copyProjectMutation, map[string]interface{})
|
|||
}
|
||||
}
|
||||
|
||||
func printResults(config copyConfig, project queries.Project) error {
|
||||
func printResults(config copyConfig, project queries.ProjectMutationQuery) error {
|
||||
if !config.io.IsStdoutTTY() {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ type createConfig struct {
|
|||
|
||||
type createProjectMutation struct {
|
||||
CreateProjectV2 struct {
|
||||
ProjectV2 queries.Project `graphql:"projectV2"`
|
||||
ProjectV2 queries.ProjectMutationQuery `graphql:"projectV2"`
|
||||
} `graphql:"createProjectV2(input:$input)"`
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ func createArgs(config createConfig) (*createProjectMutation, map[string]interfa
|
|||
}
|
||||
}
|
||||
|
||||
func printResults(config createConfig, project queries.Project) error {
|
||||
func printResults(config createConfig, project queries.ProjectMutationQuery) error {
|
||||
if !config.io.IsStdoutTTY() {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ type deleteConfig struct {
|
|||
|
||||
type deleteProjectMutation struct {
|
||||
DeleteProject struct {
|
||||
Project queries.Project `graphql:"projectV2"`
|
||||
Project queries.ProjectMutationQuery `graphql:"projectV2"`
|
||||
} `graphql:"deleteProjectV2(input:$input)"`
|
||||
}
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ func deleteItemArgs(config deleteConfig) (*deleteProjectMutation, map[string]int
|
|||
}
|
||||
}
|
||||
|
||||
func printResults(config deleteConfig, project queries.Project) error {
|
||||
func printResults(config deleteConfig, project queries.ProjectMutationQuery) error {
|
||||
if !config.io.IsStdoutTTY() {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ type editConfig struct {
|
|||
|
||||
type updateProjectMutation struct {
|
||||
UpdateProjectV2 struct {
|
||||
ProjectV2 queries.Project `graphql:"projectV2"`
|
||||
ProjectV2 queries.ProjectMutationQuery `graphql:"projectV2"`
|
||||
} `graphql:"updateProjectV2(input:$input)"`
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ func editArgs(config editConfig) (*updateProjectMutation, map[string]interface{}
|
|||
}
|
||||
}
|
||||
|
||||
func printResults(config editConfig, project queries.Project) error {
|
||||
func printResults(config editConfig, project queries.ProjectMutationQuery) error {
|
||||
if !config.io.IsStdoutTTY() {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ type markTemplateConfig struct {
|
|||
|
||||
type markProjectTemplateMutation struct {
|
||||
TemplateProject struct {
|
||||
Project queries.Project `graphql:"projectV2"`
|
||||
Project queries.ProjectMutationQuery `graphql:"projectV2"`
|
||||
} `graphql:"markProjectV2AsTemplate(input:$input)"`
|
||||
}
|
||||
type unmarkProjectTemplateMutation struct {
|
||||
TemplateProject struct {
|
||||
Project queries.Project `graphql:"projectV2"`
|
||||
Project queries.ProjectMutationQuery `graphql:"projectV2"`
|
||||
} `graphql:"unmarkProjectV2AsTemplate(input:$input)"`
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +150,7 @@ func unmarkTemplateArgs(config markTemplateConfig) (*unmarkProjectTemplateMutati
|
|||
}
|
||||
}
|
||||
|
||||
func printResults(config markTemplateConfig, project queries.Project) error {
|
||||
func printResults(config markTemplateConfig, project queries.ProjectMutationQuery) error {
|
||||
if !config.io.IsStdoutTTY() {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,6 +147,34 @@ type Project struct {
|
|||
}
|
||||
}
|
||||
|
||||
// ProjectMutationQuery is a ProjectV2 response shape for mutation payloads.
|
||||
// It intentionally avoids the queryable items connection to prevent requiring a $query variable.
|
||||
type ProjectMutationQuery struct {
|
||||
Number int32
|
||||
URL string
|
||||
ShortDescription string
|
||||
Public bool
|
||||
Closed bool
|
||||
Title string
|
||||
ID string
|
||||
Readme string
|
||||
Items struct {
|
||||
TotalCount int
|
||||
} `graphql:"items(first: $firstItems, after: $afterItems)"`
|
||||
Fields struct {
|
||||
TotalCount int
|
||||
} `graphql:"fields(first: $firstFields, after: $afterFields)"`
|
||||
Owner struct {
|
||||
TypeName string `graphql:"__typename"`
|
||||
User struct {
|
||||
Login string
|
||||
} `graphql:"... on User"`
|
||||
Organization struct {
|
||||
Login string
|
||||
} `graphql:"... on Organization"`
|
||||
}
|
||||
}
|
||||
|
||||
// Below, you will find the query structs to represent fetching a project via the GraphQL API.
|
||||
// Prior to GHES 3.20, the query argument did not exist on the items connection, so we have
|
||||
// one base struct and two structs that embed and add the Items connection with and without the query argument.
|
||||
|
|
@ -265,6 +293,40 @@ func (p Project) OwnerLogin() string {
|
|||
return p.Owner.Organization.Login
|
||||
}
|
||||
|
||||
func (p ProjectMutationQuery) ExportData(_ []string) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"number": p.Number,
|
||||
"url": p.URL,
|
||||
"shortDescription": p.ShortDescription,
|
||||
"public": p.Public,
|
||||
"closed": p.Closed,
|
||||
"title": p.Title,
|
||||
"id": p.ID,
|
||||
"readme": p.Readme,
|
||||
"items": map[string]interface{}{
|
||||
"totalCount": p.Items.TotalCount,
|
||||
},
|
||||
"fields": map[string]interface{}{
|
||||
"totalCount": p.Fields.TotalCount,
|
||||
},
|
||||
"owner": map[string]interface{}{
|
||||
"type": p.OwnerType(),
|
||||
"login": p.OwnerLogin(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p ProjectMutationQuery) OwnerType() string {
|
||||
return p.Owner.TypeName
|
||||
}
|
||||
|
||||
func (p ProjectMutationQuery) OwnerLogin() string {
|
||||
if p.OwnerType() == "User" {
|
||||
return p.Owner.User.Login
|
||||
}
|
||||
return p.Owner.Organization.Login
|
||||
}
|
||||
|
||||
type Projects struct {
|
||||
Nodes []Project
|
||||
TotalCount int
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/shurcooL/githubv4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/h2non/gock.v1"
|
||||
)
|
||||
|
|
@ -18,6 +19,52 @@ func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
|||
return f(req)
|
||||
}
|
||||
|
||||
func TestProjectMutationQuery_DoesNotRequireQueryVariable(t *testing.T) {
|
||||
ios, _, _, _ := iostreams.Test()
|
||||
httpClient := &http.Client{
|
||||
Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||
body, err := io.ReadAll(req.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.NotContains(t, string(body), "$query")
|
||||
|
||||
return &http.Response{
|
||||
StatusCode: 200,
|
||||
Header: http.Header{
|
||||
"Content-Type": []string{"application/json"},
|
||||
},
|
||||
Body: io.NopCloser(strings.NewReader(`{
|
||||
"data": {
|
||||
"updateProjectV2": {
|
||||
"projectV2": {
|
||||
"id": "project ID",
|
||||
"url": "http://example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
}`)),
|
||||
}, nil
|
||||
}),
|
||||
}
|
||||
|
||||
client := NewClient(httpClient, "github.com", ios)
|
||||
mutation := struct {
|
||||
UpdateProjectV2 struct {
|
||||
ProjectV2 ProjectMutationQuery `graphql:"projectV2"`
|
||||
} `graphql:"updateProjectV2(input:$input)"`
|
||||
}{}
|
||||
|
||||
err := client.Mutate("UpdateProjectV2", &mutation, map[string]interface{}{
|
||||
"input": githubv4.UpdateProjectV2Input{
|
||||
ProjectID: githubv4.ID("project ID"),
|
||||
},
|
||||
"firstItems": githubv4.Int(0),
|
||||
"afterItems": (*githubv4.String)(nil),
|
||||
"firstFields": githubv4.Int(0),
|
||||
"afterFields": (*githubv4.String)(nil),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestProjectItems_DefaultLimit(t *testing.T) {
|
||||
defer gock.Off()
|
||||
gock.Observe(gock.DumpRequest)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue