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/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/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/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/forge.go b/internal/forge/forge.go index 2db4b620e..cb8f72486 100644 --- a/internal/forge/forge.go +++ b/internal/forge/forge.go @@ -234,9 +234,21 @@ 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. + 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 +442,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 +589,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/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/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/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/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/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/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/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/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/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 new file mode 100644 index 000000000..195d92d7c --- /dev/null +++ b/internal/forge/shamhub/checks.go @@ -0,0 +1,179 @@ +package shamhub + +import ( + "context" + "fmt" + "strconv" + + "go.abhg.dev/gs/internal/forge" +) + +// 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( + ctx context.Context, + fid forge.ChangeID, +) (forge.ChecksState, error) { + 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 e00f5ad42..7d17b1a84 100644 --- a/internal/forge/shamhub/cli.go +++ b/internal/forge/shamhub/cli.go @@ -249,6 +249,55 @@ 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 "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/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/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 173a3e275..136dc3ffc 100644 --- a/internal/gateway/bitbucket/api.go +++ b/internal/gateway/bitbucket/api.go @@ -358,6 +358,102 @@ 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"` +} + +// 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/ +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 +} + +// 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 ffb34ea36..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: @@ -480,8 +504,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 +667,23 @@ 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"` +} + +// 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. 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)