diff --git a/config.go b/config.go index 3c929bdf1fa..b4b0782a865 100644 --- a/config.go +++ b/config.go @@ -34,7 +34,7 @@ var ( // ClientVersion is the commandline version string used to control updating // the CLI. The format is the calendar date (YYYY-MM-DD). - ClientVersion = "2024-05-23" + ClientVersion = "2024-05-24" // Agent version to control agent rollover. The format is the calendar date // (YYYY-MM-DD). diff --git a/graphql/generated.go b/graphql/generated.go index 403bf6a2071..4347d3c71dc 100644 --- a/graphql/generated.go +++ b/graphql/generated.go @@ -1716,6 +1716,7 @@ type PatchResolver interface { AuthorDisplayName(ctx context.Context, obj *model.APIPatch) (string, error) BaseTaskStatuses(ctx context.Context, obj *model.APIPatch) ([]string, error) Builds(ctx context.Context, obj *model.APIPatch) ([]*model.APIBuild, error) + CanEnqueueToCommitQueue(ctx context.Context, obj *model.APIPatch) (bool, error) CommitQueuePosition(ctx context.Context, obj *model.APIPatch) (*int, error) @@ -34368,7 +34369,7 @@ func (ec *executionContext) _Patch_canEnqueueToCommitQueue(ctx context.Context, }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.CanEnqueueToCommitQueue, nil + return ec.resolvers.Patch().CanEnqueueToCommitQueue(rctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -34389,8 +34390,8 @@ func (ec *executionContext) fieldContext_Patch_canEnqueueToCommitQueue(ctx conte fc = &graphql.FieldContext{ Object: "Patch", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, @@ -78199,10 +78200,41 @@ func (ec *executionContext) _Patch(ctx context.Context, sel ast.SelectionSet, ob out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "canEnqueueToCommitQueue": - out.Values[i] = ec._Patch_canEnqueueToCommitQueue(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Patch_canEnqueueToCommitQueue(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "childPatchAliases": out.Values[i] = ec._Patch_childPatchAliases(ctx, field, obj) case "childPatches": diff --git a/graphql/patch_resolver.go b/graphql/patch_resolver.go index 39a42f516b3..54692ac7a01 100644 --- a/graphql/patch_resolver.go +++ b/graphql/patch_resolver.go @@ -58,6 +58,28 @@ func (r *patchResolver) Builds(ctx context.Context, obj *restModel.APIPatch) ([] return apiBuilds, nil } +// CanEnqueueToCommitQueue is the resolver for the canEnqueueToCommitQueue field. +func (r *patchResolver) CanEnqueueToCommitQueue(ctx context.Context, obj *restModel.APIPatch) (bool, error) { + patchID := utility.FromStringPtr(obj.Id) + p, err := patch.FindOneId(patchID) + if err != nil { + return false, InternalServerError.Send(ctx, fmt.Sprintf("error finding patch '%s': %s", patchID, err.Error())) + } + if p == nil { + return false, ResourceNotFound.Send(ctx, fmt.Sprintf("patch '%s' not found", patchID)) + } + + proj, err := model.FindMergedProjectRef(p.Project, p.Version, false) + if err != nil { + return false, InternalServerError.Send(ctx, fmt.Sprintf("error getting project '%s': %s", p.Project, err.Error())) + } + if proj == nil { + return false, ResourceNotFound.Send(ctx, fmt.Sprintf("project '%s' not found", p.Project)) + } + // Projects that use the GitHub merge queue cannot enqueue to the commit queue. + return (p.HasValidGitInfo() || p.IsGithubPRPatch()) && proj.CommitQueue.MergeQueue != model.MergeQueueGitHub, nil +} + // CommitQueuePosition is the resolver for the commitQueuePosition field. func (r *patchResolver) CommitQueuePosition(ctx context.Context, obj *restModel.APIPatch) (*int, error) { if err := obj.GetCommitQueuePosition(); err != nil { diff --git a/graphql/query_resolver.go b/graphql/query_resolver.go index 7192838533d..c234df397b4 100644 --- a/graphql/query_resolver.go +++ b/graphql/query_resolver.go @@ -374,19 +374,22 @@ func (r *queryResolver) Pod(ctx context.Context, podID string) (*restModel.APIPo // Patch is the resolver for the patch field. func (r *queryResolver) Patch(ctx context.Context, patchID string) (*restModel.APIPatch, error) { - patch, err := data.FindPatchById(patchID) + apiPatch, err := data.FindPatchById(patchID) if err != nil { return nil, InternalServerError.Send(ctx, err.Error()) } + if apiPatch == nil { + return nil, ResourceNotFound.Send(ctx, fmt.Sprintf("patch '%s' not found", patchID)) + } - if evergreen.IsFinishedVersionStatus(*patch.Status) { + if evergreen.IsFinishedVersionStatus(*apiPatch.Status) { statuses, err := task.GetTaskStatusesByVersion(ctx, patchID) if err != nil { return nil, InternalServerError.Send(ctx, fmt.Sprintf("fetching task statuses for patch: %s", err.Error())) } - if len(patch.ChildPatches) > 0 { - for _, cp := range patch.ChildPatches { + if len(apiPatch.ChildPatches) > 0 { + for _, cp := range apiPatch.ChildPatches { childPatchStatuses, err := task.GetTaskStatusesByVersion(ctx, *cp.Id) if err != nil { return nil, InternalServerError.Send(ctx, fmt.Sprintf("fetching task statuses for child patch: %s", err.Error())) @@ -398,11 +401,12 @@ func (r *queryResolver) Patch(ctx context.Context, patchID string) (*restModel.A // If theres an aborted task we should set the patch status to aborted if there are no other failures if utility.StringSliceContains(statuses, evergreen.TaskAborted) { if len(utility.StringSliceIntersection(statuses, evergreen.TaskFailureStatuses)) == 0 { - patch.Status = utility.ToStringPtr(evergreen.VersionAborted) + apiPatch.Status = utility.ToStringPtr(evergreen.VersionAborted) } } } - return patch, nil + + return apiPatch, nil } // GithubProjectConflicts is the resolver for the githubProjectConflicts field. diff --git a/graphql/tests/patch/canEnqueueToCommitQueue/data.json b/graphql/tests/patch/canEnqueueToCommitQueue/data.json new file mode 100644 index 00000000000..a00d73d6877 --- /dev/null +++ b/graphql/tests/patch/canEnqueueToCommitQueue/data.json @@ -0,0 +1,72 @@ +{ + "patches": [ + { + "_id": { + "$oid": "5e4ff3abe3c3317e352062e4" + }, + "branch": "spruce", + "version": "5e4ff3abe3c3317e352062e4", + "activated": true, + "githash": "5e823e1f28baeaa22ae00823d83e03082cd148ab", + "git_info": { + "username": "bob.smith", + "email": "bob.smith@gmail.com" + }, + "github_patch_data": { + "pr_number": 27, + "base_owner": "evergreen-ci", + "base_repo": "spruce", + "base_branch": "main", + "head_owner": "evergreen-ci", + "head_repo": "spruce", + "head_hash": "2b37dacf86f9d4d1545faaba37c7c5693202e645", + "author": "tgrander", + "author_uid": 15262143, + "merge_commit_sha": "" + } + }, + { + "_id": { + "$oid": "4e4ff3abe3c3317e352062e4" + }, + "branch": "mci", + "version": "4e4ff3abe3c3317e352062e4", + "activated": true, + "githash": "5e823e1f28baeaa22ae00823d83e03082cd148ab", + "git_info": { + "username": "bob.smith", + "email": "bob.smith@gmail.com" + }, + "github_patch_data": { + "pr_number": 27, + "base_owner": "evergreen-ci", + "base_repo": "spruce", + "base_branch": "main", + "head_owner": "evergreen-ci", + "head_repo": "spruce", + "head_hash": "2b37dacf86f9d4d1545faaba37c7c5693202e645", + "author": "tgrander", + "author_uid": 15262143, + "merge_commit_sha": "" + } + } + ], + "project_ref": [ + { + "_id": "spruce", + "identifier": "spruce", + "commit_queue": { + "enabled": true, + "merge_queue": "EVERGREEN" + } + }, + { + "_id": "mci", + "identifier": "mci", + "commit_queue": { + "enabled": true, + "merge_queue": "GITHUB" + } + } + ] +} diff --git a/graphql/tests/patch/canEnqueueToCommitQueue/queries/can_enqueue_pr_patch.graphql b/graphql/tests/patch/canEnqueueToCommitQueue/queries/can_enqueue_pr_patch.graphql new file mode 100644 index 00000000000..f5751c7e126 --- /dev/null +++ b/graphql/tests/patch/canEnqueueToCommitQueue/queries/can_enqueue_pr_patch.graphql @@ -0,0 +1,5 @@ +{ + patch(patchId: "5e4ff3abe3c3317e352062e4") { + canEnqueueToCommitQueue + } +} diff --git a/graphql/tests/patch/canEnqueueToCommitQueue/queries/cannot_enqueue_using_github_queue.graphql b/graphql/tests/patch/canEnqueueToCommitQueue/queries/cannot_enqueue_using_github_queue.graphql new file mode 100644 index 00000000000..7b8e442fa97 --- /dev/null +++ b/graphql/tests/patch/canEnqueueToCommitQueue/queries/cannot_enqueue_using_github_queue.graphql @@ -0,0 +1,5 @@ +{ + patch(patchId: "4e4ff3abe3c3317e352062e4") { + canEnqueueToCommitQueue + } +} diff --git a/graphql/tests/patch/canEnqueueToCommitQueue/results.json b/graphql/tests/patch/canEnqueueToCommitQueue/results.json new file mode 100644 index 00000000000..b9dcfa68014 --- /dev/null +++ b/graphql/tests/patch/canEnqueueToCommitQueue/results.json @@ -0,0 +1,24 @@ +{ + "tests": [ + { + "query_file": "can_enqueue_pr_patch.graphql", + "result": { + "data": { + "patch": { + "canEnqueueToCommitQueue": true + } + } + } + }, + { + "query_file": "cannot_enqueue_using_github_queue.graphql", + "result": { + "data": { + "patch": { + "canEnqueueToCommitQueue": false + } + } + } + } + ] +} diff --git a/rest/model/patch.go b/rest/model/patch.go index 8f0c1570a6f..21b35e5b0bd 100644 --- a/rest/model/patch.go +++ b/rest/model/patch.go @@ -52,17 +52,16 @@ type APIPatch struct { // List of documents of available tasks and associated build variant VariantsTasks []VariantTask `json:"variants_tasks"` // Whether the patch has been finalized and activated - Activated bool `json:"activated"` - Alias *string `json:"alias,omitempty"` - GithubPatchData githubPatch `json:"github_patch_data,omitempty"` - ModuleCodeChanges []APIModulePatch `json:"module_code_changes"` - Parameters []APIParameter `json:"parameters"` - ProjectStorageMethod *string `json:"project_storage_method,omitempty"` - CanEnqueueToCommitQueue bool `json:"can_enqueue_to_commit_queue"` - ChildPatches []APIPatch `json:"child_patches"` - ChildPatchAliases []APIChildPatchAlias `json:"child_patch_aliases,omitempty"` - Requester *string `json:"requester"` - MergedFrom *string `json:"merged_from"` + Activated bool `json:"activated"` + Alias *string `json:"alias,omitempty"` + GithubPatchData githubPatch `json:"github_patch_data,omitempty"` + ModuleCodeChanges []APIModulePatch `json:"module_code_changes"` + Parameters []APIParameter `json:"parameters"` + ProjectStorageMethod *string `json:"project_storage_method,omitempty"` + ChildPatches []APIPatch `json:"child_patches"` + ChildPatchAliases []APIChildPatchAlias `json:"child_patch_aliases,omitempty"` + Requester *string `json:"requester"` + MergedFrom *string `json:"merged_from"` // Only populated for commit queue patches: returns the 0-indexed position of the patch on the queue, or -1 if not on the queue anymore CommitQueuePosition *int `json:"commit_queue_position,omitempty"` } @@ -155,16 +154,6 @@ func (apiPatch *APIPatch) BuildFromService(p patch.Patch, args *APIPatchArgs) er apiPatch.buildBasePatch(p) projectIdentifier := p.Project - proj, err := model.FindMergedProjectRef(projectIdentifier, p.Version, false) - if err != nil { - return errors.Wrapf(err, "finding project ref '%s'", projectIdentifier) - } - if proj == nil { - return errors.Errorf("project ref '%s' not found", projectIdentifier) - } - // Projects that use the GitHub merge queue cannot enqueue to the commit queue. - apiPatch.CanEnqueueToCommitQueue = (p.HasValidGitInfo() || p.IsGithubPRPatch()) && proj.CommitQueue.MergeQueue != model.MergeQueueGitHub - if args != nil { if args.IncludeProjectIdentifier && p.Project != "" { apiPatch.GetIdentifier() @@ -173,6 +162,7 @@ func (apiPatch *APIPatch) BuildFromService(p patch.Patch, args *APIPatchArgs) er } } + if args.IncludeCommitQueuePosition { if err := apiPatch.GetCommitQueuePosition(); err != nil { return errors.Wrap(err, "getting commit queue position") diff --git a/trigger/payloads_test.go b/trigger/payloads_test.go index 8a412f60de8..e0a1ab7d2a6 100644 --- a/trigger/payloads_test.go +++ b/trigger/payloads_test.go @@ -132,7 +132,7 @@ func (s *payloadSuite) TestEvergreenWebhook() { s.NoError(err) s.Require().NotNil(m) - s.Len(m.Body, 613) + s.Len(m.Body, 577) s.Len(m.Headers, 1) }