diff options
Diffstat (limited to 'graphql')
-rw-r--r-- | graphql/gqlgen.yml | 15 | ||||
-rw-r--r-- | graphql/graph/gen_graph.go | 717 | ||||
-rw-r--r-- | graphql/graphql_test.go | 162 | ||||
-rw-r--r-- | graphql/handler.go | 3 | ||||
-rw-r--r-- | graphql/resolvers/identity.go | 44 | ||||
-rw-r--r-- | graphql/resolvers/mutation.go | 10 | ||||
-rw-r--r-- | graphql/resolvers/person.go | 37 | ||||
-rw-r--r-- | graphql/resolvers/root.go | 4 | ||||
-rw-r--r-- | graphql/schema/bug.graphql (renamed from graphql/bug.graphql) | 19 | ||||
-rw-r--r-- | graphql/schema/identity.graphql | 18 | ||||
-rw-r--r-- | graphql/schema/operations.graphql (renamed from graphql/operations.graphql) | 16 | ||||
-rw-r--r-- | graphql/schema/root.graphql (renamed from graphql/root.graphql) | 4 | ||||
-rw-r--r-- | graphql/schema/timeline.graphql (renamed from graphql/timeline.graphql) | 12 |
13 files changed, 663 insertions, 398 deletions
diff --git a/graphql/gqlgen.yml b/graphql/gqlgen.yml index b6dc3ae5..0e389a53 100644 --- a/graphql/gqlgen.yml +++ b/graphql/gqlgen.yml @@ -1,4 +1,4 @@ -schema: "*.graphql" +schema: "schema/*.graphql" exec: filename: graph/gen_graph.go model: @@ -13,17 +13,8 @@ models: model: github.com/MichaelMure/git-bug/bug.Snapshot Comment: model: github.com/MichaelMure/git-bug/bug.Comment - Person: - model: github.com/MichaelMure/git-bug/bug.Person - fields: - name: - resolver: true - email: - resolver: true - login: - resolver: true - avatarUrl: - resolver: true + Identity: + model: github.com/MichaelMure/git-bug/identity.Interface Label: model: github.com/MichaelMure/git-bug/bug.Label Hash: diff --git a/graphql/graph/gen_graph.go b/graphql/graph/gen_graph.go index e7d09ef4..548e808a 100644 --- a/graphql/graph/gen_graph.go +++ b/graphql/graph/gen_graph.go @@ -15,6 +15,7 @@ import ( "github.com/99designs/gqlgen/graphql/introspection" "github.com/MichaelMure/git-bug/bug" "github.com/MichaelMure/git-bug/graphql/models" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/vektah/gqlparser" "github.com/vektah/gqlparser/ast" @@ -43,10 +44,10 @@ type ResolverRoot interface { CreateOperation() CreateOperationResolver CreateTimelineItem() CreateTimelineItemResolver EditCommentOperation() EditCommentOperationResolver + Identity() IdentityResolver LabelChangeOperation() LabelChangeOperationResolver LabelChangeTimelineItem() LabelChangeTimelineItemResolver Mutation() MutationResolver - Person() PersonResolver Query() QueryResolver Repository() RepositoryResolver SetStatusOperation() SetStatusOperationResolver @@ -158,6 +159,16 @@ type ComplexityRoot struct { Files func(childComplexity int) int } + Identity struct { + Id func(childComplexity int) int + Name func(childComplexity int) int + Email func(childComplexity int) int + Login func(childComplexity int) int + DisplayName func(childComplexity int) int + AvatarUrl func(childComplexity int) int + IsProtected func(childComplexity int) int + } + LabelChangeOperation struct { Hash func(childComplexity int) int Author func(childComplexity int) int @@ -203,14 +214,6 @@ type ComplexityRoot struct { EndCursor func(childComplexity int) int } - Person struct { - Name func(childComplexity int) int - Email func(childComplexity int) int - Login func(childComplexity int) int - DisplayName func(childComplexity int) int - AvatarUrl func(childComplexity int) int - } - Query struct { DefaultRepository func(childComplexity int) int Repository func(childComplexity int, id string) int @@ -292,6 +295,15 @@ type CreateTimelineItemResolver interface { type EditCommentOperationResolver interface { Date(ctx context.Context, obj *bug.EditCommentOperation) (time.Time, error) } +type IdentityResolver interface { + ID(ctx context.Context, obj *identity.Interface) (string, error) + Name(ctx context.Context, obj *identity.Interface) (*string, error) + Email(ctx context.Context, obj *identity.Interface) (*string, error) + Login(ctx context.Context, obj *identity.Interface) (*string, error) + DisplayName(ctx context.Context, obj *identity.Interface) (string, error) + AvatarURL(ctx context.Context, obj *identity.Interface) (*string, error) + IsProtected(ctx context.Context, obj *identity.Interface) (bool, error) +} type LabelChangeOperationResolver interface { Date(ctx context.Context, obj *bug.LabelChangeOperation) (time.Time, error) } @@ -307,13 +319,6 @@ type MutationResolver interface { SetTitle(ctx context.Context, repoRef *string, prefix string, title string) (bug.Snapshot, error) Commit(ctx context.Context, repoRef *string, prefix string) (bug.Snapshot, error) } -type PersonResolver interface { - Name(ctx context.Context, obj *bug.Person) (*string, error) - Email(ctx context.Context, obj *bug.Person) (*string, error) - Login(ctx context.Context, obj *bug.Person) (*string, error) - - AvatarURL(ctx context.Context, obj *bug.Person) (*string, error) -} type QueryResolver interface { DefaultRepository(ctx context.Context) (*models.Repository, error) Repository(ctx context.Context, id string) (*models.Repository, error) @@ -1453,6 +1458,55 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.EditCommentOperation.Files(childComplexity), true + case "Identity.id": + if e.complexity.Identity.Id == nil { + break + } + + return e.complexity.Identity.Id(childComplexity), true + + case "Identity.name": + if e.complexity.Identity.Name == nil { + break + } + + return e.complexity.Identity.Name(childComplexity), true + + case "Identity.email": + if e.complexity.Identity.Email == nil { + break + } + + return e.complexity.Identity.Email(childComplexity), true + + case "Identity.login": + if e.complexity.Identity.Login == nil { + break + } + + return e.complexity.Identity.Login(childComplexity), true + + case "Identity.displayName": + if e.complexity.Identity.DisplayName == nil { + break + } + + return e.complexity.Identity.DisplayName(childComplexity), true + + case "Identity.avatarUrl": + if e.complexity.Identity.AvatarUrl == nil { + break + } + + return e.complexity.Identity.AvatarUrl(childComplexity), true + + case "Identity.isProtected": + if e.complexity.Identity.IsProtected == nil { + break + } + + return e.complexity.Identity.IsProtected(childComplexity), true + case "LabelChangeOperation.hash": if e.complexity.LabelChangeOperation.Hash == nil { break @@ -1677,41 +1731,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.PageInfo.EndCursor(childComplexity), true - case "Person.name": - if e.complexity.Person.Name == nil { - break - } - - return e.complexity.Person.Name(childComplexity), true - - case "Person.email": - if e.complexity.Person.Email == nil { - break - } - - return e.complexity.Person.Email(childComplexity), true - - case "Person.login": - if e.complexity.Person.Login == nil { - break - } - - return e.complexity.Person.Login(childComplexity), true - - case "Person.displayName": - if e.complexity.Person.DisplayName == nil { - break - } - - return e.complexity.Person.DisplayName(childComplexity), true - - case "Person.avatarUrl": - if e.complexity.Person.AvatarUrl == nil { - break - } - - return e.complexity.Person.AvatarUrl(childComplexity), true - case "Query.defaultRepository": if e.complexity.Query.DefaultRepository == nil { break @@ -2072,11 +2091,11 @@ func (ec *executionContext) _AddCommentOperation_author(ctx context.Context, fie } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -2296,11 +2315,11 @@ func (ec *executionContext) _AddCommentTimelineItem_author(ctx context.Context, } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -2800,11 +2819,11 @@ func (ec *executionContext) _Bug_author(ctx context.Context, field graphql.Colle } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -3334,11 +3353,11 @@ func (ec *executionContext) _Comment_author(ctx context.Context, field graphql.C } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -3916,11 +3935,11 @@ func (ec *executionContext) _CreateOperation_author(ctx context.Context, field g } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -4167,11 +4186,11 @@ func (ec *executionContext) _CreateTimelineItem_author(ctx context.Context, fiel } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -4513,11 +4532,11 @@ func (ec *executionContext) _EditCommentOperation_author(ctx context.Context, fi } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -4637,6 +4656,276 @@ func (ec *executionContext) _EditCommentOperation_files(ctx context.Context, fie return arr1 } +var identityImplementors = []string{"Identity"} + +// nolint: gocyclo, errcheck, gas, goconst +func (ec *executionContext) _Identity(ctx context.Context, sel ast.SelectionSet, obj *identity.Interface) graphql.Marshaler { + fields := graphql.CollectFields(ctx, sel, identityImplementors) + + var wg sync.WaitGroup + out := graphql.NewOrderedMap(len(fields)) + invalid := false + for i, field := range fields { + out.Keys[i] = field.Alias + + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Identity") + case "id": + wg.Add(1) + go func(i int, field graphql.CollectedField) { + out.Values[i] = ec._Identity_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalid = true + } + wg.Done() + }(i, field) + case "name": + wg.Add(1) + go func(i int, field graphql.CollectedField) { + out.Values[i] = ec._Identity_name(ctx, field, obj) + wg.Done() + }(i, field) + case "email": + wg.Add(1) + go func(i int, field graphql.CollectedField) { + out.Values[i] = ec._Identity_email(ctx, field, obj) + wg.Done() + }(i, field) + case "login": + wg.Add(1) + go func(i int, field graphql.CollectedField) { + out.Values[i] = ec._Identity_login(ctx, field, obj) + wg.Done() + }(i, field) + case "displayName": + wg.Add(1) + go func(i int, field graphql.CollectedField) { + out.Values[i] = ec._Identity_displayName(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalid = true + } + wg.Done() + }(i, field) + case "avatarUrl": + wg.Add(1) + go func(i int, field graphql.CollectedField) { + out.Values[i] = ec._Identity_avatarUrl(ctx, field, obj) + wg.Done() + }(i, field) + case "isProtected": + wg.Add(1) + go func(i int, field graphql.CollectedField) { + out.Values[i] = ec._Identity_isProtected(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalid = true + } + wg.Done() + }(i, field) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + wg.Wait() + if invalid { + return graphql.Null + } + return out +} + +// nolint: vetshadow +func (ec *executionContext) _Identity_id(ctx context.Context, field graphql.CollectedField, obj *identity.Interface) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Identity", + Args: nil, + Field: field, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Identity().ID(rctx, obj) + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return graphql.MarshalString(res) +} + +// nolint: vetshadow +func (ec *executionContext) _Identity_name(ctx context.Context, field graphql.CollectedField, obj *identity.Interface) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Identity", + Args: nil, + Field: field, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Identity().Name(rctx, obj) + }) + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + + if res == nil { + return graphql.Null + } + return graphql.MarshalString(*res) +} + +// nolint: vetshadow +func (ec *executionContext) _Identity_email(ctx context.Context, field graphql.CollectedField, obj *identity.Interface) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Identity", + Args: nil, + Field: field, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Identity().Email(rctx, obj) + }) + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + + if res == nil { + return graphql.Null + } + return graphql.MarshalString(*res) +} + +// nolint: vetshadow +func (ec *executionContext) _Identity_login(ctx context.Context, field graphql.CollectedField, obj *identity.Interface) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Identity", + Args: nil, + Field: field, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Identity().Login(rctx, obj) + }) + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + + if res == nil { + return graphql.Null + } + return graphql.MarshalString(*res) +} + +// nolint: vetshadow +func (ec *executionContext) _Identity_displayName(ctx context.Context, field graphql.CollectedField, obj *identity.Interface) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Identity", + Args: nil, + Field: field, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Identity().DisplayName(rctx, obj) + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return graphql.MarshalString(res) +} + +// nolint: vetshadow +func (ec *executionContext) _Identity_avatarUrl(ctx context.Context, field graphql.CollectedField, obj *identity.Interface) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Identity", + Args: nil, + Field: field, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Identity().AvatarURL(rctx, obj) + }) + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + + if res == nil { + return graphql.Null + } + return graphql.MarshalString(*res) +} + +// nolint: vetshadow +func (ec *executionContext) _Identity_isProtected(ctx context.Context, field graphql.CollectedField, obj *identity.Interface) graphql.Marshaler { + ctx = ec.Tracer.StartFieldExecution(ctx, field) + defer func() { ec.Tracer.EndFieldExecution(ctx) }() + rctx := &graphql.ResolverContext{ + Object: "Identity", + Args: nil, + Field: field, + } + ctx = graphql.WithResolverContext(ctx, rctx) + ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) + resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Identity().IsProtected(rctx, obj) + }) + if resTmp == nil { + if !ec.HasError(rctx) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + rctx.Result = res + ctx = ec.Tracer.StartFieldChildExecution(ctx) + return graphql.MarshalBoolean(res) +} + var labelChangeOperationImplementors = []string{"LabelChangeOperation", "Operation", "Authored"} // nolint: gocyclo, errcheck, gas, goconst @@ -4740,11 +5029,11 @@ func (ec *executionContext) _LabelChangeOperation_author(ctx context.Context, fi } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -4949,11 +5238,11 @@ func (ec *executionContext) _LabelChangeTimelineItem_author(ctx context.Context, } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -5820,200 +6109,6 @@ func (ec *executionContext) _PageInfo_endCursor(ctx context.Context, field graph return graphql.MarshalString(res) } -var personImplementors = []string{"Person"} - -// nolint: gocyclo, errcheck, gas, goconst -func (ec *executionContext) _Person(ctx context.Context, sel ast.SelectionSet, obj *bug.Person) graphql.Marshaler { - fields := graphql.CollectFields(ctx, sel, personImplementors) - - var wg sync.WaitGroup - out := graphql.NewOrderedMap(len(fields)) - invalid := false - for i, field := range fields { - out.Keys[i] = field.Alias - - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Person") - case "name": - wg.Add(1) - go func(i int, field graphql.CollectedField) { - out.Values[i] = ec._Person_name(ctx, field, obj) - wg.Done() - }(i, field) - case "email": - wg.Add(1) - go func(i int, field graphql.CollectedField) { - out.Values[i] = ec._Person_email(ctx, field, obj) - wg.Done() - }(i, field) - case "login": - wg.Add(1) - go func(i int, field graphql.CollectedField) { - out.Values[i] = ec._Person_login(ctx, field, obj) - wg.Done() - }(i, field) - case "displayName": - out.Values[i] = ec._Person_displayName(ctx, field, obj) - if out.Values[i] == graphql.Null { - invalid = true - } - case "avatarUrl": - wg.Add(1) - go func(i int, field graphql.CollectedField) { - out.Values[i] = ec._Person_avatarUrl(ctx, field, obj) - wg.Done() - }(i, field) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - wg.Wait() - if invalid { - return graphql.Null - } - return out -} - -// nolint: vetshadow -func (ec *executionContext) _Person_name(ctx context.Context, field graphql.CollectedField, obj *bug.Person) graphql.Marshaler { - ctx = ec.Tracer.StartFieldExecution(ctx, field) - defer func() { ec.Tracer.EndFieldExecution(ctx) }() - rctx := &graphql.ResolverContext{ - Object: "Person", - Args: nil, - Field: field, - } - ctx = graphql.WithResolverContext(ctx, rctx) - ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) - resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Person().Name(rctx, obj) - }) - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - rctx.Result = res - ctx = ec.Tracer.StartFieldChildExecution(ctx) - - if res == nil { - return graphql.Null - } - return graphql.MarshalString(*res) -} - -// nolint: vetshadow -func (ec *executionContext) _Person_email(ctx context.Context, field graphql.CollectedField, obj *bug.Person) graphql.Marshaler { - ctx = ec.Tracer.StartFieldExecution(ctx, field) - defer func() { ec.Tracer.EndFieldExecution(ctx) }() - rctx := &graphql.ResolverContext{ - Object: "Person", - Args: nil, - Field: field, - } - ctx = graphql.WithResolverContext(ctx, rctx) - ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) - resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Person().Email(rctx, obj) - }) - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - rctx.Result = res - ctx = ec.Tracer.StartFieldChildExecution(ctx) - - if res == nil { - return graphql.Null - } - return graphql.MarshalString(*res) -} - -// nolint: vetshadow -func (ec *executionContext) _Person_login(ctx context.Context, field graphql.CollectedField, obj *bug.Person) graphql.Marshaler { - ctx = ec.Tracer.StartFieldExecution(ctx, field) - defer func() { ec.Tracer.EndFieldExecution(ctx) }() - rctx := &graphql.ResolverContext{ - Object: "Person", - Args: nil, - Field: field, - } - ctx = graphql.WithResolverContext(ctx, rctx) - ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) - resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Person().Login(rctx, obj) - }) - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - rctx.Result = res - ctx = ec.Tracer.StartFieldChildExecution(ctx) - - if res == nil { - return graphql.Null - } - return graphql.MarshalString(*res) -} - -// nolint: vetshadow -func (ec *executionContext) _Person_displayName(ctx context.Context, field graphql.CollectedField, obj *bug.Person) graphql.Marshaler { - ctx = ec.Tracer.StartFieldExecution(ctx, field) - defer func() { ec.Tracer.EndFieldExecution(ctx) }() - rctx := &graphql.ResolverContext{ - Object: "Person", - Args: nil, - Field: field, - } - ctx = graphql.WithResolverContext(ctx, rctx) - ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) - resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DisplayName(), nil - }) - if resTmp == nil { - if !ec.HasError(rctx) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - rctx.Result = res - ctx = ec.Tracer.StartFieldChildExecution(ctx) - return graphql.MarshalString(res) -} - -// nolint: vetshadow -func (ec *executionContext) _Person_avatarUrl(ctx context.Context, field graphql.CollectedField, obj *bug.Person) graphql.Marshaler { - ctx = ec.Tracer.StartFieldExecution(ctx, field) - defer func() { ec.Tracer.EndFieldExecution(ctx) }() - rctx := &graphql.ResolverContext{ - Object: "Person", - Args: nil, - Field: field, - } - ctx = graphql.WithResolverContext(ctx, rctx) - ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) - resTmp := ec.FieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Person().AvatarURL(rctx, obj) - }) - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - rctx.Result = res - ctx = ec.Tracer.StartFieldChildExecution(ctx) - - if res == nil { - return graphql.Null - } - return graphql.MarshalString(*res) -} - var queryImplementors = []string{"Query"} // nolint: gocyclo, errcheck, gas, goconst @@ -6400,11 +6495,11 @@ func (ec *executionContext) _SetStatusOperation_author(ctx context.Context, fiel } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -6563,11 +6658,11 @@ func (ec *executionContext) _SetStatusTimelineItem_author(ctx context.Context, f } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -6727,11 +6822,11 @@ func (ec *executionContext) _SetTitleOperation_author(ctx context.Context, field } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -6918,11 +7013,11 @@ func (ec *executionContext) _SetTitleTimelineItem_author(ctx context.Context, fi } return graphql.Null } - res := resTmp.(bug.Person) + res := resTmp.(identity.Interface) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) - return ec._Person(ctx, field.Selections, &res) + return ec._Identity(ctx, field.Selections, &res) } // nolint: vetshadow @@ -8862,24 +8957,10 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er } var parsedSchema = gqlparser.MustLoadSchema( - &ast.Source{Name: "bug.graphql", Input: `"""Represents an person""" -type Person { - """The name of the person, if known.""" - name: String - """The email of the person, if known.""" - email: String - """The login of the person, if known.""" - login: String - """A string containing the either the name of the person, its login or both""" - displayName: String! - """An url to an avatar""" - avatarUrl: String -} - -"""Represents a comment on a bug.""" + &ast.Source{Name: "schema/bug.graphql", Input: `"""Represents a comment on a bug.""" type Comment implements Authored { """The author of this comment.""" - author: Person! + author: Identity! """The message of this comment.""" message: String! @@ -8911,7 +8992,7 @@ type Bug { status: Status! title: String! labels: [Label!]! - author: Person! + author: Identity! createdAt: Time! lastEdit: Time! @@ -8983,14 +9064,31 @@ type Repository { ): BugConnection! bug(prefix: String!): Bug } - `}, - &ast.Source{Name: "operations.graphql", Input: `"""An operation applied to a bug.""" + &ast.Source{Name: "schema/identity.graphql", Input: `"""Represents an identity""" +type Identity { + """The identifier for this identity""" + id: String! + """The name of the person, if known.""" + name: String + """The email of the person, if known.""" + email: String + """The login of the person, if known.""" + login: String + """A string containing the either the name of the person, its login or both""" + displayName: String! + """An url to an avatar""" + avatarUrl: String + """isProtected is true if the chain of git commits started to be signed. + If that's the case, only signed commit with a valid key for this identity can be added.""" + isProtected: Boolean! +}`}, + &ast.Source{Name: "schema/operations.graphql", Input: `"""An operation applied to a bug.""" interface Operation { """The hash of the operation""" hash: Hash! """The operations author.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! } @@ -9017,7 +9115,7 @@ type CreateOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! @@ -9030,7 +9128,7 @@ type SetTitleOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! @@ -9042,7 +9140,7 @@ type AddCommentOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! @@ -9054,7 +9152,7 @@ type EditCommentOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! @@ -9067,7 +9165,7 @@ type SetStatusOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! @@ -9078,14 +9176,15 @@ type LabelChangeOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! added: [Label!]! removed: [Label!]! -}`}, - &ast.Source{Name: "root.graphql", Input: `scalar Time +} +`}, + &ast.Source{Name: "schema/root.graphql", Input: `scalar Time scalar Label scalar Hash @@ -9104,7 +9203,7 @@ type PageInfo { """An object that has an author.""" interface Authored { """The author of this object.""" - author: Person! + author: Identity! } type Query { @@ -9122,8 +9221,9 @@ type Mutation { setTitle(repoRef: String, prefix: String!, title: String!): Bug! commit(repoRef: String, prefix: String!): Bug! -}`}, - &ast.Source{Name: "timeline.graphql", Input: `"""An item in the timeline of events""" +} +`}, + &ast.Source{Name: "schema/timeline.graphql", Input: `"""An item in the timeline of events""" interface TimelineItem { """The hash of the source operation""" hash: Hash! @@ -9157,7 +9257,7 @@ type TimelineItemEdge { type CreateTimelineItem implements TimelineItem { """The hash of the source operation""" hash: Hash! - author: Person! + author: Identity! message: String! messageIsEmpty: Boolean! files: [Hash!]! @@ -9171,7 +9271,7 @@ type CreateTimelineItem implements TimelineItem { type AddCommentTimelineItem implements TimelineItem { """The hash of the source operation""" hash: Hash! - author: Person! + author: Identity! message: String! messageIsEmpty: Boolean! files: [Hash!]! @@ -9185,7 +9285,7 @@ type AddCommentTimelineItem implements TimelineItem { type LabelChangeTimelineItem implements TimelineItem { """The hash of the source operation""" hash: Hash! - author: Person! + author: Identity! date: Time! added: [Label!]! removed: [Label!]! @@ -9195,7 +9295,7 @@ type LabelChangeTimelineItem implements TimelineItem { type SetStatusTimelineItem implements TimelineItem { """The hash of the source operation""" hash: Hash! - author: Person! + author: Identity! date: Time! status: Status! } @@ -9204,9 +9304,10 @@ type SetStatusTimelineItem implements TimelineItem { type SetTitleTimelineItem implements TimelineItem { """The hash of the source operation""" hash: Hash! - author: Person! + author: Identity! date: Time! title: String! was: String! -}`}, +} +`}, ) diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go new file mode 100644 index 00000000..d571ce51 --- /dev/null +++ b/graphql/graphql_test.go @@ -0,0 +1,162 @@ +package graphql + +import ( + "net/http/httptest" + "testing" + + "github.com/MichaelMure/git-bug/graphql/models" + "github.com/MichaelMure/git-bug/misc/random_bugs" + "github.com/MichaelMure/git-bug/repository" + "github.com/MichaelMure/git-bug/util/test" + "github.com/vektah/gqlgen/client" +) + +func CreateFilledRepo(bugNumber int) repository.ClockedRepo { + repo := test.CreateRepo(false) + + var seed int64 = 42 + options := random_bugs.DefaultOptions() + + options.BugNumber = bugNumber + + random_bugs.CommitRandomBugsWithSeed(repo, options, seed) + return repo +} + +func TestQueries(t *testing.T) { + repo := CreateFilledRepo(10) + + handler, err := NewHandler(repo) + if err != nil { + t.Fatal(err) + } + + srv := httptest.NewServer(handler) + c := client.New(srv.URL) + + query := ` + query { + defaultRepository { + allBugs(first: 2) { + pageInfo { + endCursor + hasNextPage + startCursor + hasPreviousPage + } + nodes{ + author { + name + email + avatarUrl + } + + createdAt + humanId + id + lastEdit + status + title + + comments(first: 2) { + pageInfo { + endCursor + hasNextPage + startCursor + hasPreviousPage + } + nodes { + files + message + } + } + + operations(first: 20) { + pageInfo { + endCursor + hasNextPage + startCursor + hasPreviousPage + } + nodes { + author { + name + email + avatarUrl + } + date + ... on CreateOperation { + title + message + files + } + ... on SetTitleOperation { + title + was + } + ... on AddCommentOperation { + files + message + } + ... on SetStatusOperation { + status + } + ... on LabelChangeOperation { + added + removed + } + } + } + } + } + } + }` + + type Person struct { + Name string `json:"name"` + Email string `json:"email"` + AvatarUrl string `json:"avatarUrl"` + } + + var resp struct { + DefaultRepository struct { + AllBugs struct { + PageInfo models.PageInfo + Nodes []struct { + Author Person + CreatedAt string `json:"createdAt"` + HumanId string `json:"humanId"` + Id string + LastEdit string `json:"lastEdit"` + Status string + Title string + + Comments struct { + PageInfo models.PageInfo + Nodes []struct { + Files []string + Message string + } + } + + Operations struct { + PageInfo models.PageInfo + Nodes []struct { + Author Person + Date string + Title string + Files []string + Message string + Was string + Status string + Added []string + Removed []string + } + } + } + } + } + } + + c.MustPost(query, &resp) +} diff --git a/graphql/handler.go b/graphql/handler.go index 1e8498c8..aadcf4cb 100644 --- a/graphql/handler.go +++ b/graphql/handler.go @@ -4,11 +4,12 @@ package graphql import ( + "net/http" + "github.com/99designs/gqlgen/handler" "github.com/MichaelMure/git-bug/graphql/graph" "github.com/MichaelMure/git-bug/graphql/resolvers" "github.com/MichaelMure/git-bug/repository" - "net/http" ) // Handler is the root GraphQL http handler diff --git a/graphql/resolvers/identity.go b/graphql/resolvers/identity.go new file mode 100644 index 00000000..d4f9bba2 --- /dev/null +++ b/graphql/resolvers/identity.go @@ -0,0 +1,44 @@ +package resolvers + +import ( + "context" + + "github.com/MichaelMure/git-bug/identity" +) + +type identityResolver struct{} + +func (identityResolver) ID(ctx context.Context, obj *identity.Interface) (string, error) { + return (*obj).Id(), nil +} + +func (identityResolver) Name(ctx context.Context, obj *identity.Interface) (*string, error) { + return nilIfEmpty((*obj).Name()) +} + +func (identityResolver) Email(ctx context.Context, obj *identity.Interface) (*string, error) { + return nilIfEmpty((*obj).Email()) +} + +func (identityResolver) Login(ctx context.Context, obj *identity.Interface) (*string, error) { + return nilIfEmpty((*obj).Login()) +} + +func (identityResolver) DisplayName(ctx context.Context, obj *identity.Interface) (string, error) { + return (*obj).DisplayName(), nil +} + +func (identityResolver) AvatarURL(ctx context.Context, obj *identity.Interface) (*string, error) { + return nilIfEmpty((*obj).AvatarUrl()) +} + +func (identityResolver) IsProtected(ctx context.Context, obj *identity.Interface) (bool, error) { + return (*obj).IsProtected(), nil +} + +func nilIfEmpty(s string) (*string, error) { + if s == "" { + return nil, nil + } + return &s, nil +} diff --git a/graphql/resolvers/mutation.go b/graphql/resolvers/mutation.go index ee79ce6b..be6956af 100644 --- a/graphql/resolvers/mutation.go +++ b/graphql/resolvers/mutation.go @@ -68,7 +68,7 @@ func (r mutationResolver) AddComment(ctx context.Context, repoRef *string, prefi return bug.Snapshot{}, err } - err = b.AddCommentWithFiles(message, files) + _, err = b.AddCommentWithFiles(message, files) if err != nil { return bug.Snapshot{}, err } @@ -89,7 +89,7 @@ func (r mutationResolver) ChangeLabels(ctx context.Context, repoRef *string, pre return bug.Snapshot{}, err } - _, err = b.ChangeLabels(added, removed) + _, _, err = b.ChangeLabels(added, removed) if err != nil { return bug.Snapshot{}, err } @@ -110,7 +110,7 @@ func (r mutationResolver) Open(ctx context.Context, repoRef *string, prefix stri return bug.Snapshot{}, err } - err = b.Open() + _, err = b.Open() if err != nil { return bug.Snapshot{}, err } @@ -131,7 +131,7 @@ func (r mutationResolver) Close(ctx context.Context, repoRef *string, prefix str return bug.Snapshot{}, err } - err = b.Close() + _, err = b.Close() if err != nil { return bug.Snapshot{}, err } @@ -152,7 +152,7 @@ func (r mutationResolver) SetTitle(ctx context.Context, repoRef *string, prefix return bug.Snapshot{}, err } - err = b.SetTitle(title) + _, err = b.SetTitle(title) if err != nil { return bug.Snapshot{}, err } diff --git a/graphql/resolvers/person.go b/graphql/resolvers/person.go deleted file mode 100644 index bb4bcb0d..00000000 --- a/graphql/resolvers/person.go +++ /dev/null @@ -1,37 +0,0 @@ -package resolvers - -import ( - "context" - - "github.com/MichaelMure/git-bug/bug" -) - -type personResolver struct{} - -func (personResolver) Name(ctx context.Context, obj *bug.Person) (*string, error) { - if obj.Name == "" { - return nil, nil - } - return &obj.Name, nil -} - -func (personResolver) Email(ctx context.Context, obj *bug.Person) (*string, error) { - if obj.Email == "" { - return nil, nil - } - return &obj.Email, nil -} - -func (personResolver) Login(ctx context.Context, obj *bug.Person) (*string, error) { - if obj.Login == "" { - return nil, nil - } - return &obj.Login, nil -} - -func (personResolver) AvatarURL(ctx context.Context, obj *bug.Person) (*string, error) { - if obj.AvatarUrl == "" { - return nil, nil - } - return &obj.AvatarUrl, nil -} diff --git a/graphql/resolvers/root.go b/graphql/resolvers/root.go index d7bd6021..cfdfe346 100644 --- a/graphql/resolvers/root.go +++ b/graphql/resolvers/root.go @@ -32,8 +32,8 @@ func (RootResolver) Bug() graph.BugResolver { return &bugResolver{} } -func (r RootResolver) Person() graph.PersonResolver { - return &personResolver{} +func (r RootResolver) Identity() graph.IdentityResolver { + return &identityResolver{} } func (RootResolver) CommentHistoryStep() graph.CommentHistoryStepResolver { diff --git a/graphql/bug.graphql b/graphql/schema/bug.graphql index 27bbba99..7e1c57b5 100644 --- a/graphql/bug.graphql +++ b/graphql/schema/bug.graphql @@ -1,21 +1,7 @@ -"""Represents an person""" -type Person { - """The name of the person, if known.""" - name: String - """The email of the person, if known.""" - email: String - """The login of the person, if known.""" - login: String - """A string containing the either the name of the person, its login or both""" - displayName: String! - """An url to an avatar""" - avatarUrl: String -} - """Represents a comment on a bug.""" type Comment implements Authored { """The author of this comment.""" - author: Person! + author: Identity! """The message of this comment.""" message: String! @@ -47,7 +33,7 @@ type Bug { status: Status! title: String! labels: [Label!]! - author: Person! + author: Identity! createdAt: Time! lastEdit: Time! @@ -119,4 +105,3 @@ type Repository { ): BugConnection! bug(prefix: String!): Bug } - diff --git a/graphql/schema/identity.graphql b/graphql/schema/identity.graphql new file mode 100644 index 00000000..18666f76 --- /dev/null +++ b/graphql/schema/identity.graphql @@ -0,0 +1,18 @@ +"""Represents an identity""" +type Identity { + """The identifier for this identity""" + id: String! + """The name of the person, if known.""" + name: String + """The email of the person, if known.""" + email: String + """The login of the person, if known.""" + login: String + """A string containing the either the name of the person, its login or both""" + displayName: String! + """An url to an avatar""" + avatarUrl: String + """isProtected is true if the chain of git commits started to be signed. + If that's the case, only signed commit with a valid key for this identity can be added.""" + isProtected: Boolean! +} diff --git a/graphql/operations.graphql b/graphql/schema/operations.graphql index 420a9e12..d37df2e2 100644 --- a/graphql/operations.graphql +++ b/graphql/schema/operations.graphql @@ -3,7 +3,7 @@ interface Operation { """The hash of the operation""" hash: Hash! """The operations author.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! } @@ -30,7 +30,7 @@ type CreateOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! @@ -43,7 +43,7 @@ type SetTitleOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! @@ -55,7 +55,7 @@ type AddCommentOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! @@ -67,7 +67,7 @@ type EditCommentOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! @@ -80,7 +80,7 @@ type SetStatusOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! @@ -91,10 +91,10 @@ type LabelChangeOperation implements Operation & Authored { """The hash of the operation""" hash: Hash! """The author of this object.""" - author: Person! + author: Identity! """The datetime when this operation was issued.""" date: Time! added: [Label!]! removed: [Label!]! -}
\ No newline at end of file +} diff --git a/graphql/root.graphql b/graphql/schema/root.graphql index fd8419fa..7b43366f 100644 --- a/graphql/root.graphql +++ b/graphql/schema/root.graphql @@ -17,7 +17,7 @@ type PageInfo { """An object that has an author.""" interface Authored { """The author of this object.""" - author: Person! + author: Identity! } type Query { @@ -35,4 +35,4 @@ type Mutation { setTitle(repoRef: String, prefix: String!, title: String!): Bug! commit(repoRef: String, prefix: String!): Bug! -}
\ No newline at end of file +} diff --git a/graphql/timeline.graphql b/graphql/schema/timeline.graphql index 75f72305..35bb88bf 100644 --- a/graphql/timeline.graphql +++ b/graphql/schema/timeline.graphql @@ -32,7 +32,7 @@ type TimelineItemEdge { type CreateTimelineItem implements TimelineItem { """The hash of the source operation""" hash: Hash! - author: Person! + author: Identity! message: String! messageIsEmpty: Boolean! files: [Hash!]! @@ -46,7 +46,7 @@ type CreateTimelineItem implements TimelineItem { type AddCommentTimelineItem implements TimelineItem { """The hash of the source operation""" hash: Hash! - author: Person! + author: Identity! message: String! messageIsEmpty: Boolean! files: [Hash!]! @@ -60,7 +60,7 @@ type AddCommentTimelineItem implements TimelineItem { type LabelChangeTimelineItem implements TimelineItem { """The hash of the source operation""" hash: Hash! - author: Person! + author: Identity! date: Time! added: [Label!]! removed: [Label!]! @@ -70,7 +70,7 @@ type LabelChangeTimelineItem implements TimelineItem { type SetStatusTimelineItem implements TimelineItem { """The hash of the source operation""" hash: Hash! - author: Person! + author: Identity! date: Time! status: Status! } @@ -79,8 +79,8 @@ type SetStatusTimelineItem implements TimelineItem { type SetTitleTimelineItem implements TimelineItem { """The hash of the source operation""" hash: Hash! - author: Person! + author: Identity! date: Time! title: String! was: String! -}
\ No newline at end of file +} |