From 335448c705b8437d416acf48a439bd04a290dbcc Mon Sep 17 00:00:00 2001 From: Michael Reimsbach Date: Wed, 10 Jul 2024 16:00:58 +0200 Subject: [PATCH 1/2] feat(issue): add mutations for activities/componentVersions --- internal/api/graphql/graph/generated.go | 472 ++++++++++++++++++ .../queryCollection/activity/addIssue.graphql | 18 + .../activity/removeIssue.graphql | 18 + .../issue/addComponentVersion.graphql | 18 + .../issue/removeComponentVersion.graphql | 18 + .../api/graphql/graph/resolver/mutation.go | 88 ++++ .../graphql/graph/schema/mutation.graphqls | 4 + internal/app/activity.go | 34 ++ internal/app/activity_test.go | 44 ++ internal/app/interface.go | 4 + internal/app/issue.go | 52 ++ internal/app/issue_test.go | 44 ++ internal/database/interface.go | 4 + internal/database/mariadb/activity.go | 50 ++ internal/database/mariadb/activity_test.go | 65 +++ internal/database/mariadb/issue.go | 51 ++ internal/database/mariadb/issue_test.go | 60 +++ internal/e2e/activity_query_test.go | 115 +++++ internal/e2e/issue_query_test.go | 115 +++++ internal/mocks/mock_Database.go | 188 +++++++ internal/mocks/mock_Heureka.go | 236 +++++++++ 21 files changed, 1698 insertions(+) create mode 100644 internal/api/graphql/graph/queryCollection/activity/addIssue.graphql create mode 100644 internal/api/graphql/graph/queryCollection/activity/removeIssue.graphql create mode 100644 internal/api/graphql/graph/queryCollection/issue/addComponentVersion.graphql create mode 100644 internal/api/graphql/graph/queryCollection/issue/removeComponentVersion.graphql diff --git a/internal/api/graphql/graph/generated.go b/internal/api/graphql/graph/generated.go index 1c402163..d3ed84fa 100644 --- a/internal/api/graphql/graph/generated.go +++ b/internal/api/graphql/graph/generated.go @@ -348,8 +348,10 @@ type ComplexityRoot struct { } Mutation struct { + AddComponentVersionToIssue func(childComplexity int, issueID string, componentVersionID string) int AddEvidenceToIssueMatch func(childComplexity int, issueMatchID string, evidenceID string) int AddIssueRepositoryToService func(childComplexity int, serviceID string, issueRepositoryID string, priority int) int + AddIssueToActivity func(childComplexity int, activityID string, issueID string) int AddOwnerToService func(childComplexity int, serviceID string, userID string) int AddServiceToActivity func(childComplexity int, activityID string, serviceID string) int AddServiceToSupportGroup func(childComplexity int, supportGroupID string, serviceID string) int @@ -379,7 +381,9 @@ type ComplexityRoot struct { DeleteService func(childComplexity int, id string) int DeleteSupportGroup func(childComplexity int, id string) int DeleteUser func(childComplexity int, id string) int + RemoveComponentVersionFromIssue func(childComplexity int, issueID string, componentVersionID string) int RemoveEvidenceFromIssueMatch func(childComplexity int, issueMatchID string, evidenceID string) int + RemoveIssueFromActivity func(childComplexity int, activityID string, issueID string) int RemoveIssueRepositoryFromService func(childComplexity int, serviceID string, issueRepositoryID string) int RemoveOwnerFromService func(childComplexity int, serviceID string, userID string) int RemoveServiceFromActivity func(childComplexity int, activityID string, serviceID string) int @@ -583,6 +587,8 @@ type MutationResolver interface { CreateIssue(ctx context.Context, input model.IssueInput) (*model.Issue, error) UpdateIssue(ctx context.Context, id string, input model.IssueInput) (*model.Issue, error) DeleteIssue(ctx context.Context, id string) (string, error) + AddComponentVersionToIssue(ctx context.Context, issueID string, componentVersionID string) (*model.Issue, error) + RemoveComponentVersionFromIssue(ctx context.Context, issueID string, componentVersionID string) (*model.Issue, error) CreateIssueVariant(ctx context.Context, input model.IssueVariantInput) (*model.IssueVariant, error) UpdateIssueVariant(ctx context.Context, id string, input model.IssueVariantInput) (*model.IssueVariant, error) DeleteIssueVariant(ctx context.Context, id string) (string, error) @@ -602,6 +608,8 @@ type MutationResolver interface { DeleteActivity(ctx context.Context, id string) (string, error) AddServiceToActivity(ctx context.Context, activityID string, serviceID string) (*model.Activity, error) RemoveServiceFromActivity(ctx context.Context, activityID string, serviceID string) (*model.Activity, error) + AddIssueToActivity(ctx context.Context, activityID string, issueID string) (*model.Activity, error) + RemoveIssueFromActivity(ctx context.Context, activityID string, issueID string) (*model.Activity, error) } type QueryResolver interface { Issues(ctx context.Context, filter *model.IssueFilter, first *int, after *string) (*model.IssueConnection, error) @@ -1970,6 +1978,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.IssueVariantEdge.UpdatedAt(childComplexity), true + case "Mutation.addComponentVersionToIssue": + if e.complexity.Mutation.AddComponentVersionToIssue == nil { + break + } + + args, err := ec.field_Mutation_addComponentVersionToIssue_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.AddComponentVersionToIssue(childComplexity, args["issueId"].(string), args["componentVersionId"].(string)), true + case "Mutation.addEvidenceToIssueMatch": if e.complexity.Mutation.AddEvidenceToIssueMatch == nil { break @@ -1994,6 +2014,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.AddIssueRepositoryToService(childComplexity, args["serviceId"].(string), args["issueRepositoryId"].(string), args["priority"].(int)), true + case "Mutation.addIssueToActivity": + if e.complexity.Mutation.AddIssueToActivity == nil { + break + } + + args, err := ec.field_Mutation_addIssueToActivity_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.AddIssueToActivity(childComplexity, args["activityId"].(string), args["issueId"].(string)), true + case "Mutation.addOwnerToService": if e.complexity.Mutation.AddOwnerToService == nil { break @@ -2342,6 +2374,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.DeleteUser(childComplexity, args["id"].(string)), true + case "Mutation.removeComponentVersionFromIssue": + if e.complexity.Mutation.RemoveComponentVersionFromIssue == nil { + break + } + + args, err := ec.field_Mutation_removeComponentVersionFromIssue_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.RemoveComponentVersionFromIssue(childComplexity, args["issueId"].(string), args["componentVersionId"].(string)), true + case "Mutation.removeEvidenceFromIssueMatch": if e.complexity.Mutation.RemoveEvidenceFromIssueMatch == nil { break @@ -2354,6 +2398,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.RemoveEvidenceFromIssueMatch(childComplexity, args["issueMatchId"].(string), args["evidenceId"].(string)), true + case "Mutation.removeIssueFromActivity": + if e.complexity.Mutation.RemoveIssueFromActivity == nil { + break + } + + args, err := ec.field_Mutation_removeIssueFromActivity_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.RemoveIssueFromActivity(childComplexity, args["activityId"].(string), args["issueId"].(string)), true + case "Mutation.removeIssueRepositoryFromService": if e.complexity.Mutation.RemoveIssueRepositoryFromService == nil { break @@ -3793,6 +3849,30 @@ func (ec *executionContext) field_Issue_issueVariants_args(ctx context.Context, return args, nil } +func (ec *executionContext) field_Mutation_addComponentVersionToIssue_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["issueId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("issueId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["issueId"] = arg0 + var arg1 string + if tmp, ok := rawArgs["componentVersionId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("componentVersionId")) + arg1, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["componentVersionId"] = arg1 + return args, nil +} + func (ec *executionContext) field_Mutation_addEvidenceToIssueMatch_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -3850,6 +3930,30 @@ func (ec *executionContext) field_Mutation_addIssueRepositoryToService_args(ctx return args, nil } +func (ec *executionContext) field_Mutation_addIssueToActivity_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["activityId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("activityId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["activityId"] = arg0 + var arg1 string + if tmp, ok := rawArgs["issueId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("issueId")) + arg1, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["issueId"] = arg1 + return args, nil +} + func (ec *executionContext) field_Mutation_addOwnerToService_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -4312,6 +4416,30 @@ func (ec *executionContext) field_Mutation_deleteUser_args(ctx context.Context, return args, nil } +func (ec *executionContext) field_Mutation_removeComponentVersionFromIssue_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["issueId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("issueId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["issueId"] = arg0 + var arg1 string + if tmp, ok := rawArgs["componentVersionId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("componentVersionId")) + arg1, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["componentVersionId"] = arg1 + return args, nil +} + func (ec *executionContext) field_Mutation_removeEvidenceFromIssueMatch_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -4336,6 +4464,30 @@ func (ec *executionContext) field_Mutation_removeEvidenceFromIssueMatch_args(ctx return args, nil } +func (ec *executionContext) field_Mutation_removeIssueFromActivity_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["activityId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("activityId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["activityId"] = arg0 + var arg1 string + if tmp, ok := rawArgs["issueId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("issueId")) + arg1, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["issueId"] = arg1 + return args, nil +} + func (ec *executionContext) field_Mutation_removeIssueRepositoryFromService_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -15856,6 +16008,160 @@ func (ec *executionContext) fieldContext_Mutation_deleteIssue(ctx context.Contex return fc, nil } +func (ec *executionContext) _Mutation_addComponentVersionToIssue(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_addComponentVersionToIssue(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().AddComponentVersionToIssue(rctx, fc.Args["issueId"].(string), fc.Args["componentVersionId"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Issue) + fc.Result = res + return ec.marshalNIssue2ᚖgithubᚗwdfᚗsapᚗcorpᚋccᚋheurekaᚋinternalᚋapiᚋgraphqlᚋgraphᚋmodelᚐIssue(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_addComponentVersionToIssue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Issue_id(ctx, field) + case "type": + return ec.fieldContext_Issue_type(ctx, field) + case "primaryName": + return ec.fieldContext_Issue_primaryName(ctx, field) + case "description": + return ec.fieldContext_Issue_description(ctx, field) + case "lastModified": + return ec.fieldContext_Issue_lastModified(ctx, field) + case "issueVariants": + return ec.fieldContext_Issue_issueVariants(ctx, field) + case "activities": + return ec.fieldContext_Issue_activities(ctx, field) + case "issueMatches": + return ec.fieldContext_Issue_issueMatches(ctx, field) + case "componentVersions": + return ec.fieldContext_Issue_componentVersions(ctx, field) + case "metadata": + return ec.fieldContext_Issue_metadata(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Issue", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_addComponentVersionToIssue_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_removeComponentVersionFromIssue(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_removeComponentVersionFromIssue(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().RemoveComponentVersionFromIssue(rctx, fc.Args["issueId"].(string), fc.Args["componentVersionId"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Issue) + fc.Result = res + return ec.marshalNIssue2ᚖgithubᚗwdfᚗsapᚗcorpᚋccᚋheurekaᚋinternalᚋapiᚋgraphqlᚋgraphᚋmodelᚐIssue(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_removeComponentVersionFromIssue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Issue_id(ctx, field) + case "type": + return ec.fieldContext_Issue_type(ctx, field) + case "primaryName": + return ec.fieldContext_Issue_primaryName(ctx, field) + case "description": + return ec.fieldContext_Issue_description(ctx, field) + case "lastModified": + return ec.fieldContext_Issue_lastModified(ctx, field) + case "issueVariants": + return ec.fieldContext_Issue_issueVariants(ctx, field) + case "activities": + return ec.fieldContext_Issue_activities(ctx, field) + case "issueMatches": + return ec.fieldContext_Issue_issueMatches(ctx, field) + case "componentVersions": + return ec.fieldContext_Issue_componentVersions(ctx, field) + case "metadata": + return ec.fieldContext_Issue_metadata(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Issue", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_removeComponentVersionFromIssue_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Mutation_createIssueVariant(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation_createIssueVariant(ctx, field) if err != nil { @@ -17201,6 +17507,144 @@ func (ec *executionContext) fieldContext_Mutation_removeServiceFromActivity(ctx return fc, nil } +func (ec *executionContext) _Mutation_addIssueToActivity(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_addIssueToActivity(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().AddIssueToActivity(rctx, fc.Args["activityId"].(string), fc.Args["issueId"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Activity) + fc.Result = res + return ec.marshalNActivity2ᚖgithubᚗwdfᚗsapᚗcorpᚋccᚋheurekaᚋinternalᚋapiᚋgraphqlᚋgraphᚋmodelᚐActivity(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_addIssueToActivity(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Activity_id(ctx, field) + case "status": + return ec.fieldContext_Activity_status(ctx, field) + case "services": + return ec.fieldContext_Activity_services(ctx, field) + case "issues": + return ec.fieldContext_Activity_issues(ctx, field) + case "evidences": + return ec.fieldContext_Activity_evidences(ctx, field) + case "issueMatchChanges": + return ec.fieldContext_Activity_issueMatchChanges(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Activity", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_addIssueToActivity_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_removeIssueFromActivity(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_removeIssueFromActivity(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().RemoveIssueFromActivity(rctx, fc.Args["activityId"].(string), fc.Args["issueId"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Activity) + fc.Result = res + return ec.marshalNActivity2ᚖgithubᚗwdfᚗsapᚗcorpᚋccᚋheurekaᚋinternalᚋapiᚋgraphqlᚋgraphᚋmodelᚐActivity(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_removeIssueFromActivity(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Activity_id(ctx, field) + case "status": + return ec.fieldContext_Activity_status(ctx, field) + case "services": + return ec.fieldContext_Activity_services(ctx, field) + case "issues": + return ec.fieldContext_Activity_issues(ctx, field) + case "evidences": + return ec.fieldContext_Activity_evidences(ctx, field) + case "issueMatchChanges": + return ec.fieldContext_Activity_issueMatchChanges(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Activity", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_removeIssueFromActivity_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Page_after(ctx context.Context, field graphql.CollectedField, obj *model.Page) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Page_after(ctx, field) if err != nil { @@ -26240,6 +26684,20 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "addComponentVersionToIssue": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_addComponentVersionToIssue(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "removeComponentVersionFromIssue": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_removeComponentVersionFromIssue(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "createIssueVariant": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_createIssueVariant(ctx, field) @@ -26373,6 +26831,20 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "addIssueToActivity": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_addIssueToActivity(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "removeIssueFromActivity": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_removeIssueFromActivity(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } diff --git a/internal/api/graphql/graph/queryCollection/activity/addIssue.graphql b/internal/api/graphql/graph/queryCollection/activity/addIssue.graphql new file mode 100644 index 00000000..11e311c0 --- /dev/null +++ b/internal/api/graphql/graph/queryCollection/activity/addIssue.graphql @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors +# SPDX-License-Identifier: Apache-2.0 + +mutation ($activityId: ID!, $issueId: ID!) { + addIssueToActivity ( + activityId: $activityId, + issueId: $issueId + ) { + id + issues { + edges { + node { + id + } + } + } + } +} \ No newline at end of file diff --git a/internal/api/graphql/graph/queryCollection/activity/removeIssue.graphql b/internal/api/graphql/graph/queryCollection/activity/removeIssue.graphql new file mode 100644 index 00000000..93e3b030 --- /dev/null +++ b/internal/api/graphql/graph/queryCollection/activity/removeIssue.graphql @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors +# SPDX-License-Identifier: Apache-2.0 + +mutation ($activityId: ID!, $issueId: ID!) { + removeIssueFromActivity ( + activityId: $activityId, + issueId: $issueId + ) { + id + issues { + edges { + node { + id + } + } + } + } +} \ No newline at end of file diff --git a/internal/api/graphql/graph/queryCollection/issue/addComponentVersion.graphql b/internal/api/graphql/graph/queryCollection/issue/addComponentVersion.graphql new file mode 100644 index 00000000..14a5b410 --- /dev/null +++ b/internal/api/graphql/graph/queryCollection/issue/addComponentVersion.graphql @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors +# SPDX-License-Identifier: Apache-2.0 + +mutation ($issueId: ID!, $componentVersionId: ID!) { + addComponentVersionToIssue ( + issueId: $issueId, + componentVersionId: $componentVersionId + ) { + id + componentVersions { + edges { + node { + id + } + } + } + } +} \ No newline at end of file diff --git a/internal/api/graphql/graph/queryCollection/issue/removeComponentVersion.graphql b/internal/api/graphql/graph/queryCollection/issue/removeComponentVersion.graphql new file mode 100644 index 00000000..5daee719 --- /dev/null +++ b/internal/api/graphql/graph/queryCollection/issue/removeComponentVersion.graphql @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Greenhouse contributors +# SPDX-License-Identifier: Apache-2.0 + +mutation ($issueId: ID!, $componentVersionId: ID!) { + removeComponentVersionFromIssue ( + issueId: $issueId, + componentVersionId: $componentVersionId + ) { + id + componentVersions { + edges { + node { + id + } + } + } + } +} \ No newline at end of file diff --git a/internal/api/graphql/graph/resolver/mutation.go b/internal/api/graphql/graph/resolver/mutation.go index 0d682217..0dcfac23 100644 --- a/internal/api/graphql/graph/resolver/mutation.go +++ b/internal/api/graphql/graph/resolver/mutation.go @@ -467,6 +467,50 @@ func (r *mutationResolver) DeleteIssue(ctx context.Context, id string) (string, return id, nil } +// AddComponentVersionToIssue is the resolver for the addComponentVersionToIssue field. +func (r *mutationResolver) AddComponentVersionToIssue(ctx context.Context, issueID string, componentVersionID string) (*model.Issue, error) { + issueIdInt, err := baseResolver.ParseCursor(&issueID) + if err != nil { + return nil, baseResolver.NewResolverError("AddComponentVersionToIssueMutationResolver", "Internal Error - when adding componentVersion to issue") + } + + componentVersionIdInt, err := baseResolver.ParseCursor(&componentVersionID) + if err != nil { + return nil, baseResolver.NewResolverError("AddComponentVersionToIssueMutationResolver", "Internal Error - when adding componentVersion to issue") + } + + issue, err := r.App.AddComponentVersionToIssue(*issueIdInt, *componentVersionIdInt) + + if err != nil { + return nil, baseResolver.NewResolverError("AddComponentVersionToIssueMutationResolver", "Internal Error - when adding componentVersion to issue") + } + + i := model.NewIssue(issue) + return &i, nil +} + +// RemoveComponentVersionFromIssue is the resolver for the removeComponentVersionFromIssue field. +func (r *mutationResolver) RemoveComponentVersionFromIssue(ctx context.Context, issueID string, componentVersionID string) (*model.Issue, error) { + issueIdInt, err := baseResolver.ParseCursor(&issueID) + if err != nil { + return nil, baseResolver.NewResolverError("RemoveComponentVersionFromIssueMutationResolver", "Internal Error - when removing componentVersion from issue") + } + + componentVersionIdInt, err := baseResolver.ParseCursor(&componentVersionID) + if err != nil { + return nil, baseResolver.NewResolverError("RemoveComponentVersionFromIssueMutationResolver", "Internal Error - when removing componentVersion from issue") + } + + issue, err := r.App.RemoveComponentVersionFromIssue(*issueIdInt, *componentVersionIdInt) + + if err != nil { + return nil, baseResolver.NewResolverError("RemoveComponentVersionFromIssueMutationResolver", "Internal Error - when removing componentVersion from issue") + } + + i := model.NewIssue(issue) + return &i, nil +} + // CreateIssueVariant is the resolver for the createIssueVariant field. func (r *mutationResolver) CreateIssueVariant(ctx context.Context, input model.IssueVariantInput) (*model.IssueVariant, error) { issueVariant := model.NewIssueVariantEntity(&input) @@ -755,6 +799,50 @@ func (r *mutationResolver) RemoveServiceFromActivity(ctx context.Context, activi return &a, nil } +// AddIssueToActivity is the resolver for the addIssueToActivity field. +func (r *mutationResolver) AddIssueToActivity(ctx context.Context, activityID string, issueID string) (*model.Activity, error) { + activityIdInt, err := baseResolver.ParseCursor(&activityID) + if err != nil { + return nil, baseResolver.NewResolverError("AddIssueToActivityMutationResolver", "Internal Error - when adding issue to activity") + } + + issueIdInt, err := baseResolver.ParseCursor(&issueID) + if err != nil { + return nil, baseResolver.NewResolverError("AddIssueToActivityMutationResolver", "Internal Error - when adding issue to activity") + } + + activity, err := r.App.AddIssueToActivity(*activityIdInt, *issueIdInt) + + if err != nil { + return nil, baseResolver.NewResolverError("AddIssueToActivityMutationResolver", "Internal Error - when adding issue to activity") + } + + a := model.NewActivity(activity) + return &a, nil +} + +// RemoveIssueFromActivity is the resolver for the removeIssueFromActivity field. +func (r *mutationResolver) RemoveIssueFromActivity(ctx context.Context, activityID string, issueID string) (*model.Activity, error) { + activityIdInt, err := baseResolver.ParseCursor(&activityID) + if err != nil { + return nil, baseResolver.NewResolverError("RemoveIssueFromActivityMutationResolver", "Internal Error - when removing issue from activity") + } + + issueIdInt, err := baseResolver.ParseCursor(&issueID) + if err != nil { + return nil, baseResolver.NewResolverError("RemoveIssueFromActivityMutationResolver", "Internal Error - when removing issue from activity") + } + + activity, err := r.App.RemoveIssueFromActivity(*activityIdInt, *issueIdInt) + + if err != nil { + return nil, baseResolver.NewResolverError("RemoveIssueFromActivityMutationResolver", "Internal Error - when removing issue from activity") + } + + a := model.NewActivity(activity) + return &a, nil +} + // Mutation returns graph.MutationResolver implementation. func (r *Resolver) Mutation() graph.MutationResolver { return &mutationResolver{r} } diff --git a/internal/api/graphql/graph/schema/mutation.graphqls b/internal/api/graphql/graph/schema/mutation.graphqls index 06b0f944..da16aa30 100644 --- a/internal/api/graphql/graph/schema/mutation.graphqls +++ b/internal/api/graphql/graph/schema/mutation.graphqls @@ -39,6 +39,8 @@ type Mutation { createIssue(input: IssueInput!): Issue! updateIssue(id: ID!, input: IssueInput!): Issue! deleteIssue(id: ID!): String! + addComponentVersionToIssue(issueId: ID!, componentVersionId: ID!): Issue! + removeComponentVersionFromIssue(issueId: ID!, componentVersionId: ID!): Issue! createIssueVariant(input: IssueVariantInput!): IssueVariant! updateIssueVariant(id: ID!, input: IssueVariantInput!): IssueVariant! @@ -63,4 +65,6 @@ type Mutation { deleteActivity(id: ID!): String! addServiceToActivity(activityId: ID!, serviceId: ID!): Activity! removeServiceFromActivity(activityId: ID!, serviceId: ID!): Activity! + addIssueToActivity(activityId: ID!, issueId: ID!): Activity! + removeIssueFromActivity(activityId: ID!, issueId: ID!): Activity! } \ No newline at end of file diff --git a/internal/app/activity.go b/internal/app/activity.go index d1862473..f7462078 100644 --- a/internal/app/activity.go +++ b/internal/app/activity.go @@ -171,3 +171,37 @@ func (h *HeurekaApp) RemoveServiceFromActivity(activityId, serviceId int64) (*en return h.GetActivity(activityId) } + +func (h *HeurekaApp) AddIssueToActivity(activityId, issueId int64) (*entity.Activity, error) { + l := logrus.WithFields(logrus.Fields{ + "event": "app.AddIssueToActivity", + "activityId": activityId, + "issueId": issueId, + }) + + err := h.database.AddIssueToActivity(activityId, issueId) + + if err != nil { + l.Error(err) + return nil, heurekaError("Internal error while adding issue to activity.") + } + + return h.GetActivity(activityId) +} + +func (h *HeurekaApp) RemoveIssueFromActivity(activityId, issueId int64) (*entity.Activity, error) { + l := logrus.WithFields(logrus.Fields{ + "event": "app.RemoveIssueFromActivity", + "activityId": activityId, + "issueId": issueId, + }) + + err := h.database.RemoveIssueFromActivity(activityId, issueId) + + if err != nil { + l.Error(err) + return nil, heurekaError("Internal error while removing issue from activity.") + } + + return h.GetActivity(activityId) +} diff --git a/internal/app/activity_test.go b/internal/app/activity_test.go index 0405fbcb..91692c3c 100644 --- a/internal/app/activity_test.go +++ b/internal/app/activity_test.go @@ -235,3 +235,47 @@ var _ = Describe("When modifying relationship of Service and Activity", Label("a Expect(activity).NotTo(BeNil(), "activity should be returned") }) }) + +var _ = Describe("When modifying Issue and Activity", Label("app", "IssueActivity"), func() { + var ( + db *mocks.MockDatabase + heureka app.Heureka + issue entity.Issue + activity entity.Activity + filter *entity.ActivityFilter + ) + + BeforeEach(func() { + db = mocks.NewMockDatabase(GinkgoT()) + issue = test.NewFakeIssueEntity() + activity = test.NewFakeActivityEntity() + first := 10 + var after int64 + after = 0 + filter = &entity.ActivityFilter{ + Paginated: entity.Paginated{ + First: &first, + After: &after, + }, + Id: []*int64{&activity.Id}, + } + }) + + It("adds issue to activity", func() { + db.On("AddIssueToActivity", activity.Id, issue.Id).Return(nil) + db.On("GetActivities", filter).Return([]entity.Activity{activity}, nil) + heureka = app.NewHeurekaApp(db) + activity, err := heureka.AddIssueToActivity(activity.Id, issue.Id) + Expect(err).To(BeNil(), "no error should be thrown") + Expect(activity).NotTo(BeNil(), "activity should be returned") + }) + + It("removes issue from activity", func() { + db.On("RemoveIssueFromActivity", activity.Id, issue.Id).Return(nil) + db.On("GetActivities", filter).Return([]entity.Activity{activity}, nil) + heureka = app.NewHeurekaApp(db) + activity, err := heureka.RemoveIssueFromActivity(activity.Id, issue.Id) + Expect(err).To(BeNil(), "no error should be thrown") + Expect(activity).NotTo(BeNil(), "activity should be returned") + }) +}) diff --git a/internal/app/interface.go b/internal/app/interface.go index 0a26d3d7..40a46ed4 100644 --- a/internal/app/interface.go +++ b/internal/app/interface.go @@ -12,6 +12,8 @@ type Heureka interface { CreateIssue(*entity.Issue) (*entity.Issue, error) UpdateIssue(*entity.Issue) (*entity.Issue, error) DeleteIssue(int64) error + AddComponentVersionToIssue(int64, int64) (*entity.Issue, error) + RemoveComponentVersionFromIssue(int64, int64) (*entity.Issue, error) ListIssueVariants(*entity.IssueVariantFilter, *entity.ListOptions) (*entity.List[entity.IssueVariantResult], error) ListEffectiveIssueVariants(*entity.IssueVariantFilter, *entity.ListOptions) (*entity.List[entity.IssueVariantResult], error) @@ -72,6 +74,8 @@ type Heureka interface { DeleteActivity(int64) error AddServiceToActivity(int64, int64) (*entity.Activity, error) RemoveServiceFromActivity(int64, int64) (*entity.Activity, error) + AddIssueToActivity(int64, int64) (*entity.Activity, error) + RemoveIssueFromActivity(int64, int64) (*entity.Activity, error) ListEvidences(*entity.EvidenceFilter, *entity.ListOptions) (*entity.List[entity.EvidenceResult], error) CreateEvidence(*entity.Evidence) (*entity.Evidence, error) diff --git a/internal/app/issue.go b/internal/app/issue.go index 8959fa20..9d200e9e 100644 --- a/internal/app/issue.go +++ b/internal/app/issue.go @@ -48,6 +48,26 @@ func (h *HeurekaApp) getIssueResults(filter *entity.IssueFilter) ([]entity.Issue return issueResults, nil } +func (h *HeurekaApp) GetIssue(id int64) (*entity.Issue, error) { + l := logrus.WithFields(logrus.Fields{ + "event": "app.GetIssue", + "id": id, + }) + + issues, err := h.ListIssues(&entity.IssueFilter{Id: []*int64{&id}}, &entity.ListOptions{}) + + if err != nil { + l.Error(err) + return nil, heurekaError("Internal error while retrieving issue.") + } + + if len(issues.Elements) != 1 { + return nil, heurekaError(fmt.Sprintf("Issue %d not found.", id)) + } + + return issues.Elements[0].Issue, nil +} + func (h *HeurekaApp) ListIssues(filter *entity.IssueFilter, options *entity.ListOptions) (*entity.List[entity.IssueResult], error) { var count int64 var pageInfo *entity.PageInfo @@ -175,3 +195,35 @@ func (h *HeurekaApp) DeleteIssue(id int64) error { return nil } + +func (h *HeurekaApp) AddComponentVersionToIssue(issueId, componentVersionId int64) (*entity.Issue, error) { + l := logrus.WithFields(logrus.Fields{ + "event": "app.AddComponentVersionToIssue", + "id": issueId, + }) + + err := h.database.AddComponentVersionToIssue(issueId, componentVersionId) + + if err != nil { + l.Error(err) + return nil, heurekaError("Internal error while adding component version to issue.") + } + + return h.GetIssue(issueId) +} + +func (h *HeurekaApp) RemoveComponentVersionFromIssue(issueId, componentVersionId int64) (*entity.Issue, error) { + l := logrus.WithFields(logrus.Fields{ + "event": "app.RemoveComponentVersionFromIssue", + "id": issueId, + }) + + err := h.database.RemoveComponentVersionFromIssue(issueId, componentVersionId) + + if err != nil { + l.Error(err) + return nil, heurekaError("Internal error while removing component version from issue.") + } + + return h.GetIssue(issueId) +} diff --git a/internal/app/issue_test.go b/internal/app/issue_test.go index 812ff127..937e06ce 100644 --- a/internal/app/issue_test.go +++ b/internal/app/issue_test.go @@ -291,3 +291,47 @@ var _ = Describe("When deleting Issue", Label("app", "DeleteIssue"), func() { Expect(issues.Elements).To(BeEmpty(), "no error should be thrown") }) }) + +var _ = Describe("When modifying ComponentVersion and Issue", Label("app", "ComponentVersionIssue"), func() { + var ( + db *mocks.MockDatabase + heureka app.Heureka + issue entity.Issue + componentVersion entity.ComponentVersion + filter *entity.IssueFilter + ) + + BeforeEach(func() { + db = mocks.NewMockDatabase(GinkgoT()) + issue = test.NewFakeIssueEntity() + componentVersion = test.NewFakeComponentVersionEntity() + first := 10 + var after int64 + after = 0 + filter = &entity.IssueFilter{ + Paginated: entity.Paginated{ + First: &first, + After: &after, + }, + Id: []*int64{&issue.Id}, + } + }) + + It("adds componentVersion to issue", func() { + db.On("AddComponentVersionToIssue", issue.Id, componentVersion.Id).Return(nil) + db.On("GetIssues", filter).Return([]entity.Issue{issue}, nil) + heureka = app.NewHeurekaApp(db) + issue, err := heureka.AddComponentVersionToIssue(issue.Id, componentVersion.Id) + Expect(err).To(BeNil(), "no error should be thrown") + Expect(issue).NotTo(BeNil(), "issue should be returned") + }) + + It("removes componentVersion from issue", func() { + db.On("RemoveComponentVersionFromIssue", issue.Id, componentVersion.Id).Return(nil) + db.On("GetIssues", filter).Return([]entity.Issue{issue}, nil) + heureka = app.NewHeurekaApp(db) + issue, err := heureka.RemoveComponentVersionFromIssue(issue.Id, componentVersion.Id) + Expect(err).To(BeNil(), "no error should be thrown") + Expect(issue).NotTo(BeNil(), "issue should be returned") + }) +}) diff --git a/internal/database/interface.go b/internal/database/interface.go index ca0281db..b28bef9b 100644 --- a/internal/database/interface.go +++ b/internal/database/interface.go @@ -13,6 +13,8 @@ type Database interface { CreateIssue(*entity.Issue) (*entity.Issue, error) UpdateIssue(*entity.Issue) error DeleteIssue(int64) error + AddComponentVersionToIssue(int64, int64) error + RemoveComponentVersionFromIssue(int64, int64) error GetIssueVariants(*entity.IssueVariantFilter) ([]entity.IssueVariant, error) GetAllIssueVariantIds(*entity.IssueVariantFilter) ([]int64, error) @@ -86,6 +88,8 @@ type Database interface { DeleteActivity(int64) error AddServiceToActivity(int64, int64) error RemoveServiceFromActivity(int64, int64) error + AddIssueToActivity(int64, int64) error + RemoveIssueFromActivity(int64, int64) error GetEvidences(*entity.EvidenceFilter) ([]entity.Evidence, error) GetAllEvidenceIds(*entity.EvidenceFilter) ([]int64, error) diff --git a/internal/database/mariadb/activity.go b/internal/database/mariadb/activity.go index 804551fa..1970d623 100644 --- a/internal/database/mariadb/activity.go +++ b/internal/database/mariadb/activity.go @@ -322,3 +322,53 @@ func (s *SqlDatabase) RemoveServiceFromActivity(activityId int64, serviceId int6 return err } + +func (s *SqlDatabase) AddIssueToActivity(activityId int64, issueId int64) error { + l := logrus.WithFields(logrus.Fields{ + "issueId": issueId, + "activityId": activityId, + "event": "database.AddIssueToActivity", + }) + + query := ` + INSERT INTO ActivityHasIssue ( + activityhasissue_issue_id, + activityhasissue_activity_id + ) VALUES ( + :issue_id, + :activity_id + ) + ` + + args := map[string]interface{}{ + "issue_id": issueId, + "activity_id": activityId, + } + + _, err := performExec(s, query, args, l) + + return err +} + +func (s *SqlDatabase) RemoveIssueFromActivity(activityId int64, issueId int64) error { + l := logrus.WithFields(logrus.Fields{ + "issueId": issueId, + "activityId": activityId, + "event": "database.RemoveIssueFromActivity", + }) + + query := ` + DELETE FROM ActivityHasIssue + WHERE activityhasissue_issue_id = :issue_id + AND activityhasissue_activity_id = :activity_id + ` + + args := map[string]interface{}{ + "issue_id": issueId, + "activity_id": activityId, + } + + _, err := performExec(s, query, args, l) + + return err +} diff --git a/internal/database/mariadb/activity_test.go b/internal/database/mariadb/activity_test.go index 46db51d3..660c9099 100644 --- a/internal/database/mariadb/activity_test.go +++ b/internal/database/mariadb/activity_test.go @@ -572,4 +572,69 @@ var _ = Describe("Activity", Label("database", "Activity"), func() { }) }) }) + When("Add Issue To Activity", Label("AddIssueToActivity"), func() { + Context("and we have 10 Activities in the database", func() { + var seedCollection *test.SeedCollection + var newIssueRow mariadb.IssueRow + var newIssue entity.Issue + var issue *entity.Issue + BeforeEach(func() { + seedCollection = seeder.SeedDbWithNFakeData(10) + newIssueRow = test.NewFakeIssue() + newIssue = newIssueRow.AsIssue() + issue, _ = db.CreateIssue(&newIssue) + }) + It("can add issue correctly", func() { + activity := seedCollection.ActivityRows[0].AsActivity() + + err := db.AddIssueToActivity(activity.Id, issue.Id) + + By("throwing no error", func() { + Expect(err).To(BeNil()) + }) + + activityFilter := &entity.ActivityFilter{ + IssueId: []*int64{&issue.Id}, + } + + a, err := db.GetActivities(activityFilter) + By("throwing no error", func() { + Expect(err).To(BeNil()) + }) + By("returning activity", func() { + Expect(len(a)).To(BeEquivalentTo(1)) + }) + }) + }) + }) + When("Remove Issue From Activity", Label("RemoveIssueFromActivity"), func() { + Context("and we have 10 Activities in the database", func() { + var seedCollection *test.SeedCollection + var activityHasIssueRow mariadb.ActivityHasIssueRow + BeforeEach(func() { + seedCollection = seeder.SeedDbWithNFakeData(10) + activityHasIssueRow = seedCollection.ActivityHasIssueRows[0] + }) + It("can remove issue correctly", func() { + err := db.RemoveIssueFromActivity(activityHasIssueRow.ActivityId.Int64, activityHasIssueRow.IssueId.Int64) + + By("throwing no error", func() { + Expect(err).To(BeNil()) + }) + + activityFilter := &entity.ActivityFilter{ + IssueId: []*int64{&activityHasIssueRow.IssueId.Int64}, + } + + activities, err := db.GetActivities(activityFilter) + By("throwing no error", func() { + Expect(err).To(BeNil()) + }) + + for _, a := range activities { + Expect(a.Id).ToNot(BeEquivalentTo(activityHasIssueRow.ActivityId.Int64)) + } + }) + }) + }) }) diff --git a/internal/database/mariadb/issue.go b/internal/database/mariadb/issue.go index 712f8089..f7e4b12c 100644 --- a/internal/database/mariadb/issue.go +++ b/internal/database/mariadb/issue.go @@ -370,3 +370,54 @@ func (s *SqlDatabase) DeleteIssue(id int64) error { return err } + +func (s *SqlDatabase) AddComponentVersionToIssue(issueId int64, componentVersionId int64) error { + l := logrus.WithFields(logrus.Fields{ + "issueId": issueId, + "componentVersionId": componentVersionId, + "event": "database.AddComponentVersionToIssue", + }) + + query := ` + INSERT INTO ComponentVersionIssue ( + componentversionissue_issue_id, + componentversionissue_component_version_id + ) VALUES ( + :issue_id, + :component_version_id + ) + ` + + args := map[string]interface{}{ + "issue_id": issueId, + "component_version_id": componentVersionId, + } + + _, err := performExec(s, query, args, l) + + return err +} + +func (s *SqlDatabase) RemoveComponentVersionFromIssue(issueId int64, componentVersionId int64) error { + l := logrus.WithFields(logrus.Fields{ + "issueId": issueId, + "componentVersionId": componentVersionId, + "event": "database.RemoveComponentVersionFromIssue", + }) + + query := ` + DELETE FROM ComponentVersionIssue + WHERE + componentversionissue_issue_id = :issue_id + AND componentversionissue_component_version_id = :component_version_id + ` + + args := map[string]interface{}{ + "issue_id": issueId, + "component_version_id": componentVersionId, + } + + _, err := performExec(s, query, args, l) + + return err +} diff --git a/internal/database/mariadb/issue_test.go b/internal/database/mariadb/issue_test.go index b66b608c..debc39e8 100644 --- a/internal/database/mariadb/issue_test.go +++ b/internal/database/mariadb/issue_test.go @@ -565,4 +565,64 @@ var _ = Describe("Issue", Label("database", "Issue"), func() { }) }) }) + When("Add Component Version to Issue", Label("AddComponentVersionToIssue"), func() { + Context("and we have 10 Issues in the database", func() { + var seedCollection *test.SeedCollection + BeforeEach(func() { + seedCollection = seeder.SeedDbWithNFakeData(10) + }) + It("can add component version correctly", func() { + issue := seedCollection.IssueRows[0].AsIssue() + componentVersion := seedCollection.ComponentVersionRows[0].AsComponentVersion() + componentVersion.ComponentId = seedCollection.ComponentRows[0].Id.Int64 + + err := db.AddComponentVersionToIssue(issue.Id, componentVersion.Id) + + By("throwing no error", func() { + Expect(err).To(BeNil()) + }) + + issueFilter := &entity.IssueFilter{ + Id: []*int64{&issue.Id}, + } + + i, err := db.GetIssues(issueFilter) + By("throwing no error", func() { + Expect(err).To(BeNil()) + }) + By("returning issue", func() { + Expect(len(i)).To(BeEquivalentTo(1)) + }) + }) + }) + }) + When("Remove Component Version from Issue", Label("RemoveComponentVersionFromIssue"), func() { + Context("and we have 10 Issues in the database", func() { + var seedCollection *test.SeedCollection + var componentVersionIssueRow mariadb.ComponentVersionIssueRow + BeforeEach(func() { + seedCollection = seeder.SeedDbWithNFakeData(10) + componentVersionIssueRow = seedCollection.ComponentVersionIssueRows[0] + }) + It("can remove component version correctly", func() { + err := db.RemoveComponentVersionFromIssue(componentVersionIssueRow.IssueId.Int64, componentVersionIssueRow.ComponentVersionId.Int64) + + By("throwing no error", func() { + Expect(err).To(BeNil()) + }) + + issueFilter := &entity.IssueFilter{ + ComponentVersionId: []*int64{&componentVersionIssueRow.ComponentVersionId.Int64}, + } + + issues, err := db.GetIssues(issueFilter) + By("throwing no error", func() { + Expect(err).To(BeNil()) + }) + for _, issue := range issues { + Expect(issue.Id).ToNot(BeEquivalentTo(componentVersionIssueRow.IssueId.Int64)) + } + }) + }) + }) }) diff --git a/internal/e2e/activity_query_test.go b/internal/e2e/activity_query_test.go index 6a4183eb..9448d533 100644 --- a/internal/e2e/activity_query_test.go +++ b/internal/e2e/activity_query_test.go @@ -489,3 +489,118 @@ var _ = Describe("Modifying Services of Activity via API", Label("e2e", "Service }) }) }) + +var _ = Describe("Modifying Issues of Activity via API", Label("e2e", "ServiceIssue"), func() { + + var seeder *test.DatabaseSeeder + var s *server.Server + var cfg util.Config + + BeforeEach(func() { + var err error + _ = dbm.NewTestSchema() + seeder, err = test.NewDatabaseSeeder(dbm.DbConfig()) + Expect(err).To(BeNil(), "Database Seeder Setup should work") + + cfg = dbm.DbConfig() + cfg.Port = util2.GetRandomFreePort() + s = server.NewServer(cfg) + + s.NonBlockingStart() + }) + + AfterEach(func() { + s.BlockingStop() + }) + + When("the database has 10 entries", func() { + var seedCollection *test.SeedCollection + + BeforeEach(func() { + seedCollection = seeder.SeedDbWithNFakeData(10) + }) + + Context("and a mutation query is performed", func() { + It("adds issue to activity", Label("addIssue.graphql"), func() { + // create a queryCollection (safe to share across requests) + client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", cfg.Port)) + + //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? + b, err := os.ReadFile("../api/graphql/graph/queryCollection/activity/addIssue.graphql") + + Expect(err).To(BeNil()) + str := string(b) + req := graphql.NewRequest(str) + + activity := seedCollection.ActivityRows[0].AsActivity() + issueIds := lo.FilterMap(seedCollection.ActivityHasIssueRows, func(row mariadb.ActivityHasIssueRow, _ int) (int64, bool) { + if row.ActivityId.Int64 == activity.Id { + return row.IssueId.Int64, true + } + return 0, false + }) + + issueRow, _ := lo.Find(seedCollection.IssueRows, func(row mariadb.IssueRow) bool { + return !lo.Contains(issueIds, row.Id.Int64) + }) + + req.Var("activityId", fmt.Sprintf("%d", activity.Id)) + req.Var("issueId", fmt.Sprintf("%d", issueRow.Id.Int64)) + + req.Header.Set("Cache-Control", "no-cache") + ctx := context.Background() + + var respData struct { + Activity model.Activity `json:"addIssueToActivity"` + } + if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { + logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") + } + + _, found := lo.Find(respData.Activity.Issues.Edges, func(edge *model.IssueEdge) bool { + return edge.Node.ID == fmt.Sprintf("%d", issueRow.Id.Int64) + }) + + Expect(respData.Activity.ID).To(Equal(fmt.Sprintf("%d", activity.Id))) + Expect(found).To(BeTrue()) + }) + It("removes issue from activity", Label("removeIssue.graphql"), func() { + // create a queryCollection (safe to share across requests) + client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", cfg.Port)) + + //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? + b, err := os.ReadFile("../api/graphql/graph/queryCollection/activity/removeIssue.graphql") + + Expect(err).To(BeNil()) + str := string(b) + req := graphql.NewRequest(str) + + activity := seedCollection.ActivityRows[0].AsActivity() + + issueRow, _ := lo.Find(seedCollection.ActivityHasIssueRows, func(row mariadb.ActivityHasIssueRow) bool { + return row.ActivityId.Int64 == activity.Id + }) + + req.Var("activityId", fmt.Sprintf("%d", activity.Id)) + req.Var("issueId", fmt.Sprintf("%d", issueRow.IssueId.Int64)) + + req.Header.Set("Cache-Control", "no-cache") + ctx := context.Background() + + var respData struct { + Activity model.Activity `json:"removeIssueFromActivity"` + } + if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { + logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") + } + + _, found := lo.Find(respData.Activity.Issues.Edges, func(edge *model.IssueEdge) bool { + return edge.Node.ID == fmt.Sprintf("%d", issueRow.ActivityId.Int64) + }) + + Expect(respData.Activity.ID).To(Equal(fmt.Sprintf("%d", activity.Id))) + Expect(found).To(BeFalse()) + }) + }) + }) +}) diff --git a/internal/e2e/issue_query_test.go b/internal/e2e/issue_query_test.go index a1138be6..faf9854a 100644 --- a/internal/e2e/issue_query_test.go +++ b/internal/e2e/issue_query_test.go @@ -397,3 +397,118 @@ var _ = Describe("Deleting Issue via API", Label("e2e", "Issues"), func() { }) }) }) + +var _ = Describe("Modifying ComponentVersion of Issue via API", Label("e2e", "Issues"), func() { + + var seeder *test.DatabaseSeeder + var s *server.Server + var cfg util.Config + + BeforeEach(func() { + var err error + _ = dbm.NewTestSchema() + seeder, err = test.NewDatabaseSeeder(dbm.DbConfig()) + Expect(err).To(BeNil(), "Database Seeder Setup should work") + + cfg = dbm.DbConfig() + cfg.Port = util2.GetRandomFreePort() + s = server.NewServer(cfg) + + s.NonBlockingStart() + }) + + AfterEach(func() { + s.BlockingStop() + }) + + When("the database has 10 entries", func() { + var seedCollection *test.SeedCollection + + BeforeEach(func() { + seedCollection = seeder.SeedDbWithNFakeData(10) + }) + + Context("and a mutation query is performed", func() { + It("adds componentVersion to issue", Label("addComponentVersion.graphql"), func() { + // create a queryCollection (safe to share across requests) + client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", cfg.Port)) + + //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? + b, err := os.ReadFile("../api/graphql/graph/queryCollection/issue/addComponentVersion.graphql") + + Expect(err).To(BeNil()) + str := string(b) + req := graphql.NewRequest(str) + + issue := seedCollection.IssueRows[0].AsIssue() + componentVersionIds := lo.FilterMap(seedCollection.ComponentVersionIssueRows, func(row mariadb.ComponentVersionIssueRow, _ int) (int64, bool) { + if row.IssueId.Int64 == issue.Id { + return row.ComponentVersionId.Int64, true + } + return 0, false + }) + + componentVersionRow, _ := lo.Find(seedCollection.ComponentVersionRows, func(row mariadb.ComponentVersionRow) bool { + return !lo.Contains(componentVersionIds, row.Id.Int64) + }) + + req.Var("issueId", fmt.Sprintf("%d", issue.Id)) + req.Var("componentVersionId", fmt.Sprintf("%d", componentVersionRow.Id.Int64)) + + req.Header.Set("Cache-Control", "no-cache") + ctx := context.Background() + + var respData struct { + Issue model.Issue `json:"addComponentVersionToIssue"` + } + if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { + logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") + } + + _, found := lo.Find(respData.Issue.ComponentVersions.Edges, func(edge *model.ComponentVersionEdge) bool { + return edge.Node.ID == fmt.Sprintf("%d", componentVersionRow.Id.Int64) + }) + + Expect(respData.Issue.ID).To(Equal(fmt.Sprintf("%d", issue.Id))) + Expect(found).To(BeTrue()) + }) + It("removes componentVersion from issue", Label("removeComponentVersion.graphql"), func() { + // create a queryCollection (safe to share across requests) + client := graphql.NewClient(fmt.Sprintf("http://localhost:%s/query", cfg.Port)) + + //@todo may need to make this more fault proof?! What if the test is executed from the root dir? does it still work? + b, err := os.ReadFile("../api/graphql/graph/queryCollection/issue/removeComponentVersion.graphql") + + Expect(err).To(BeNil()) + str := string(b) + req := graphql.NewRequest(str) + + issue := seedCollection.IssueRows[0].AsIssue() + + componentVersionRow, _ := lo.Find(seedCollection.ComponentVersionIssueRows, func(row mariadb.ComponentVersionIssueRow) bool { + return row.IssueId.Int64 == issue.Id + }) + + req.Var("issueId", fmt.Sprintf("%d", issue.Id)) + req.Var("componentVersionId", fmt.Sprintf("%d", componentVersionRow.ComponentVersionId.Int64)) + + req.Header.Set("Cache-Control", "no-cache") + ctx := context.Background() + + var respData struct { + Issue model.Issue `json:"removeComponentVersionFromIssue"` + } + if err := util2.RequestWithBackoff(func() error { return client.Run(ctx, req, &respData) }); err != nil { + logrus.WithError(err).WithField("request", req).Fatalln("Error while unmarshaling") + } + + _, found := lo.Find(respData.Issue.ComponentVersions.Edges, func(edge *model.ComponentVersionEdge) bool { + return edge.Node.ID == fmt.Sprintf("%d", componentVersionRow.ComponentVersionId.Int64) + }) + + Expect(respData.Issue.ID).To(Equal(fmt.Sprintf("%d", issue.Id))) + Expect(found).To(BeFalse()) + }) + }) + }) +}) diff --git a/internal/mocks/mock_Database.go b/internal/mocks/mock_Database.go index 60f087aa..c509b3aa 100644 --- a/internal/mocks/mock_Database.go +++ b/internal/mocks/mock_Database.go @@ -23,6 +23,53 @@ func (_m *MockDatabase) EXPECT() *MockDatabase_Expecter { return &MockDatabase_Expecter{mock: &_m.Mock} } +// AddComponentVersionToIssue provides a mock function with given fields: _a0, _a1 +func (_m *MockDatabase) AddComponentVersionToIssue(_a0 int64, _a1 int64) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for AddComponentVersionToIssue") + } + + var r0 error + if rf, ok := ret.Get(0).(func(int64, int64) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockDatabase_AddComponentVersionToIssue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddComponentVersionToIssue' +type MockDatabase_AddComponentVersionToIssue_Call struct { + *mock.Call +} + +// AddComponentVersionToIssue is a helper method to define mock.On call +// - _a0 int64 +// - _a1 int64 +func (_e *MockDatabase_Expecter) AddComponentVersionToIssue(_a0 interface{}, _a1 interface{}) *MockDatabase_AddComponentVersionToIssue_Call { + return &MockDatabase_AddComponentVersionToIssue_Call{Call: _e.mock.On("AddComponentVersionToIssue", _a0, _a1)} +} + +func (_c *MockDatabase_AddComponentVersionToIssue_Call) Run(run func(_a0 int64, _a1 int64)) *MockDatabase_AddComponentVersionToIssue_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int64), args[1].(int64)) + }) + return _c +} + +func (_c *MockDatabase_AddComponentVersionToIssue_Call) Return(_a0 error) *MockDatabase_AddComponentVersionToIssue_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockDatabase_AddComponentVersionToIssue_Call) RunAndReturn(run func(int64, int64) error) *MockDatabase_AddComponentVersionToIssue_Call { + _c.Call.Return(run) + return _c +} + // AddEvidenceToIssueMatch provides a mock function with given fields: _a0, _a1 func (_m *MockDatabase) AddEvidenceToIssueMatch(_a0 int64, _a1 int64) error { ret := _m.Called(_a0, _a1) @@ -118,6 +165,53 @@ func (_c *MockDatabase_AddIssueRepositoryToService_Call) RunAndReturn(run func(i return _c } +// AddIssueToActivity provides a mock function with given fields: _a0, _a1 +func (_m *MockDatabase) AddIssueToActivity(_a0 int64, _a1 int64) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for AddIssueToActivity") + } + + var r0 error + if rf, ok := ret.Get(0).(func(int64, int64) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockDatabase_AddIssueToActivity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddIssueToActivity' +type MockDatabase_AddIssueToActivity_Call struct { + *mock.Call +} + +// AddIssueToActivity is a helper method to define mock.On call +// - _a0 int64 +// - _a1 int64 +func (_e *MockDatabase_Expecter) AddIssueToActivity(_a0 interface{}, _a1 interface{}) *MockDatabase_AddIssueToActivity_Call { + return &MockDatabase_AddIssueToActivity_Call{Call: _e.mock.On("AddIssueToActivity", _a0, _a1)} +} + +func (_c *MockDatabase_AddIssueToActivity_Call) Run(run func(_a0 int64, _a1 int64)) *MockDatabase_AddIssueToActivity_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int64), args[1].(int64)) + }) + return _c +} + +func (_c *MockDatabase_AddIssueToActivity_Call) Return(_a0 error) *MockDatabase_AddIssueToActivity_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockDatabase_AddIssueToActivity_Call) RunAndReturn(run func(int64, int64) error) *MockDatabase_AddIssueToActivity_Call { + _c.Call.Return(run) + return _c +} + // AddOwnerToService provides a mock function with given fields: _a0, _a1 func (_m *MockDatabase) AddOwnerToService(_a0 int64, _a1 int64) error { ret := _m.Called(_a0, _a1) @@ -3950,6 +4044,53 @@ func (_c *MockDatabase_GetUsers_Call) RunAndReturn(run func(*entity.UserFilter) return _c } +// RemoveComponentVersionFromIssue provides a mock function with given fields: _a0, _a1 +func (_m *MockDatabase) RemoveComponentVersionFromIssue(_a0 int64, _a1 int64) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for RemoveComponentVersionFromIssue") + } + + var r0 error + if rf, ok := ret.Get(0).(func(int64, int64) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockDatabase_RemoveComponentVersionFromIssue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveComponentVersionFromIssue' +type MockDatabase_RemoveComponentVersionFromIssue_Call struct { + *mock.Call +} + +// RemoveComponentVersionFromIssue is a helper method to define mock.On call +// - _a0 int64 +// - _a1 int64 +func (_e *MockDatabase_Expecter) RemoveComponentVersionFromIssue(_a0 interface{}, _a1 interface{}) *MockDatabase_RemoveComponentVersionFromIssue_Call { + return &MockDatabase_RemoveComponentVersionFromIssue_Call{Call: _e.mock.On("RemoveComponentVersionFromIssue", _a0, _a1)} +} + +func (_c *MockDatabase_RemoveComponentVersionFromIssue_Call) Run(run func(_a0 int64, _a1 int64)) *MockDatabase_RemoveComponentVersionFromIssue_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int64), args[1].(int64)) + }) + return _c +} + +func (_c *MockDatabase_RemoveComponentVersionFromIssue_Call) Return(_a0 error) *MockDatabase_RemoveComponentVersionFromIssue_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockDatabase_RemoveComponentVersionFromIssue_Call) RunAndReturn(run func(int64, int64) error) *MockDatabase_RemoveComponentVersionFromIssue_Call { + _c.Call.Return(run) + return _c +} + // RemoveEvidenceFromIssueMatch provides a mock function with given fields: _a0, _a1 func (_m *MockDatabase) RemoveEvidenceFromIssueMatch(_a0 int64, _a1 int64) error { ret := _m.Called(_a0, _a1) @@ -3997,6 +4138,53 @@ func (_c *MockDatabase_RemoveEvidenceFromIssueMatch_Call) RunAndReturn(run func( return _c } +// RemoveIssueFromActivity provides a mock function with given fields: _a0, _a1 +func (_m *MockDatabase) RemoveIssueFromActivity(_a0 int64, _a1 int64) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for RemoveIssueFromActivity") + } + + var r0 error + if rf, ok := ret.Get(0).(func(int64, int64) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockDatabase_RemoveIssueFromActivity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveIssueFromActivity' +type MockDatabase_RemoveIssueFromActivity_Call struct { + *mock.Call +} + +// RemoveIssueFromActivity is a helper method to define mock.On call +// - _a0 int64 +// - _a1 int64 +func (_e *MockDatabase_Expecter) RemoveIssueFromActivity(_a0 interface{}, _a1 interface{}) *MockDatabase_RemoveIssueFromActivity_Call { + return &MockDatabase_RemoveIssueFromActivity_Call{Call: _e.mock.On("RemoveIssueFromActivity", _a0, _a1)} +} + +func (_c *MockDatabase_RemoveIssueFromActivity_Call) Run(run func(_a0 int64, _a1 int64)) *MockDatabase_RemoveIssueFromActivity_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int64), args[1].(int64)) + }) + return _c +} + +func (_c *MockDatabase_RemoveIssueFromActivity_Call) Return(_a0 error) *MockDatabase_RemoveIssueFromActivity_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockDatabase_RemoveIssueFromActivity_Call) RunAndReturn(run func(int64, int64) error) *MockDatabase_RemoveIssueFromActivity_Call { + _c.Call.Return(run) + return _c +} + // RemoveIssueRepositoryFromService provides a mock function with given fields: _a0, _a1 func (_m *MockDatabase) RemoveIssueRepositoryFromService(_a0 int64, _a1 int64) error { ret := _m.Called(_a0, _a1) diff --git a/internal/mocks/mock_Heureka.go b/internal/mocks/mock_Heureka.go index 41da8f29..ba41b9d0 100644 --- a/internal/mocks/mock_Heureka.go +++ b/internal/mocks/mock_Heureka.go @@ -23,6 +23,124 @@ func (_m *MockHeureka) EXPECT() *MockHeureka_Expecter { return &MockHeureka_Expecter{mock: &_m.Mock} } +// AddComponentVersionToIssue provides a mock function with given fields: _a0, _a1 +func (_m *MockHeureka) AddComponentVersionToIssue(_a0 int64, _a1 int64) (*entity.Issue, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for AddComponentVersionToIssue") + } + + var r0 *entity.Issue + var r1 error + if rf, ok := ret.Get(0).(func(int64, int64) (*entity.Issue, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(int64, int64) *entity.Issue); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entity.Issue) + } + } + + if rf, ok := ret.Get(1).(func(int64, int64) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockHeureka_AddComponentVersionToIssue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddComponentVersionToIssue' +type MockHeureka_AddComponentVersionToIssue_Call struct { + *mock.Call +} + +// AddComponentVersionToIssue is a helper method to define mock.On call +// - _a0 int64 +// - _a1 int64 +func (_e *MockHeureka_Expecter) AddComponentVersionToIssue(_a0 interface{}, _a1 interface{}) *MockHeureka_AddComponentVersionToIssue_Call { + return &MockHeureka_AddComponentVersionToIssue_Call{Call: _e.mock.On("AddComponentVersionToIssue", _a0, _a1)} +} + +func (_c *MockHeureka_AddComponentVersionToIssue_Call) Run(run func(_a0 int64, _a1 int64)) *MockHeureka_AddComponentVersionToIssue_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int64), args[1].(int64)) + }) + return _c +} + +func (_c *MockHeureka_AddComponentVersionToIssue_Call) Return(_a0 *entity.Issue, _a1 error) *MockHeureka_AddComponentVersionToIssue_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockHeureka_AddComponentVersionToIssue_Call) RunAndReturn(run func(int64, int64) (*entity.Issue, error)) *MockHeureka_AddComponentVersionToIssue_Call { + _c.Call.Return(run) + return _c +} + +// AddEvidenceToIssueMatch provides a mock function with given fields: _a0, _a1 +func (_m *MockHeureka) AddEvidenceToIssueMatch(_a0 int64, _a1 int64) (*entity.IssueMatch, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for AddEvidenceToIssueMatch") + } + + var r0 *entity.IssueMatch + var r1 error + if rf, ok := ret.Get(0).(func(int64, int64) (*entity.IssueMatch, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(int64, int64) *entity.IssueMatch); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entity.IssueMatch) + } + } + + if rf, ok := ret.Get(1).(func(int64, int64) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockHeureka_AddEvidenceToIssueMatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddEvidenceToIssueMatch' +type MockHeureka_AddEvidenceToIssueMatch_Call struct { + *mock.Call +} + +// AddEvidenceToIssueMatch is a helper method to define mock.On call +// - _a0 int64 +// - _a1 int64 +func (_e *MockHeureka_Expecter) AddEvidenceToIssueMatch(_a0 interface{}, _a1 interface{}) *MockHeureka_AddEvidenceToIssueMatch_Call { + return &MockHeureka_AddEvidenceToIssueMatch_Call{Call: _e.mock.On("AddEvidenceToIssueMatch", _a0, _a1)} +} + +func (_c *MockHeureka_AddEvidenceToIssueMatch_Call) Run(run func(_a0 int64, _a1 int64)) *MockHeureka_AddEvidenceToIssueMatch_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int64), args[1].(int64)) + }) + return _c +} + +func (_c *MockHeureka_AddEvidenceToIssueMatch_Call) Return(_a0 *entity.IssueMatch, _a1 error) *MockHeureka_AddEvidenceToIssueMatch_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockHeureka_AddEvidenceToIssueMatch_Call) RunAndReturn(run func(int64, int64) (*entity.IssueMatch, error)) *MockHeureka_AddEvidenceToIssueMatch_Call { + _c.Call.Return(run) + return _c +} + // AddIssueRepositoryToService provides a mock function with given fields: _a0, _a1, _a2 func (_m *MockHeureka) AddIssueRepositoryToService(_a0 int64, _a1 int64, _a2 int64) (*entity.Service, error) { ret := _m.Called(_a0, _a1, _a2) @@ -2496,6 +2614,124 @@ func (_c *MockHeureka_ListUsers_Call) RunAndReturn(run func(*entity.UserFilter, return _c } +// RemoveComponentVersionFromIssue provides a mock function with given fields: _a0, _a1 +func (_m *MockHeureka) RemoveComponentVersionFromIssue(_a0 int64, _a1 int64) (*entity.Issue, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for RemoveComponentVersionFromIssue") + } + + var r0 *entity.Issue + var r1 error + if rf, ok := ret.Get(0).(func(int64, int64) (*entity.Issue, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(int64, int64) *entity.Issue); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entity.Issue) + } + } + + if rf, ok := ret.Get(1).(func(int64, int64) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockHeureka_RemoveComponentVersionFromIssue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveComponentVersionFromIssue' +type MockHeureka_RemoveComponentVersionFromIssue_Call struct { + *mock.Call +} + +// RemoveComponentVersionFromIssue is a helper method to define mock.On call +// - _a0 int64 +// - _a1 int64 +func (_e *MockHeureka_Expecter) RemoveComponentVersionFromIssue(_a0 interface{}, _a1 interface{}) *MockHeureka_RemoveComponentVersionFromIssue_Call { + return &MockHeureka_RemoveComponentVersionFromIssue_Call{Call: _e.mock.On("RemoveComponentVersionFromIssue", _a0, _a1)} +} + +func (_c *MockHeureka_RemoveComponentVersionFromIssue_Call) Run(run func(_a0 int64, _a1 int64)) *MockHeureka_RemoveComponentVersionFromIssue_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int64), args[1].(int64)) + }) + return _c +} + +func (_c *MockHeureka_RemoveComponentVersionFromIssue_Call) Return(_a0 *entity.Issue, _a1 error) *MockHeureka_RemoveComponentVersionFromIssue_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockHeureka_RemoveComponentVersionFromIssue_Call) RunAndReturn(run func(int64, int64) (*entity.Issue, error)) *MockHeureka_RemoveComponentVersionFromIssue_Call { + _c.Call.Return(run) + return _c +} + +// RemoveEvidenceFromIssueMatch provides a mock function with given fields: _a0, _a1 +func (_m *MockHeureka) RemoveEvidenceFromIssueMatch(_a0 int64, _a1 int64) (*entity.IssueMatch, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for RemoveEvidenceFromIssueMatch") + } + + var r0 *entity.IssueMatch + var r1 error + if rf, ok := ret.Get(0).(func(int64, int64) (*entity.IssueMatch, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(int64, int64) *entity.IssueMatch); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*entity.IssueMatch) + } + } + + if rf, ok := ret.Get(1).(func(int64, int64) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockHeureka_RemoveEvidenceFromIssueMatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveEvidenceFromIssueMatch' +type MockHeureka_RemoveEvidenceFromIssueMatch_Call struct { + *mock.Call +} + +// RemoveEvidenceFromIssueMatch is a helper method to define mock.On call +// - _a0 int64 +// - _a1 int64 +func (_e *MockHeureka_Expecter) RemoveEvidenceFromIssueMatch(_a0 interface{}, _a1 interface{}) *MockHeureka_RemoveEvidenceFromIssueMatch_Call { + return &MockHeureka_RemoveEvidenceFromIssueMatch_Call{Call: _e.mock.On("RemoveEvidenceFromIssueMatch", _a0, _a1)} +} + +func (_c *MockHeureka_RemoveEvidenceFromIssueMatch_Call) Run(run func(_a0 int64, _a1 int64)) *MockHeureka_RemoveEvidenceFromIssueMatch_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int64), args[1].(int64)) + }) + return _c +} + +func (_c *MockHeureka_RemoveEvidenceFromIssueMatch_Call) Return(_a0 *entity.IssueMatch, _a1 error) *MockHeureka_RemoveEvidenceFromIssueMatch_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockHeureka_RemoveEvidenceFromIssueMatch_Call) RunAndReturn(run func(int64, int64) (*entity.IssueMatch, error)) *MockHeureka_RemoveEvidenceFromIssueMatch_Call { + _c.Call.Return(run) + return _c +} + // RemoveIssueRepositoryFromService provides a mock function with given fields: _a0, _a1 func (_m *MockHeureka) RemoveIssueRepositoryFromService(_a0 int64, _a1 int64) (*entity.Service, error) { ret := _m.Called(_a0, _a1) From 847645a074ce0167ee23799a35473a969621b1ff Mon Sep 17 00:00:00 2001 From: Michael Reimsbach Date: Fri, 12 Jul 2024 10:20:01 +0200 Subject: [PATCH 2/2] feat(issue): add mutations for activities/componentVersions --- internal/app/activity_test.go | 2 +- internal/app/issue_test.go | 2 +- internal/e2e/activity_query_test.go | 3 +++ internal/e2e/issue_query_test.go | 5 ++++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/app/activity_test.go b/internal/app/activity_test.go index 91692c3c..a4515f32 100644 --- a/internal/app/activity_test.go +++ b/internal/app/activity_test.go @@ -236,7 +236,7 @@ var _ = Describe("When modifying relationship of Service and Activity", Label("a }) }) -var _ = Describe("When modifying Issue and Activity", Label("app", "IssueActivity"), func() { +var _ = Describe("When modifying relationship of Issue and Activity", Label("app", "IssueActivityRelationship"), func() { var ( db *mocks.MockDatabase heureka app.Heureka diff --git a/internal/app/issue_test.go b/internal/app/issue_test.go index 937e06ce..783c03a8 100644 --- a/internal/app/issue_test.go +++ b/internal/app/issue_test.go @@ -292,7 +292,7 @@ var _ = Describe("When deleting Issue", Label("app", "DeleteIssue"), func() { }) }) -var _ = Describe("When modifying ComponentVersion and Issue", Label("app", "ComponentVersionIssue"), func() { +var _ = Describe("When modifying relationship of ComponentVersion and Issue", Label("app", "ComponentVersionIssueRelationship"), func() { var ( db *mocks.MockDatabase heureka app.Heureka diff --git a/internal/e2e/activity_query_test.go b/internal/e2e/activity_query_test.go index 9448d533..4160c322 100644 --- a/internal/e2e/activity_query_test.go +++ b/internal/e2e/activity_query_test.go @@ -533,6 +533,7 @@ var _ = Describe("Modifying Issues of Activity via API", Label("e2e", "ServiceIs req := graphql.NewRequest(str) activity := seedCollection.ActivityRows[0].AsActivity() + // find all issues that are assigned to the activity issueIds := lo.FilterMap(seedCollection.ActivityHasIssueRows, func(row mariadb.ActivityHasIssueRow, _ int) (int64, bool) { if row.ActivityId.Int64 == activity.Id { return row.IssueId.Int64, true @@ -540,6 +541,7 @@ var _ = Describe("Modifying Issues of Activity via API", Label("e2e", "ServiceIs return 0, false }) + // find an issue that is not assigned to the activity issueRow, _ := lo.Find(seedCollection.IssueRows, func(row mariadb.IssueRow) bool { return !lo.Contains(issueIds, row.Id.Int64) }) @@ -577,6 +579,7 @@ var _ = Describe("Modifying Issues of Activity via API", Label("e2e", "ServiceIs activity := seedCollection.ActivityRows[0].AsActivity() + // find an issue that is assigned to the activity issueRow, _ := lo.Find(seedCollection.ActivityHasIssueRows, func(row mariadb.ActivityHasIssueRow) bool { return row.ActivityId.Int64 == activity.Id }) diff --git a/internal/e2e/issue_query_test.go b/internal/e2e/issue_query_test.go index faf9854a..8e073b91 100644 --- a/internal/e2e/issue_query_test.go +++ b/internal/e2e/issue_query_test.go @@ -398,7 +398,7 @@ var _ = Describe("Deleting Issue via API", Label("e2e", "Issues"), func() { }) }) -var _ = Describe("Modifying ComponentVersion of Issue via API", Label("e2e", "Issues"), func() { +var _ = Describe("Modifying relationship of ComponentVersion of Issue via API", Label("e2e", "ComponentVersionIssueRelationship"), func() { var seeder *test.DatabaseSeeder var s *server.Server @@ -441,6 +441,7 @@ var _ = Describe("Modifying ComponentVersion of Issue via API", Label("e2e", "Is req := graphql.NewRequest(str) issue := seedCollection.IssueRows[0].AsIssue() + // find all componentVersions that are assigned to the issue componentVersionIds := lo.FilterMap(seedCollection.ComponentVersionIssueRows, func(row mariadb.ComponentVersionIssueRow, _ int) (int64, bool) { if row.IssueId.Int64 == issue.Id { return row.ComponentVersionId.Int64, true @@ -448,6 +449,7 @@ var _ = Describe("Modifying ComponentVersion of Issue via API", Label("e2e", "Is return 0, false }) + // find a componentVersion that is not assigned to the issue componentVersionRow, _ := lo.Find(seedCollection.ComponentVersionRows, func(row mariadb.ComponentVersionRow) bool { return !lo.Contains(componentVersionIds, row.Id.Int64) }) @@ -485,6 +487,7 @@ var _ = Describe("Modifying ComponentVersion of Issue via API", Label("e2e", "Is issue := seedCollection.IssueRows[0].AsIssue() + // find a componentVersion that is assigned to the issue componentVersionRow, _ := lo.Find(seedCollection.ComponentVersionIssueRows, func(row mariadb.ComponentVersionIssueRow) bool { return row.IssueId.Int64 == issue.Id })