From 31ac90d0b0abbe3e03b6b564a933b8cd01553e79 Mon Sep 17 00:00:00 2001 From: Edmund Kohlwey Date: Sat, 30 May 2026 15:33:09 -0700 Subject: [PATCH 1/3] forge: Add merge and checks APIs Teach forge repositories how to merge changes directly and report aggregate checks state. This gives command handlers a provider-neutral contract for merge operations while keeping provider-specific REST and GraphQL shapes behind the forge boundary. GitHub and GitLab pass expected head SHAs through their merge APIs so callers can reject stale plans. Bitbucket exposes merge support without head assertions because its API does not provide that guard. Checks state now has a shared `forge.ChecksState` contract. GitHub, GitLab, Bitbucket, and ShamHub map provider statuses into pending, passed, or failed so merge orchestration can wait on CI without knowing provider-specific status names. ShamHub gains a REST merge endpoint and `shamhub config mergeMethod` for tests that need server-side merge or squash behavior when the client does not specify a method. Extracted from #1152 Co-Authored-By: Abhinav Gupta --- internal/forge/bitbucket/checks.go | 59 +++++++++ internal/forge/bitbucket/merge.go | 27 ++++ internal/forge/forge.go | 77 +++++++++++ internal/forge/forgetest/mocks.go | 77 +++++++++++ internal/forge/github/checks.go | 82 ++++++++++++ internal/forge/github/merge.go | 51 ++++++++ internal/forge/github/repository_int_test.go | 18 +-- internal/forge/gitlab/checks.go | 42 ++++++ internal/forge/gitlab/merge.go | 32 +++++ internal/forge/gitlab/repository_int_test.go | 14 +- internal/forge/shamhub/checks.go | 15 +++ internal/forge/shamhub/cli.go | 24 ++++ internal/forge/shamhub/shamhub.go | 12 +- internal/forge/shamhub/states.go | 127 ++++++++++++++++++- internal/gateway/bitbucket/api.go | 65 ++++++++++ internal/gateway/gitlab/api.go | 29 ++++- 16 files changed, 718 insertions(+), 33 deletions(-) create mode 100644 internal/forge/bitbucket/checks.go create mode 100644 internal/forge/bitbucket/merge.go create mode 100644 internal/forge/github/checks.go create mode 100644 internal/forge/github/merge.go create mode 100644 internal/forge/gitlab/checks.go create mode 100644 internal/forge/gitlab/merge.go create mode 100644 internal/forge/shamhub/checks.go diff --git a/internal/forge/bitbucket/checks.go b/internal/forge/bitbucket/checks.go new file mode 100644 index 000000000..663de1666 --- /dev/null +++ b/internal/forge/bitbucket/checks.go @@ -0,0 +1,59 @@ +package bitbucket + +import ( + "context" + "fmt" + + "go.abhg.dev/gs/internal/forge" + "go.abhg.dev/gs/internal/gateway/bitbucket" +) + +// ChangeChecksState reports the aggregate build status +// for the given pull request. +func (r *Repository) ChangeChecksState( + ctx context.Context, fid forge.ChangeID, +) (forge.ChecksState, error) { + id := mustPR(fid) + pr, err := r.getPullRequest(ctx, id.Number) + if err != nil { + return 0, fmt.Errorf("get pull request: %w", err) + } + + if pr.Source.Commit == nil { + return forge.ChecksPassed, nil + } + return r.commitChecksState(ctx, pr.Source.Commit.Hash) +} + +func (r *Repository) commitChecksState( + ctx context.Context, commitHash string, +) (forge.ChecksState, error) { + statuses, _, err := r.client.CommitStatusList( + ctx, r.workspace, r.repo, commitHash, + ) + if err != nil { + return 0, fmt.Errorf("get commit statuses: %w", err) + } + + return aggregateStatuses(statuses.Values), nil +} + +func aggregateStatuses( + statuses []bitbucket.CommitStatus, +) forge.ChecksState { + if len(statuses) == 0 { + return forge.ChecksPassed // no checks configured + } + + for _, s := range statuses { + switch s.State { + case bitbucket.CommitStatusFailed, + bitbucket.CommitStatusStopped: + return forge.ChecksFailed + case bitbucket.CommitStatusInProgress: + return forge.ChecksPending + } + } + + return forge.ChecksPassed +} diff --git a/internal/forge/bitbucket/merge.go b/internal/forge/bitbucket/merge.go new file mode 100644 index 000000000..de0e7a443 --- /dev/null +++ b/internal/forge/bitbucket/merge.go @@ -0,0 +1,27 @@ +package bitbucket + +import ( + "context" + "fmt" + + "go.abhg.dev/gs/internal/forge" +) + +// MergeChange merges an open pull request into its base branch. +// +// Bitbucket does not support expected-SHA assertions; +// opts.HeadHash is ignored. +func (r *Repository) MergeChange( + ctx context.Context, fid forge.ChangeID, + _ forge.MergeChangeOptions, +) error { + id := mustPR(fid) + if _, _, err := r.client.PullRequestMerge( + ctx, r.workspace, r.repo, id.Number, + ); err != nil { + return fmt.Errorf("merge pull request: %w", err) + } + + r.log.Debug("Merged pull request", "pr", id.Number) + return nil +} diff --git a/internal/forge/forge.go b/internal/forge/forge.go index 2db4b620e..453e39081 100644 --- a/internal/forge/forge.go +++ b/internal/forge/forge.go @@ -221,6 +221,11 @@ type RepositoryID interface { // because the base branch has not been pushed yet. var ErrUnsubmittedBase = errors.New("base branch has not been submitted yet") +// ErrMergeNotAllowed indicates that a change cannot be merged +// because preconditions are not met +// (e.g., failing checks, review requirements, conflicts). +var ErrMergeNotAllowed = errors.New("merge not allowed") + // Repository is a Git repository hosted on a forge. type Repository interface { Forge() Forge @@ -234,9 +239,24 @@ type Repository interface { SubmitChange(ctx context.Context, req SubmitChangeRequest) (SubmitChangeResult, error) EditChange(ctx context.Context, id ChangeID, opts EditChangeOptions) error + + // MergeChange merges an open change into its base branch. + // + // Returns ErrMergeNotAllowed if the change cannot be merged + // (e.g., failing checks, review requirements, conflicts). + MergeChange(ctx context.Context, id ChangeID, opts MergeChangeOptions) error + FindChangesByBranch(ctx context.Context, branch string, opts FindChangesOptions) ([]*FindChangeItem, error) FindChangeByID(ctx context.Context, id ChangeID) (*FindChangeItem, error) ChangeStatuses(ctx context.Context, ids []ChangeID) ([]ChangeStatus, error) + + // ChangeChecksState reports the aggregate CI/checks + // state for the given change. + // + // If the forge has no CI/checks integration + // or the change has no required checks, + // implementations should return ChecksPassed. + ChangeChecksState(ctx context.Context, id ChangeID) (ChecksState, error) CommentCountsByChange(ctx context.Context, ids []ChangeID) ([]*CommentCounts, error) // Post, update, and delete comments on changes. @@ -430,6 +450,18 @@ type EditChangeOptions struct { AddAssignees []string } +// MergeChangeOptions specifies options for a merge operation. +type MergeChangeOptions struct { + // HeadHash, if non-empty, causes the merge to fail + // if the change's current head commit doesn't match. + // This prevents merging a change whose content + // has changed since the caller last inspected it. + // + // Not all forges support this; unsupported forges + // ignore the field. + HeadHash git.Hash +} + // FindChangeItem is a single result from searching for changes in the // repository. type FindChangeItem struct { @@ -565,3 +597,48 @@ func (s *ChangeState) UnmarshalText(b []byte) error { } return nil } + +// ChecksState represents the aggregate CI/checks +// status for a change. +// +// TODO: Teach this type the names of individual statuses +// so merge failures can report exactly what's blocking the user. +type ChecksState int + +const ( + // ChecksPending indicates checks are still running. + ChecksPending ChecksState = iota + 1 + + // ChecksPassed indicates all checks have passed. + ChecksPassed + + // ChecksFailed indicates one or more checks failed. + ChecksFailed +) + +func (s ChecksState) String() string { + switch s { + case ChecksPending: + return "pending" + case ChecksPassed: + return "passed" + case ChecksFailed: + return "failed" + default: + return fmt.Sprintf("ChecksState(%d)", int(s)) + } +} + +// GoString returns a Go-syntax representation. +func (s ChecksState) GoString() string { + switch s { + case ChecksPending: + return "ChecksPending" + case ChecksPassed: + return "ChecksPassed" + case ChecksFailed: + return "ChecksFailed" + default: + return fmt.Sprintf("ChecksState(%d)", int(s)) + } +} diff --git a/internal/forge/forgetest/mocks.go b/internal/forge/forgetest/mocks.go index 5230b1023..1db56ed21 100644 --- a/internal/forge/forgetest/mocks.go +++ b/internal/forge/forgetest/mocks.go @@ -671,6 +671,45 @@ func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { return m.recorder } +// ChangeChecksState mocks base method. +func (m *MockRepository) ChangeChecksState(ctx context.Context, id forge.ChangeID) (forge.ChecksState, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChangeChecksState", ctx, id) + ret0, _ := ret[0].(forge.ChecksState) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ChangeChecksState indicates an expected call of ChangeChecksState. +func (mr *MockRepositoryMockRecorder) ChangeChecksState(ctx, id any) *MockRepositoryChangeChecksStateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeChecksState", reflect.TypeOf((*MockRepository)(nil).ChangeChecksState), ctx, id) + return &MockRepositoryChangeChecksStateCall{Call: call} +} + +// MockRepositoryChangeChecksStateCall wrap *gomock.Call +type MockRepositoryChangeChecksStateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockRepositoryChangeChecksStateCall) Return(arg0 forge.ChecksState, arg1 error) *MockRepositoryChangeChecksStateCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockRepositoryChangeChecksStateCall) Do(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockRepositoryChangeChecksStateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockRepositoryChangeChecksStateCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockRepositoryChangeChecksStateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // ChangeStatuses mocks base method. func (m *MockRepository) ChangeStatuses(ctx context.Context, ids []forge.ChangeID) ([]forge.ChangeStatus, error) { m.ctrl.T.Helper() @@ -1018,6 +1057,44 @@ func (c *MockRepositoryListChangeTemplatesCall) DoAndReturn(f func(context.Conte return c } +// MergeChange mocks base method. +func (m *MockRepository) MergeChange(ctx context.Context, id forge.ChangeID, opts forge.MergeChangeOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MergeChange", ctx, id, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// MergeChange indicates an expected call of MergeChange. +func (mr *MockRepositoryMockRecorder) MergeChange(ctx, id, opts any) *MockRepositoryMergeChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MergeChange", reflect.TypeOf((*MockRepository)(nil).MergeChange), ctx, id, opts) + return &MockRepositoryMergeChangeCall{Call: call} +} + +// MockRepositoryMergeChangeCall wrap *gomock.Call +type MockRepositoryMergeChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockRepositoryMergeChangeCall) Return(arg0 error) *MockRepositoryMergeChangeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockRepositoryMergeChangeCall) Do(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockRepositoryMergeChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockRepositoryMergeChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockRepositoryMergeChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // NewChangeMetadata mocks base method. func (m *MockRepository) NewChangeMetadata(ctx context.Context, id forge.ChangeID) (forge.ChangeMetadata, error) { m.ctrl.T.Helper() diff --git a/internal/forge/github/checks.go b/internal/forge/github/checks.go new file mode 100644 index 000000000..4eaf7c008 --- /dev/null +++ b/internal/forge/github/checks.go @@ -0,0 +1,82 @@ +package github + +import ( + "context" + "fmt" + + "github.com/shurcooL/githubv4" + "go.abhg.dev/gs/internal/forge" +) + +// GitHub StatusState values. +// +// https://docs.github.com/en/graphql/reference/enums#statusstate +const ( + statusStateError = "ERROR" + statusStateExpected = "EXPECTED" + statusStateFailure = "FAILURE" + statusStatePending = "PENDING" + statusStateSuccess = "SUCCESS" +) + +// ChangeChecksState reports the aggregate CI/checks state +// for the given pull request. +func (r *Repository) ChangeChecksState( + ctx context.Context, fid forge.ChangeID, +) (forge.ChecksState, error) { + pr := mustPR(fid) + gqlID, err := r.graphQLID(ctx, pr) + if err != nil { + return 0, fmt.Errorf("resolve PR ID: %w", err) + } + + return r.queryChecksRollup(ctx, gqlID) +} + +func (r *Repository) queryChecksRollup( + ctx context.Context, gqlID githubv4.ID, +) (forge.ChecksState, error) { + var q struct { + Node struct { + PullRequest struct { + Commits struct { + Nodes []struct { + Commit struct { + StatusCheckRollup *struct { + State string + } + } + } + } `graphql:"commits(last: 1)"` + } `graphql:"... on PullRequest"` + } `graphql:"node(id: $id)"` + } + + err := r.client.Query(ctx, &q, map[string]any{ + "id": gqlID, + }) + if err != nil { + return 0, fmt.Errorf("query status checks: %w", err) + } + + commits := q.Node.PullRequest.Commits.Nodes + if len(commits) == 0 { + return forge.ChecksPassed, nil + } + + rollup := commits[0].Commit.StatusCheckRollup + if rollup == nil { + return forge.ChecksPassed, nil // no checks configured + } + + switch rollup.State { + case statusStateSuccess: + return forge.ChecksPassed, nil + case statusStatePending, statusStateExpected: + return forge.ChecksPending, nil + case statusStateError, statusStateFailure: + return forge.ChecksFailed, nil + default: + return forge.ChecksFailed, nil + } +} diff --git a/internal/forge/github/merge.go b/internal/forge/github/merge.go new file mode 100644 index 000000000..00c288c1a --- /dev/null +++ b/internal/forge/github/merge.go @@ -0,0 +1,51 @@ +package github + +import ( + "context" + "fmt" + + "github.com/shurcooL/githubv4" + "go.abhg.dev/gs/internal/forge" +) + +// MergeChange merges an open pull request into its base branch. +func (r *Repository) MergeChange( + ctx context.Context, fid forge.ChangeID, + opts forge.MergeChangeOptions, +) error { + id := mustPR(fid) + + gqlID, err := r.graphQLID(ctx, id) + if err != nil { + return fmt.Errorf("resolve PR ID: %w", err) + } + + return r.mergePullRequest(ctx, id, gqlID, opts) +} + +func (r *Repository) mergePullRequest( + ctx context.Context, id *PR, gqlID githubv4.ID, + opts forge.MergeChangeOptions, +) error { + var m struct { + MergePullRequest struct { + PullRequest struct { + ID githubv4.ID `graphql:"id"` + } `graphql:"pullRequest"` + } `graphql:"mergePullRequest(input: $input)"` + } + + input := githubv4.MergePullRequestInput{ + PullRequestID: gqlID, + } + if opts.HeadHash != "" { + oid := githubv4.GitObjectID(opts.HeadHash) + input.ExpectedHeadOid = &oid + } + if err := r.client.Mutate(ctx, &m, input, nil); err != nil { + return fmt.Errorf("merge pull request: %w", err) + } + + r.log.Debug("Merged pull request", "pr", id.Number) + return nil +} diff --git a/internal/forge/github/repository_int_test.go b/internal/forge/github/repository_int_test.go index fb09e2061..b20f5a769 100644 --- a/internal/forge/github/repository_int_test.go +++ b/internal/forge/github/repository_int_test.go @@ -5,28 +5,16 @@ import ( "fmt" "github.com/shurcooL/githubv4" + "go.abhg.dev/gs/internal/forge" ) // NewRepository re-exports the private NewRepository function // for testing. var NewRepository = newRepository +// MergeChange merges a pull request using the production method. func MergeChange(ctx context.Context, repo *Repository, id *PR) error { - var m struct { - MergePullRequest struct { - PullRequest struct { - ID githubv4.ID `graphql:"id"` - } `graphql:"pullRequest"` - } `graphql:"mergePullRequest(input: $input)"` - } - input := githubv4.MergePullRequestInput{PullRequestID: id.GQLID} - - if err := repo.client.Mutate(ctx, &m, input, nil); err != nil { - return fmt.Errorf("merge pull request: %w", err) - } - - repo.log.Debug("Merged pull request", "pr", id.Number) - return nil + return repo.MergeChange(ctx, id, forge.MergeChangeOptions{}) } func CloseChange(ctx context.Context, repo *Repository, id *PR) error { diff --git a/internal/forge/gitlab/checks.go b/internal/forge/gitlab/checks.go new file mode 100644 index 000000000..c1257edd3 --- /dev/null +++ b/internal/forge/gitlab/checks.go @@ -0,0 +1,42 @@ +package gitlab + +import ( + "context" + "fmt" + + "go.abhg.dev/gs/internal/forge" + "go.abhg.dev/gs/internal/gateway/gitlab" +) + +// ChangeChecksState reports the aggregate CI pipeline state +// for the given merge request. +func (r *Repository) ChangeChecksState( + ctx context.Context, fid forge.ChangeID, +) (forge.ChecksState, error) { + id := mustMR(fid) + mr, _, err := r.client.MergeRequestGet( + ctx, r.repoID, id.Number, nil, + ) + if err != nil { + return 0, fmt.Errorf("get merge request: %w", err) + } + + return pipelineState(mr.HeadPipeline), nil +} + +func pipelineState( + pipeline *gitlab.Pipeline, +) forge.ChecksState { + if pipeline == nil { + return forge.ChecksPassed // no CI configured + } + + switch pipeline.Status { + case gitlab.PipelineStatusSuccess, gitlab.PipelineStatusSkipped: + return forge.ChecksPassed + case gitlab.PipelineStatusFailed, gitlab.PipelineStatusCanceled: + return forge.ChecksFailed + default: + return forge.ChecksPending + } +} diff --git a/internal/forge/gitlab/merge.go b/internal/forge/gitlab/merge.go new file mode 100644 index 000000000..9033bdf86 --- /dev/null +++ b/internal/forge/gitlab/merge.go @@ -0,0 +1,32 @@ +package gitlab + +import ( + "context" + "fmt" + + "go.abhg.dev/gs/internal/forge" + "go.abhg.dev/gs/internal/gateway/gitlab" +) + +// MergeChange merges an open merge request into its base branch. +func (r *Repository) MergeChange( + ctx context.Context, fid forge.ChangeID, + opts forge.MergeChangeOptions, +) error { + id := mustMR(fid) + + mrOpts := &gitlab.AcceptMergeRequestOptions{} + if opts.HeadHash != "" { + sha := string(opts.HeadHash) + mrOpts.SHA = &sha + } + + if _, _, err := r.client.MergeRequestAccept( + ctx, r.repoID, id.Number, mrOpts, + ); err != nil { + return fmt.Errorf("merge merge request: %w", err) + } + + r.log.Debug("Merged merge request", "mr", id.Number) + return nil +} diff --git a/internal/forge/gitlab/repository_int_test.go b/internal/forge/gitlab/repository_int_test.go index d04ee0c68..b3a7285d7 100644 --- a/internal/forge/gitlab/repository_int_test.go +++ b/internal/forge/gitlab/repository_int_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "go.abhg.dev/gs/internal/forge" "go.abhg.dev/gs/internal/gateway/gitlab" ) @@ -18,18 +19,9 @@ func RepositoryProjectID(repo *Repository) int64 { return repo.repoID } +// MergeChange merges a merge request using the production method. func MergeChange(ctx context.Context, repo *Repository, id *MR) error { - _, _, err := repo.client.MergeRequestAccept( - ctx, - repo.repoID, - id.Number, - &gitlab.AcceptMergeRequestOptions{}, - ) - if err != nil { - return fmt.Errorf("merge merge request: %w", err) - } - repo.log.Debug("Merged merge request", "mr", id.Number) - return nil + return repo.MergeChange(ctx, id, forge.MergeChangeOptions{}) } func CloseChange(ctx context.Context, repo *Repository, id *MR) error { diff --git a/internal/forge/shamhub/checks.go b/internal/forge/shamhub/checks.go new file mode 100644 index 000000000..7606faf18 --- /dev/null +++ b/internal/forge/shamhub/checks.go @@ -0,0 +1,15 @@ +package shamhub + +import ( + "context" + + "go.abhg.dev/gs/internal/forge" +) + +// ChangeChecksState always reports ChecksPassed. +// ShamHub does not simulate CI/checks. +func (r *forgeRepository) ChangeChecksState( + _ context.Context, _ forge.ChangeID, +) (forge.ChecksState, error) { + return forge.ChecksPassed, nil +} diff --git a/internal/forge/shamhub/cli.go b/internal/forge/shamhub/cli.go index e00f5ad42..d31e7c4fc 100644 --- a/internal/forge/shamhub/cli.go +++ b/internal/forge/shamhub/cli.go @@ -249,6 +249,30 @@ runCommand: ts.Logf("Forked %s/%s to %s", owner, repo, sh.RepoURL(forkOwner, repo)) + case "config": + if len(args) != 2 { + ts.Fatalf("usage: shamhub config ") + } + if sh == nil { + ts.Fatalf("ShamHub not initialized") + } + + key, value := args[0], args[1] + switch key { + case "mergeMethod": + mergeMethod, err := parseMergeMethod(value) + if err != nil { + ts.Fatalf("%s", err) + } + + sh.mu.Lock() + sh.defaultMergeMethod = mergeMethod + sh.mu.Unlock() + + default: + ts.Fatalf("unknown shamhub config key: %s", key) + } + case "merge": if sh == nil { ts.Fatalf("ShamHub not initialized") diff --git a/internal/forge/shamhub/shamhub.go b/internal/forge/shamhub/shamhub.go index d4ba63d1c..b72603c32 100644 --- a/internal/forge/shamhub/shamhub.go +++ b/internal/forge/shamhub/shamhub.go @@ -40,7 +40,8 @@ type ShamHub struct { comments []shamComment // all comments repos []shamRepo // all repositories - tokens map[string]string // token -> username + tokens map[string]string // token -> username + defaultMergeMethod MergeMethod // used when API merge requests omit a method } // Config configures a ShamHub server. @@ -74,10 +75,11 @@ func New(cfg Config) (*ShamHub, error) { } sh := ShamHub{ - log: cfg.Log.With("module", "shamhub"), - gitRoot: gitRoot, - gitExe: cfg.Git, - tokens: make(map[string]string), + log: cfg.Log.With("module", "shamhub"), + gitRoot: gitRoot, + gitExe: cfg.Git, + tokens: make(map[string]string), + defaultMergeMethod: MergeMethodMerge, } sh.apiServer = httptest.NewServer(sh.apiHandler()) sh.gitServer = httptest.NewServer(&cgi.Handler{ diff --git a/internal/forge/shamhub/states.go b/internal/forge/shamhub/states.go index 959e647f6..93e873394 100644 --- a/internal/forge/shamhub/states.go +++ b/internal/forge/shamhub/states.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "strconv" "strings" "time" @@ -126,10 +127,42 @@ type MergeChangeRequest struct { // should be deleted after the merge. DeleteBranch bool + // MergeMethod controls how the CR is merged. + // If empty, MergeChange uses the normal merge commit behavior. + MergeMethod MergeMethod + // Squash requests that the CR be merged // as a single squashed commit with the PR subject/body // instead of a merge commit. Squash bool + + // HeadHash, if non-empty, causes the merge to fail + // if the change's head doesn't match this hash. + HeadHash string +} + +// MergeMethod names a server-side merge strategy. +type MergeMethod string + +const ( + // MergeMethodMerge creates a two-parent merge commit. + MergeMethodMerge MergeMethod = "merge" + + // MergeMethodSquash creates a single-parent squashed commit. + MergeMethodSquash MergeMethod = "squash" +) + +func parseMergeMethod(value string) (MergeMethod, error) { + switch MergeMethod(value) { + case MergeMethodMerge, MergeMethodSquash: + return MergeMethod(value), nil + default: + return "", fmt.Errorf("unsupported mergeMethod %q", value) + } +} + +func (m MergeMethod) squash() bool { + return m == MergeMethodSquash } // MergeChange merges an open change against this forge. @@ -144,6 +177,15 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error { if req.CommitterEmail == "" { req.CommitterEmail = "shamhub@example.com" } + if req.MergeMethod == "" { + req.MergeMethod = MergeMethodMerge + } + if req.Squash { + req.MergeMethod = MergeMethodSquash + } + if _, err := parseMergeMethod(string(req.MergeMethod)); err != nil { + return err + } commitEnv := []string{ "GIT_COMMITTER_NAME=" + req.CommitterName, @@ -189,6 +231,25 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + // If a HeadHash is provided, verify the head matches. + if req.HeadHash != "" { + headRepoDir := sh.repoDir(headRef.Owner, headRef.Repo) + out, err := xec.Command(ctx, sh.log, sh.gitExe, + "rev-parse", headRef.Name). + WithDir(headRepoDir). + Output() + if err != nil { + return fmt.Errorf("resolve head ref: %w", err) + } + actual := strings.TrimSpace(string(out)) + if actual != req.HeadHash { + return fmt.Errorf( + "head hash mismatch: expected %s, got %s", + req.HeadHash, actual, + ) + } + } + // If head is in a different repository (fork), fetch it. if headRef.Owner != req.Owner || headRef.Repo != req.Repo { // Fetch the head branch from the fork @@ -228,7 +289,7 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error { var msg string args := []string{"commit-tree", "-p", baseRef.Name} - if req.Squash { + if req.MergeMethod.squash() { msg = fmt.Sprintf("%s (#%d)\n\n%s", change.Subject, req.Number, @@ -301,3 +362,67 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error { sh.changes[changeIdx].HeadHash = headHash return nil } + +// REST endpoint: merge a change. + +type mergeChangeRequest struct { + Owner string `path:"owner" json:"-"` + Repo string `path:"repo" json:"-"` + Number int `path:"number" json:"-"` + HeadHash string `json:"headHash,omitempty"` + MergeMethod string `json:"mergeMethod,omitempty"` +} + +type mergeChangeResponse struct{} + +var _ = shamhubRESTHandler( + "POST /{owner}/{repo}/change/{number}/merge", + (*ShamHub).handleMergeChange, +) + +func (sh *ShamHub) handleMergeChange( + _ context.Context, req *mergeChangeRequest, +) (*mergeChangeResponse, error) { + mergeMethod := MergeMethod(req.MergeMethod) + if mergeMethod == "" { + sh.mu.RLock() + mergeMethod = sh.defaultMergeMethod + sh.mu.RUnlock() + } else if _, err := parseMergeMethod(string(mergeMethod)); err != nil { + return nil, badRequestErrorf("%s", err) + } + + err := sh.MergeChange(MergeChangeRequest{ + Owner: req.Owner, + Repo: req.Repo, + Number: req.Number, + HeadHash: req.HeadHash, + MergeMethod: mergeMethod, + }) + if err != nil { + return nil, err + } + return &mergeChangeResponse{}, nil +} + +// MergeChange merges a change via the ShamHub REST API. +func (r *forgeRepository) MergeChange( + ctx context.Context, fid forge.ChangeID, + opts forge.MergeChangeOptions, +) error { + id := fid.(ChangeID) + u := r.apiURL.JoinPath( + r.owner, r.repo, + "change", strconv.Itoa(int(id)), "merge", + ) + + body := mergeChangeRequest{ + HeadHash: string(opts.HeadHash), + } + var res mergeChangeResponse + if err := r.client.Post(ctx, u.String(), body, &res); err != nil { + return fmt.Errorf("merge change: %w", err) + } + + return nil +} diff --git a/internal/gateway/bitbucket/api.go b/internal/gateway/bitbucket/api.go index 173a3e275..8f39708e8 100644 --- a/internal/gateway/bitbucket/api.go +++ b/internal/gateway/bitbucket/api.go @@ -358,6 +358,71 @@ func (c *Client) WorkspaceMemberList( return &response, resp, nil } +// PullRequestMerge merges an open pull request. +func (c *Client) PullRequestMerge( + ctx context.Context, + workspace string, + repo string, + prID int64, +) (*PullRequest, *Response, error) { + var response PullRequest + resp, err := c.post( + ctx, + fmt.Sprintf( + "/repositories/%s/%s/pullrequests/%d/merge", + workspace, repo, prID, + ), + nil, nil, &response, + ) + if err != nil { + return nil, resp, err + } + return &response, resp, nil +} + +// CommitStatus is a build status on a commit. +type CommitStatus struct { + State string `json:"state"` +} + +// Bitbucket Cloud build status states. +// +// https://developer.atlassian.com/cloud/bitbucket/rest/api-group-commit-statuses/ +const ( + CommitStatusSuccessful = "SUCCESSFUL" + CommitStatusInProgress = "INPROGRESS" + CommitStatusFailed = "FAILED" + CommitStatusStopped = "STOPPED" +) + +// CommitStatusList is the response for listing commit statuses. +type CommitStatusList struct { + Values []CommitStatus `json:"values"` + Next string `json:"next,omitempty"` +} + +// CommitStatusList lists build statuses for a commit. +func (c *Client) CommitStatusList( + ctx context.Context, + workspace string, + repo string, + commitHash string, +) (*CommitStatusList, *Response, error) { + var response CommitStatusList + resp, err := c.get( + ctx, + fmt.Sprintf( + "/repositories/%s/%s/commit/%s/statuses", + workspace, repo, commitHash, + ), + nil, &response, + ) + if err != nil { + return nil, resp, err + } + return &response, resp, nil +} + func buildPullRequestListRequest( workspace string, repo string, diff --git a/internal/gateway/gitlab/api.go b/internal/gateway/gitlab/api.go index ffb34ea36..9c5a975cd 100644 --- a/internal/gateway/gitlab/api.go +++ b/internal/gateway/gitlab/api.go @@ -480,8 +480,34 @@ type BasicMergeRequest struct { // https://docs.gitlab.com/api/merge_requests/ type MergeRequest struct { BasicMergeRequest + HeadPipeline *Pipeline `json:"head_pipeline,omitempty"` } +// Pipeline is a GitLab CI pipeline status summary. +// +// GitLab pipelines API: +// https://docs.gitlab.com/api/pipelines/ +type Pipeline struct { + Status string `json:"status"` +} + +// GitLab pipeline status values. +// +// https://docs.gitlab.com/api/pipelines/ +const ( + PipelineStatusCreated = "created" + PipelineStatusWaitingForResource = "waiting_for_resource" + PipelineStatusPreparing = "preparing" + PipelineStatusPending = "pending" + PipelineStatusRunning = "running" + PipelineStatusSuccess = "success" + PipelineStatusFailed = "failed" + PipelineStatusCanceled = "canceled" + PipelineStatusSkipped = "skipped" + PipelineStatusManual = "manual" + PipelineStatusScheduled = "scheduled" +) + // NoteAuthor matches the nested author object in note responses. // // GitLab notes API: @@ -617,7 +643,8 @@ func (o *ListProjectMergeRequestsOptions) encodeQuery() url.Values { // AcceptMergeRequestOptions configures merge-request acceptance. type AcceptMergeRequestOptions struct { - ShouldRemoveSourceBranch *bool `json:"should_remove_source_branch,omitempty"` + ShouldRemoveSourceBranch *bool `json:"should_remove_source_branch,omitempty"` + SHA *string `json:"sha,omitempty"` } // CreateMergeRequestNoteOptions configures note creation. From cf7dbd7c3252a4ad2b0d05cae3afb92bb87745e9 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Sun, 31 May 2026 06:04:17 -0700 Subject: [PATCH 2/3] test(forge): Add checks-state integration Checks-state support needs replayable coverage that exercises each forge boundary without relying on manually configured CI jobs. Add a shared integration scenario that submits fresh changes and asks each provider test harness to install pending, passed, and failed checks state. ShamHub now models that state directly and exposes `shamhub set-status` for script tests, while GitHub, GitLab, and Bitbucket use provider status APIs for fixture recording. --- internal/forge/bitbucket/integration_test.go | 18 ++ .../forge/bitbucket/repository_int_test.go | 42 ++++ internal/forge/forgetest/integration.go | 92 +++++++++ internal/forge/github/integration_test.go | 92 +++++++++ .../ChangeChecksState/Failed/branch | 1 + .../ChangeChecksState/Failed/headHash | 1 + .../ChangeChecksState/Passed/branch | 1 + .../ChangeChecksState/Passed/headHash | 1 + .../ChangeChecksState/Pending/branch | 1 + .../ChangeChecksState/Pending/headHash | 1 + .../ChangeChecksState/Failed.yaml | 109 +++++++++++ .../ChangeChecksState/Passed.yaml | 109 +++++++++++ .../ChangeChecksState/Pending.yaml | 111 +++++++++++ internal/forge/gitlab/integration_test.go | 45 +++++ .../ChangeChecksState/Failed/branch | 1 + .../ChangeChecksState/Failed/headHash | 1 + .../ChangeChecksState/Passed/branch | 1 + .../ChangeChecksState/Passed/headHash | 1 + .../ChangeChecksState/Pending/branch | 1 + .../ChangeChecksState/Pending/headHash | 1 + .../ChangeChecksState/Failed.yaml | 136 +++++++++++++ .../ChangeChecksState/Passed.yaml | 136 +++++++++++++ .../ChangeChecksState/Pending.yaml | 136 +++++++++++++ internal/forge/shamhub/change.go | 3 + internal/forge/shamhub/checks.go | 172 ++++++++++++++++- internal/forge/shamhub/cli.go | 25 +++ internal/forge/shamhub/integration_test.go | 15 ++ .../ChangeChecksState/Failed/branch | 1 + .../ChangeChecksState/Failed/headHash | 1 + .../ChangeChecksState/Passed/branch | 1 + .../ChangeChecksState/Passed/headHash | 1 + .../ChangeChecksState/Pending/branch | 1 + .../ChangeChecksState/Pending/headHash | 1 + .../UpdateComment/updated-comment | 2 +- .../TestIntegration/ChangeComments/branch | 2 +- .../TestIntegration/ChangeComments/comments | 20 +- .../ChangesStates/closedBranch | 2 +- .../ChangesStates/mergedBranch | 2 +- .../TestIntegration/ChangesStates/openBranch | 2 +- .../CommentCountsByChange/branch | 2 +- .../TemplatesPresent/empty-template | 2 +- .../TemplatesPresent/non-empty-template | 2 +- .../SubmitBaseDoesNotExist/base-branch | 2 +- .../SubmitBaseDoesNotExist/branch | 2 +- .../fork-branch | 2 +- .../forkCommitHash | 2 +- .../AddAssignee/branch-no-assignee | 2 +- .../branch-no-assignee-one-by-one | 2 +- .../SubmitWithAssignee/branch-with-assignee | 2 +- .../TestIntegration/SubmitEditBase/base | 2 +- .../TestIntegration/SubmitEditBase/branch | 2 +- .../TestIntegration/SubmitEditChange/branch | 2 +- .../SubmitEditChange/firstCommitHash | 2 +- .../TestIntegration/SubmitEditDraft/branch | 2 +- .../TestIntegration/SubmitEditLabels/branch | 2 +- .../TestIntegration/SubmitEditLabels/label1 | 2 +- .../TestIntegration/SubmitEditLabels/label2 | 2 +- .../TestIntegration/SubmitEditLabels/label3 | 2 +- .../AddReviewer/branch-no-reviewer | 2 +- .../branch-no-reviewer-one-by-one | 2 +- .../SubmitWithReviewer/branch-with-reviewer | 2 +- .../shamhub/testdata/TestIntegration/apiURL | 2 +- .../shamhub/testdata/TestIntegration/gitURL | 2 +- .../testdata/TestIntegration/pushRepoURL | 2 +- .../shamhub/testdata/TestIntegration/repoURL | 2 +- .../shamhub/testdata/TestIntegration/token | 2 +- .../ChangeChecksState/Failed.yaml | 82 ++++++++ .../ChangeChecksState/Passed.yaml | 82 ++++++++ .../ChangeChecksState/Pending.yaml | 82 ++++++++ .../TestIntegration/ChangeComments.yaml | 180 +++++++++--------- .../TestIntegration/ChangesStates.yaml | 60 +++--- .../CommentCountsByChange.yaml | 16 +- .../FindChangesByBranchDoesNotExist.yaml | 6 +- .../ListChangeTemplates/NoTemplates.yaml | 6 +- .../ListChangeTemplates/TemplatesPresent.yaml | 14 +- .../SubmitBaseDoesNotExist.yaml | 16 +- .../SubmitChangeFromPushRepository.yaml | 66 +++---- .../SubmitEditAssignees/AddAssignee.yaml | 54 +++--- .../AddAssigneesOneByOne.yaml | 50 ++--- .../SubmitWithAssignee.yaml | 48 ++--- .../TestIntegration/SubmitEditBase.yaml | 56 +++--- .../TestIntegration/SubmitEditChange.yaml | 48 ++--- .../TestIntegration/SubmitEditDraft.yaml | 78 ++++---- .../TestIntegration/SubmitEditLabels.yaml | 72 +++---- .../SubmitEditReviewers/AddReviewer.yaml | 54 +++--- .../AddReviewersOneByOne.yaml | 60 +++--- .../SubmitWithReviewer.yaml | 30 +-- internal/gateway/bitbucket/api.go | 31 +++ internal/gateway/bitbucket/api_test.go | 72 +++++++ internal/gateway/gitlab/api.go | 39 ++++ internal/gateway/gitlab/api_test.go | 60 ++++++ 91 files changed, 2202 insertions(+), 503 deletions(-) create mode 100644 internal/forge/github/testdata/TestIntegration/ChangeChecksState/Failed/branch create mode 100644 internal/forge/github/testdata/TestIntegration/ChangeChecksState/Failed/headHash create mode 100644 internal/forge/github/testdata/TestIntegration/ChangeChecksState/Passed/branch create mode 100644 internal/forge/github/testdata/TestIntegration/ChangeChecksState/Passed/headHash create mode 100644 internal/forge/github/testdata/TestIntegration/ChangeChecksState/Pending/branch create mode 100644 internal/forge/github/testdata/TestIntegration/ChangeChecksState/Pending/headHash create mode 100644 internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml create mode 100644 internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml create mode 100644 internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml create mode 100644 internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Failed/branch create mode 100644 internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Failed/headHash create mode 100644 internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Passed/branch create mode 100644 internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Passed/headHash create mode 100644 internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Pending/branch create mode 100644 internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Pending/headHash create mode 100644 internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml create mode 100644 internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml create mode 100644 internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml create mode 100644 internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Failed/branch create mode 100644 internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Failed/headHash create mode 100644 internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Passed/branch create mode 100644 internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Passed/headHash create mode 100644 internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Pending/branch create mode 100644 internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Pending/headHash create mode 100644 internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml create mode 100644 internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml create mode 100644 internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml diff --git a/internal/forge/bitbucket/integration_test.go b/internal/forge/bitbucket/integration_test.go index 006946cf1..107fe77ab 100644 --- a/internal/forge/bitbucket/integration_test.go +++ b/internal/forge/bitbucket/integration_test.go @@ -102,6 +102,24 @@ func TestIntegration(t *testing.T) { change.(*bitbucket.PR), )) }, + // TODO: record fixtures for BitBucket + // + // SetChangeChecksState: func( + // t *testing.T, + // _ *http.Client, + // repo forge.Repository, + // _ forge.ChangeID, + // headHash git.Hash, + // state forge.ChecksState, + // ) { + // require.NoError(t, + // bitbucket.SetChangeChecksState( + // t.Context(), + // repo.(*bitbucket.Repository), + // headHash, + // state, + // )) + // }, SetCommentsPageSize: bitbucket.SetListChangeCommentsPageSize, Reviewers: []string{cfg.Reviewer}, Assignees: []string{}, diff --git a/internal/forge/bitbucket/repository_int_test.go b/internal/forge/bitbucket/repository_int_test.go index da5f6521e..36f884139 100644 --- a/internal/forge/bitbucket/repository_int_test.go +++ b/internal/forge/bitbucket/repository_int_test.go @@ -4,6 +4,10 @@ import ( "context" "fmt" "net/http" + + "go.abhg.dev/gs/internal/forge" + bitbucketapi "go.abhg.dev/gs/internal/gateway/bitbucket" + "go.abhg.dev/gs/internal/git" ) func prActionPath( @@ -36,6 +40,44 @@ func MergeChange( return nil } +// SetChangeChecksState sets a synthetic build status +// for integration tests. +func SetChangeChecksState( + ctx context.Context, + repo *Repository, + headHash git.Hash, + state forge.ChecksState, +) error { + _, _, err := repo.client.CommitStatusCreate( + ctx, + repo.workspace, + repo.repo, + headHash.String(), + &bitbucketapi.CommitStatusCreateRequest{ + Key: "git-spice-integration", + State: bitbucketStatusState(state), + Description: "Synthetic status for git-spice integration tests", + }, + ) + if err != nil { + return fmt.Errorf("set commit status: %w", err) + } + return nil +} + +func bitbucketStatusState(state forge.ChecksState) string { + switch state { + case forge.ChecksPending: + return bitbucketapi.CommitStatusInProgress + case forge.ChecksPassed: + return bitbucketapi.CommitStatusSuccessful + case forge.ChecksFailed: + return bitbucketapi.CommitStatusFailed + default: + return bitbucketapi.CommitStatusFailed + } +} + func approvePR( ctx context.Context, repo *Repository, id *PR, ) error { diff --git a/internal/forge/forgetest/integration.go b/internal/forge/forgetest/integration.go index 7bccce7db..cabddf406 100644 --- a/internal/forge/forgetest/integration.go +++ b/internal/forge/forgetest/integration.go @@ -221,6 +221,17 @@ type ( repo forge.Repository, changeID forge.ChangeID, ) + + // SetChangeChecksStateFunc sets the aggregate checks state + // that a forge reports for a change. + SetChangeChecksStateFunc func( + t *testing.T, + httpClient *http.Client, + repo forge.Repository, + changeID forge.ChangeID, + headHash git.Hash, + state forge.ChecksState, + ) ) // IntegrationConfig configures a forge integration test run. @@ -248,6 +259,9 @@ type IntegrationConfig struct { // CloseChange closes a change without merging. CloseChange CloseChangeFunc // required + // SetChangeChecksState sets checks state for a change. + SetChangeChecksState SetChangeChecksStateFunc // optional + // Reviewers is a list of usernames that can be added as reviewers to changes. Reviewers []string // required @@ -316,6 +330,7 @@ func RunIntegration(t *testing.T, config IntegrationConfig) { openRepository: config.OpenRepository, MergeChange: config.MergeChange, CloseChange: config.CloseChange, + SetChangeChecksState: config.SetChangeChecksState, Reviewers: config.Reviewers, Assignees: config.Assignees, SetCommentsPageSize: config.SetCommentsPageSize, @@ -355,6 +370,14 @@ func RunIntegration(t *testing.T, config IntegrationConfig) { }) } + if config.SetChangeChecksState != nil { + t.Run("ChangeChecksState", func(t *testing.T) { + t.Parallel() + + suite.TestChangeChecksState(t) + }) + } + t.Run("FindChangesByBranchDoesNotExist", func(t *testing.T) { t.Parallel() @@ -446,6 +469,9 @@ type integrationSuite struct { // CloseChange closes a change without merging. CloseChange CloseChangeFunc + // SetChangeChecksState sets checks state for a change. + SetChangeChecksState SetChangeChecksStateFunc + // Reviewers is a list of usernames that can be added as reviewers to changes. Reviewers []string @@ -786,6 +812,72 @@ func (s *integrationSuite) TestChangeStates(t *testing.T) { assert.NotEmpty(t, statuses[2].HeadHash) } +// TestChangeChecksState verifies that forges report aggregate checks state +// for newly submitted changes. +func (s *integrationSuite) TestChangeChecksState(t *testing.T) { + tests := []struct { + name string + want forge.ChecksState + }{ + {name: "Pending", want: forge.ChecksPending}, + {name: "Passed", want: forge.ChecksPassed}, + {name: "Failed", want: forge.ChecksFailed}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + branchFixture := fixturetest.New(s.Fixtures, "branch", func() string { + return randomString(8) + }) + headHashFixture, setHeadHash := fixturetest.Stored[string]( + s.Fixtures, + "headHash", + ) + + branch := branchFixture.Get(t) + if Update() { + testRepo := newTestRepository(t, s.RemoteURL) + testRepo.CheckoutBranch("main") + testRepo.CreateBranch(branch) + testRepo.CheckoutBranch(branch) + testRepo.WriteFile(branch+".txt", randomString(32)) + hash := testRepo.AddAllAndCommit("commit for checks " + tt.name) + testRepo.Push(branch) + setHeadHash(hash.String()) + + t.Cleanup(func() { + testRepo.DeleteRemoteBranch(branch) + }) + } + + httpClient := s.HTTPClient(t) + repo := s.openRepository(t, httpClient) + headHash := git.Hash(headHashFixture.Get(t)) + + change, err := repo.SubmitChange(t.Context(), forge.SubmitChangeRequest{ + Subject: "Checks " + branch, + Body: "Checks state test", + Base: "main", + Head: branch, + }) + require.NoError(t, err, "error creating change") + + s.SetChangeChecksState( + t, + httpClient, + repo, + change.ID, + headHash, + tt.want, + ) + + got, err := repo.ChangeChecksState(t.Context(), change.ID) + require.NoError(t, err, "error fetching checks") + assert.Equal(t, tt.want, got) + }) + } +} + // FindChangesByBranch returns no error, and an empty slice // when the branch does not exist. func (s *integrationSuite) TestFindChangesByBranchDoesNotExist(t *testing.T) { diff --git a/internal/forge/github/integration_test.go b/internal/forge/github/integration_test.go index f433f396a..e86859d76 100644 --- a/internal/forge/github/integration_test.go +++ b/internal/forge/github/integration_test.go @@ -1,8 +1,12 @@ package github_test import ( + "bytes" "context" "crypto/rand" + "encoding/json" + "fmt" + "io" "net/http" "testing" @@ -13,6 +17,7 @@ import ( "go.abhg.dev/gs/internal/forge" "go.abhg.dev/gs/internal/forge/forgetest" "go.abhg.dev/gs/internal/forge/github" + "go.abhg.dev/gs/internal/git" "go.abhg.dev/gs/internal/graphqlutil" "go.abhg.dev/gs/internal/httptest" "go.abhg.dev/gs/internal/silog/silogtest" @@ -120,6 +125,23 @@ func TestIntegration(t *testing.T) { CloseChange: func(t *testing.T, repo forge.Repository, change forge.ChangeID) { require.NoError(t, github.CloseChange(t.Context(), repo.(*github.Repository), change.(*github.PR))) }, + SetChangeChecksState: func( + t *testing.T, + httpClient *http.Client, + _ forge.Repository, + _ forge.ChangeID, + headHash git.Hash, + state forge.ChecksState, + ) { + require.NoError(t, setGitHubChangeChecksState( + t.Context(), + httpClient, + cfg.Owner, + cfg.Repo, + headHash, + state, + )) + }, SetCommentsPageSize: github.SetListChangeCommentsPageSize, Reviewers: []string{cfg.Reviewer}, Assignees: []string{cfg.Assignee}, @@ -212,3 +234,73 @@ func randomString(n int) string { } return string(b) } + +func setGitHubChangeChecksState( + ctx context.Context, + httpClient *http.Client, + owner string, + repo string, + headHash git.Hash, + state forge.ChecksState, +) error { + // GitHub's GraphQL schema exposes the status rollup we read, + // but commit status creation remains a REST API operation. + // Check runs are a separate GitHub App-authenticated mechanism, + // so these tests create classic commit statuses instead. + body, err := json.Marshal(gitHubStatusRequest{ + State: gitHubStatusState(state), + Context: "git-spice integration", + Description: "Synthetic status for git-spice integration tests", + }) + if err != nil { + return fmt.Errorf("marshal status: %w", err) + } + + req, err := http.NewRequestWithContext( + ctx, + http.MethodPost, + fmt.Sprintf( + "https://api.github.com/repos/%s/%s/statuses/%s", + owner, repo, headHash, + ), + bytes.NewReader(body), + ) + if err != nil { + return fmt.Errorf("create request: %w", err) + } + req.Header.Set("Accept", "application/vnd.github+json") + req.Header.Set("Content-Type", "application/json") + + resp, err := httpClient.Do(req) + if err != nil { + return fmt.Errorf("post status: %w", err) + } + defer func() { + _ = resp.Body.Close() + }() + + if resp.StatusCode >= http.StatusBadRequest { + body, _ := io.ReadAll(resp.Body) + return fmt.Errorf("post status: %s: %s", resp.Status, body) + } + return nil +} + +type gitHubStatusRequest struct { + State string `json:"state"` + Context string `json:"context"` + Description string `json:"description"` +} + +func gitHubStatusState(state forge.ChecksState) string { + switch state { + case forge.ChecksPending: + return "pending" + case forge.ChecksPassed: + return "success" + case forge.ChecksFailed: + return "failure" + default: + return "error" + } +} diff --git a/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Failed/branch b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Failed/branch new file mode 100644 index 000000000..c6d4e685f --- /dev/null +++ b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Failed/branch @@ -0,0 +1 @@ +"yM56ezjo" \ No newline at end of file diff --git a/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Failed/headHash b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Failed/headHash new file mode 100644 index 000000000..aa7fa14d8 --- /dev/null +++ b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Failed/headHash @@ -0,0 +1 @@ +"9e6578e14024e1c59bb7f4f927f08e6c71d7bb02" \ No newline at end of file diff --git a/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Passed/branch b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Passed/branch new file mode 100644 index 000000000..5ba9e0c3f --- /dev/null +++ b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Passed/branch @@ -0,0 +1 @@ +"bahWsMYl" \ No newline at end of file diff --git a/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Passed/headHash b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Passed/headHash new file mode 100644 index 000000000..97f6f84c7 --- /dev/null +++ b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Passed/headHash @@ -0,0 +1 @@ +"5ec8ad693e18267d3bb6fa27e31e0cee2a44d70b" \ No newline at end of file diff --git a/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Pending/branch b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Pending/branch new file mode 100644 index 000000000..f5ed2b96c --- /dev/null +++ b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Pending/branch @@ -0,0 +1 @@ +"OMAT1uZX" \ No newline at end of file diff --git a/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Pending/headHash b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Pending/headHash new file mode 100644 index 000000000..d332bd21c --- /dev/null +++ b/internal/forge/github/testdata/TestIntegration/ChangeChecksState/Pending/headHash @@ -0,0 +1 @@ +"263e2c55f2fc94fc690736b264550850b111f38c" \ No newline at end of file diff --git a/internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml b/internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml new file mode 100644 index 000000000..6042d1e6e --- /dev/null +++ b/internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml @@ -0,0 +1,109 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 142 + host: api.github.com + body: | + {"query":"query($owner:String!$repo:String!){repository(owner: $owner, name: $repo){id}}","variables":{"owner":"test-owner","repo":"test-repo"}} + headers: + Content-Type: + - application/json + url: https://api.github.com/graphql + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + body: '{"data":{"repository":{"id":"R_kgDOMVd0xg"}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 376.24475ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 268 + host: api.github.com + body: | + {"query":"mutation($input:CreatePullRequestInput!){createPullRequest(input: $input){pullRequest{id,number,url}}}","variables":{"input":{"repositoryId":"R_kgDOMVd0xg","baseRefName":"main","headRefName":"yM56ezjo","title":"Checks yM56ezjo","body":"Checks state test"}}} + headers: + Content-Type: + - application/json + url: https://api.github.com/graphql + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"data":{"createPullRequest":{"pullRequest":{"id":"PR_kwDOMVd0xs7hF5ly","number":89,"url":"https://github.com/test-owner/test-repo/pull/89"}}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 991.140167ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 118 + host: api.github.com + body: '{"state":"failure","context":"git-spice integration","description":"Synthetic status for git-spice integration tests"}' + headers: + Content-Type: + - application/json + url: https://api.github.com/repos/test-owner/test-repo/statuses/9e6578e14024e1c59bb7f4f927f08e6c71d7bb02 + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: 1434 + body: '{"url":"https://api.github.com/repos/test-owner/test-repo/statuses/9e6578e14024e1c59bb7f4f927f08e6c71d7bb02","avatar_url":"https://avatars.githubusercontent.com/oa/1157143?v=4","id":48196548162,"node_id":"SC_kwDOMVd0xs8AAAALOLz2Qg","state":"failure","description":"Synthetic status for git-spice integration tests","target_url":null,"context":"git-spice integration","created_at":"2026-05-31T13:05:20Z","updated_at":"2026-05-31T13:05:20Z","creator":{"login":"test-owner-robot","id":187913561,"node_id":"U_kgDOCzNVWQ","avatar_url":"https://avatars.githubusercontent.com/u/187913561?v=4","gravatar_id":"","url":"https://api.github.com/users/test-owner-robot","html_url":"https://github.com/test-owner-robot","followers_url":"https://api.github.com/users/test-owner-robot/followers","following_url":"https://api.github.com/users/test-owner-robot/following{/other_user}","gists_url":"https://api.github.com/users/test-owner-robot/gists{/gist_id}","starred_url":"https://api.github.com/users/test-owner-robot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/test-owner-robot/subscriptions","organizations_url":"https://api.github.com/users/test-owner-robot/orgs","repos_url":"https://api.github.com/users/test-owner-robot/repos","events_url":"https://api.github.com/users/test-owner-robot/events{/privacy}","received_events_url":"https://api.github.com/users/test-owner-robot/received_events","type":"User","user_view_type":"public","site_admin":false}}' + headers: + Content-Length: + - "1434" + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 555.79575ms + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 162 + host: api.github.com + body: | + {"query":"query($id:ID!){node(id: $id){... on PullRequest{commits(last: 1){nodes{commit{statusCheckRollup{state}}}}}}}","variables":{"id":"PR_kwDOMVd0xs7hF5ly"}} + headers: + Content-Type: + - application/json + url: https://api.github.com/graphql + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + body: '{"data":{"node":{"commits":{"nodes":[{"commit":{"statusCheckRollup":{"state":"FAILURE"}}}]}}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 394.533208ms diff --git a/internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml b/internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml new file mode 100644 index 000000000..0b1708c1f --- /dev/null +++ b/internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml @@ -0,0 +1,109 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 142 + host: api.github.com + body: | + {"query":"query($owner:String!$repo:String!){repository(owner: $owner, name: $repo){id}}","variables":{"owner":"test-owner","repo":"test-repo"}} + headers: + Content-Type: + - application/json + url: https://api.github.com/graphql + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"data":{"repository":{"id":"R_kgDOMVd0xg"}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 224.609208ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 268 + host: api.github.com + body: | + {"query":"mutation($input:CreatePullRequestInput!){createPullRequest(input: $input){pullRequest{id,number,url}}}","variables":{"input":{"repositoryId":"R_kgDOMVd0xg","baseRefName":"main","headRefName":"bahWsMYl","title":"Checks bahWsMYl","body":"Checks state test"}}} + headers: + Content-Type: + - application/json + url: https://api.github.com/graphql + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + body: '{"data":{"createPullRequest":{"pullRequest":{"id":"PR_kwDOMVd0xs7hF5i6","number":88,"url":"https://github.com/test-owner/test-repo/pull/88"}}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 1.121566292s + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 118 + host: api.github.com + body: '{"state":"success","context":"git-spice integration","description":"Synthetic status for git-spice integration tests"}' + headers: + Content-Type: + - application/json + url: https://api.github.com/repos/test-owner/test-repo/statuses/5ec8ad693e18267d3bb6fa27e31e0cee2a44d70b + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: 1434 + body: '{"url":"https://api.github.com/repos/test-owner/test-repo/statuses/5ec8ad693e18267d3bb6fa27e31e0cee2a44d70b","avatar_url":"https://avatars.githubusercontent.com/oa/1157143?v=4","id":48196546390,"node_id":"SC_kwDOMVd0xs8AAAALOLzvVg","state":"success","description":"Synthetic status for git-spice integration tests","target_url":null,"context":"git-spice integration","created_at":"2026-05-31T13:05:14Z","updated_at":"2026-05-31T13:05:14Z","creator":{"login":"test-owner-robot","id":187913561,"node_id":"U_kgDOCzNVWQ","avatar_url":"https://avatars.githubusercontent.com/u/187913561?v=4","gravatar_id":"","url":"https://api.github.com/users/test-owner-robot","html_url":"https://github.com/test-owner-robot","followers_url":"https://api.github.com/users/test-owner-robot/followers","following_url":"https://api.github.com/users/test-owner-robot/following{/other_user}","gists_url":"https://api.github.com/users/test-owner-robot/gists{/gist_id}","starred_url":"https://api.github.com/users/test-owner-robot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/test-owner-robot/subscriptions","organizations_url":"https://api.github.com/users/test-owner-robot/orgs","repos_url":"https://api.github.com/users/test-owner-robot/repos","events_url":"https://api.github.com/users/test-owner-robot/events{/privacy}","received_events_url":"https://api.github.com/users/test-owner-robot/received_events","type":"User","user_view_type":"public","site_admin":false}}' + headers: + Content-Length: + - "1434" + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 511.119458ms + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 162 + host: api.github.com + body: | + {"query":"query($id:ID!){node(id: $id){... on PullRequest{commits(last: 1){nodes{commit{statusCheckRollup{state}}}}}}}","variables":{"id":"PR_kwDOMVd0xs7hF5i6"}} + headers: + Content-Type: + - application/json + url: https://api.github.com/graphql + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + body: '{"data":{"node":{"commits":{"nodes":[{"commit":{"statusCheckRollup":{"state":"SUCCESS"}}}]}}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 412.8945ms diff --git a/internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml b/internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml new file mode 100644 index 000000000..98e266f96 --- /dev/null +++ b/internal/forge/github/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml @@ -0,0 +1,111 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 142 + host: api.github.com + body: | + {"query":"query($owner:String!$repo:String!){repository(owner: $owner, name: $repo){id}}","variables":{"owner":"test-owner","repo":"test-repo"}} + headers: + Content-Type: + - application/json + url: https://api.github.com/graphql + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"data":{"repository":{"id":"R_kgDOMVd0xg"}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 297.691167ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 268 + host: api.github.com + body: | + {"query":"mutation($input:CreatePullRequestInput!){createPullRequest(input: $input){pullRequest{id,number,url}}}","variables":{"input":{"repositoryId":"R_kgDOMVd0xg","baseRefName":"main","headRefName":"OMAT1uZX","title":"Checks OMAT1uZX","body":"Checks state test"}}} + headers: + Content-Type: + - application/json + url: https://api.github.com/graphql + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"data":{"createPullRequest":{"pullRequest":{"id":"PR_kwDOMVd0xs7hF5gH","number":87,"url":"https://github.com/test-owner/test-repo/pull/87"}}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 1.262561833s + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 118 + host: api.github.com + body: '{"state":"pending","context":"git-spice integration","description":"Synthetic status for git-spice integration tests"}' + headers: + Content-Type: + - application/json + url: https://api.github.com/repos/test-owner/test-repo/statuses/263e2c55f2fc94fc690736b264550850b111f38c + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: 1434 + body: '{"url":"https://api.github.com/repos/test-owner/test-repo/statuses/263e2c55f2fc94fc690736b264550850b111f38c","avatar_url":"https://avatars.githubusercontent.com/oa/1157143?v=4","id":48196545020,"node_id":"SC_kwDOMVd0xs8AAAALOLzp_A","state":"pending","description":"Synthetic status for git-spice integration tests","target_url":null,"context":"git-spice integration","created_at":"2026-05-31T13:05:09Z","updated_at":"2026-05-31T13:05:09Z","creator":{"login":"test-owner-robot","id":187913561,"node_id":"U_kgDOCzNVWQ","avatar_url":"https://avatars.githubusercontent.com/u/187913561?v=4","gravatar_id":"","url":"https://api.github.com/users/test-owner-robot","html_url":"https://github.com/test-owner-robot","followers_url":"https://api.github.com/users/test-owner-robot/followers","following_url":"https://api.github.com/users/test-owner-robot/following{/other_user}","gists_url":"https://api.github.com/users/test-owner-robot/gists{/gist_id}","starred_url":"https://api.github.com/users/test-owner-robot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/test-owner-robot/subscriptions","organizations_url":"https://api.github.com/users/test-owner-robot/orgs","repos_url":"https://api.github.com/users/test-owner-robot/repos","events_url":"https://api.github.com/users/test-owner-robot/events{/privacy}","received_events_url":"https://api.github.com/users/test-owner-robot/received_events","type":"User","user_view_type":"public","site_admin":false}}' + headers: + Content-Length: + - "1434" + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 397.670333ms + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 162 + host: api.github.com + body: | + {"query":"query($id:ID!){node(id: $id){... on PullRequest{commits(last: 1){nodes{commit{statusCheckRollup{state}}}}}}}","variables":{"id":"PR_kwDOMVd0xs7hF5gH"}} + headers: + Content-Type: + - application/json + url: https://api.github.com/graphql + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"data":{"node":{"commits":{"nodes":[{"commit":{"statusCheckRollup":{"state":"PENDING"}}}]}}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 420.510416ms diff --git a/internal/forge/gitlab/integration_test.go b/internal/forge/gitlab/integration_test.go index a22395abd..9d3542ed5 100644 --- a/internal/forge/gitlab/integration_test.go +++ b/internal/forge/gitlab/integration_test.go @@ -8,6 +8,7 @@ import ( "os/exec" "path/filepath" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -119,6 +120,37 @@ func TestIntegration(t *testing.T) { CloseChange: func(t *testing.T, repo forge.Repository, change forge.ChangeID) { require.NoError(t, gitlabforge.CloseChange(t.Context(), repo.(*gitlabforge.Repository), change.(*gitlabforge.MR))) }, + SetChangeChecksState: func( + t *testing.T, + httpClient *http.Client, + repo forge.Repository, + _ forge.ChangeID, + headHash git.Hash, + state forge.ChecksState, + ) { + client := newGitLabClient(t, httpClient) + name := "git-spice integration" + description := "Synthetic status for git-spice integration tests" + status := gitLabStatusState(state) + _, _, err := client.CommitStatusSet( + t.Context(), + gitlabforge.RepositoryProjectID( + repo.(*gitlabforge.Repository), + ), + headHash.String(), + &gitlab.SetCommitStatusOptions{ + State: &status, + Name: &name, + Description: &description, + }, + ) + require.NoError(t, err) + if forgetest.Update() { + // GitLab accepts external commit statuses before the + // merge-request head_pipeline field reflects them. + time.Sleep(2 * time.Second) + } + }, SetCommentsPageSize: gitlabforge.SetListChangeCommentsPageSize, BaseBranchMayBeAbsent: true, SkipMerge: true, // Merge requires MR approval settings to be disabled @@ -250,3 +282,16 @@ func randomString(n int) string { } return string(b) } + +func gitLabStatusState(state forge.ChecksState) string { + switch state { + case forge.ChecksPending: + return gitlab.PipelineStatusPending + case forge.ChecksPassed: + return gitlab.PipelineStatusSuccess + case forge.ChecksFailed: + return gitlab.PipelineStatusFailed + default: + return gitlab.PipelineStatusFailed + } +} diff --git a/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Failed/branch b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Failed/branch new file mode 100644 index 000000000..928a08447 --- /dev/null +++ b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Failed/branch @@ -0,0 +1 @@ +"ympFgY6M" \ No newline at end of file diff --git a/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Failed/headHash b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Failed/headHash new file mode 100644 index 000000000..d59e45f1f --- /dev/null +++ b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Failed/headHash @@ -0,0 +1 @@ +"b193787743c8cfa916e42eed609781723a8b5fb7" \ No newline at end of file diff --git a/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Passed/branch b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Passed/branch new file mode 100644 index 000000000..8e3bcd968 --- /dev/null +++ b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Passed/branch @@ -0,0 +1 @@ +"Mnz6SoOh" \ No newline at end of file diff --git a/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Passed/headHash b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Passed/headHash new file mode 100644 index 000000000..f13e828fd --- /dev/null +++ b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Passed/headHash @@ -0,0 +1 @@ +"5edcba5cbe947db2e38e86c8819a8cdc86229b08" \ No newline at end of file diff --git a/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Pending/branch b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Pending/branch new file mode 100644 index 000000000..48459cb55 --- /dev/null +++ b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Pending/branch @@ -0,0 +1 @@ +"94pBee7g" \ No newline at end of file diff --git a/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Pending/headHash b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Pending/headHash new file mode 100644 index 000000000..886d42ad8 --- /dev/null +++ b/internal/forge/gitlab/testdata/TestIntegration/ChangeChecksState/Pending/headHash @@ -0,0 +1 @@ +"25609dfe1a0fe25ecae61e88823987049b139265" \ No newline at end of file diff --git a/internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml b/internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml new file mode 100644 index 000000000..7108aeb78 --- /dev/null +++ b/internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml @@ -0,0 +1,136 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: gitlab.com + headers: + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/test-owner%2Ftest-repo + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"id":64779801,"description":null,"name":"test-repo","name_with_namespace":"Abhinav Gupta / test-repo","path":"test-repo","path_with_namespace":"test-owner/test-repo","created_at":"2024-11-23T16:35:46.252Z","default_branch":"main","tag_list":[],"topics":[],"ssh_url_to_repo":"git@gitlab.com:test-owner/test-repo.git","http_url_to_repo":"https://gitlab.com/test-owner/test-repo.git","web_url":"https://gitlab.com/test-owner/test-repo","readme_url":null,"forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2026-05-31T13:06:12.128Z","visibility":"public","namespace":{"id":1117393,"name":"Abhinav Gupta","path":"test-owner","kind":"user","full_path":"test-owner","parent_id":null,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"container_registry_image_prefix":"registry.gitlab.com/test-owner/test-repo","_links":{"self":"https://gitlab.com/api/v4/projects/64779801","merge_requests":"https://gitlab.com/api/v4/projects/64779801/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/64779801/repository/branches","labels":"https://gitlab.com/api/v4/projects/64779801/labels","events":"https://gitlab.com/api/v4/projects/64779801/events","members":"https://gitlab.com/api/v4/projects/64779801/members","cluster_agents":"https://gitlab.com/api/v4/projects/64779801/cluster_agents"},"marked_for_deletion_at":null,"marked_for_deletion_on":null,"packages_enabled":false,"empty_repo":false,"archived":false,"owner":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"resolve_outdated_diff_discussions":false,"container_expiration_policy":{"cadence":"1d","enabled":false,"keep_n":10,"older_than":"90d","name_regex":".*","name_regex_keep":null,"next_run_at":"2024-11-24T16:35:46.274Z"},"repository_object_format":"sha1","issues_enabled":false,"merge_requests_enabled":true,"wiki_enabled":false,"jobs_enabled":false,"snippets_enabled":false,"container_registry_enabled":false,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"disabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"disabled","builds_access_level":"disabled","snippets_access_level":"disabled","pages_access_level":"disabled","analytics_access_level":"disabled","container_registry_access_level":"disabled","security_and_compliance_access_level":"disabled","releases_access_level":"disabled","environments_access_level":"disabled","feature_flags_access_level":"disabled","infrastructure_access_level":"disabled","monitor_access_level":"disabled","model_experiments_access_level":"disabled","model_registry_access_level":"disabled","package_registry_access_level":"disabled","emails_disabled":true,"emails_enabled":false,"show_diff_preview_in_email":false,"shared_runners_enabled":true,"lfs_enabled":false,"creator_id":930270,"import_url":null,"import_type":null,"import_status":"none","import_error":null,"description_html":"","updated_at":"2026-05-31T13:19:24.304Z","ci_default_git_depth":20,"ci_delete_pipelines_in_seconds":null,"ci_forward_deployment_enabled":true,"ci_forward_deployment_rollback_allowed":true,"ci_job_token_scope_enabled":false,"ci_separated_caches":true,"ci_allow_fork_pipelines_to_run_in_parent_project":true,"ci_id_token_sub_claim_components":["project_path","ref_type","ref"],"build_git_strategy":"fetch","keep_latest_artifact":true,"restrict_user_defined_variables":false,"ci_pipeline_variables_minimum_override_role":"developer","runner_token_expiration_interval":null,"group_runners_enabled":true,"resource_group_default_process_mode":"unordered","auto_cancel_pending_pipelines":"enabled","build_timeout":3600,"auto_devops_enabled":false,"auto_devops_deploy_strategy":"continuous","ci_push_repository_for_job_token_allowed":false,"protect_merge_request_pipelines":false,"ci_display_pipeline_variables":false,"runners_token":"GR1348941cpXSMHzfUhGHayaS5Bxv","ci_config_path":"","public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":false,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_on","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":"","merge_commit_template":null,"squash_commit_template":null,"mr_default_title_template":null,"issue_branch_template":null,"warn_about_potentially_unwanted_characters":true,"autoclose_referenced_issues":true,"max_artifacts_size":null,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"web_based_commit_signing_enabled":false,"permissions":{"project_access":{"access_level":50,"notification_level":3},"group_access":null}}' + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 505.057084ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: gitlab.com + headers: + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/user + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner","created_at":"2017-01-07T03:40:46.795Z","bio":"","location":"","linkedin":"","twitter":"","discord":"","website_url":"https://abhinavg.net","github":"","job_title":"","pronouns":"","organization":"","bot":false,"work_information":null,"local_time":null,"last_sign_in_at":"2026-03-12T18:51:34.248Z","confirmed_at":"2021-10-19T01:30:11.688Z","last_activity_on":"2026-05-31","email":"mail@abhinavg.net","theme_id":3,"color_scheme_id":2,"projects_limit":100000,"current_sign_in_at":"2026-05-02T20:37:39.186Z","identities":[{"provider":"github","extern_uid":"41730","saml_provider_id":null}],"can_create_group":true,"can_create_project":true,"two_factor_enabled":true,"external":false,"private_profile":false,"commit_email":"mail@abhinavg.net","preferred_language":"en","shared_runners_minutes_limit":null,"extra_shared_runners_minutes_limit":null,"scim_identities":[]}' + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 409.50125ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 111 + host: gitlab.com + body: '{"title":"Checks ympFgY6M","description":"Checks state test","source_branch":"ympFgY6M","target_branch":"main"}' + headers: + Content-Type: + - application/json + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/64779801/merge_requests + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: 1784 + body: '{"id":490633307,"iid":68,"project_id":64779801,"title":"Checks ympFgY6M","description":"Checks state test","state":"opened","created_at":"2026-05-31T13:21:14.900Z","updated_at":"2026-05-31T13:21:14.900Z","merged_by":null,"merge_user":null,"merged_at":null,"closed_by":null,"closed_at":null,"target_branch":"main","source_branch":"ympFgY6M","user_notes_count":0,"upvotes":0,"downvotes":0,"author":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"assignees":[],"assignee":null,"reviewers":[],"source_project_id":64779801,"target_project_id":64779801,"labels":[],"draft":false,"imported":false,"imported_from":"none","work_in_progress":false,"milestone":null,"merge_when_pipeline_succeeds":false,"merge_status":"checking","detailed_merge_status":"preparing","merge_after":null,"sha":"b193787743c8cfa916e42eed609781723a8b5fb7","merge_commit_sha":null,"squash_commit_sha":null,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"prepared_at":null,"reference":"!68","references":{"short":"!68","relative":"!68","full":"test-owner/test-repo!68"},"web_url":"https://gitlab.com/test-owner/test-repo/-/merge_requests/68","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":true,"squash_on_merge":true,"task_completion_status":{"count":0,"completed_count":0},"has_conflicts":false,"blocking_discussions_resolved":true,"approvals_before_merge":null,"subscribed":true,"changes_count":null,"head_pipeline":null,"diff_refs":null,"merge_error":null,"user":{"can_merge":true}}' + headers: + Content-Length: + - "1784" + Content-Type: + - application/json + status: 201 Created + code: 201 + duration: 452.916583ms + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 114 + host: gitlab.com + body: '{"state":"failed","name":"git-spice integration","description":"Synthetic status for git-spice integration tests"}' + headers: + Content-Type: + - application/json + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/64779801/statuses/b193787743c8cfa916e42eed609781723a8b5fb7 + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: 663 + body: '{"id":14620495425,"sha":"b193787743c8cfa916e42eed609781723a8b5fb7","ref":"ympFgY6M","status":"failed","name":"git-spice integration","target_url":null,"description":"Synthetic status for git-spice integration tests","created_at":"2026-05-31T13:21:15.440Z","started_at":null,"finished_at":"2026-05-31T13:21:15.438Z","allow_failure":false,"coverage":null,"pipeline_id":2565298133,"author":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"}}' + headers: + Content-Length: + - "663" + Content-Type: + - application/json + status: 201 Created + code: 201 + duration: 460.654542ms + - id: 4 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: gitlab.com + headers: + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/64779801/merge_requests/68 + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"id":490633307,"iid":68,"project_id":64779801,"title":"Checks ympFgY6M","description":"Checks state test","state":"opened","created_at":"2026-05-31T13:21:14.900Z","updated_at":"2026-05-31T13:21:16.065Z","merged_by":null,"merge_user":null,"merged_at":null,"closed_by":null,"closed_at":null,"target_branch":"main","source_branch":"ympFgY6M","user_notes_count":0,"upvotes":0,"downvotes":0,"author":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"assignees":[],"assignee":null,"reviewers":[],"source_project_id":64779801,"target_project_id":64779801,"labels":[],"draft":false,"imported":false,"imported_from":"none","work_in_progress":false,"milestone":null,"merge_when_pipeline_succeeds":false,"merge_status":"can_be_merged","detailed_merge_status":"mergeable","merge_after":null,"sha":"b193787743c8cfa916e42eed609781723a8b5fb7","merge_commit_sha":null,"squash_commit_sha":null,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"prepared_at":"2026-05-31T13:21:16.056Z","reference":"!68","references":{"short":"!68","relative":"!68","full":"test-owner/test-repo!68"},"web_url":"https://gitlab.com/test-owner/test-repo/-/merge_requests/68","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":true,"squash_on_merge":true,"task_completion_status":{"count":0,"completed_count":0},"has_conflicts":false,"blocking_discussions_resolved":true,"approvals_before_merge":null,"subscribed":true,"changes_count":"1","head_pipeline":{"id":2565298133,"iid":9,"project_id":64779801,"sha":"b193787743c8cfa916e42eed609781723a8b5fb7","ref":"ympFgY6M","status":"failed","source":"external","created_at":"2026-05-31T13:21:15.269Z","updated_at":"2026-05-31T13:21:15.530Z","web_url":"https://gitlab.com/test-owner/test-repo/-/pipelines/2565298133","before_sha":"0000000000000000000000000000000000000000","tag":false,"yaml_errors":null,"user":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"started_at":null,"finished_at":"2026-05-31T13:21:15.529Z","committed_at":null,"duration":null,"queued_duration":null,"coverage":null,"detailed_status":{"icon":"status_failed","text":"Failed","label":"failed","group":"failed","tooltip":"failed","has_details":true,"details_path":"/test-owner/test-repo/-/pipelines/2565298133","illustration":null,"favicon":"/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png"},"archived":false},"diff_refs":{"base_sha":"027a92ee885af88f36b90ec20ea933dcd3f444c6","head_sha":"b193787743c8cfa916e42eed609781723a8b5fb7","start_sha":"027a92ee885af88f36b90ec20ea933dcd3f444c6"},"merge_error":null,"first_contribution":false,"user":{"can_merge":true}}' + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 328.792ms diff --git a/internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml b/internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml new file mode 100644 index 000000000..909dd9f3a --- /dev/null +++ b/internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml @@ -0,0 +1,136 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: gitlab.com + headers: + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/test-owner%2Ftest-repo + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"id":64779801,"description":null,"name":"test-repo","name_with_namespace":"Abhinav Gupta / test-repo","path":"test-repo","path_with_namespace":"test-owner/test-repo","created_at":"2024-11-23T16:35:46.252Z","default_branch":"main","tag_list":[],"topics":[],"ssh_url_to_repo":"git@gitlab.com:test-owner/test-repo.git","http_url_to_repo":"https://gitlab.com/test-owner/test-repo.git","web_url":"https://gitlab.com/test-owner/test-repo","readme_url":null,"forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2026-05-31T13:06:12.128Z","visibility":"public","namespace":{"id":1117393,"name":"Abhinav Gupta","path":"test-owner","kind":"user","full_path":"test-owner","parent_id":null,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"container_registry_image_prefix":"registry.gitlab.com/test-owner/test-repo","_links":{"self":"https://gitlab.com/api/v4/projects/64779801","merge_requests":"https://gitlab.com/api/v4/projects/64779801/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/64779801/repository/branches","labels":"https://gitlab.com/api/v4/projects/64779801/labels","events":"https://gitlab.com/api/v4/projects/64779801/events","members":"https://gitlab.com/api/v4/projects/64779801/members","cluster_agents":"https://gitlab.com/api/v4/projects/64779801/cluster_agents"},"marked_for_deletion_at":null,"marked_for_deletion_on":null,"packages_enabled":false,"empty_repo":false,"archived":false,"owner":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"resolve_outdated_diff_discussions":false,"container_expiration_policy":{"cadence":"1d","enabled":false,"keep_n":10,"older_than":"90d","name_regex":".*","name_regex_keep":null,"next_run_at":"2024-11-24T16:35:46.274Z"},"repository_object_format":"sha1","issues_enabled":false,"merge_requests_enabled":true,"wiki_enabled":false,"jobs_enabled":false,"snippets_enabled":false,"container_registry_enabled":false,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"disabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"disabled","builds_access_level":"disabled","snippets_access_level":"disabled","pages_access_level":"disabled","analytics_access_level":"disabled","container_registry_access_level":"disabled","security_and_compliance_access_level":"disabled","releases_access_level":"disabled","environments_access_level":"disabled","feature_flags_access_level":"disabled","infrastructure_access_level":"disabled","monitor_access_level":"disabled","model_experiments_access_level":"disabled","model_registry_access_level":"disabled","package_registry_access_level":"disabled","emails_disabled":true,"emails_enabled":false,"show_diff_preview_in_email":false,"shared_runners_enabled":true,"lfs_enabled":false,"creator_id":930270,"import_url":null,"import_type":null,"import_status":"none","import_error":null,"description_html":"","updated_at":"2026-05-31T13:19:24.304Z","ci_default_git_depth":20,"ci_delete_pipelines_in_seconds":null,"ci_forward_deployment_enabled":true,"ci_forward_deployment_rollback_allowed":true,"ci_job_token_scope_enabled":false,"ci_separated_caches":true,"ci_allow_fork_pipelines_to_run_in_parent_project":true,"ci_id_token_sub_claim_components":["project_path","ref_type","ref"],"build_git_strategy":"fetch","keep_latest_artifact":true,"restrict_user_defined_variables":false,"ci_pipeline_variables_minimum_override_role":"developer","runner_token_expiration_interval":null,"group_runners_enabled":true,"resource_group_default_process_mode":"unordered","auto_cancel_pending_pipelines":"enabled","build_timeout":3600,"auto_devops_enabled":false,"auto_devops_deploy_strategy":"continuous","ci_push_repository_for_job_token_allowed":false,"protect_merge_request_pipelines":false,"ci_display_pipeline_variables":false,"runners_token":"GR1348941cpXSMHzfUhGHayaS5Bxv","ci_config_path":"","public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":false,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_on","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":"","merge_commit_template":null,"squash_commit_template":null,"mr_default_title_template":null,"issue_branch_template":null,"warn_about_potentially_unwanted_characters":true,"autoclose_referenced_issues":true,"max_artifacts_size":null,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"web_based_commit_signing_enabled":false,"permissions":{"project_access":{"access_level":50,"notification_level":3},"group_access":null}}' + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 243.719709ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: gitlab.com + headers: + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/user + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner","created_at":"2017-01-07T03:40:46.795Z","bio":"","location":"","linkedin":"","twitter":"","discord":"","website_url":"https://abhinavg.net","github":"","job_title":"","pronouns":"","organization":"","bot":false,"work_information":null,"local_time":null,"last_sign_in_at":"2026-03-12T18:51:34.248Z","confirmed_at":"2021-10-19T01:30:11.688Z","last_activity_on":"2026-05-31","email":"mail@abhinavg.net","theme_id":3,"color_scheme_id":2,"projects_limit":100000,"current_sign_in_at":"2026-05-02T20:37:39.186Z","identities":[{"provider":"github","extern_uid":"41730","saml_provider_id":null}],"can_create_group":true,"can_create_project":true,"two_factor_enabled":true,"external":false,"private_profile":false,"commit_email":"mail@abhinavg.net","preferred_language":"en","shared_runners_minutes_limit":null,"extra_shared_runners_minutes_limit":null,"scim_identities":[]}' + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 181.530875ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 111 + host: gitlab.com + body: '{"title":"Checks Mnz6SoOh","description":"Checks state test","source_branch":"Mnz6SoOh","target_branch":"main"}' + headers: + Content-Type: + - application/json + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/64779801/merge_requests + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: 1784 + body: '{"id":490633300,"iid":67,"project_id":64779801,"title":"Checks Mnz6SoOh","description":"Checks state test","state":"opened","created_at":"2026-05-31T13:21:06.116Z","updated_at":"2026-05-31T13:21:06.116Z","merged_by":null,"merge_user":null,"merged_at":null,"closed_by":null,"closed_at":null,"target_branch":"main","source_branch":"Mnz6SoOh","user_notes_count":0,"upvotes":0,"downvotes":0,"author":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"assignees":[],"assignee":null,"reviewers":[],"source_project_id":64779801,"target_project_id":64779801,"labels":[],"draft":false,"imported":false,"imported_from":"none","work_in_progress":false,"milestone":null,"merge_when_pipeline_succeeds":false,"merge_status":"checking","detailed_merge_status":"preparing","merge_after":null,"sha":"5edcba5cbe947db2e38e86c8819a8cdc86229b08","merge_commit_sha":null,"squash_commit_sha":null,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"prepared_at":null,"reference":"!67","references":{"short":"!67","relative":"!67","full":"test-owner/test-repo!67"},"web_url":"https://gitlab.com/test-owner/test-repo/-/merge_requests/67","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":true,"squash_on_merge":true,"task_completion_status":{"count":0,"completed_count":0},"has_conflicts":false,"blocking_discussions_resolved":true,"approvals_before_merge":null,"subscribed":true,"changes_count":null,"head_pipeline":null,"diff_refs":null,"merge_error":null,"user":{"can_merge":true}}' + headers: + Content-Length: + - "1784" + Content-Type: + - application/json + status: 201 Created + code: 201 + duration: 401.899584ms + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 115 + host: gitlab.com + body: '{"state":"success","name":"git-spice integration","description":"Synthetic status for git-spice integration tests"}' + headers: + Content-Type: + - application/json + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/64779801/statuses/5edcba5cbe947db2e38e86c8819a8cdc86229b08 + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: 664 + body: '{"id":14620495117,"sha":"5edcba5cbe947db2e38e86c8819a8cdc86229b08","ref":"Mnz6SoOh","status":"success","name":"git-spice integration","target_url":null,"description":"Synthetic status for git-spice integration tests","created_at":"2026-05-31T13:21:06.739Z","started_at":null,"finished_at":"2026-05-31T13:21:06.736Z","allow_failure":false,"coverage":null,"pipeline_id":2565298061,"author":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"}}' + headers: + Content-Length: + - "664" + Content-Type: + - application/json + status: 201 Created + code: 201 + duration: 484.285292ms + - id: 4 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: gitlab.com + headers: + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/64779801/merge_requests/67 + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"id":490633300,"iid":67,"project_id":64779801,"title":"Checks Mnz6SoOh","description":"Checks state test","state":"opened","created_at":"2026-05-31T13:21:06.116Z","updated_at":"2026-05-31T13:21:07.282Z","merged_by":null,"merge_user":null,"merged_at":null,"closed_by":null,"closed_at":null,"target_branch":"main","source_branch":"Mnz6SoOh","user_notes_count":0,"upvotes":0,"downvotes":0,"author":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"assignees":[],"assignee":null,"reviewers":[],"source_project_id":64779801,"target_project_id":64779801,"labels":[],"draft":false,"imported":false,"imported_from":"none","work_in_progress":false,"milestone":null,"merge_when_pipeline_succeeds":false,"merge_status":"can_be_merged","detailed_merge_status":"mergeable","merge_after":null,"sha":"5edcba5cbe947db2e38e86c8819a8cdc86229b08","merge_commit_sha":null,"squash_commit_sha":null,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"prepared_at":"2026-05-31T13:21:07.274Z","reference":"!67","references":{"short":"!67","relative":"!67","full":"test-owner/test-repo!67"},"web_url":"https://gitlab.com/test-owner/test-repo/-/merge_requests/67","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":true,"squash_on_merge":true,"task_completion_status":{"count":0,"completed_count":0},"has_conflicts":false,"blocking_discussions_resolved":true,"approvals_before_merge":null,"subscribed":true,"changes_count":"1","head_pipeline":{"id":2565298061,"iid":8,"project_id":64779801,"sha":"5edcba5cbe947db2e38e86c8819a8cdc86229b08","ref":"Mnz6SoOh","status":"success","source":"external","created_at":"2026-05-31T13:21:06.561Z","updated_at":"2026-05-31T13:21:06.842Z","web_url":"https://gitlab.com/test-owner/test-repo/-/pipelines/2565298061","before_sha":"0000000000000000000000000000000000000000","tag":false,"yaml_errors":null,"user":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"started_at":null,"finished_at":"2026-05-31T13:21:06.841Z","committed_at":null,"duration":null,"queued_duration":null,"coverage":null,"detailed_status":{"icon":"status_success","text":"Passed","label":"passed","group":"success","tooltip":"passed","has_details":true,"details_path":"/test-owner/test-repo/-/pipelines/2565298061","illustration":null,"favicon":"/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png"},"archived":false},"diff_refs":{"base_sha":"027a92ee885af88f36b90ec20ea933dcd3f444c6","head_sha":"5edcba5cbe947db2e38e86c8819a8cdc86229b08","start_sha":"027a92ee885af88f36b90ec20ea933dcd3f444c6"},"merge_error":null,"first_contribution":false,"user":{"can_merge":true}}' + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 380.999792ms diff --git a/internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml b/internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml new file mode 100644 index 000000000..01cbb92ad --- /dev/null +++ b/internal/forge/gitlab/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml @@ -0,0 +1,136 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: gitlab.com + headers: + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/test-owner%2Ftest-repo + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"id":64779801,"description":null,"name":"test-repo","name_with_namespace":"Abhinav Gupta / test-repo","path":"test-repo","path_with_namespace":"test-owner/test-repo","created_at":"2024-11-23T16:35:46.252Z","default_branch":"main","tag_list":[],"topics":[],"ssh_url_to_repo":"git@gitlab.com:test-owner/test-repo.git","http_url_to_repo":"https://gitlab.com/test-owner/test-repo.git","web_url":"https://gitlab.com/test-owner/test-repo","readme_url":null,"forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2026-05-31T13:06:12.128Z","visibility":"public","namespace":{"id":1117393,"name":"Abhinav Gupta","path":"test-owner","kind":"user","full_path":"test-owner","parent_id":null,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"container_registry_image_prefix":"registry.gitlab.com/test-owner/test-repo","_links":{"self":"https://gitlab.com/api/v4/projects/64779801","merge_requests":"https://gitlab.com/api/v4/projects/64779801/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/64779801/repository/branches","labels":"https://gitlab.com/api/v4/projects/64779801/labels","events":"https://gitlab.com/api/v4/projects/64779801/events","members":"https://gitlab.com/api/v4/projects/64779801/members","cluster_agents":"https://gitlab.com/api/v4/projects/64779801/cluster_agents"},"marked_for_deletion_at":null,"marked_for_deletion_on":null,"packages_enabled":false,"empty_repo":false,"archived":false,"owner":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"resolve_outdated_diff_discussions":false,"container_expiration_policy":{"cadence":"1d","enabled":false,"keep_n":10,"older_than":"90d","name_regex":".*","name_regex_keep":null,"next_run_at":"2024-11-24T16:35:46.274Z"},"repository_object_format":"sha1","issues_enabled":false,"merge_requests_enabled":true,"wiki_enabled":false,"jobs_enabled":false,"snippets_enabled":false,"container_registry_enabled":false,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"disabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"disabled","builds_access_level":"disabled","snippets_access_level":"disabled","pages_access_level":"disabled","analytics_access_level":"disabled","container_registry_access_level":"disabled","security_and_compliance_access_level":"disabled","releases_access_level":"disabled","environments_access_level":"disabled","feature_flags_access_level":"disabled","infrastructure_access_level":"disabled","monitor_access_level":"disabled","model_experiments_access_level":"disabled","model_registry_access_level":"disabled","package_registry_access_level":"disabled","emails_disabled":true,"emails_enabled":false,"show_diff_preview_in_email":false,"shared_runners_enabled":true,"lfs_enabled":false,"creator_id":930270,"import_url":null,"import_type":null,"import_status":"none","import_error":null,"description_html":"","updated_at":"2026-05-31T13:19:24.304Z","ci_default_git_depth":20,"ci_delete_pipelines_in_seconds":null,"ci_forward_deployment_enabled":true,"ci_forward_deployment_rollback_allowed":true,"ci_job_token_scope_enabled":false,"ci_separated_caches":true,"ci_allow_fork_pipelines_to_run_in_parent_project":true,"ci_id_token_sub_claim_components":["project_path","ref_type","ref"],"build_git_strategy":"fetch","keep_latest_artifact":true,"restrict_user_defined_variables":false,"ci_pipeline_variables_minimum_override_role":"developer","runner_token_expiration_interval":null,"group_runners_enabled":true,"resource_group_default_process_mode":"unordered","auto_cancel_pending_pipelines":"enabled","build_timeout":3600,"auto_devops_enabled":false,"auto_devops_deploy_strategy":"continuous","ci_push_repository_for_job_token_allowed":false,"protect_merge_request_pipelines":false,"ci_display_pipeline_variables":false,"runners_token":"GR1348941cpXSMHzfUhGHayaS5Bxv","ci_config_path":"","public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":false,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_on","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":"","merge_commit_template":null,"squash_commit_template":null,"mr_default_title_template":null,"issue_branch_template":null,"warn_about_potentially_unwanted_characters":true,"autoclose_referenced_issues":true,"max_artifacts_size":null,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"web_based_commit_signing_enabled":false,"permissions":{"project_access":{"access_level":50,"notification_level":3},"group_access":null}}' + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 284.250375ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: gitlab.com + headers: + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/user + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner","created_at":"2017-01-07T03:40:46.795Z","bio":"","location":"","linkedin":"","twitter":"","discord":"","website_url":"https://abhinavg.net","github":"","job_title":"","pronouns":"","organization":"","bot":false,"work_information":null,"local_time":null,"last_sign_in_at":"2026-03-12T18:51:34.248Z","confirmed_at":"2021-10-19T01:30:11.688Z","last_activity_on":"2026-05-31","email":"mail@abhinavg.net","theme_id":3,"color_scheme_id":2,"projects_limit":100000,"current_sign_in_at":"2026-05-02T20:37:39.186Z","identities":[{"provider":"github","extern_uid":"41730","saml_provider_id":null}],"can_create_group":true,"can_create_project":true,"two_factor_enabled":true,"external":false,"private_profile":false,"commit_email":"mail@abhinavg.net","preferred_language":"en","shared_runners_minutes_limit":null,"extra_shared_runners_minutes_limit":null,"scim_identities":[]}' + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 145.275083ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 111 + host: gitlab.com + body: '{"title":"Checks 94pBee7g","description":"Checks state test","source_branch":"94pBee7g","target_branch":"main"}' + headers: + Content-Type: + - application/json + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/64779801/merge_requests + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: 1784 + body: '{"id":490633284,"iid":66,"project_id":64779801,"title":"Checks 94pBee7g","description":"Checks state test","state":"opened","created_at":"2026-05-31T13:20:57.521Z","updated_at":"2026-05-31T13:20:57.521Z","merged_by":null,"merge_user":null,"merged_at":null,"closed_by":null,"closed_at":null,"target_branch":"main","source_branch":"94pBee7g","user_notes_count":0,"upvotes":0,"downvotes":0,"author":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"assignees":[],"assignee":null,"reviewers":[],"source_project_id":64779801,"target_project_id":64779801,"labels":[],"draft":false,"imported":false,"imported_from":"none","work_in_progress":false,"milestone":null,"merge_when_pipeline_succeeds":false,"merge_status":"checking","detailed_merge_status":"preparing","merge_after":null,"sha":"25609dfe1a0fe25ecae61e88823987049b139265","merge_commit_sha":null,"squash_commit_sha":null,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"prepared_at":null,"reference":"!66","references":{"short":"!66","relative":"!66","full":"test-owner/test-repo!66"},"web_url":"https://gitlab.com/test-owner/test-repo/-/merge_requests/66","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":true,"squash_on_merge":true,"task_completion_status":{"count":0,"completed_count":0},"has_conflicts":false,"blocking_discussions_resolved":true,"approvals_before_merge":null,"subscribed":true,"changes_count":null,"head_pipeline":null,"diff_refs":null,"merge_error":null,"user":{"can_merge":true}}' + headers: + Content-Length: + - "1784" + Content-Type: + - application/json + status: 201 Created + code: 201 + duration: 373.556166ms + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 115 + host: gitlab.com + body: '{"state":"pending","name":"git-spice integration","description":"Synthetic status for git-spice integration tests"}' + headers: + Content-Type: + - application/json + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/64779801/statuses/25609dfe1a0fe25ecae61e88823987049b139265 + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: 642 + body: '{"id":14620494819,"sha":"25609dfe1a0fe25ecae61e88823987049b139265","ref":"94pBee7g","status":"pending","name":"git-spice integration","target_url":null,"description":"Synthetic status for git-spice integration tests","created_at":"2026-05-31T13:20:58.072Z","started_at":null,"finished_at":null,"allow_failure":false,"coverage":null,"pipeline_id":2565297985,"author":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"}}' + headers: + Content-Length: + - "642" + Content-Type: + - application/json + status: 201 Created + code: 201 + duration: 534.810583ms + - id: 4 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: gitlab.com + headers: + User-Agent: + - git-spice + url: https://gitlab.com/api/v4/projects/64779801/merge_requests/66 + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: '{"id":490633284,"iid":66,"project_id":64779801,"title":"Checks 94pBee7g","description":"Checks state test","state":"opened","created_at":"2026-05-31T13:20:57.521Z","updated_at":"2026-05-31T13:20:58.938Z","merged_by":null,"merge_user":null,"merged_at":null,"closed_by":null,"closed_at":null,"target_branch":"main","source_branch":"94pBee7g","user_notes_count":0,"upvotes":0,"downvotes":0,"author":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"assignees":[],"assignee":null,"reviewers":[],"source_project_id":64779801,"target_project_id":64779801,"labels":[],"draft":false,"imported":false,"imported_from":"none","work_in_progress":false,"milestone":null,"merge_when_pipeline_succeeds":false,"merge_status":"can_be_merged","detailed_merge_status":"mergeable","merge_after":null,"sha":"25609dfe1a0fe25ecae61e88823987049b139265","merge_commit_sha":null,"squash_commit_sha":null,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"prepared_at":"2026-05-31T13:20:58.932Z","reference":"!66","references":{"short":"!66","relative":"!66","full":"test-owner/test-repo!66"},"web_url":"https://gitlab.com/test-owner/test-repo/-/merge_requests/66","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":true,"squash_on_merge":true,"task_completion_status":{"count":0,"completed_count":0},"has_conflicts":false,"blocking_discussions_resolved":true,"approvals_before_merge":null,"subscribed":true,"changes_count":"1","head_pipeline":{"id":2565297985,"iid":7,"project_id":64779801,"sha":"25609dfe1a0fe25ecae61e88823987049b139265","ref":"94pBee7g","status":"pending","source":"external","created_at":"2026-05-31T13:20:57.913Z","updated_at":"2026-05-31T13:20:58.161Z","web_url":"https://gitlab.com/test-owner/test-repo/-/pipelines/2565297985","before_sha":"0000000000000000000000000000000000000000","tag":false,"yaml_errors":null,"user":{"id":930270,"username":"test-owner","public_email":"","name":"Abhinav Gupta","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/e9a34bfd0e7f9ab63137b7653f656daaddbb65e84d3ef0852febd4c3e889a835?s=80\u0026d=identicon","web_url":"https://gitlab.com/test-owner"},"started_at":null,"finished_at":null,"committed_at":null,"duration":null,"queued_duration":null,"coverage":null,"detailed_status":{"icon":"status_pending","text":"Pending","label":"pending","group":"pending","tooltip":"pending","has_details":true,"details_path":"/test-owner/test-repo/-/pipelines/2565297985","illustration":null,"favicon":"/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png"},"archived":false},"diff_refs":{"base_sha":"027a92ee885af88f36b90ec20ea933dcd3f444c6","head_sha":"25609dfe1a0fe25ecae61e88823987049b139265","start_sha":"027a92ee885af88f36b90ec20ea933dcd3f444c6"},"merge_error":null,"first_contribution":false,"user":{"can_merge":true}}' + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 388.408584ms diff --git a/internal/forge/shamhub/change.go b/internal/forge/shamhub/change.go index fbd916864..76e41806c 100644 --- a/internal/forge/shamhub/change.go +++ b/internal/forge/shamhub/change.go @@ -107,6 +107,9 @@ type shamChange struct { // Assignees are users assigned to the change. Assignees []string + + // ChecksState is the aggregate CI/checks state for the change. + ChecksState forge.ChecksState } // Change is a change proposal against a repository. diff --git a/internal/forge/shamhub/checks.go b/internal/forge/shamhub/checks.go index 7606faf18..195d92d7c 100644 --- a/internal/forge/shamhub/checks.go +++ b/internal/forge/shamhub/checks.go @@ -2,14 +2,178 @@ package shamhub import ( "context" + "fmt" + "strconv" "go.abhg.dev/gs/internal/forge" ) -// ChangeChecksState always reports ChecksPassed. -// ShamHub does not simulate CI/checks. +// changeChecksRequest identifies the change whose checks state +// should be reported. +type changeChecksRequest struct { + // Owner is the base repository owner. + Owner string `path:"owner" json:"-"` + + // Repo is the base repository name. + Repo string `path:"repo" json:"-"` + + // Number is the change number in the base repository. + Number int `path:"number" json:"-"` +} + +// changeChecksResponse is the wire response for aggregate checks state. +type changeChecksResponse struct { + // State is one of pending, passed, or failed. + State string `json:"state"` +} + +var _ = shamhubRESTHandler( + "GET /{owner}/{repo}/change/{number}/checks", + (*ShamHub).handleChangeChecks, +) + +func (sh *ShamHub) handleChangeChecks( + _ context.Context, req changeChecksRequest, +) (*changeChecksResponse, error) { + state, err := sh.ChangeChecksState(req.Owner, req.Repo, req.Number) + if err != nil { + return nil, err + } + return &changeChecksResponse{State: state.String()}, nil +} + +// ChangeChecksState reports the aggregate checks state for a change. +func (sh *ShamHub) ChangeChecksState( + owner string, + repo string, + number int, +) (forge.ChecksState, error) { + sh.mu.RLock() + defer sh.mu.RUnlock() + + for _, change := range sh.changes { + if change.Base.Owner == owner && + change.Base.Repo == repo && + change.Number == number { + if change.ChecksState == 0 { + return forge.ChecksPassed, nil + } + return change.ChecksState, nil + } + } + + return 0, notFoundErrorf("change %d (%v/%v) not found", number, owner, repo) +} + +// setStatusRequest updates the simulated checks state for a change. +type setStatusRequest struct { + // Owner is the base repository owner. + Owner string `path:"owner" json:"-"` + + // Repo is the base repository name. + Repo string `path:"repo" json:"-"` + + // Number is the change number in the base repository. + Number int `path:"number" json:"-"` + + // State is one of pending, passed, or failed. + State string `json:"state"` +} + +// setStatusResponse is empty because setting status has no result payload. +type setStatusResponse struct{} + +var _ = shamhubRESTHandler( + "POST /{owner}/{repo}/change/{number}/checks", + (*ShamHub).handleSetStatus, +) + +func (sh *ShamHub) handleSetStatus( + _ context.Context, req setStatusRequest, +) (*setStatusResponse, error) { + state, err := parseChecksState(req.State) + if err != nil { + return nil, badRequestErrorf("%s", err) + } + if err := sh.SetChangeChecksState( + req.Owner, req.Repo, req.Number, state, + ); err != nil { + return nil, err + } + return &setStatusResponse{}, nil +} + +// SetChangeChecksState sets the aggregate checks state for a change. +func (sh *ShamHub) SetChangeChecksState( + owner string, + repo string, + number int, + state forge.ChecksState, +) error { + sh.mu.Lock() + defer sh.mu.Unlock() + + for i, change := range sh.changes { + if change.Base.Owner == owner && + change.Base.Repo == repo && + change.Number == number { + sh.changes[i].ChecksState = state + return nil + } + } + + return notFoundErrorf("change %d (%v/%v) not found", number, owner, repo) +} + +// ChangeChecksState reports the aggregate checks state for a change. func (r *forgeRepository) ChangeChecksState( - _ context.Context, _ forge.ChangeID, + ctx context.Context, + fid forge.ChangeID, ) (forge.ChecksState, error) { - return forge.ChecksPassed, nil + id := fid.(ChangeID) + u := r.apiURL.JoinPath( + r.owner, r.repo, + "change", strconv.Itoa(int(id)), "checks", + ) + + var res changeChecksResponse + if err := r.client.Get(ctx, u.String(), &res); err != nil { + return 0, fmt.Errorf("get checks: %w", err) + } + + return parseChecksState(res.State) +} + +func (r *forgeRepository) setChangeChecksState( + ctx context.Context, + fid forge.ChangeID, + state forge.ChecksState, +) error { + id := fid.(ChangeID) + u := r.apiURL.JoinPath( + r.owner, r.repo, + "change", strconv.Itoa(int(id)), "checks", + ) + + req := setStatusRequest{ + State: state.String(), + } + var res setStatusResponse + if err := r.client.Post(ctx, u.String(), req, &res); err != nil { + return fmt.Errorf("set checks: %w", err) + } + return nil +} + +func parseChecksState(value string) (forge.ChecksState, error) { + switch value { + case "pending": + return forge.ChecksPending, nil + case "passed": + return forge.ChecksPassed, nil + case "failed": + return forge.ChecksFailed, nil + default: + return 0, fmt.Errorf("unsupported status %q", value) + } } diff --git a/internal/forge/shamhub/cli.go b/internal/forge/shamhub/cli.go index d31e7c4fc..7d17b1a84 100644 --- a/internal/forge/shamhub/cli.go +++ b/internal/forge/shamhub/cli.go @@ -273,6 +273,31 @@ runCommand: ts.Fatalf("unknown shamhub config key: %s", key) } + case "set-status": + if len(args) != 3 { + ts.Fatalf("usage: shamhub set-status ") + } + if sh == nil { + ts.Fatalf("ShamHub not initialized") + } + + ownerRepo, prStr, status := args[0], args[1], args[2] + owner, repo, ok := strings.Cut(ownerRepo, "/") + if !ok { + ts.Fatalf("invalid owner/repo: %s", ownerRepo) + } + repo = strings.TrimSuffix(repo, ".git") + pr, err := strconv.Atoi(prStr) + if err != nil { + ts.Fatalf("invalid PR number: %s", err) + } + state, err := parseChecksState(status) + if err != nil { + ts.Fatalf("%s", err) + } + + ts.Check(sh.SetChangeChecksState(owner, repo, pr, state)) + case "merge": if sh == nil { ts.Fatalf("ShamHub not initialized") diff --git a/internal/forge/shamhub/integration_test.go b/internal/forge/shamhub/integration_test.go index 421392a9b..4b62e082a 100644 --- a/internal/forge/shamhub/integration_test.go +++ b/internal/forge/shamhub/integration_test.go @@ -173,6 +173,21 @@ func TestIntegration(t *testing.T) { })) } }, + SetChangeChecksState: func( + t *testing.T, + _ *http.Client, + repo forge.Repository, + changeID forge.ChangeID, + _ git.Hash, + state forge.ChecksState, + ) { + require.NoError(t, + repo.(*forgeRepository).setChangeChecksState( + t.Context(), + changeID, + state, + )) + }, SetCommentsPageSize: SetListChangeCommentsPageSize, Reviewers: []string{"reviewer1", "reviewer2"}, Assignees: []string{"assignee1", "assignee2"}, diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Failed/branch b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Failed/branch new file mode 100644 index 000000000..c01dc85f3 --- /dev/null +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Failed/branch @@ -0,0 +1 @@ +"qP4Hn8gu" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Failed/headHash b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Failed/headHash new file mode 100644 index 000000000..beb4afa19 --- /dev/null +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Failed/headHash @@ -0,0 +1 @@ +"f0eef766af05db1a4fc90e3cb591833890bcf68a" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Passed/branch b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Passed/branch new file mode 100644 index 000000000..61c3c1b4f --- /dev/null +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Passed/branch @@ -0,0 +1 @@ +"f0XMOiaa" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Passed/headHash b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Passed/headHash new file mode 100644 index 000000000..08638008a --- /dev/null +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Passed/headHash @@ -0,0 +1 @@ +"f2923f5d9162ba6ddd3fec6f1725a3ee39c4c5c1" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Pending/branch b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Pending/branch new file mode 100644 index 000000000..502ef233f --- /dev/null +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Pending/branch @@ -0,0 +1 @@ +"MGWUNTrV" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Pending/headHash b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Pending/headHash new file mode 100644 index 000000000..c3bdf4602 --- /dev/null +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeChecksState/Pending/headHash @@ -0,0 +1 @@ +"9bd48588e29fbb9251bc614b2c23d84830937d61" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/UpdateComment/updated-comment b/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/UpdateComment/updated-comment index 6f1186b69..85760ee02 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/UpdateComment/updated-comment +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/UpdateComment/updated-comment @@ -1 +1 @@ -"jMcWDschXQ7Ao6pdn2WspequdF1sCngn" \ No newline at end of file +"uXAhcpF8V9XZWbQom2aI0nM6Q9fbiqpd" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/branch b/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/branch index e920b2948..3d68dade2 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/branch @@ -1 +1 @@ -"my9IRXgl" \ No newline at end of file +"uO3v3Jiu" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/comments b/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/comments index 3206ee8f6..e57864939 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/comments +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/comments @@ -1,12 +1,12 @@ [ - "HaSbldoe0FhdAxmHzzyxjcDnx3GGifzK", - "rUL1FDSIjjFZNaiPugKqLZtIx0r0G0Ey", - "F05iPsXYyyGLd5DMJKXiPwsPDf7NbbOp", - "4YEXT0fm290HhVRtiILhs1XZbZhR67W2", - "FKRggronpGETGHjZrhY06pTy3met7qqH", - "hSYkN6R2MNvstIxMe3E6ZqbdkUivltgj", - "Auj0vPAeRLAfrhVCN6LJmofLqXXoRbwz", - "qThWCqP3gYL8XntCItmU7cU9qxVUSxEu", - "zJV0TjRAZCYugvps3P7kTEg5baPrjUMj", - "vUK7jbl0dWp9EJWhOm2crRR7ROLaHYm0" + "M9TCBnUn2veSjGnStFRLruw4FhpFbpPr", + "ooErWPQY4wHcWm8bJDNOeA2G2BHnMcl1", + "DU3TnJBDljtJOjrPNPgfJRo44fzPxWxZ", + "WeEXYW6yjMMf0jmnnze12omw5CmTHrDt", + "S4IQsdn1dgnUfOJEFb5JEm7kVxLd8oil", + "JNpsluBOeFN8cwri2EMfI8BrYjbArxPf", + "FgUJanBcocO1ablzVyYVjDh6fUZbZXyI", + "qp1FOZUVrehYPmU311YMEQDrHlJ2BJ40", + "sODVHSvcIOhqxyrkgurNH9HMl2b2LSg6", + "k7NLLLvg5wMj1tasfkFfqdbhqfa8Ah0E" ] \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/closedBranch b/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/closedBranch index 48ea0818a..d616a2169 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/closedBranch +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/closedBranch @@ -1 +1 @@ -"YVWetzbP" \ No newline at end of file +"IEtiDhFs" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/mergedBranch b/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/mergedBranch index 814c767be..2142ea6ab 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/mergedBranch +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/mergedBranch @@ -1 +1 @@ -"HUExsFLI" \ No newline at end of file +"C5hzQ5Ik" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/openBranch b/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/openBranch index 366f1a222..7c13c61bf 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/openBranch +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/openBranch @@ -1 +1 @@ -"zvzYpb6I" \ No newline at end of file +"jMfwXkYK" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/CommentCountsByChange/branch b/internal/forge/shamhub/testdata/TestIntegration/CommentCountsByChange/branch index 02673d040..778cc9b7f 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/CommentCountsByChange/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/CommentCountsByChange/branch @@ -1 +1 @@ -"77smA5WD" \ No newline at end of file +"HQWHaq9z" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ListChangeTemplates/TemplatesPresent/empty-template b/internal/forge/shamhub/testdata/TestIntegration/ListChangeTemplates/TemplatesPresent/empty-template index 8136db74a..3da52d175 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ListChangeTemplates/TemplatesPresent/empty-template +++ b/internal/forge/shamhub/testdata/TestIntegration/ListChangeTemplates/TemplatesPresent/empty-template @@ -1 +1 @@ -"mKUnZQxM.md" \ No newline at end of file +"1HQqVNZV.md" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/ListChangeTemplates/TemplatesPresent/non-empty-template b/internal/forge/shamhub/testdata/TestIntegration/ListChangeTemplates/TemplatesPresent/non-empty-template index 4b6a8a908..0c924f438 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ListChangeTemplates/TemplatesPresent/non-empty-template +++ b/internal/forge/shamhub/testdata/TestIntegration/ListChangeTemplates/TemplatesPresent/non-empty-template @@ -1 +1 @@ -"Ff332o7r.md" \ No newline at end of file +"yE3Lj2v5.md" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/base-branch b/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/base-branch index d070fdf81..b8e719155 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/base-branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/base-branch @@ -1 +1 @@ -"byC0EtoD" \ No newline at end of file +"9s9oMX6C" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/branch b/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/branch index 92ce12630..02926e09f 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/branch @@ -1 +1 @@ -"AdS2AoV9" \ No newline at end of file +"vY4xsORW" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitChangeFromPushRepository/fork-branch b/internal/forge/shamhub/testdata/TestIntegration/SubmitChangeFromPushRepository/fork-branch index 3863e27aa..4bc253db7 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitChangeFromPushRepository/fork-branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitChangeFromPushRepository/fork-branch @@ -1 +1 @@ -"Y8voLfph" \ No newline at end of file +"QDezbUVv" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitChangeFromPushRepository/forkCommitHash b/internal/forge/shamhub/testdata/TestIntegration/SubmitChangeFromPushRepository/forkCommitHash index cdb69d976..8846db890 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitChangeFromPushRepository/forkCommitHash +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitChangeFromPushRepository/forkCommitHash @@ -1 +1 @@ -"5ccf55fc5c77aca121ee5ee2b0da370a637013d1" \ No newline at end of file +"eae86575792255a697dad42dac57206c639e7777" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/AddAssignee/branch-no-assignee b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/AddAssignee/branch-no-assignee index d3984ec8f..b92100789 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/AddAssignee/branch-no-assignee +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/AddAssignee/branch-no-assignee @@ -1 +1 @@ -"KF0alFtl" \ No newline at end of file +"66MtCOhk" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne/branch-no-assignee-one-by-one b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne/branch-no-assignee-one-by-one index 732b801f7..e678e3903 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne/branch-no-assignee-one-by-one +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne/branch-no-assignee-one-by-one @@ -1 +1 @@ -"XmwHAeeO" \ No newline at end of file +"Op9WQIRi" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/SubmitWithAssignee/branch-with-assignee b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/SubmitWithAssignee/branch-with-assignee index 5316aa91f..d3f1200a7 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/SubmitWithAssignee/branch-with-assignee +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditAssignees/SubmitWithAssignee/branch-with-assignee @@ -1 +1 @@ -"F5224yXL" \ No newline at end of file +"lE3mefp0" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/base b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/base index c866f6a42..5a0613317 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/base +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/base @@ -1 +1 @@ -"JlZl317W" \ No newline at end of file +"t8XzNN0X" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/branch b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/branch index ec04fd957..133b93253 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/branch @@ -1 +1 @@ -"bIKXbeOh" \ No newline at end of file +"9YbzXae4" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/branch b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/branch index 36e7695af..879ccaf2e 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/branch @@ -1 +1 @@ -"lOFITYc8" \ No newline at end of file +"RowsHzO8" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/firstCommitHash b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/firstCommitHash index bbda7fb24..68000fd15 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/firstCommitHash +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/firstCommitHash @@ -1 +1 @@ -"083b339f7b7815b9673f1ae6e5b0e7b0052d8674" \ No newline at end of file +"1ee3894a24c031b5d053a0b8bb25a9182fd77604" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditDraft/branch b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditDraft/branch index b5a713fbc..5bfde7014 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditDraft/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditDraft/branch @@ -1 +1 @@ -"yrEkWkkt" \ No newline at end of file +"pCyU7Tpe" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/branch b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/branch index 472fc496b..82678979f 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/branch @@ -1 +1 @@ -"6gi1Uroc" \ No newline at end of file +"jbBnJuHT" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label1 b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label1 index 0ac521c44..de5114824 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label1 +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label1 @@ -1 +1 @@ -"F3SIbmB8" \ No newline at end of file +"QcHb0icn" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label2 b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label2 index 058787f8b..7b3d9d81e 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label2 +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label2 @@ -1 +1 @@ -"KoEoCody" \ No newline at end of file +"820svnw8" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label3 b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label3 index d70d50fec..c09704b58 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label3 +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label3 @@ -1 +1 @@ -"ebDVmdoP" \ No newline at end of file +"bUnh1ONJ" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/AddReviewer/branch-no-reviewer b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/AddReviewer/branch-no-reviewer index e73f13a8c..876aafd30 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/AddReviewer/branch-no-reviewer +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/AddReviewer/branch-no-reviewer @@ -1 +1 @@ -"k1KdwAhv" \ No newline at end of file +"qS0oWVxR" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/AddReviewersOneByOne/branch-no-reviewer-one-by-one b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/AddReviewersOneByOne/branch-no-reviewer-one-by-one index 6ab456f8a..df22e5ade 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/AddReviewersOneByOne/branch-no-reviewer-one-by-one +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/AddReviewersOneByOne/branch-no-reviewer-one-by-one @@ -1 +1 @@ -"Sp5h5qsm" \ No newline at end of file +"sN0uOM0J" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/SubmitWithReviewer/branch-with-reviewer b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/SubmitWithReviewer/branch-with-reviewer index be00aa4e4..9bf39d178 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/SubmitWithReviewer/branch-with-reviewer +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditReviewers/SubmitWithReviewer/branch-with-reviewer @@ -1 +1 @@ -"E0vn4LsV" \ No newline at end of file +"4oj7KI1p" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/apiURL b/internal/forge/shamhub/testdata/TestIntegration/apiURL index 9831cd552..38ca6faef 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/apiURL +++ b/internal/forge/shamhub/testdata/TestIntegration/apiURL @@ -1 +1 @@ -"http://127.0.0.1:58759" \ No newline at end of file +"http://127.0.0.1:56373" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/gitURL b/internal/forge/shamhub/testdata/TestIntegration/gitURL index 565e64784..0d906a389 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/gitURL +++ b/internal/forge/shamhub/testdata/TestIntegration/gitURL @@ -1 +1 @@ -"http://127.0.0.1:58760" \ No newline at end of file +"http://127.0.0.1:56374" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/pushRepoURL b/internal/forge/shamhub/testdata/TestIntegration/pushRepoURL index 19560fa40..03fa24f07 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/pushRepoURL +++ b/internal/forge/shamhub/testdata/TestIntegration/pushRepoURL @@ -1 +1 @@ -"http://127.0.0.1:58760/abhinav-fork/test-repo.git" \ No newline at end of file +"http://127.0.0.1:56374/abhinav-fork/test-repo.git" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/repoURL b/internal/forge/shamhub/testdata/TestIntegration/repoURL index 2f6908827..4551e0131 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/repoURL +++ b/internal/forge/shamhub/testdata/TestIntegration/repoURL @@ -1 +1 @@ -"http://127.0.0.1:58760/abhinav/test-repo.git" \ No newline at end of file +"http://127.0.0.1:56374/abhinav/test-repo.git" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/token b/internal/forge/shamhub/testdata/TestIntegration/token index 457018d34..a5ee830ce 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/token +++ b/internal/forge/shamhub/testdata/TestIntegration/token @@ -1 +1 @@ -"fd8412e5c5e613da" \ No newline at end of file +"444a9baa5f8f8904" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml new file mode 100644 index 000000000..343a0d353 --- /dev/null +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml @@ -0,0 +1,82 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 88 + host: 127.0.0.1:56373 + body: '{"subject":"Checks qP4Hn8gu","body":"Checks state test","base":"main","head":"qP4Hn8gu"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 82 + body: | + { + "number": 19, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/19" + } + headers: + Content-Length: + - "82" + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 40.153542ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 18 + host: 127.0.0.1:56373 + body: '{"state":"failed"}' + url: http://127.0.0.1:56373/abhinav/test-repo/change/19/checks + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 3 + body: | + {} + headers: + Content-Length: + - "3" + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 10.451959ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/19/checks + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 24 + body: | + { + "state": "failed" + } + headers: + Content-Length: + - "24" + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 264.458µs diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml new file mode 100644 index 000000000..fc08268b0 --- /dev/null +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml @@ -0,0 +1,82 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 88 + host: 127.0.0.1:56373 + body: '{"subject":"Checks f0XMOiaa","body":"Checks state test","base":"main","head":"f0XMOiaa"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 80 + body: | + { + "number": 9, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/9" + } + headers: + Content-Length: + - "80" + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 27.135375ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 18 + host: 127.0.0.1:56373 + body: '{"state":"passed"}' + url: http://127.0.0.1:56373/abhinav/test-repo/change/9/checks + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 3 + body: | + {} + headers: + Content-Length: + - "3" + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 2.757584ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/9/checks + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 24 + body: | + { + "state": "passed" + } + headers: + Content-Length: + - "24" + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 1.189959ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml new file mode 100644 index 000000000..76558920f --- /dev/null +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml @@ -0,0 +1,82 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 88 + host: 127.0.0.1:56373 + body: '{"subject":"Checks MGWUNTrV","body":"Checks state test","base":"main","head":"MGWUNTrV"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 80 + body: | + { + "number": 3, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/3" + } + headers: + Content-Length: + - "80" + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 27.517959ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 19 + host: 127.0.0.1:56373 + body: '{"state":"pending"}' + url: http://127.0.0.1:56373/abhinav/test-repo/change/3/checks + method: POST + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 3 + body: | + {} + headers: + Content-Length: + - "3" + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 161.792µs + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/3/checks + method: GET + response: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 25 + body: | + { + "state": "pending" + } + headers: + Content-Length: + - "25" + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 207.709µs diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeComments.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeComments.yaml index 31ce0f1c0..889179595 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeComments.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeComments.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 92 - host: 127.0.0.1:58759 - body: '{"subject":"Testing my9IRXgl","body":"Test PR for comments","base":"main","head":"my9IRXgl"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing uO3v3Jiu","body":"Test PR for comments","base":"main","head":"uO3v3Jiu"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 80 body: | { - "number": 9, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/9" + "number": 4, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/4" } headers: Content-Length: @@ -28,16 +28,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 19.27275ms + duration: 20.3975ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:58759 - body: '{"changeNumber":9,"body":"HaSbldoe0FhdAxmHzzyxjcDnx3GGifzK"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments + host: 127.0.0.1:56373 + body: '{"changeNumber":4,"body":"M9TCBnUn2veSjGnStFRLruw4FhpFbpPr"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -55,16 +55,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 366.125µs + duration: 123.292µs - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:58759 - body: '{"changeNumber":9,"body":"rUL1FDSIjjFZNaiPugKqLZtIx0r0G0Ey"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments + host: 127.0.0.1:56373 + body: '{"changeNumber":4,"body":"ooErWPQY4wHcWm8bJDNOeA2G2BHnMcl1"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -82,16 +82,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 207.667µs + duration: 1.531375ms - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:58759 - body: '{"changeNumber":9,"body":"F05iPsXYyyGLd5DMJKXiPwsPDf7NbbOp"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments + host: 127.0.0.1:56373 + body: '{"changeNumber":4,"body":"DU3TnJBDljtJOjrPNPgfJRo44fzPxWxZ"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -109,16 +109,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 136µs + duration: 84.25µs - id: 4 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:58759 - body: '{"changeNumber":9,"body":"4YEXT0fm290HhVRtiILhs1XZbZhR67W2"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments + host: 127.0.0.1:56373 + body: '{"changeNumber":4,"body":"WeEXYW6yjMMf0jmnnze12omw5CmTHrDt"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -136,16 +136,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 359.875µs + duration: 482.875µs - id: 5 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:58759 - body: '{"changeNumber":9,"body":"FKRggronpGETGHjZrhY06pTy3met7qqH"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments + host: 127.0.0.1:56373 + body: '{"changeNumber":4,"body":"S4IQsdn1dgnUfOJEFb5JEm7kVxLd8oil"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -163,16 +163,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 210.458µs + duration: 224.083µs - id: 6 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:58759 - body: '{"changeNumber":9,"body":"hSYkN6R2MNvstIxMe3E6ZqbdkUivltgj"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments + host: 127.0.0.1:56373 + body: '{"changeNumber":4,"body":"JNpsluBOeFN8cwri2EMfI8BrYjbArxPf"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -190,16 +190,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 566.5µs + duration: 103.5µs - id: 7 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:58759 - body: '{"changeNumber":9,"body":"Auj0vPAeRLAfrhVCN6LJmofLqXXoRbwz"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments + host: 127.0.0.1:56373 + body: '{"changeNumber":4,"body":"FgUJanBcocO1ablzVyYVjDh6fUZbZXyI"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -217,16 +217,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 163.25µs + duration: 257.333µs - id: 8 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:58759 - body: '{"changeNumber":9,"body":"qThWCqP3gYL8XntCItmU7cU9qxVUSxEu"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments + host: 127.0.0.1:56373 + body: '{"changeNumber":4,"body":"qp1FOZUVrehYPmU311YMEQDrHlJ2BJ40"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -244,16 +244,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 99.083µs + duration: 140.333µs - id: 9 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:58759 - body: '{"changeNumber":9,"body":"zJV0TjRAZCYugvps3P7kTEg5baPrjUMj"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments + host: 127.0.0.1:56373 + body: '{"changeNumber":4,"body":"sODVHSvcIOhqxyrkgurNH9HMl2b2LSg6"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -271,16 +271,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 74.125µs + duration: 121.5µs - id: 10 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:58759 - body: '{"changeNumber":9,"body":"vUK7jbl0dWp9EJWhOm2crRR7ROLaHYm0"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments + host: 127.0.0.1:56373 + body: '{"changeNumber":4,"body":"k7NLLLvg5wMj1tasfkFfqdbhqfa8Ah0E"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -298,16 +298,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 69.542µs + duration: 115.833µs - id: 11 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 43 - host: 127.0.0.1:58759 - body: '{"body":"jMcWDschXQ7Ao6pdn2WspequdF1sCngn"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments/1 + host: 127.0.0.1:56373 + body: '{"body":"uXAhcpF8V9XZWbQom2aI0nM6Q9fbiqpd"}' + url: http://127.0.0.1:56373/abhinav/test-repo/comments/1 method: PATCH response: proto: HTTP/1.1 @@ -325,15 +325,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 175.25µs + duration: 1.85ms - id: 12 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/comments/2 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/comments/2 method: DELETE response: proto: HTTP/1.1 @@ -349,16 +349,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 117.959µs + duration: 450µs - id: 13 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 22 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"body":"should fail"}' - url: http://127.0.0.1:58759/abhinav/test-repo/comments/2 + url: http://127.0.0.1:56373/abhinav/test-repo/comments/2 method: PATCH response: proto: HTTP/1.1 @@ -374,22 +374,22 @@ interactions: - text/plain; charset=utf-8 status: 404 Not Found code: 404 - duration: 127.708µs + duration: 314.5µs - id: 14 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: change: - - "9" + - "4" limit: - "3" offset: - "0" - url: http://127.0.0.1:58759/abhinav/test-repo/comments?change=9&limit=3&offset=0 + url: http://127.0.0.1:56373/abhinav/test-repo/comments?change=4&limit=3&offset=0 method: GET response: proto: HTTP/1.1 @@ -401,15 +401,15 @@ interactions: "items": [ { "id": 1, - "body": "jMcWDschXQ7Ao6pdn2WspequdF1sCngn" + "body": "uXAhcpF8V9XZWbQom2aI0nM6Q9fbiqpd" }, { "id": 3, - "body": "F05iPsXYyyGLd5DMJKXiPwsPDf7NbbOp" + "body": "DU3TnJBDljtJOjrPNPgfJRo44fzPxWxZ" }, { "id": 4, - "body": "4YEXT0fm290HhVRtiILhs1XZbZhR67W2" + "body": "WeEXYW6yjMMf0jmnnze12omw5CmTHrDt" } ], "offset": 3, @@ -422,22 +422,22 @@ interactions: - application/json status: 200 OK code: 200 - duration: 161.417µs + duration: 387.292µs - id: 15 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: change: - - "9" + - "4" limit: - "3" offset: - "3" - url: http://127.0.0.1:58759/abhinav/test-repo/comments?change=9&limit=3&offset=3 + url: http://127.0.0.1:56373/abhinav/test-repo/comments?change=4&limit=3&offset=3 method: GET response: proto: HTTP/1.1 @@ -449,15 +449,15 @@ interactions: "items": [ { "id": 5, - "body": "FKRggronpGETGHjZrhY06pTy3met7qqH" + "body": "S4IQsdn1dgnUfOJEFb5JEm7kVxLd8oil" }, { "id": 6, - "body": "hSYkN6R2MNvstIxMe3E6ZqbdkUivltgj" + "body": "JNpsluBOeFN8cwri2EMfI8BrYjbArxPf" }, { "id": 7, - "body": "Auj0vPAeRLAfrhVCN6LJmofLqXXoRbwz" + "body": "FgUJanBcocO1ablzVyYVjDh6fUZbZXyI" } ], "offset": 6, @@ -470,22 +470,22 @@ interactions: - application/json status: 200 OK code: 200 - duration: 94.584µs + duration: 1.042458ms - id: 16 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: change: - - "9" + - "4" limit: - "3" offset: - "6" - url: http://127.0.0.1:58759/abhinav/test-repo/comments?change=9&limit=3&offset=6 + url: http://127.0.0.1:56373/abhinav/test-repo/comments?change=4&limit=3&offset=6 method: GET response: proto: HTTP/1.1 @@ -497,15 +497,15 @@ interactions: "items": [ { "id": 8, - "body": "qThWCqP3gYL8XntCItmU7cU9qxVUSxEu" + "body": "qp1FOZUVrehYPmU311YMEQDrHlJ2BJ40" }, { "id": 9, - "body": "zJV0TjRAZCYugvps3P7kTEg5baPrjUMj" + "body": "sODVHSvcIOhqxyrkgurNH9HMl2b2LSg6" }, { "id": 10, - "body": "vUK7jbl0dWp9EJWhOm2crRR7ROLaHYm0" + "body": "k7NLLLvg5wMj1tasfkFfqdbhqfa8Ah0E" } ], "offset": 9 @@ -517,22 +517,22 @@ interactions: - application/json status: 200 OK code: 200 - duration: 633.417µs + duration: 1.038417ms - id: 17 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: change: - - "9" + - "4" limit: - "10" offset: - "0" - url: http://127.0.0.1:58759/abhinav/test-repo/comments?change=9&limit=10&offset=0 + url: http://127.0.0.1:56373/abhinav/test-repo/comments?change=4&limit=10&offset=0 method: GET response: proto: HTTP/1.1 @@ -544,39 +544,39 @@ interactions: "items": [ { "id": 1, - "body": "jMcWDschXQ7Ao6pdn2WspequdF1sCngn" + "body": "uXAhcpF8V9XZWbQom2aI0nM6Q9fbiqpd" }, { "id": 3, - "body": "F05iPsXYyyGLd5DMJKXiPwsPDf7NbbOp" + "body": "DU3TnJBDljtJOjrPNPgfJRo44fzPxWxZ" }, { "id": 4, - "body": "4YEXT0fm290HhVRtiILhs1XZbZhR67W2" + "body": "WeEXYW6yjMMf0jmnnze12omw5CmTHrDt" }, { "id": 5, - "body": "FKRggronpGETGHjZrhY06pTy3met7qqH" + "body": "S4IQsdn1dgnUfOJEFb5JEm7kVxLd8oil" }, { "id": 6, - "body": "hSYkN6R2MNvstIxMe3E6ZqbdkUivltgj" + "body": "JNpsluBOeFN8cwri2EMfI8BrYjbArxPf" }, { "id": 7, - "body": "Auj0vPAeRLAfrhVCN6LJmofLqXXoRbwz" + "body": "FgUJanBcocO1ablzVyYVjDh6fUZbZXyI" }, { "id": 8, - "body": "qThWCqP3gYL8XntCItmU7cU9qxVUSxEu" + "body": "qp1FOZUVrehYPmU311YMEQDrHlJ2BJ40" }, { "id": 9, - "body": "zJV0TjRAZCYugvps3P7kTEg5baPrjUMj" + "body": "sODVHSvcIOhqxyrkgurNH9HMl2b2LSg6" }, { "id": 10, - "body": "vUK7jbl0dWp9EJWhOm2crRR7ROLaHYm0" + "body": "k7NLLLvg5wMj1tasfkFfqdbhqfa8Ah0E" } ], "offset": 9 @@ -588,4 +588,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 236.875µs + duration: 177.583µs diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangesStates.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangesStates.yaml index 2e4287f5c..32e610d37 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangesStates.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangesStates.yaml @@ -7,65 +7,65 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 80 - host: 127.0.0.1:58759 - body: '{"subject":"Open zvzYpb6I","body":"Open change","base":"main","head":"zvzYpb6I"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Open jMfwXkYK","body":"Open change","base":"main","head":"jMfwXkYK"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 80 + content_length: 82 body: | { - "number": 7, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/7" + "number": 15, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/15" } headers: Content-Length: - - "80" + - "82" Content-Type: - application/json status: 200 OK code: 200 - duration: 20.3095ms + duration: 13.188042ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 84 - host: 127.0.0.1:58759 - body: '{"subject":"Merged HUExsFLI","body":"Merged change","base":"main","head":"HUExsFLI"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Merged C5hzQ5Ik","body":"Merged change","base":"main","head":"C5hzQ5Ik"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 80 + content_length: 82 body: | { - "number": 8, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/8" + "number": 16, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/16" } headers: Content-Length: - - "80" + - "82" Content-Type: - application/json status: 200 OK code: 200 - duration: 19.118458ms + duration: 13.844667ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 84 - host: 127.0.0.1:58759 - body: '{"subject":"Closed YVWetzbP","body":"Closed change","base":"main","head":"YVWetzbP"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Closed IEtiDhFs","body":"Closed change","base":"main","head":"IEtiDhFs"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -74,8 +74,8 @@ interactions: content_length: 82 body: | { - "number": 10, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/10" + "number": 18, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/18" } headers: Content-Length: @@ -84,16 +84,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 19.336042ms + duration: 14.069959ms - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 16 - host: 127.0.0.1:58759 - body: '{"ids":[7,8,10]}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/states + content_length: 18 + host: 127.0.0.1:56373 + body: '{"ids":[15,16,18]}' + url: http://127.0.0.1:56373/abhinav/test-repo/change/states method: POST response: proto: HTTP/1.1 @@ -105,15 +105,15 @@ interactions: "statuses": [ { "state": "open", - "headHash": "f5a9d5cb4a52f965b15a000be7aa275d13d8c9c2" + "headHash": "84a9e994290ae89ccc93f7d2a03d009b39d103ea" }, { "state": "merged", - "headHash": "32823ce03626a08e26505aa071c1e412fc329581" + "headHash": "25b03948515094aec6d2cf82537f16d56a1486dc" }, { "state": "closed", - "headHash": "7162b367a7a5a1e2a485150aed5d65f0d56af66c" + "headHash": "0c32e505344f156f8aa70189cfd851a1a40765cd" } ] } @@ -124,4 +124,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 20.187791ms + duration: 10.51575ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/CommentCountsByChange.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/CommentCountsByChange.yaml index 9eb541125..a6c9cab53 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/CommentCountsByChange.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/CommentCountsByChange.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 98 - host: 127.0.0.1:58759 - body: '{"subject":"Testing 77smA5WD","body":"Test PR for comment counts","base":"main","head":"77smA5WD"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing HQWHaq9z","body":"Test PR for comment counts","base":"main","head":"HQWHaq9z"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -19,7 +19,7 @@ interactions: body: | { "number": 11, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/11" + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/11" } headers: Content-Length: @@ -28,16 +28,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 44.606667ms + duration: 28.731083ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 12 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"ids":[11]}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/comment-counts + url: http://127.0.0.1:56373/abhinav/test-repo/change/comment-counts method: POST response: proto: HTTP/1.1 @@ -61,4 +61,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 627.25µs + duration: 1.628833ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/FindChangesByBranchDoesNotExist.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/FindChangesByBranchDoesNotExist.yaml index 4b0f65830..4673e14a0 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/FindChangesByBranchDoesNotExist.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/FindChangesByBranchDoesNotExist.yaml @@ -7,13 +7,13 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: limit: - "10" state: - all - url: http://127.0.0.1:58759/abhinav/test-repo/changes/by-branch/does-not-exist?limit=10&state=all + url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/does-not-exist?limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -29,4 +29,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 3.968291ms + duration: 752.916µs diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/NoTemplates.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/NoTemplates.yaml index 2f8da0cb1..4e2249722 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/NoTemplates.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/NoTemplates.yaml @@ -7,8 +7,8 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change-template + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change-template method: GET response: proto: HTTP/1.1 @@ -24,4 +24,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 112.050791ms + duration: 138.274667ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/TemplatesPresent.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/TemplatesPresent.yaml index 497c7d0c8..2736a773b 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/TemplatesPresent.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/TemplatesPresent.yaml @@ -7,8 +7,8 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change-template + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change-template method: GET response: proto: HTTP/1.1 @@ -18,12 +18,12 @@ interactions: body: | [ { - "filename": "Ff332o7r.md", - "body": "This is a test template\n" + "filename": "1HQqVNZV.md", + "body": "\n" }, { - "filename": "mKUnZQxM.md", - "body": "\n" + "filename": "yE3Lj2v5.md", + "body": "This is a test template\n" } ] headers: @@ -33,4 +33,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 122.858083ms + duration: 149.63575ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitBaseDoesNotExist.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitBaseDoesNotExist.yaml index 5c72eee21..4c536dd39 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitBaseDoesNotExist.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitBaseDoesNotExist.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 106 - host: 127.0.0.1:58759 - body: '{"subject":"Testing AdS2AoV9","body":"Test PR with non-existent base","base":"byC0EtoD","head":"AdS2AoV9"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing vY4xsORW","body":"Test PR with non-existent base","base":"9s9oMX6C","head":"vY4xsORW"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -25,16 +25,16 @@ interactions: - text/plain; charset=utf-8 status: 400 Bad Request code: 400 - duration: 11.32675ms + duration: 9.87325ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 29 - host: 127.0.0.1:58759 - body: '{"ref":"refs/heads/byC0EtoD"}' - url: http://127.0.0.1:58759/abhinav/test-repo/ref/exists + host: 127.0.0.1:56373 + body: '{"ref":"refs/heads/9s9oMX6C"}' + url: http://127.0.0.1:56373/abhinav/test-repo/ref/exists method: POST response: proto: HTTP/1.1 @@ -52,4 +52,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 9.76225ms + duration: 10.2145ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitChangeFromPushRepository.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitChangeFromPushRepository.yaml index 1065386da..be69f95da 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitChangeFromPushRepository.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitChangeFromPushRepository.yaml @@ -7,48 +7,48 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 138 - host: 127.0.0.1:58759 - body: '{"subject":"Testing fork Y8voLfph","body":"Test fork change request","base":"main","head":"Y8voLfph","head_repo":"abhinav-fork/test-repo"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing fork QDezbUVv","body":"Test fork change request","base":"main","head":"QDezbUVv","head_repo":"abhinav-fork/test-repo"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 80 + content_length: 82 body: | { - "number": 5, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/5" + "number": 12, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/12" } headers: Content-Length: - - "80" + - "82" Content-Type: - application/json status: 200 OK code: 200 - duration: 20.181209ms + duration: 22.375459ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/5 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/12 method: GET response: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 525 + content_length: 527 body: | { - "number": 5, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/5", + "number": 12, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/12", "state": "open", - "title": "Testing fork Y8voLfph", + "title": "Testing fork QDezbUVv", "body": "Test fork change request", "base": { "repository": { @@ -56,32 +56,32 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav-fork", "name": "test-repo" }, - "ref": "Y8voLfph", - "sha": "5ccf55fc5c77aca121ee5ee2b0da370a637013d1" + "ref": "QDezbUVv", + "sha": "eae86575792255a697dad42dac57206c639e7777" } } headers: Content-Length: - - "525" + - "527" Content-Type: - application/json status: 200 OK code: 200 - duration: 21.381959ms + duration: 20.375916ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: head_repo: - abhinav-fork/test-repo @@ -89,20 +89,20 @@ interactions: - "10" state: - all - url: http://127.0.0.1:58759/abhinav/test-repo/changes/by-branch/Y8voLfph?head_repo=abhinav-fork%2Ftest-repo&limit=10&state=all + url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/QDezbUVv?head_repo=abhinav-fork%2Ftest-repo&limit=10&state=all method: GET response: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 575 + content_length: 577 body: | [ { - "number": 5, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/5", + "number": 12, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/12", "state": "open", - "title": "Testing fork Y8voLfph", + "title": "Testing fork QDezbUVv", "body": "Test fork change request", "base": { "repository": { @@ -110,39 +110,39 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav-fork", "name": "test-repo" }, - "ref": "Y8voLfph", - "sha": "5ccf55fc5c77aca121ee5ee2b0da370a637013d1" + "ref": "QDezbUVv", + "sha": "eae86575792255a697dad42dac57206c639e7777" } } ] headers: Content-Length: - - "575" + - "577" Content-Type: - application/json status: 200 OK code: 200 - duration: 17.586417ms + duration: 18.822042ms - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: limit: - "10" state: - all - url: http://127.0.0.1:58759/abhinav/test-repo/changes/by-branch/Y8voLfph?limit=10&state=all + url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/QDezbUVv?limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -158,4 +158,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 571.5µs + duration: 455.042µs diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssignee.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssignee.yaml index a9086eb45..aeb06a334 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssignee.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssignee.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 97 - host: 127.0.0.1:58759 - body: '{"subject":"Testing KF0alFtl","body":"Test PR without assignees","base":"main","head":"KF0alFtl"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing 66MtCOhk","body":"Test PR without assignees","base":"main","head":"66MtCOhk"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 82 body: | { - "number": 13, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/13" + "number": 10, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/10" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 20.877291ms + duration: 25.159916ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/13 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/10 method: GET response: proto: HTTP/1.1 @@ -45,10 +45,10 @@ interactions: content_length: 518 body: | { - "number": 13, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/13", + "number": 10, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/10", "state": "open", - "title": "Testing KF0alFtl", + "title": "Testing 66MtCOhk", "body": "Test PR without assignees", "base": { "repository": { @@ -56,15 +56,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "ab081f41b2e6a172f2b938d18331f8bb4a50f76d" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "KF0alFtl", - "sha": "acefe6b3eb9b8c1ac45492d7dea923a1f02bfc3d" + "ref": "66MtCOhk", + "sha": "66a0c50cac60c34e761b18838932a3aab48deac9" } } headers: @@ -74,16 +74,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 15.333583ms + duration: 22.786459ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 39 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"assignees":["assignee1","assignee2"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/13 + url: http://127.0.0.1:56373/abhinav/test-repo/change/10 method: PATCH response: proto: HTTP/1.1 @@ -99,15 +99,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 1.150625ms + duration: 696.167µs - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/13 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/10 method: GET response: proto: HTTP/1.1 @@ -116,10 +116,10 @@ interactions: content_length: 573 body: | { - "number": 13, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/13", + "number": 10, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/10", "state": "open", - "title": "Testing KF0alFtl", + "title": "Testing 66MtCOhk", "body": "Test PR without assignees", "base": { "repository": { @@ -127,15 +127,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "ab081f41b2e6a172f2b938d18331f8bb4a50f76d" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "KF0alFtl", - "sha": "acefe6b3eb9b8c1ac45492d7dea923a1f02bfc3d" + "ref": "66MtCOhk", + "sha": "66a0c50cac60c34e761b18838932a3aab48deac9" }, "assignees": [ "assignee1", @@ -149,4 +149,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 18.314542ms + duration: 17.645625ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne.yaml index dc2a77364..0f7dfd8b2 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne.yaml @@ -7,37 +7,37 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 97 - host: 127.0.0.1:58759 - body: '{"subject":"Testing XmwHAeeO","body":"Test PR without assignees","base":"main","head":"XmwHAeeO"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing Op9WQIRi","body":"Test PR without assignees","base":"main","head":"Op9WQIRi"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 82 + content_length: 80 body: | { - "number": 12, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/12" + "number": 5, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/5" } headers: Content-Length: - - "82" + - "80" Content-Type: - application/json status: 200 OK code: 200 - duration: 32.595417ms + duration: 21.201041ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 27 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"assignees":["assignee1"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/12 + url: http://127.0.0.1:56373/abhinav/test-repo/change/5 method: PATCH response: proto: HTTP/1.1 @@ -53,16 +53,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 551.667µs + duration: 263.792µs - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 27 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"assignees":["assignee2"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/12 + url: http://127.0.0.1:56373/abhinav/test-repo/change/5 method: PATCH response: proto: HTTP/1.1 @@ -78,27 +78,27 @@ interactions: - application/json status: 200 OK code: 200 - duration: 459.875µs + duration: 2.75425ms - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/12 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/5 method: GET response: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 573 + content_length: 571 body: | { - "number": 12, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/12", + "number": 5, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/5", "state": "open", - "title": "Testing XmwHAeeO", + "title": "Testing Op9WQIRi", "body": "Test PR without assignees", "base": { "repository": { @@ -106,15 +106,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "ab081f41b2e6a172f2b938d18331f8bb4a50f76d" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "XmwHAeeO", - "sha": "09108e5870ffe5a55cbbbc5e8d77a651bafb68f1" + "ref": "Op9WQIRi", + "sha": "34d6de08ed0a392a6ec261c288d5516e65dc2614" }, "assignees": [ "assignee1", @@ -123,9 +123,9 @@ interactions: } headers: Content-Length: - - "573" + - "571" Content-Type: - application/json status: 200 OK code: 200 - duration: 16.010333ms + duration: 21.133625ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/SubmitWithAssignee.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/SubmitWithAssignee.yaml index 4cc8c8b02..1bd09cc14 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/SubmitWithAssignee.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/SubmitWithAssignee.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 131 - host: 127.0.0.1:58759 - body: '{"subject":"Testing F5224yXL","body":"Test PR with assignee","base":"main","head":"F5224yXL","assignees":["assignee1","assignee2"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing lE3mefp0","body":"Test PR with assignee","base":"main","head":"lE3mefp0","assignees":["assignee1","assignee2"]}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 80 body: | { - "number": 3, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/3" + "number": 7, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/7" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 23.2185ms + duration: 21.594125ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/3 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/7 method: GET response: proto: HTTP/1.1 @@ -45,10 +45,10 @@ interactions: content_length: 567 body: | { - "number": 3, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/3", + "number": 7, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/7", "state": "open", - "title": "Testing F5224yXL", + "title": "Testing lE3mefp0", "body": "Test PR with assignee", "base": { "repository": { @@ -56,15 +56,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "F5224yXL", - "sha": "15e67ab14c5575f06cc1534173528f46639eed57" + "ref": "lE3mefp0", + "sha": "1294690f93a2b746dbb81d60a23b512988633d14" }, "assignees": [ "assignee1", @@ -78,20 +78,20 @@ interactions: - application/json status: 200 OK code: 200 - duration: 19.111166ms + duration: 17.238667ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: limit: - "10" state: - all - url: http://127.0.0.1:58759/abhinav/test-repo/changes/by-branch/F5224yXL?limit=10&state=all + url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/lE3mefp0?limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -101,10 +101,10 @@ interactions: body: | [ { - "number": 3, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/3", + "number": 7, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/7", "state": "open", - "title": "Testing F5224yXL", + "title": "Testing lE3mefp0", "body": "Test PR with assignee", "base": { "repository": { @@ -112,15 +112,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "F5224yXL", - "sha": "15e67ab14c5575f06cc1534173528f46639eed57" + "ref": "lE3mefp0", + "sha": "1294690f93a2b746dbb81d60a23b512988633d14" }, "assignees": [ "assignee1", @@ -135,4 +135,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 20.942792ms + duration: 20.395ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditBase.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditBase.yaml index df03c1ee3..ed56e8e18 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditBase.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditBase.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 100 - host: 127.0.0.1:58759 - body: '{"subject":"Testing bIKXbeOh","body":"Test PR with custom base","base":"JlZl317W","head":"bIKXbeOh"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing 9YbzXae4","body":"Test PR with custom base","base":"t8XzNN0X","head":"9YbzXae4"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 80 body: | { - "number": 6, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/6" + "number": 8, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/8" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 23.10825ms + duration: 23.763167ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/6 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/8 method: GET response: proto: HTTP/1.1 @@ -45,26 +45,26 @@ interactions: content_length: 519 body: | { - "number": 6, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/6", + "number": 8, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/8", "state": "open", - "title": "Testing bIKXbeOh", + "title": "Testing 9YbzXae4", "body": "Test PR with custom base", "base": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "JlZl317W", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "ref": "t8XzNN0X", + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "bIKXbeOh", - "sha": "1ae4e1c270b84aef31788c2477465dee9e862b03" + "ref": "9YbzXae4", + "sha": "a3fc1801625662da2cc43a337ee7ba729a73d732" } } headers: @@ -74,16 +74,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 16.326958ms + duration: 19.21925ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 15 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"base":"main"}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/6 + url: http://127.0.0.1:56373/abhinav/test-repo/change/8 method: PATCH response: proto: HTTP/1.1 @@ -99,15 +99,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 918.25µs + duration: 485.75µs - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/6 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/8 method: GET response: proto: HTTP/1.1 @@ -116,10 +116,10 @@ interactions: content_length: 515 body: | { - "number": 6, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/6", + "number": 8, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/8", "state": "open", - "title": "Testing bIKXbeOh", + "title": "Testing 9YbzXae4", "body": "Test PR with custom base", "base": { "repository": { @@ -127,15 +127,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "bIKXbeOh", - "sha": "1ae4e1c270b84aef31788c2477465dee9e862b03" + "ref": "9YbzXae4", + "sha": "a3fc1801625662da2cc43a337ee7ba729a73d732" } } headers: @@ -145,4 +145,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 19.171708ms + duration: 17.355333ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditChange.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditChange.yaml index f88c0e925..e0876df1f 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditChange.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditChange.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 79 - host: 127.0.0.1:58759 - body: '{"subject":"Testing lOFITYc8","body":"Test PR","base":"main","head":"lOFITYc8"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing RowsHzO8","body":"Test PR","base":"main","head":"RowsHzO8"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 80 body: | { - "number": 2, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/2" + "number": 1, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/1" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 25.637625ms + duration: 22.12625ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/2 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/1 method: GET response: proto: HTTP/1.1 @@ -45,10 +45,10 @@ interactions: content_length: 498 body: | { - "number": 2, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/2", + "number": 1, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/1", "state": "open", - "title": "Testing lOFITYc8", + "title": "Testing RowsHzO8", "body": "Test PR", "base": { "repository": { @@ -56,15 +56,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "lOFITYc8", - "sha": "083b339f7b7815b9673f1ae6e5b0e7b0052d8674" + "ref": "RowsHzO8", + "sha": "1ee3894a24c031b5d053a0b8bb25a9182fd77604" } } headers: @@ -74,20 +74,20 @@ interactions: - application/json status: 200 OK code: 200 - duration: 17.6775ms + duration: 18.941208ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: limit: - "10" state: - all - url: http://127.0.0.1:58759/abhinav/test-repo/changes/by-branch/lOFITYc8?limit=10&state=all + url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/RowsHzO8?limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -97,10 +97,10 @@ interactions: body: | [ { - "number": 2, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/2", + "number": 1, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/1", "state": "open", - "title": "Testing lOFITYc8", + "title": "Testing RowsHzO8", "body": "Test PR", "base": { "repository": { @@ -108,15 +108,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "lOFITYc8", - "sha": "083b339f7b7815b9673f1ae6e5b0e7b0052d8674" + "ref": "RowsHzO8", + "sha": "1ee3894a24c031b5d053a0b8bb25a9182fd77604" } } ] @@ -127,4 +127,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 19.458959ms + duration: 16.2305ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditDraft.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditDraft.yaml index addec8ee5..5114cb40a 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditDraft.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditDraft.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 98 - host: 127.0.0.1:58759 - body: '{"subject":"Testing yrEkWkkt","body":"Test draft PR","base":"main","head":"yrEkWkkt","draft":true}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing pCyU7Tpe","body":"Test draft PR","base":"main","head":"pCyU7Tpe","draft":true}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 80 body: | { - "number": 1, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/1" + "number": 2, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/2" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 22.147125ms + duration: 22.713917ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/1 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/2 method: GET response: proto: HTTP/1.1 @@ -45,11 +45,11 @@ interactions: content_length: 521 body: | { - "number": 1, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/1", + "number": 2, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/2", "draft": true, "state": "open", - "title": "Testing yrEkWkkt", + "title": "Testing pCyU7Tpe", "body": "Test draft PR", "base": { "repository": { @@ -57,15 +57,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "yrEkWkkt", - "sha": "f380bfa502b48c621dd0d57e6d48aaf8ecd9bc9e" + "ref": "pCyU7Tpe", + "sha": "7bd9a65f890645f1b36eb13dd6a622b6c4b32b13" } } headers: @@ -75,16 +75,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 17.980042ms + duration: 20.71025ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 15 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"draft":false}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/1 + url: http://127.0.0.1:56373/abhinav/test-repo/change/2 method: PATCH response: proto: HTTP/1.1 @@ -100,15 +100,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 335.833µs + duration: 134.583µs - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/1 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/2 method: GET response: proto: HTTP/1.1 @@ -117,10 +117,10 @@ interactions: content_length: 504 body: | { - "number": 1, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/1", + "number": 2, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/2", "state": "open", - "title": "Testing yrEkWkkt", + "title": "Testing pCyU7Tpe", "body": "Test draft PR", "base": { "repository": { @@ -128,15 +128,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "yrEkWkkt", - "sha": "f380bfa502b48c621dd0d57e6d48aaf8ecd9bc9e" + "ref": "pCyU7Tpe", + "sha": "7bd9a65f890645f1b36eb13dd6a622b6c4b32b13" } } headers: @@ -146,16 +146,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 20.174667ms + duration: 17.1405ms - id: 4 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 14 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"draft":true}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/1 + url: http://127.0.0.1:56373/abhinav/test-repo/change/2 method: PATCH response: proto: HTTP/1.1 @@ -171,15 +171,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 604µs + duration: 1.807125ms - id: 5 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/1 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/2 method: GET response: proto: HTTP/1.1 @@ -188,11 +188,11 @@ interactions: content_length: 521 body: | { - "number": 1, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/1", + "number": 2, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/2", "draft": true, "state": "open", - "title": "Testing yrEkWkkt", + "title": "Testing pCyU7Tpe", "body": "Test draft PR", "base": { "repository": { @@ -200,15 +200,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "yrEkWkkt", - "sha": "f380bfa502b48c621dd0d57e6d48aaf8ecd9bc9e" + "ref": "pCyU7Tpe", + "sha": "7bd9a65f890645f1b36eb13dd6a622b6c4b32b13" } } headers: @@ -218,4 +218,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 18.246833ms + duration: 20.676166ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditLabels.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditLabels.yaml index 616473446..7b515d983 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditLabels.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditLabels.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 113 - host: 127.0.0.1:58759 - body: '{"subject":"Testing 6gi1Uroc","body":"Test PR with labels","base":"main","head":"6gi1Uroc","labels":["F3SIbmB8"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing jbBnJuHT","body":"Test PR with labels","base":"main","head":"jbBnJuHT","labels":["QcHb0icn"]}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 80 body: | { - "number": 4, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/4" + "number": 6, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/6" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 19.850458ms + duration: 21.992708ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/4 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/6 method: GET response: proto: HTTP/1.1 @@ -45,10 +45,10 @@ interactions: content_length: 544 body: | { - "number": 4, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/4", + "number": 6, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/6", "state": "open", - "title": "Testing 6gi1Uroc", + "title": "Testing jbBnJuHT", "body": "Test PR with labels", "base": { "repository": { @@ -56,18 +56,18 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "6gi1Uroc", - "sha": "4cc58e58caa402e6ed954869a9e7e0c1bef9b094" + "ref": "jbBnJuHT", + "sha": "c34dbee79699111d2299f1fd5737e5535ae1f643" }, "labels": [ - "F3SIbmB8" + "QcHb0icn" ] } headers: @@ -77,16 +77,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 17.958458ms + duration: 15.358041ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 23 - host: 127.0.0.1:58759 - body: '{"labels":["KoEoCody"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/4 + host: 127.0.0.1:56373 + body: '{"labels":["820svnw8"]}' + url: http://127.0.0.1:56373/abhinav/test-repo/change/6 method: PATCH response: proto: HTTP/1.1 @@ -102,16 +102,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 930.458µs + duration: 1.308292ms - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 34 - host: 127.0.0.1:58759 - body: '{"labels":["KoEoCody","ebDVmdoP"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/4 + host: 127.0.0.1:56373 + body: '{"labels":["820svnw8","bUnh1ONJ"]}' + url: http://127.0.0.1:56373/abhinav/test-repo/change/6 method: PATCH response: proto: HTTP/1.1 @@ -127,20 +127,20 @@ interactions: - application/json status: 200 OK code: 200 - duration: 315.417µs + duration: 242.25µs - id: 4 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: limit: - "10" state: - all - url: http://127.0.0.1:58759/abhinav/test-repo/changes/by-branch/6gi1Uroc?limit=10&state=all + url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/jbBnJuHT?limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -150,10 +150,10 @@ interactions: body: | [ { - "number": 4, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/4", + "number": 6, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/6", "state": "open", - "title": "Testing 6gi1Uroc", + "title": "Testing jbBnJuHT", "body": "Test PR with labels", "base": { "repository": { @@ -161,20 +161,20 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "a5d51b179b81f5b03c6ee4647ea57c81969f653f" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "6gi1Uroc", - "sha": "4cc58e58caa402e6ed954869a9e7e0c1bef9b094" + "ref": "jbBnJuHT", + "sha": "c34dbee79699111d2299f1fd5737e5535ae1f643" }, "labels": [ - "F3SIbmB8", - "KoEoCody", - "ebDVmdoP" + "QcHb0icn", + "820svnw8", + "bUnh1ONJ" ] } ] @@ -185,4 +185,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 17.562ms + duration: 20.795292ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewer.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewer.yaml index e75fc8b0b..a9ce1ed31 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewer.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewer.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 97 - host: 127.0.0.1:58759 - body: '{"subject":"Testing k1KdwAhv","body":"Test PR without reviewers","base":"main","head":"k1KdwAhv"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing qS0oWVxR","body":"Test PR without reviewers","base":"main","head":"qS0oWVxR"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 82 body: | { - "number": 16, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/16" + "number": 17, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/17" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 11.433083ms + duration: 13.741459ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/16 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/17 method: GET response: proto: HTTP/1.1 @@ -45,10 +45,10 @@ interactions: content_length: 518 body: | { - "number": 16, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/16", + "number": 17, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/17", "state": "open", - "title": "Testing k1KdwAhv", + "title": "Testing qS0oWVxR", "body": "Test PR without reviewers", "base": { "repository": { @@ -56,15 +56,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "ab081f41b2e6a172f2b938d18331f8bb4a50f76d" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "k1KdwAhv", - "sha": "465fb1a7d9bfc71324ac03dfb10896918b49711d" + "ref": "qS0oWVxR", + "sha": "d10f53257e22f018a3d5d54780611749d959d3ed" } } headers: @@ -74,16 +74,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 10.142167ms + duration: 13.343458ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 39 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"reviewers":["reviewer1","reviewer2"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/16 + url: http://127.0.0.1:56373/abhinav/test-repo/change/17 method: PATCH response: proto: HTTP/1.1 @@ -99,15 +99,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 144.583µs + duration: 20.163792ms - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/16 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/17 method: GET response: proto: HTTP/1.1 @@ -116,10 +116,10 @@ interactions: content_length: 583 body: | { - "number": 16, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/16", + "number": 17, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/17", "state": "open", - "title": "Testing k1KdwAhv", + "title": "Testing qS0oWVxR", "body": "Test PR without reviewers", "base": { "repository": { @@ -127,15 +127,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "ab081f41b2e6a172f2b938d18331f8bb4a50f76d" + "sha": "78e7fffc2e2f2b050db2efb7f3de43be063e31f3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "k1KdwAhv", - "sha": "465fb1a7d9bfc71324ac03dfb10896918b49711d" + "ref": "qS0oWVxR", + "sha": "d10f53257e22f018a3d5d54780611749d959d3ed" }, "requested_reviewers": [ "reviewer1", @@ -149,4 +149,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 10.676416ms + duration: 21.720042ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewersOneByOne.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewersOneByOne.yaml index d0dd35ae0..e2a72c93e 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewersOneByOne.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewersOneByOne.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 97 - host: 127.0.0.1:58759 - body: '{"subject":"Testing Sp5h5qsm","body":"Test PR without reviewers","base":"main","head":"Sp5h5qsm"}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing sN0uOM0J","body":"Test PR without reviewers","base":"main","head":"sN0uOM0J"}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 82 body: | { - "number": 15, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/15" + "number": 14, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/14" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 21.380625ms + duration: 14.613166ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/15 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/14 method: GET response: proto: HTTP/1.1 @@ -45,10 +45,10 @@ interactions: content_length: 518 body: | { - "number": 15, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/15", + "number": 14, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/14", "state": "open", - "title": "Testing Sp5h5qsm", + "title": "Testing sN0uOM0J", "body": "Test PR without reviewers", "base": { "repository": { @@ -56,15 +56,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "ab081f41b2e6a172f2b938d18331f8bb4a50f76d" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "Sp5h5qsm", - "sha": "7d3beb7025942a85f23367dc3e0921483951f0a3" + "ref": "sN0uOM0J", + "sha": "fe1856b3db7f006918e699a1c316e92ad3342d93" } } headers: @@ -74,16 +74,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 17.052209ms + duration: 11.315875ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 27 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"reviewers":["reviewer1"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/15 + url: http://127.0.0.1:56373/abhinav/test-repo/change/14 method: PATCH response: proto: HTTP/1.1 @@ -99,16 +99,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 309.25µs + duration: 415.5µs - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 27 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 body: '{"reviewers":["reviewer2"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/change/15 + url: http://127.0.0.1:56373/abhinav/test-repo/change/14 method: PATCH response: proto: HTTP/1.1 @@ -124,15 +124,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 2.047ms + duration: 102.334µs - id: 4 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 - url: http://127.0.0.1:58759/abhinav/test-repo/change/15 + host: 127.0.0.1:56373 + url: http://127.0.0.1:56373/abhinav/test-repo/change/14 method: GET response: proto: HTTP/1.1 @@ -141,10 +141,10 @@ interactions: content_length: 583 body: | { - "number": 15, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/15", + "number": 14, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/14", "state": "open", - "title": "Testing Sp5h5qsm", + "title": "Testing sN0uOM0J", "body": "Test PR without reviewers", "base": { "repository": { @@ -152,15 +152,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "ab081f41b2e6a172f2b938d18331f8bb4a50f76d" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "Sp5h5qsm", - "sha": "7d3beb7025942a85f23367dc3e0921483951f0a3" + "ref": "sN0uOM0J", + "sha": "fe1856b3db7f006918e699a1c316e92ad3342d93" }, "requested_reviewers": [ "reviewer1", @@ -174,4 +174,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 13.748958ms + duration: 11.028083ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/SubmitWithReviewer.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/SubmitWithReviewer.yaml index 9d6562a1e..0c837343b 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/SubmitWithReviewer.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/SubmitWithReviewer.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 131 - host: 127.0.0.1:58759 - body: '{"subject":"Testing E0vn4LsV","body":"Test PR with reviewer","base":"main","head":"E0vn4LsV","reviewers":["reviewer1","reviewer2"]}' - url: http://127.0.0.1:58759/abhinav/test-repo/changes + host: 127.0.0.1:56373 + body: '{"subject":"Testing 4oj7KI1p","body":"Test PR with reviewer","base":"main","head":"4oj7KI1p","reviewers":["reviewer1","reviewer2"]}' + url: http://127.0.0.1:56373/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 82 body: | { - "number": 14, - "url": "http://127.0.0.1:58760/abhinav/test-repo/change/14" + "number": 13, + "url": "http://127.0.0.1:56374/abhinav/test-repo/change/13" } headers: Content-Length: @@ -28,20 +28,20 @@ interactions: - application/json status: 200 OK code: 200 - duration: 23.823333ms + duration: 23.097875ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:58759 + host: 127.0.0.1:56373 form: limit: - "10" state: - all - url: http://127.0.0.1:58759/abhinav/test-repo/changes/by-branch/E0vn4LsV?limit=10&state=all + url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/4oj7KI1p?limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -51,10 +51,10 @@ interactions: body: | [ { - "number": 14, - "html_url": "http://127.0.0.1:58760/abhinav/test-repo/change/14", + "number": 13, + "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/13", "state": "open", - "title": "Testing E0vn4LsV", + "title": "Testing 4oj7KI1p", "body": "Test PR with reviewer", "base": { "repository": { @@ -62,15 +62,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "ab081f41b2e6a172f2b938d18331f8bb4a50f76d" + "sha": "71012226be854d2a77b193ca779abba5cc84cca0" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "E0vn4LsV", - "sha": "fea0709b1c947152b9fbf9ed0cb3d22a0e8679c4" + "ref": "4oj7KI1p", + "sha": "d42a7e9d935c9911190197ad4e04542af2500250" }, "requested_reviewers": [ "reviewer1", @@ -85,4 +85,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 18.551333ms + duration: 23.390833ms diff --git a/internal/gateway/bitbucket/api.go b/internal/gateway/bitbucket/api.go index 8f39708e8..136dc3ffc 100644 --- a/internal/gateway/bitbucket/api.go +++ b/internal/gateway/bitbucket/api.go @@ -385,6 +385,14 @@ type CommitStatus struct { State string `json:"state"` } +// CommitStatusCreateRequest is the request body for creating a build status. +type CommitStatusCreateRequest struct { + Key string `json:"key"` + State string `json:"state"` + Description string `json:"description,omitempty"` + URL string `json:"url,omitempty"` +} + // Bitbucket Cloud build status states. // // https://developer.atlassian.com/cloud/bitbucket/rest/api-group-commit-statuses/ @@ -423,6 +431,29 @@ func (c *Client) CommitStatusList( return &response, resp, nil } +// CommitStatusCreate creates or updates a build status for a commit. +func (c *Client) CommitStatusCreate( + ctx context.Context, + workspace string, + repo string, + commitHash string, + req *CommitStatusCreateRequest, +) (*CommitStatus, *Response, error) { + var response CommitStatus + resp, err := c.post( + ctx, + fmt.Sprintf( + "/repositories/%s/%s/commit/%s/statuses/build", + workspace, repo, commitHash, + ), + nil, req, &response, + ) + if err != nil { + return nil, resp, err + } + return &response, resp, nil +} + func buildPullRequestListRequest( workspace string, repo string, diff --git a/internal/gateway/bitbucket/api_test.go b/internal/gateway/bitbucket/api_test.go index 463f0b0ba..90502ed2e 100644 --- a/internal/gateway/bitbucket/api_test.go +++ b/internal/gateway/bitbucket/api_test.go @@ -91,6 +91,25 @@ func TestClient_PullRequestGet(t *testing.T) { assert.Equal(t, "main", pr.Destination.Branch.Name) } +func TestClient_PullRequestMerge(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + assert.Equal(t, "/2.0/repositories/engineering/warp-core/pullrequests/55/merge", r.URL.Path) + writeJSON(t, w, http.StatusOK, PullRequest{ + ID: 55, + State: "MERGED", + }) + })) + defer srv.Close() + + client := newTestClient(t, srv) + pr, _, err := client.PullRequestMerge( + t.Context(), "engineering", "warp-core", 55, + ) + require.NoError(t, err) + assert.Equal(t, "MERGED", pr.State) +} + func TestClient_PullRequestUpdate(t *testing.T) { title := "Draft: Stabilize nacelles" base := "release" @@ -160,6 +179,59 @@ func TestClient_PullRequestList(t *testing.T) { assert.Equal(t, int64(56), prs.Values[1].ID) } +func TestClient_CommitStatusList(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method) + assert.Equal(t, "/2.0/repositories/engineering/warp-core/commit/abc123/statuses", r.URL.Path) + writeJSON(t, w, http.StatusOK, CommitStatusList{ + Values: []CommitStatus{ + {State: CommitStatusInProgress}, + {State: CommitStatusSuccessful}, + }, + }) + })) + defer srv.Close() + + client := newTestClient(t, srv) + statuses, _, err := client.CommitStatusList( + t.Context(), "engineering", "warp-core", "abc123", + ) + require.NoError(t, err) + require.Len(t, statuses.Values, 2) + assert.Equal(t, CommitStatusInProgress, statuses.Values[0].State) +} + +func TestClient_CommitStatusCreate(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + assert.Equal(t, "/2.0/repositories/engineering/warp-core/commit/abc123/statuses/build", r.URL.Path) + assertJSONBody(t, r, `{ + "key":"git-spice", + "state":"SUCCESSFUL", + "description":"Warp core stable" + }`) + writeJSON(t, w, http.StatusOK, CommitStatus{ + State: CommitStatusSuccessful, + }) + })) + defer srv.Close() + + client := newTestClient(t, srv) + status, _, err := client.CommitStatusCreate( + t.Context(), + "engineering", + "warp-core", + "abc123", + &CommitStatusCreateRequest{ + Key: "git-spice", + State: CommitStatusSuccessful, + Description: "Warp core stable", + }, + ) + require.NoError(t, err) + assert.Equal(t, CommitStatusSuccessful, status.State) +} + func TestClient_CommentMethods(t *testing.T) { t.Run("Create", func(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/internal/gateway/gitlab/api.go b/internal/gateway/gitlab/api.go index 9c5a975cd..8ab93daac 100644 --- a/internal/gateway/gitlab/api.go +++ b/internal/gateway/gitlab/api.go @@ -176,6 +176,30 @@ func (c *Client) MergeRequestAccept( return &response, resp, nil } +// CommitStatusSet sets a commit status. +// +// GitLab API: +// https://docs.gitlab.com/api/commits/#set-commit-pipeline-status +func (c *Client) CommitStatusSet( + ctx context.Context, + projectID int64, + sha string, + opt *SetCommitStatusOptions, +) (*Pipeline, *Response, error) { + var response Pipeline + resp, err := c.post( + ctx, + fmt.Sprintf("projects/%d/statuses/%s", projectID, sha), + nil, + opt, + &response, + ) + if err != nil { + return nil, resp, err + } + return &response, resp, nil +} + // MergeRequestNoteCreate creates a merge request note. // // GitLab API: @@ -647,6 +671,21 @@ type AcceptMergeRequestOptions struct { SHA *string `json:"sha,omitempty"` } +// SetCommitStatusOptions configures commit status creation. +type SetCommitStatusOptions struct { + // State is the commit status to report. + // + // Supported values include pending, running, success, + // failed, canceled, and skipped. + State *string `json:"state,omitempty"` + + // Name identifies the status context shown in GitLab. + Name *string `json:"name,omitempty"` + + // Description explains the status result. + Description *string `json:"description,omitempty"` +} + // CreateMergeRequestNoteOptions configures note creation. type CreateMergeRequestNoteOptions struct { Body *string `json:"body,omitempty"` diff --git a/internal/gateway/gitlab/api_test.go b/internal/gateway/gitlab/api_test.go index de942fa0f..dfc7089f2 100644 --- a/internal/gateway/gitlab/api_test.go +++ b/internal/gateway/gitlab/api_test.go @@ -286,6 +286,66 @@ func TestClient_MergeRequestAccept(t *testing.T) { assert.Equal(t, "merged", mr.State) } +func TestClient_MergeRequestAccept_withSHA(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPut, r.Method) + assert.Equal(t, "/api/v4/projects/42/merge_requests/55/merge", r.URL.Path) + assertJSONBody(t, r, `{"sha":"abc123"}`) + writeJSON(t, w, http.StatusOK, MergeRequest{ + BasicMergeRequest: BasicMergeRequest{ + IID: 55, + State: "merged", + }, + }) + })) + defer srv.Close() + + client := newTestClient(t, srv) + mr, _, err := client.MergeRequestAccept( + t.Context(), + int64(42), + 55, + &AcceptMergeRequestOptions{ + SHA: new("abc123"), + }, + ) + require.NoError(t, err) + assert.Equal(t, "merged", mr.State) +} + +func TestClient_CommitStatusSet(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method) + assert.Equal(t, "/api/v4/projects/42/statuses/abc123", r.URL.Path) + assertJSONBody(t, r, `{ + "state":"success", + "name":"git-spice", + "description":"Warp core stable" + }`) + writeJSON(t, w, http.StatusCreated, Pipeline{ + Status: PipelineStatusSuccess, + }) + })) + defer srv.Close() + + client := newTestClient(t, srv) + status := PipelineStatusSuccess + name := "git-spice" + description := "Warp core stable" + pipeline, _, err := client.CommitStatusSet( + t.Context(), + int64(42), + "abc123", + &SetCommitStatusOptions{ + State: &status, + Name: &name, + Description: &description, + }, + ) + require.NoError(t, err) + assert.Equal(t, PipelineStatusSuccess, pipeline.Status) +} + func TestClient_MergeRequestNoteCreate(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPost, r.Method) From 442412069d3b1e01c6bf6bfdb39833b5be64cf04 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Sun, 31 May 2026 06:33:54 -0700 Subject: [PATCH 3/3] forge: Remove unused merge sentinel Unused here and in branch-merge. --- internal/forge/forge.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/internal/forge/forge.go b/internal/forge/forge.go index 453e39081..cb8f72486 100644 --- a/internal/forge/forge.go +++ b/internal/forge/forge.go @@ -221,11 +221,6 @@ type RepositoryID interface { // because the base branch has not been pushed yet. var ErrUnsubmittedBase = errors.New("base branch has not been submitted yet") -// ErrMergeNotAllowed indicates that a change cannot be merged -// because preconditions are not met -// (e.g., failing checks, review requirements, conflicts). -var ErrMergeNotAllowed = errors.New("merge not allowed") - // Repository is a Git repository hosted on a forge. type Repository interface { Forge() Forge @@ -241,9 +236,6 @@ type Repository interface { EditChange(ctx context.Context, id ChangeID, opts EditChangeOptions) error // MergeChange merges an open change into its base branch. - // - // Returns ErrMergeNotAllowed if the change cannot be merged - // (e.g., failing checks, review requirements, conflicts). MergeChange(ctx context.Context, id ChangeID, opts MergeChangeOptions) error FindChangesByBranch(ctx context.Context, branch string, opts FindChangesOptions) ([]*FindChangeItem, error)