From 5d42709d0b3bc3ba47a02a8474d21abf8d3fcf53 Mon Sep 17 00:00:00 2001 From: Edmund Kohlwey Date: Thu, 14 May 2026 09:33:52 -0400 Subject: [PATCH 1/3] forge: Add inline comment support Forge implementations can now list, post, reply to, batch-submit, resolve, and edit inline review comments. GitHub, GitLab, Bitbucket, and ShamHub implement the shared inline-comment interfaces so higher-level comment workflows can depend on one forge boundary instead of forge-specific API calls. Bitbucket and GitLab comment operations use typed gateway methods for comment creation, thread resolution, and merge request discussions. That keeps inline comment support on the same gateway boundary as the rest of the forge integration. --- internal/forge/bitbucket/inline_comment.go | 333 +++ internal/forge/bitbucket/operations_test.go | 159 ++ internal/forge/forge.go | 134 +- internal/forge/forgetest/mocks.go | 2044 ++++++++++++++++- internal/forge/github/inline_comment.go | 377 +++ internal/forge/gitlab/inline_comment.go | 418 ++++ internal/forge/shamhub/comment.go | 24 +- internal/forge/shamhub/inline_comment.go | 459 ++++ .../UpdateComment/updated-comment | 2 +- .../TestIntegration/ChangeComments/branch | 2 +- .../TestIntegration/ChangeComments/comments | 20 +- .../ChangesStates/closedBranch | 2 +- .../ChangesStates/mergedBranch | 2 +- .../TestIntegration/ChangesStates/openBranch | 2 +- .../CommentCountsByChange/branch | 2 +- .../TemplatesPresent/empty-template | 2 +- .../TemplatesPresent/non-empty-template | 2 +- .../SubmitBaseDoesNotExist/base-branch | 2 +- .../SubmitBaseDoesNotExist/branch | 2 +- .../AddAssignee/branch-no-assignee | 2 +- .../branch-no-assignee-one-by-one | 2 +- .../SubmitWithAssignee/branch-with-assignee | 2 +- .../TestIntegration/SubmitEditBase/base | 2 +- .../TestIntegration/SubmitEditBase/branch | 2 +- .../TestIntegration/SubmitEditChange/branch | 2 +- .../SubmitEditChange/firstCommitHash | 2 +- .../TestIntegration/SubmitEditDraft/branch | 2 +- .../TestIntegration/SubmitEditLabels/branch | 2 +- .../TestIntegration/SubmitEditLabels/label1 | 2 +- .../TestIntegration/SubmitEditLabels/label2 | 2 +- .../TestIntegration/SubmitEditLabels/label3 | 2 +- .../AddReviewer/branch-no-reviewer | 2 +- .../branch-no-reviewer-one-by-one | 2 +- .../SubmitWithReviewer/branch-with-reviewer | 2 +- .../shamhub/testdata/TestIntegration/apiURL | 2 +- .../shamhub/testdata/TestIntegration/gitURL | 2 +- .../testdata/TestIntegration/pushRepoURL | 2 +- .../shamhub/testdata/TestIntegration/repoURL | 2 +- .../shamhub/testdata/TestIntegration/token | 2 +- .../ChangeChecksState/Failed.yaml | 14 +- .../ChangeChecksState/Passed.yaml | 14 +- .../ChangeChecksState/Pending.yaml | 14 +- .../TestIntegration/ChangeComments.yaml | 180 +- .../TestIntegration/ChangesStates.yaml | 56 +- .../CommentCountsByChange.yaml | 26 +- .../FindChangesByBranchDoesNotExist.yaml | 6 +- .../ListChangeTemplates/NoTemplates.yaml | 6 +- .../ListChangeTemplates/TemplatesPresent.yaml | 14 +- .../SubmitBaseDoesNotExist.yaml | 16 +- .../SubmitChangeFromPushRepository.yaml | 22 +- .../SubmitEditAssignees/AddAssignee.yaml | 48 +- .../AddAssigneesOneByOne.yaml | 42 +- .../SubmitWithAssignee.yaml | 48 +- .../TestIntegration/SubmitEditBase.yaml | 50 +- .../TestIntegration/SubmitEditChange.yaml | 48 +- .../TestIntegration/SubmitEditDraft.yaml | 78 +- .../TestIntegration/SubmitEditLabels.yaml | 66 +- .../SubmitEditReviewers/AddReviewer.yaml | 54 +- .../AddReviewersOneByOne.yaml | 54 +- .../SubmitWithReviewer.yaml | 30 +- internal/gateway/bitbucket/api.go | 46 + internal/gateway/gitlab/api.go | 179 +- 62 files changed, 4648 insertions(+), 491 deletions(-) create mode 100644 internal/forge/bitbucket/inline_comment.go create mode 100644 internal/forge/github/inline_comment.go create mode 100644 internal/forge/gitlab/inline_comment.go create mode 100644 internal/forge/shamhub/inline_comment.go diff --git a/internal/forge/bitbucket/inline_comment.go b/internal/forge/bitbucket/inline_comment.go new file mode 100644 index 000000000..6772a091f --- /dev/null +++ b/internal/forge/bitbucket/inline_comment.go @@ -0,0 +1,333 @@ +package bitbucket + +import ( + "context" + "fmt" + "strconv" + + "go.abhg.dev/gs/internal/forge" + "go.abhg.dev/gs/internal/gateway/bitbucket" +) + +var ( + _ forge.WithInlineComments = (*Repository)(nil) + _ forge.WithThreadResolution = (*Repository)(nil) + _ forge.WithCommentEdit = (*Repository)(nil) +) + +// ListInlineComments lists inline/review comments on a PR +// by filtering comments that have inline position data. +func (r *Repository) ListInlineComments( + ctx context.Context, + id forge.ChangeID, +) ([]*forge.InlineComment, error) { + prID := mustPR(id).Number + + var comments []*forge.InlineComment + opts := &bitbucket.CommentListOptions{} + for { + page, _, err := r.client.CommentList( + ctx, r.workspace, r.repo, prID, opts, + ) + if err != nil { + return nil, fmt.Errorf( + "list comments: %w", err, + ) + } + + for _, c := range page.Values { + if c.Inline == nil { + continue + } + + line := 0 + if c.Inline.To != nil { + line = *c.Inline.To + } + + // Thread ID encodes comment ID and PR ID + // for resolve/unresolve operations. + threadID := formatThreadID(c.ID, prID) + + comments = append(comments, + &forge.InlineComment{ + ID: &PRComment{ + ID: c.ID, + PRID: prID, + }, + ThreadID: threadID, + Path: c.Inline.Path, + Line: line, + Body: c.Content.Raw, + Author: c.User.DisplayName, + Resolved: c.Resolution != nil, + }) + } + + if page.Next == "" { + break + } + opts.PageURL = page.Next + } + + return comments, nil +} + +// SubmitReview posts a batch of inline comments +// as individual comments on a PR. +// Bitbucket does not have a native batch review API, +// so each comment is posted separately. +func (r *Repository) SubmitReview( + ctx context.Context, + id forge.ChangeID, + req forge.ReviewRequest, +) error { + prID := mustPR(id).Number + + for _, c := range req.Comments { + if err := r.submitOneComment( + ctx, prID, c, + ); err != nil { + return err + } + } + + r.log.Debug("Submitted review", + "pr", prID, + "comments", len(req.Comments), + ) + return nil +} + +func (r *Repository) submitOneComment( + ctx context.Context, + prID int64, + c forge.InlineCommentRequest, +) error { + if c.ThreadID != "" { + parentID, _, err := parseThreadID(c.ThreadID) + if err != nil { + return fmt.Errorf("parse thread ID: %w", err) + } + _, err = r.replyToComment( + ctx, prID, parentID, c.Body, + ) + return err + } + _, err := r.postInlineCommentAPI( + ctx, prID, c.Path, c.Line, c.Body, + ) + return err +} + +// PostInlineComment posts a single inline comment on a PR. +// If req.ThreadID is set, posts a reply to that thread +// instead of creating a new inline comment. +func (r *Repository) PostInlineComment( + ctx context.Context, + id forge.ChangeID, + req forge.InlineCommentRequest, +) (*forge.InlineComment, error) { + prID := mustPR(id).Number + + if req.ThreadID != "" { + return r.postReply(ctx, prID, req) + } + return r.postNewInlineComment(ctx, prID, req) +} + +func (r *Repository) postNewInlineComment( + ctx context.Context, + prID int64, + req forge.InlineCommentRequest, +) (*forge.InlineComment, error) { + comment, err := r.postInlineCommentAPI( + ctx, prID, req.Path, req.Line, req.Body, + ) + if err != nil { + return nil, err + } + + return &forge.InlineComment{ + ID: &PRComment{ + ID: comment.ID, + PRID: prID, + }, + ThreadID: formatThreadID(comment.ID, prID), + Path: req.Path, + Line: req.Line, + Body: req.Body, + Author: comment.User.DisplayName, + }, nil +} + +func (r *Repository) postReply( + ctx context.Context, + prID int64, + req forge.InlineCommentRequest, +) (*forge.InlineComment, error) { + parentID, _, err := parseThreadID(req.ThreadID) + if err != nil { + return nil, fmt.Errorf("parse thread ID: %w", err) + } + + comment, err := r.replyToComment( + ctx, prID, parentID, req.Body, + ) + if err != nil { + return nil, err + } + + return &forge.InlineComment{ + ID: &PRComment{ + ID: comment.ID, + PRID: prID, + }, + ThreadID: req.ThreadID, + Body: req.Body, + Author: comment.User.DisplayName, + }, nil +} + +func (r *Repository) replyToComment( + ctx context.Context, + prID, parentID int64, + body string, +) (*bitbucket.Comment, error) { + comment, _, err := r.client.CommentCreate( + ctx, r.workspace, r.repo, prID, + &bitbucket.CommentCreateRequest{ + Content: bitbucket.Content{Raw: body}, + Parent: &bitbucket.CommentRef{ID: parentID}, + }, + ) + if err != nil { + return nil, fmt.Errorf( + "reply to comment %d: %w", + parentID, err, + ) + } + return comment, nil +} + +func (r *Repository) postInlineCommentAPI( + ctx context.Context, + prID int64, + filePath string, + line int, + body string, +) (*bitbucket.Comment, error) { + to := line + comment, _, err := r.client.CommentCreate( + ctx, r.workspace, r.repo, prID, + &bitbucket.CommentCreateRequest{ + Content: bitbucket.Content{Raw: body}, + Inline: &bitbucket.Inline{ + Path: filePath, + To: &to, + }, + }, + ) + if err != nil { + return nil, fmt.Errorf( + "create inline comment on %s:%d: %w", + filePath, line, err, + ) + } + return comment, nil +} + +// ResolveThread marks an inline comment as resolved. +func (r *Repository) ResolveThread( + ctx context.Context, + threadID string, +) error { + commentID, prID, err := parseThreadID(threadID) + if err != nil { + return err + } + + if _, _, err := r.client.CommentResolve( + ctx, r.workspace, r.repo, prID, commentID, + &bitbucket.CommentResolveRequest{ + Resolution: &bitbucket.Resolution{Type: "resolved"}, + }, + ); err != nil { + return fmt.Errorf("resolve thread: %w", err) + } + + r.log.Debug("Resolved thread", "threadID", threadID) + return nil +} + +// UnresolveThread marks an inline comment as unresolved. +func (r *Repository) UnresolveThread( + ctx context.Context, + threadID string, +) error { + commentID, prID, err := parseThreadID(threadID) + if err != nil { + return err + } + + if _, _, err := r.client.CommentResolve( + ctx, r.workspace, r.repo, prID, commentID, + &bitbucket.CommentResolveRequest{ + Resolution: nil, + }, + ); err != nil { + return fmt.Errorf("unresolve thread: %w", err) + } + + r.log.Debug("Unresolved thread", "threadID", threadID) + return nil +} + +// EditComment updates the body of an existing comment. +func (r *Repository) EditComment( + ctx context.Context, + id forge.ChangeCommentID, + body string, +) error { + comment := mustPRComment(id) + return r.updateComment(ctx, comment.PRID, comment.ID, body) +} + +// Thread ID encoding for Bitbucket: +// "commentID:prID" + +func formatThreadID(commentID, prID int64) string { + return strconv.FormatInt(commentID, 10) + + ":" + strconv.FormatInt(prID, 10) +} + +func parseThreadID(threadID string) ( + commentID, prID int64, err error, +) { + for i := len(threadID) - 1; i >= 0; i-- { + if threadID[i] == ':' { + commentID, err = strconv.ParseInt( + threadID[:i], 10, 64, + ) + if err != nil { + return 0, 0, fmt.Errorf( + "parse thread ID %q: %w", + threadID, err, + ) + } + prID, err = strconv.ParseInt( + threadID[i+1:], 10, 64, + ) + if err != nil { + return 0, 0, fmt.Errorf( + "parse thread ID %q: %w", + threadID, err, + ) + } + return commentID, prID, nil + } + } + return 0, 0, fmt.Errorf( + "invalid thread ID format: %q", threadID, + ) +} diff --git a/internal/forge/bitbucket/operations_test.go b/internal/forge/bitbucket/operations_test.go index e2cf4566b..9f7b6845a 100644 --- a/internal/forge/bitbucket/operations_test.go +++ b/internal/forge/bitbucket/operations_test.go @@ -675,6 +675,165 @@ func TestStateToAPI(t *testing.T) { } } +func TestPostInlineComment(t *testing.T) { + srv := httptest.NewServer( + http.HandlerFunc(func( + w http.ResponseWriter, r *http.Request, + ) { + assert.Equal(t, http.MethodPost, r.Method) + assert.Contains(t, r.URL.Path, + "/pullrequests/1/comments", + ) + + var req bitbucket.CommentCreateRequest + require.NoError(t, + json.NewDecoder(r.Body).Decode(&req), + ) + assert.Equal(t, "new comment", req.Content.Raw) + assert.Equal(t, "file.go", req.Inline.Path) + require.NotNil(t, req.Inline.To) + assert.Equal(t, 42, *req.Inline.To) + + resp := bitbucket.Comment{ + ID: 10, + Content: bitbucket.Content{Raw: req.Content.Raw}, + Inline: &bitbucket.Inline{ + Path: req.Inline.Path, + To: req.Inline.To, + }, + User: bitbucket.User{DisplayName: "alice"}, + } + assert.NoError(t, + json.NewEncoder(w).Encode(resp), + ) + }), + ) + defer srv.Close() + + repo := newTestRepository(srv.URL) + posted, err := repo.PostInlineComment( + t.Context(), + &PR{Number: 1}, + forge.InlineCommentRequest{ + Path: "file.go", + Line: 42, + Body: "new comment", + }, + ) + require.NoError(t, err) + + assert.Equal(t, "new comment", posted.Body) + assert.Equal(t, "file.go", posted.Path) + assert.Equal(t, 42, posted.Line) +} + +func TestPostInlineComment_reply(t *testing.T) { + srv := httptest.NewServer( + http.HandlerFunc(func( + w http.ResponseWriter, r *http.Request, + ) { + assert.Equal(t, http.MethodPost, r.Method) + + // Decode as raw JSON to verify structure. + var raw map[string]json.RawMessage + require.NoError(t, + json.NewDecoder(r.Body).Decode(&raw), + ) + + // Must have parent.id, not inline. + assert.Contains(t, raw, "parent", + "reply must include parent field", + ) + assert.NotContains(t, raw, "inline", + "reply must not include inline field", + ) + + var parent bitbucket.CommentRef + require.NoError(t, + json.Unmarshal(raw["parent"], &parent), + ) + assert.Equal(t, int64(99), parent.ID) + + resp := bitbucket.Comment{ + ID: 20, + Content: bitbucket.Content{Raw: "reply body"}, + User: bitbucket.User{DisplayName: "bob"}, + } + assert.NoError(t, + json.NewEncoder(w).Encode(resp), + ) + }), + ) + defer srv.Close() + + repo := newTestRepository(srv.URL) + posted, err := repo.PostInlineComment( + t.Context(), + &PR{Number: 1}, + forge.InlineCommentRequest{ + Body: "reply body", + ThreadID: "99:1", // commentID:prID + }, + ) + require.NoError(t, err) + + assert.Equal(t, "reply body", posted.Body) + assert.Equal(t, "99:1", posted.ThreadID) +} + +func TestSubmitReview_withReply(t *testing.T) { + var requests []map[string]json.RawMessage + srv := httptest.NewServer( + http.HandlerFunc(func( + w http.ResponseWriter, r *http.Request, + ) { + var raw map[string]json.RawMessage + require.NoError(t, + json.NewDecoder(r.Body).Decode(&raw), + ) + requests = append(requests, raw) + + resp := bitbucket.Comment{ + ID: int64(len(requests)), + Content: bitbucket.Content{Raw: "ok"}, + } + assert.NoError(t, + json.NewEncoder(w).Encode(resp), + ) + }), + ) + defer srv.Close() + + repo := newTestRepository(srv.URL) + err := repo.SubmitReview( + t.Context(), + &PR{Number: 1}, + forge.ReviewRequest{ + Comments: []forge.InlineCommentRequest{ + { + Path: "a.go", + Line: 10, + Body: "new comment", + }, + { + Body: "thread reply", + ThreadID: "55:1", + }, + }, + }, + ) + require.NoError(t, err) + require.Len(t, requests, 2) + + // First request: new inline comment. + assert.Contains(t, requests[0], "inline") + assert.NotContains(t, requests[0], "parent") + + // Second request: reply to thread. + assert.Contains(t, requests[1], "parent") + assert.NotContains(t, requests[1], "inline") +} + func newTestRepository(baseURL string) *Repository { token := &AuthenticationToken{AccessToken: "test"} tokenSource, err := newGatewayTokenSource(token) diff --git a/internal/forge/forge.go b/internal/forge/forge.go index fee4bc38d..0d36c94d6 100644 --- a/internal/forge/forge.go +++ b/internal/forge/forge.go @@ -13,6 +13,7 @@ import ( "regexp" "strings" "sync" + "time" "go.abhg.dev/gs/internal/git" "go.abhg.dev/gs/internal/git/giturl" @@ -142,7 +143,7 @@ type WithCommentFormat interface { CommentFormat() CommentFormat } -//go:generate mockgen -destination=forgetest/mocks.go -package forgetest -typed . Forge,RepositoryID,Repository +//go:generate mockgen -destination=forgetest/mocks.go -package forgetest -typed -write_package_comment=false . Forge,RepositoryID,Repository,WithInlineComments,WithThreadResolution,WithCommentEdit // TODO: // Forge should become a struct with multiple interfaces or funcctions @@ -760,3 +761,134 @@ func (s ChecksState) GoString() string { return fmt.Sprintf("ChecksState(%d)", int(s)) } } + +// Inline comment types and optional interfaces + +// InlineCommentRequest describes a new inline comment +// to post on a change diff. +type InlineCommentRequest struct { + // Path is the file path relative to the repository root. + Path string + + // Line is the line number in the new version of the file. + Line int + + // Body is the markdown body of the comment. + Body string + + // Side indicates which side of the diff the comment + // applies to. Use "LEFT" for the old version + // or "RIGHT" (default) for the new version. + Side string + + // ThreadID is set when replying to an existing thread. + // The format is forge-specific. + ThreadID string +} + +// InlineComment is a comment on a specific line of a diff. +type InlineComment struct { + // ID is the forge-specific comment identifier. + ID ChangeCommentID + + // ThreadID is the forge-specific thread identifier. + ThreadID string + + // Path is the file path relative to the repository root. + Path string + + // Line is the line number in the diff. + Line int + + // Body is the markdown body of the comment. + Body string + + // Author is the username of the comment author. + Author string + + // Resolved indicates the comment thread is resolved. + Resolved bool + + // Outdated indicates the comment is on an outdated diff. + Outdated bool + + // CreatedAt is the time the comment was created. + CreatedAt time.Time +} + +// ReviewEvent specifies the type of review being submitted. +type ReviewEvent int + +const ( + // ReviewComment submits a review with comments only. + ReviewComment ReviewEvent = iota + + // ReviewApprove submits an approving review. + ReviewApprove + + // ReviewRequestChanges submits a review + // requesting changes. + ReviewRequestChanges +) + +// ReviewRequest is a batch of inline comments +// submitted together as a single review. +type ReviewRequest struct { + // Body is the overall review body (optional). + Body string + + // Comments are the inline comments in the review. + Comments []InlineCommentRequest + + // Event is the review event type. + Event ReviewEvent +} + +// WithInlineComments is an optional interface +// for forges that support inline/diff comments +// and code reviews. +type WithInlineComments interface { + Repository + + // ListInlineComments lists inline/review comments + // on a change. + ListInlineComments( + ctx context.Context, id ChangeID, + ) ([]*InlineComment, error) + + // SubmitReview posts a batch of inline comments + // as a single review. + SubmitReview( + ctx context.Context, id ChangeID, req ReviewRequest, + ) error + + // PostInlineComment posts a single inline comment + // outside of a batch review. + PostInlineComment( + ctx context.Context, id ChangeID, + req InlineCommentRequest, + ) (*InlineComment, error) +} + +// WithThreadResolution is an optional interface +// for forges that support resolving comment threads. +type WithThreadResolution interface { + Repository + + // ResolveThread marks a comment thread as resolved. + ResolveThread(ctx context.Context, threadID string) error + + // UnresolveThread marks a comment thread as unresolved. + UnresolveThread(ctx context.Context, threadID string) error +} + +// WithCommentEdit is an optional interface +// for forges that support editing existing comments. +type WithCommentEdit interface { + Repository + + // EditComment updates the body of an existing comment. + EditComment( + ctx context.Context, id ChangeCommentID, body string, + ) error +} diff --git a/internal/forge/forgetest/mocks.go b/internal/forge/forgetest/mocks.go index a05146005..b9ae2a647 100644 --- a/internal/forge/forgetest/mocks.go +++ b/internal/forge/forgetest/mocks.go @@ -1,12 +1,11 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: go.abhg.dev/gs/internal/forge (interfaces: Forge,RepositoryID,Repository) +// Source: go.abhg.dev/gs/internal/forge (interfaces: Forge,RepositoryID,Repository,WithInlineComments,WithThreadResolution,WithCommentEdit) // // Generated by this command: // -// mockgen -destination=forgetest/mocks.go -package forgetest -typed . Forge,RepositoryID,Repository +// mockgen -destination=forgetest/mocks.go -package forgetest -typed -write_package_comment=false . Forge,RepositoryID,Repository,WithInlineComments,WithThreadResolution,WithCommentEdit // -// Package forgetest is a generated GoMock package. package forgetest import ( @@ -1287,3 +1286,2042 @@ func (c *MockRepositoryUpdateChangeCommentCall) DoAndReturn(f func(context.Conte c.Call = c.Call.DoAndReturn(f) return c } + +// MockWithInlineComments is a mock of WithInlineComments interface. +type MockWithInlineComments struct { + ctrl *gomock.Controller + recorder *MockWithInlineCommentsMockRecorder + isgomock struct{} +} + +// MockWithInlineCommentsMockRecorder is the mock recorder for MockWithInlineComments. +type MockWithInlineCommentsMockRecorder struct { + mock *MockWithInlineComments +} + +// NewMockWithInlineComments creates a new mock instance. +func NewMockWithInlineComments(ctrl *gomock.Controller) *MockWithInlineComments { + mock := &MockWithInlineComments{ctrl: ctrl} + mock.recorder = &MockWithInlineCommentsMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockWithInlineComments) EXPECT() *MockWithInlineCommentsMockRecorder { + return m.recorder +} + +// ChangeChecksState mocks base method. +func (m *MockWithInlineComments) 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 *MockWithInlineCommentsMockRecorder) ChangeChecksState(ctx, id any) *MockWithInlineCommentsChangeChecksStateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeChecksState", reflect.TypeOf((*MockWithInlineComments)(nil).ChangeChecksState), ctx, id) + return &MockWithInlineCommentsChangeChecksStateCall{Call: call} +} + +// MockWithInlineCommentsChangeChecksStateCall wrap *gomock.Call +type MockWithInlineCommentsChangeChecksStateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsChangeChecksStateCall) Return(arg0 forge.ChecksState, arg1 error) *MockWithInlineCommentsChangeChecksStateCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsChangeChecksStateCall) Do(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockWithInlineCommentsChangeChecksStateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsChangeChecksStateCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockWithInlineCommentsChangeChecksStateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ChangeStatuses mocks base method. +func (m *MockWithInlineComments) ChangeStatuses(ctx context.Context, ids []forge.ChangeID) ([]forge.ChangeStatus, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChangeStatuses", ctx, ids) + ret0, _ := ret[0].([]forge.ChangeStatus) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ChangeStatuses indicates an expected call of ChangeStatuses. +func (mr *MockWithInlineCommentsMockRecorder) ChangeStatuses(ctx, ids any) *MockWithInlineCommentsChangeStatusesCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeStatuses", reflect.TypeOf((*MockWithInlineComments)(nil).ChangeStatuses), ctx, ids) + return &MockWithInlineCommentsChangeStatusesCall{Call: call} +} + +// MockWithInlineCommentsChangeStatusesCall wrap *gomock.Call +type MockWithInlineCommentsChangeStatusesCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsChangeStatusesCall) Return(arg0 []forge.ChangeStatus, arg1 error) *MockWithInlineCommentsChangeStatusesCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsChangeStatusesCall) Do(f func(context.Context, []forge.ChangeID) ([]forge.ChangeStatus, error)) *MockWithInlineCommentsChangeStatusesCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsChangeStatusesCall) DoAndReturn(f func(context.Context, []forge.ChangeID) ([]forge.ChangeStatus, error)) *MockWithInlineCommentsChangeStatusesCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// CommentCountsByChange mocks base method. +func (m *MockWithInlineComments) CommentCountsByChange(ctx context.Context, ids []forge.ChangeID) ([]*forge.CommentCounts, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CommentCountsByChange", ctx, ids) + ret0, _ := ret[0].([]*forge.CommentCounts) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CommentCountsByChange indicates an expected call of CommentCountsByChange. +func (mr *MockWithInlineCommentsMockRecorder) CommentCountsByChange(ctx, ids any) *MockWithInlineCommentsCommentCountsByChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommentCountsByChange", reflect.TypeOf((*MockWithInlineComments)(nil).CommentCountsByChange), ctx, ids) + return &MockWithInlineCommentsCommentCountsByChangeCall{Call: call} +} + +// MockWithInlineCommentsCommentCountsByChangeCall wrap *gomock.Call +type MockWithInlineCommentsCommentCountsByChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsCommentCountsByChangeCall) Return(arg0 []*forge.CommentCounts, arg1 error) *MockWithInlineCommentsCommentCountsByChangeCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsCommentCountsByChangeCall) Do(f func(context.Context, []forge.ChangeID) ([]*forge.CommentCounts, error)) *MockWithInlineCommentsCommentCountsByChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsCommentCountsByChangeCall) DoAndReturn(f func(context.Context, []forge.ChangeID) ([]*forge.CommentCounts, error)) *MockWithInlineCommentsCommentCountsByChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// DeleteChangeComment mocks base method. +func (m *MockWithInlineComments) DeleteChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteChangeComment", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteChangeComment indicates an expected call of DeleteChangeComment. +func (mr *MockWithInlineCommentsMockRecorder) DeleteChangeComment(arg0, arg1 any) *MockWithInlineCommentsDeleteChangeCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeComment", reflect.TypeOf((*MockWithInlineComments)(nil).DeleteChangeComment), arg0, arg1) + return &MockWithInlineCommentsDeleteChangeCommentCall{Call: call} +} + +// MockWithInlineCommentsDeleteChangeCommentCall wrap *gomock.Call +type MockWithInlineCommentsDeleteChangeCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsDeleteChangeCommentCall) Return(arg0 error) *MockWithInlineCommentsDeleteChangeCommentCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsDeleteChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID) error) *MockWithInlineCommentsDeleteChangeCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsDeleteChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID) error) *MockWithInlineCommentsDeleteChangeCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// EditChange mocks base method. +func (m *MockWithInlineComments) EditChange(ctx context.Context, id forge.ChangeID, opts forge.EditChangeOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EditChange", ctx, id, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// EditChange indicates an expected call of EditChange. +func (mr *MockWithInlineCommentsMockRecorder) EditChange(ctx, id, opts any) *MockWithInlineCommentsEditChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EditChange", reflect.TypeOf((*MockWithInlineComments)(nil).EditChange), ctx, id, opts) + return &MockWithInlineCommentsEditChangeCall{Call: call} +} + +// MockWithInlineCommentsEditChangeCall wrap *gomock.Call +type MockWithInlineCommentsEditChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsEditChangeCall) Return(arg0 error) *MockWithInlineCommentsEditChangeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsEditChangeCall) Do(f func(context.Context, forge.ChangeID, forge.EditChangeOptions) error) *MockWithInlineCommentsEditChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsEditChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.EditChangeOptions) error) *MockWithInlineCommentsEditChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// FindChangeByID mocks base method. +func (m *MockWithInlineComments) FindChangeByID(ctx context.Context, id forge.ChangeID) (*forge.FindChangeItem, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindChangeByID", ctx, id) + ret0, _ := ret[0].(*forge.FindChangeItem) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindChangeByID indicates an expected call of FindChangeByID. +func (mr *MockWithInlineCommentsMockRecorder) FindChangeByID(ctx, id any) *MockWithInlineCommentsFindChangeByIDCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindChangeByID", reflect.TypeOf((*MockWithInlineComments)(nil).FindChangeByID), ctx, id) + return &MockWithInlineCommentsFindChangeByIDCall{Call: call} +} + +// MockWithInlineCommentsFindChangeByIDCall wrap *gomock.Call +type MockWithInlineCommentsFindChangeByIDCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsFindChangeByIDCall) Return(arg0 *forge.FindChangeItem, arg1 error) *MockWithInlineCommentsFindChangeByIDCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsFindChangeByIDCall) Do(f func(context.Context, forge.ChangeID) (*forge.FindChangeItem, error)) *MockWithInlineCommentsFindChangeByIDCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsFindChangeByIDCall) DoAndReturn(f func(context.Context, forge.ChangeID) (*forge.FindChangeItem, error)) *MockWithInlineCommentsFindChangeByIDCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// FindChangesByBranch mocks base method. +func (m *MockWithInlineComments) FindChangesByBranch(ctx context.Context, branch string, opts forge.FindChangesOptions) ([]*forge.FindChangeItem, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindChangesByBranch", ctx, branch, opts) + ret0, _ := ret[0].([]*forge.FindChangeItem) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindChangesByBranch indicates an expected call of FindChangesByBranch. +func (mr *MockWithInlineCommentsMockRecorder) FindChangesByBranch(ctx, branch, opts any) *MockWithInlineCommentsFindChangesByBranchCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindChangesByBranch", reflect.TypeOf((*MockWithInlineComments)(nil).FindChangesByBranch), ctx, branch, opts) + return &MockWithInlineCommentsFindChangesByBranchCall{Call: call} +} + +// MockWithInlineCommentsFindChangesByBranchCall wrap *gomock.Call +type MockWithInlineCommentsFindChangesByBranchCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsFindChangesByBranchCall) Return(arg0 []*forge.FindChangeItem, arg1 error) *MockWithInlineCommentsFindChangesByBranchCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsFindChangesByBranchCall) Do(f func(context.Context, string, forge.FindChangesOptions) ([]*forge.FindChangeItem, error)) *MockWithInlineCommentsFindChangesByBranchCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsFindChangesByBranchCall) DoAndReturn(f func(context.Context, string, forge.FindChangesOptions) ([]*forge.FindChangeItem, error)) *MockWithInlineCommentsFindChangesByBranchCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Forge mocks base method. +func (m *MockWithInlineComments) Forge() forge.Forge { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Forge") + ret0, _ := ret[0].(forge.Forge) + return ret0 +} + +// Forge indicates an expected call of Forge. +func (mr *MockWithInlineCommentsMockRecorder) Forge() *MockWithInlineCommentsForgeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Forge", reflect.TypeOf((*MockWithInlineComments)(nil).Forge)) + return &MockWithInlineCommentsForgeCall{Call: call} +} + +// MockWithInlineCommentsForgeCall wrap *gomock.Call +type MockWithInlineCommentsForgeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsForgeCall) Return(arg0 forge.Forge) *MockWithInlineCommentsForgeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsForgeCall) Do(f func() forge.Forge) *MockWithInlineCommentsForgeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsForgeCall) DoAndReturn(f func() forge.Forge) *MockWithInlineCommentsForgeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ListChangeComments mocks base method. +func (m *MockWithInlineComments) ListChangeComments(arg0 context.Context, arg1 forge.ChangeID, arg2 *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListChangeComments", arg0, arg1, arg2) + ret0, _ := ret[0].(iter.Seq2[*forge.ListChangeCommentItem, error]) + return ret0 +} + +// ListChangeComments indicates an expected call of ListChangeComments. +func (mr *MockWithInlineCommentsMockRecorder) ListChangeComments(arg0, arg1, arg2 any) *MockWithInlineCommentsListChangeCommentsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeComments", reflect.TypeOf((*MockWithInlineComments)(nil).ListChangeComments), arg0, arg1, arg2) + return &MockWithInlineCommentsListChangeCommentsCall{Call: call} +} + +// MockWithInlineCommentsListChangeCommentsCall wrap *gomock.Call +type MockWithInlineCommentsListChangeCommentsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsListChangeCommentsCall) Return(arg0 iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithInlineCommentsListChangeCommentsCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsListChangeCommentsCall) Do(f func(context.Context, forge.ChangeID, *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithInlineCommentsListChangeCommentsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsListChangeCommentsCall) DoAndReturn(f func(context.Context, forge.ChangeID, *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithInlineCommentsListChangeCommentsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ListChangeTemplates mocks base method. +func (m *MockWithInlineComments) ListChangeTemplates(arg0 context.Context) ([]*forge.ChangeTemplate, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListChangeTemplates", arg0) + ret0, _ := ret[0].([]*forge.ChangeTemplate) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListChangeTemplates indicates an expected call of ListChangeTemplates. +func (mr *MockWithInlineCommentsMockRecorder) ListChangeTemplates(arg0 any) *MockWithInlineCommentsListChangeTemplatesCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeTemplates", reflect.TypeOf((*MockWithInlineComments)(nil).ListChangeTemplates), arg0) + return &MockWithInlineCommentsListChangeTemplatesCall{Call: call} +} + +// MockWithInlineCommentsListChangeTemplatesCall wrap *gomock.Call +type MockWithInlineCommentsListChangeTemplatesCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsListChangeTemplatesCall) Return(arg0 []*forge.ChangeTemplate, arg1 error) *MockWithInlineCommentsListChangeTemplatesCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsListChangeTemplatesCall) Do(f func(context.Context) ([]*forge.ChangeTemplate, error)) *MockWithInlineCommentsListChangeTemplatesCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsListChangeTemplatesCall) DoAndReturn(f func(context.Context) ([]*forge.ChangeTemplate, error)) *MockWithInlineCommentsListChangeTemplatesCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ListInlineComments mocks base method. +func (m *MockWithInlineComments) ListInlineComments(ctx context.Context, id forge.ChangeID) ([]*forge.InlineComment, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListInlineComments", ctx, id) + ret0, _ := ret[0].([]*forge.InlineComment) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListInlineComments indicates an expected call of ListInlineComments. +func (mr *MockWithInlineCommentsMockRecorder) ListInlineComments(ctx, id any) *MockWithInlineCommentsListInlineCommentsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListInlineComments", reflect.TypeOf((*MockWithInlineComments)(nil).ListInlineComments), ctx, id) + return &MockWithInlineCommentsListInlineCommentsCall{Call: call} +} + +// MockWithInlineCommentsListInlineCommentsCall wrap *gomock.Call +type MockWithInlineCommentsListInlineCommentsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsListInlineCommentsCall) Return(arg0 []*forge.InlineComment, arg1 error) *MockWithInlineCommentsListInlineCommentsCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsListInlineCommentsCall) Do(f func(context.Context, forge.ChangeID) ([]*forge.InlineComment, error)) *MockWithInlineCommentsListInlineCommentsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsListInlineCommentsCall) DoAndReturn(f func(context.Context, forge.ChangeID) ([]*forge.InlineComment, error)) *MockWithInlineCommentsListInlineCommentsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// MergeChange mocks base method. +func (m *MockWithInlineComments) 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 *MockWithInlineCommentsMockRecorder) MergeChange(ctx, id, opts any) *MockWithInlineCommentsMergeChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MergeChange", reflect.TypeOf((*MockWithInlineComments)(nil).MergeChange), ctx, id, opts) + return &MockWithInlineCommentsMergeChangeCall{Call: call} +} + +// MockWithInlineCommentsMergeChangeCall wrap *gomock.Call +type MockWithInlineCommentsMergeChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsMergeChangeCall) Return(arg0 error) *MockWithInlineCommentsMergeChangeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsMergeChangeCall) Do(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockWithInlineCommentsMergeChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsMergeChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockWithInlineCommentsMergeChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// NewChangeMetadata mocks base method. +func (m *MockWithInlineComments) NewChangeMetadata(ctx context.Context, id forge.ChangeID) (forge.ChangeMetadata, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewChangeMetadata", ctx, id) + ret0, _ := ret[0].(forge.ChangeMetadata) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NewChangeMetadata indicates an expected call of NewChangeMetadata. +func (mr *MockWithInlineCommentsMockRecorder) NewChangeMetadata(ctx, id any) *MockWithInlineCommentsNewChangeMetadataCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewChangeMetadata", reflect.TypeOf((*MockWithInlineComments)(nil).NewChangeMetadata), ctx, id) + return &MockWithInlineCommentsNewChangeMetadataCall{Call: call} +} + +// MockWithInlineCommentsNewChangeMetadataCall wrap *gomock.Call +type MockWithInlineCommentsNewChangeMetadataCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsNewChangeMetadataCall) Return(arg0 forge.ChangeMetadata, arg1 error) *MockWithInlineCommentsNewChangeMetadataCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsNewChangeMetadataCall) Do(f func(context.Context, forge.ChangeID) (forge.ChangeMetadata, error)) *MockWithInlineCommentsNewChangeMetadataCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsNewChangeMetadataCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChangeMetadata, error)) *MockWithInlineCommentsNewChangeMetadataCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// PostChangeComment mocks base method. +func (m *MockWithInlineComments) PostChangeComment(arg0 context.Context, arg1 forge.ChangeID, arg2 string) (forge.ChangeCommentID, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PostChangeComment", arg0, arg1, arg2) + ret0, _ := ret[0].(forge.ChangeCommentID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PostChangeComment indicates an expected call of PostChangeComment. +func (mr *MockWithInlineCommentsMockRecorder) PostChangeComment(arg0, arg1, arg2 any) *MockWithInlineCommentsPostChangeCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostChangeComment", reflect.TypeOf((*MockWithInlineComments)(nil).PostChangeComment), arg0, arg1, arg2) + return &MockWithInlineCommentsPostChangeCommentCall{Call: call} +} + +// MockWithInlineCommentsPostChangeCommentCall wrap *gomock.Call +type MockWithInlineCommentsPostChangeCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsPostChangeCommentCall) Return(arg0 forge.ChangeCommentID, arg1 error) *MockWithInlineCommentsPostChangeCommentCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsPostChangeCommentCall) Do(f func(context.Context, forge.ChangeID, string) (forge.ChangeCommentID, error)) *MockWithInlineCommentsPostChangeCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsPostChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeID, string) (forge.ChangeCommentID, error)) *MockWithInlineCommentsPostChangeCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// PostInlineComment mocks base method. +func (m *MockWithInlineComments) PostInlineComment(ctx context.Context, id forge.ChangeID, req forge.InlineCommentRequest) (*forge.InlineComment, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PostInlineComment", ctx, id, req) + ret0, _ := ret[0].(*forge.InlineComment) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PostInlineComment indicates an expected call of PostInlineComment. +func (mr *MockWithInlineCommentsMockRecorder) PostInlineComment(ctx, id, req any) *MockWithInlineCommentsPostInlineCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostInlineComment", reflect.TypeOf((*MockWithInlineComments)(nil).PostInlineComment), ctx, id, req) + return &MockWithInlineCommentsPostInlineCommentCall{Call: call} +} + +// MockWithInlineCommentsPostInlineCommentCall wrap *gomock.Call +type MockWithInlineCommentsPostInlineCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsPostInlineCommentCall) Return(arg0 *forge.InlineComment, arg1 error) *MockWithInlineCommentsPostInlineCommentCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsPostInlineCommentCall) Do(f func(context.Context, forge.ChangeID, forge.InlineCommentRequest) (*forge.InlineComment, error)) *MockWithInlineCommentsPostInlineCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsPostInlineCommentCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.InlineCommentRequest) (*forge.InlineComment, error)) *MockWithInlineCommentsPostInlineCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SubmitChange mocks base method. +func (m *MockWithInlineComments) SubmitChange(ctx context.Context, req forge.SubmitChangeRequest) (forge.SubmitChangeResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubmitChange", ctx, req) + ret0, _ := ret[0].(forge.SubmitChangeResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SubmitChange indicates an expected call of SubmitChange. +func (mr *MockWithInlineCommentsMockRecorder) SubmitChange(ctx, req any) *MockWithInlineCommentsSubmitChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitChange", reflect.TypeOf((*MockWithInlineComments)(nil).SubmitChange), ctx, req) + return &MockWithInlineCommentsSubmitChangeCall{Call: call} +} + +// MockWithInlineCommentsSubmitChangeCall wrap *gomock.Call +type MockWithInlineCommentsSubmitChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsSubmitChangeCall) Return(arg0 forge.SubmitChangeResult, arg1 error) *MockWithInlineCommentsSubmitChangeCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsSubmitChangeCall) Do(f func(context.Context, forge.SubmitChangeRequest) (forge.SubmitChangeResult, error)) *MockWithInlineCommentsSubmitChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsSubmitChangeCall) DoAndReturn(f func(context.Context, forge.SubmitChangeRequest) (forge.SubmitChangeResult, error)) *MockWithInlineCommentsSubmitChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SubmitReview mocks base method. +func (m *MockWithInlineComments) SubmitReview(ctx context.Context, id forge.ChangeID, req forge.ReviewRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubmitReview", ctx, id, req) + ret0, _ := ret[0].(error) + return ret0 +} + +// SubmitReview indicates an expected call of SubmitReview. +func (mr *MockWithInlineCommentsMockRecorder) SubmitReview(ctx, id, req any) *MockWithInlineCommentsSubmitReviewCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitReview", reflect.TypeOf((*MockWithInlineComments)(nil).SubmitReview), ctx, id, req) + return &MockWithInlineCommentsSubmitReviewCall{Call: call} +} + +// MockWithInlineCommentsSubmitReviewCall wrap *gomock.Call +type MockWithInlineCommentsSubmitReviewCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsSubmitReviewCall) Return(arg0 error) *MockWithInlineCommentsSubmitReviewCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsSubmitReviewCall) Do(f func(context.Context, forge.ChangeID, forge.ReviewRequest) error) *MockWithInlineCommentsSubmitReviewCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsSubmitReviewCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.ReviewRequest) error) *MockWithInlineCommentsSubmitReviewCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UpdateChangeComment mocks base method. +func (m *MockWithInlineComments) UpdateChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateChangeComment", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateChangeComment indicates an expected call of UpdateChangeComment. +func (mr *MockWithInlineCommentsMockRecorder) UpdateChangeComment(arg0, arg1, arg2 any) *MockWithInlineCommentsUpdateChangeCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChangeComment", reflect.TypeOf((*MockWithInlineComments)(nil).UpdateChangeComment), arg0, arg1, arg2) + return &MockWithInlineCommentsUpdateChangeCommentCall{Call: call} +} + +// MockWithInlineCommentsUpdateChangeCommentCall wrap *gomock.Call +type MockWithInlineCommentsUpdateChangeCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsUpdateChangeCommentCall) Return(arg0 error) *MockWithInlineCommentsUpdateChangeCommentCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsUpdateChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithInlineCommentsUpdateChangeCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsUpdateChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithInlineCommentsUpdateChangeCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// MockWithThreadResolution is a mock of WithThreadResolution interface. +type MockWithThreadResolution struct { + ctrl *gomock.Controller + recorder *MockWithThreadResolutionMockRecorder + isgomock struct{} +} + +// MockWithThreadResolutionMockRecorder is the mock recorder for MockWithThreadResolution. +type MockWithThreadResolutionMockRecorder struct { + mock *MockWithThreadResolution +} + +// NewMockWithThreadResolution creates a new mock instance. +func NewMockWithThreadResolution(ctrl *gomock.Controller) *MockWithThreadResolution { + mock := &MockWithThreadResolution{ctrl: ctrl} + mock.recorder = &MockWithThreadResolutionMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockWithThreadResolution) EXPECT() *MockWithThreadResolutionMockRecorder { + return m.recorder +} + +// ChangeChecksState mocks base method. +func (m *MockWithThreadResolution) 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 *MockWithThreadResolutionMockRecorder) ChangeChecksState(ctx, id any) *MockWithThreadResolutionChangeChecksStateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeChecksState", reflect.TypeOf((*MockWithThreadResolution)(nil).ChangeChecksState), ctx, id) + return &MockWithThreadResolutionChangeChecksStateCall{Call: call} +} + +// MockWithThreadResolutionChangeChecksStateCall wrap *gomock.Call +type MockWithThreadResolutionChangeChecksStateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionChangeChecksStateCall) Return(arg0 forge.ChecksState, arg1 error) *MockWithThreadResolutionChangeChecksStateCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionChangeChecksStateCall) Do(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockWithThreadResolutionChangeChecksStateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionChangeChecksStateCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockWithThreadResolutionChangeChecksStateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ChangeStatuses mocks base method. +func (m *MockWithThreadResolution) ChangeStatuses(ctx context.Context, ids []forge.ChangeID) ([]forge.ChangeStatus, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChangeStatuses", ctx, ids) + ret0, _ := ret[0].([]forge.ChangeStatus) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ChangeStatuses indicates an expected call of ChangeStatuses. +func (mr *MockWithThreadResolutionMockRecorder) ChangeStatuses(ctx, ids any) *MockWithThreadResolutionChangeStatusesCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeStatuses", reflect.TypeOf((*MockWithThreadResolution)(nil).ChangeStatuses), ctx, ids) + return &MockWithThreadResolutionChangeStatusesCall{Call: call} +} + +// MockWithThreadResolutionChangeStatusesCall wrap *gomock.Call +type MockWithThreadResolutionChangeStatusesCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionChangeStatusesCall) Return(arg0 []forge.ChangeStatus, arg1 error) *MockWithThreadResolutionChangeStatusesCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionChangeStatusesCall) Do(f func(context.Context, []forge.ChangeID) ([]forge.ChangeStatus, error)) *MockWithThreadResolutionChangeStatusesCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionChangeStatusesCall) DoAndReturn(f func(context.Context, []forge.ChangeID) ([]forge.ChangeStatus, error)) *MockWithThreadResolutionChangeStatusesCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// CommentCountsByChange mocks base method. +func (m *MockWithThreadResolution) CommentCountsByChange(ctx context.Context, ids []forge.ChangeID) ([]*forge.CommentCounts, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CommentCountsByChange", ctx, ids) + ret0, _ := ret[0].([]*forge.CommentCounts) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CommentCountsByChange indicates an expected call of CommentCountsByChange. +func (mr *MockWithThreadResolutionMockRecorder) CommentCountsByChange(ctx, ids any) *MockWithThreadResolutionCommentCountsByChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommentCountsByChange", reflect.TypeOf((*MockWithThreadResolution)(nil).CommentCountsByChange), ctx, ids) + return &MockWithThreadResolutionCommentCountsByChangeCall{Call: call} +} + +// MockWithThreadResolutionCommentCountsByChangeCall wrap *gomock.Call +type MockWithThreadResolutionCommentCountsByChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionCommentCountsByChangeCall) Return(arg0 []*forge.CommentCounts, arg1 error) *MockWithThreadResolutionCommentCountsByChangeCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionCommentCountsByChangeCall) Do(f func(context.Context, []forge.ChangeID) ([]*forge.CommentCounts, error)) *MockWithThreadResolutionCommentCountsByChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionCommentCountsByChangeCall) DoAndReturn(f func(context.Context, []forge.ChangeID) ([]*forge.CommentCounts, error)) *MockWithThreadResolutionCommentCountsByChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// DeleteChangeComment mocks base method. +func (m *MockWithThreadResolution) DeleteChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteChangeComment", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteChangeComment indicates an expected call of DeleteChangeComment. +func (mr *MockWithThreadResolutionMockRecorder) DeleteChangeComment(arg0, arg1 any) *MockWithThreadResolutionDeleteChangeCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeComment", reflect.TypeOf((*MockWithThreadResolution)(nil).DeleteChangeComment), arg0, arg1) + return &MockWithThreadResolutionDeleteChangeCommentCall{Call: call} +} + +// MockWithThreadResolutionDeleteChangeCommentCall wrap *gomock.Call +type MockWithThreadResolutionDeleteChangeCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionDeleteChangeCommentCall) Return(arg0 error) *MockWithThreadResolutionDeleteChangeCommentCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionDeleteChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID) error) *MockWithThreadResolutionDeleteChangeCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionDeleteChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID) error) *MockWithThreadResolutionDeleteChangeCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// EditChange mocks base method. +func (m *MockWithThreadResolution) EditChange(ctx context.Context, id forge.ChangeID, opts forge.EditChangeOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EditChange", ctx, id, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// EditChange indicates an expected call of EditChange. +func (mr *MockWithThreadResolutionMockRecorder) EditChange(ctx, id, opts any) *MockWithThreadResolutionEditChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EditChange", reflect.TypeOf((*MockWithThreadResolution)(nil).EditChange), ctx, id, opts) + return &MockWithThreadResolutionEditChangeCall{Call: call} +} + +// MockWithThreadResolutionEditChangeCall wrap *gomock.Call +type MockWithThreadResolutionEditChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionEditChangeCall) Return(arg0 error) *MockWithThreadResolutionEditChangeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionEditChangeCall) Do(f func(context.Context, forge.ChangeID, forge.EditChangeOptions) error) *MockWithThreadResolutionEditChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionEditChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.EditChangeOptions) error) *MockWithThreadResolutionEditChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// FindChangeByID mocks base method. +func (m *MockWithThreadResolution) FindChangeByID(ctx context.Context, id forge.ChangeID) (*forge.FindChangeItem, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindChangeByID", ctx, id) + ret0, _ := ret[0].(*forge.FindChangeItem) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindChangeByID indicates an expected call of FindChangeByID. +func (mr *MockWithThreadResolutionMockRecorder) FindChangeByID(ctx, id any) *MockWithThreadResolutionFindChangeByIDCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindChangeByID", reflect.TypeOf((*MockWithThreadResolution)(nil).FindChangeByID), ctx, id) + return &MockWithThreadResolutionFindChangeByIDCall{Call: call} +} + +// MockWithThreadResolutionFindChangeByIDCall wrap *gomock.Call +type MockWithThreadResolutionFindChangeByIDCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionFindChangeByIDCall) Return(arg0 *forge.FindChangeItem, arg1 error) *MockWithThreadResolutionFindChangeByIDCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionFindChangeByIDCall) Do(f func(context.Context, forge.ChangeID) (*forge.FindChangeItem, error)) *MockWithThreadResolutionFindChangeByIDCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionFindChangeByIDCall) DoAndReturn(f func(context.Context, forge.ChangeID) (*forge.FindChangeItem, error)) *MockWithThreadResolutionFindChangeByIDCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// FindChangesByBranch mocks base method. +func (m *MockWithThreadResolution) FindChangesByBranch(ctx context.Context, branch string, opts forge.FindChangesOptions) ([]*forge.FindChangeItem, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindChangesByBranch", ctx, branch, opts) + ret0, _ := ret[0].([]*forge.FindChangeItem) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindChangesByBranch indicates an expected call of FindChangesByBranch. +func (mr *MockWithThreadResolutionMockRecorder) FindChangesByBranch(ctx, branch, opts any) *MockWithThreadResolutionFindChangesByBranchCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindChangesByBranch", reflect.TypeOf((*MockWithThreadResolution)(nil).FindChangesByBranch), ctx, branch, opts) + return &MockWithThreadResolutionFindChangesByBranchCall{Call: call} +} + +// MockWithThreadResolutionFindChangesByBranchCall wrap *gomock.Call +type MockWithThreadResolutionFindChangesByBranchCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionFindChangesByBranchCall) Return(arg0 []*forge.FindChangeItem, arg1 error) *MockWithThreadResolutionFindChangesByBranchCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionFindChangesByBranchCall) Do(f func(context.Context, string, forge.FindChangesOptions) ([]*forge.FindChangeItem, error)) *MockWithThreadResolutionFindChangesByBranchCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionFindChangesByBranchCall) DoAndReturn(f func(context.Context, string, forge.FindChangesOptions) ([]*forge.FindChangeItem, error)) *MockWithThreadResolutionFindChangesByBranchCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Forge mocks base method. +func (m *MockWithThreadResolution) Forge() forge.Forge { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Forge") + ret0, _ := ret[0].(forge.Forge) + return ret0 +} + +// Forge indicates an expected call of Forge. +func (mr *MockWithThreadResolutionMockRecorder) Forge() *MockWithThreadResolutionForgeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Forge", reflect.TypeOf((*MockWithThreadResolution)(nil).Forge)) + return &MockWithThreadResolutionForgeCall{Call: call} +} + +// MockWithThreadResolutionForgeCall wrap *gomock.Call +type MockWithThreadResolutionForgeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionForgeCall) Return(arg0 forge.Forge) *MockWithThreadResolutionForgeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionForgeCall) Do(f func() forge.Forge) *MockWithThreadResolutionForgeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionForgeCall) DoAndReturn(f func() forge.Forge) *MockWithThreadResolutionForgeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ListChangeComments mocks base method. +func (m *MockWithThreadResolution) ListChangeComments(arg0 context.Context, arg1 forge.ChangeID, arg2 *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListChangeComments", arg0, arg1, arg2) + ret0, _ := ret[0].(iter.Seq2[*forge.ListChangeCommentItem, error]) + return ret0 +} + +// ListChangeComments indicates an expected call of ListChangeComments. +func (mr *MockWithThreadResolutionMockRecorder) ListChangeComments(arg0, arg1, arg2 any) *MockWithThreadResolutionListChangeCommentsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeComments", reflect.TypeOf((*MockWithThreadResolution)(nil).ListChangeComments), arg0, arg1, arg2) + return &MockWithThreadResolutionListChangeCommentsCall{Call: call} +} + +// MockWithThreadResolutionListChangeCommentsCall wrap *gomock.Call +type MockWithThreadResolutionListChangeCommentsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionListChangeCommentsCall) Return(arg0 iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithThreadResolutionListChangeCommentsCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionListChangeCommentsCall) Do(f func(context.Context, forge.ChangeID, *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithThreadResolutionListChangeCommentsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionListChangeCommentsCall) DoAndReturn(f func(context.Context, forge.ChangeID, *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithThreadResolutionListChangeCommentsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ListChangeTemplates mocks base method. +func (m *MockWithThreadResolution) ListChangeTemplates(arg0 context.Context) ([]*forge.ChangeTemplate, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListChangeTemplates", arg0) + ret0, _ := ret[0].([]*forge.ChangeTemplate) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListChangeTemplates indicates an expected call of ListChangeTemplates. +func (mr *MockWithThreadResolutionMockRecorder) ListChangeTemplates(arg0 any) *MockWithThreadResolutionListChangeTemplatesCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeTemplates", reflect.TypeOf((*MockWithThreadResolution)(nil).ListChangeTemplates), arg0) + return &MockWithThreadResolutionListChangeTemplatesCall{Call: call} +} + +// MockWithThreadResolutionListChangeTemplatesCall wrap *gomock.Call +type MockWithThreadResolutionListChangeTemplatesCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionListChangeTemplatesCall) Return(arg0 []*forge.ChangeTemplate, arg1 error) *MockWithThreadResolutionListChangeTemplatesCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionListChangeTemplatesCall) Do(f func(context.Context) ([]*forge.ChangeTemplate, error)) *MockWithThreadResolutionListChangeTemplatesCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionListChangeTemplatesCall) DoAndReturn(f func(context.Context) ([]*forge.ChangeTemplate, error)) *MockWithThreadResolutionListChangeTemplatesCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// MergeChange mocks base method. +func (m *MockWithThreadResolution) 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 *MockWithThreadResolutionMockRecorder) MergeChange(ctx, id, opts any) *MockWithThreadResolutionMergeChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MergeChange", reflect.TypeOf((*MockWithThreadResolution)(nil).MergeChange), ctx, id, opts) + return &MockWithThreadResolutionMergeChangeCall{Call: call} +} + +// MockWithThreadResolutionMergeChangeCall wrap *gomock.Call +type MockWithThreadResolutionMergeChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionMergeChangeCall) Return(arg0 error) *MockWithThreadResolutionMergeChangeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionMergeChangeCall) Do(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockWithThreadResolutionMergeChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionMergeChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockWithThreadResolutionMergeChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// NewChangeMetadata mocks base method. +func (m *MockWithThreadResolution) NewChangeMetadata(ctx context.Context, id forge.ChangeID) (forge.ChangeMetadata, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewChangeMetadata", ctx, id) + ret0, _ := ret[0].(forge.ChangeMetadata) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NewChangeMetadata indicates an expected call of NewChangeMetadata. +func (mr *MockWithThreadResolutionMockRecorder) NewChangeMetadata(ctx, id any) *MockWithThreadResolutionNewChangeMetadataCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewChangeMetadata", reflect.TypeOf((*MockWithThreadResolution)(nil).NewChangeMetadata), ctx, id) + return &MockWithThreadResolutionNewChangeMetadataCall{Call: call} +} + +// MockWithThreadResolutionNewChangeMetadataCall wrap *gomock.Call +type MockWithThreadResolutionNewChangeMetadataCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionNewChangeMetadataCall) Return(arg0 forge.ChangeMetadata, arg1 error) *MockWithThreadResolutionNewChangeMetadataCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionNewChangeMetadataCall) Do(f func(context.Context, forge.ChangeID) (forge.ChangeMetadata, error)) *MockWithThreadResolutionNewChangeMetadataCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionNewChangeMetadataCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChangeMetadata, error)) *MockWithThreadResolutionNewChangeMetadataCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// PostChangeComment mocks base method. +func (m *MockWithThreadResolution) PostChangeComment(arg0 context.Context, arg1 forge.ChangeID, arg2 string) (forge.ChangeCommentID, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PostChangeComment", arg0, arg1, arg2) + ret0, _ := ret[0].(forge.ChangeCommentID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PostChangeComment indicates an expected call of PostChangeComment. +func (mr *MockWithThreadResolutionMockRecorder) PostChangeComment(arg0, arg1, arg2 any) *MockWithThreadResolutionPostChangeCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostChangeComment", reflect.TypeOf((*MockWithThreadResolution)(nil).PostChangeComment), arg0, arg1, arg2) + return &MockWithThreadResolutionPostChangeCommentCall{Call: call} +} + +// MockWithThreadResolutionPostChangeCommentCall wrap *gomock.Call +type MockWithThreadResolutionPostChangeCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionPostChangeCommentCall) Return(arg0 forge.ChangeCommentID, arg1 error) *MockWithThreadResolutionPostChangeCommentCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionPostChangeCommentCall) Do(f func(context.Context, forge.ChangeID, string) (forge.ChangeCommentID, error)) *MockWithThreadResolutionPostChangeCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionPostChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeID, string) (forge.ChangeCommentID, error)) *MockWithThreadResolutionPostChangeCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ResolveThread mocks base method. +func (m *MockWithThreadResolution) ResolveThread(ctx context.Context, threadID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ResolveThread", ctx, threadID) + ret0, _ := ret[0].(error) + return ret0 +} + +// ResolveThread indicates an expected call of ResolveThread. +func (mr *MockWithThreadResolutionMockRecorder) ResolveThread(ctx, threadID any) *MockWithThreadResolutionResolveThreadCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveThread", reflect.TypeOf((*MockWithThreadResolution)(nil).ResolveThread), ctx, threadID) + return &MockWithThreadResolutionResolveThreadCall{Call: call} +} + +// MockWithThreadResolutionResolveThreadCall wrap *gomock.Call +type MockWithThreadResolutionResolveThreadCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionResolveThreadCall) Return(arg0 error) *MockWithThreadResolutionResolveThreadCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionResolveThreadCall) Do(f func(context.Context, string) error) *MockWithThreadResolutionResolveThreadCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionResolveThreadCall) DoAndReturn(f func(context.Context, string) error) *MockWithThreadResolutionResolveThreadCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SubmitChange mocks base method. +func (m *MockWithThreadResolution) SubmitChange(ctx context.Context, req forge.SubmitChangeRequest) (forge.SubmitChangeResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubmitChange", ctx, req) + ret0, _ := ret[0].(forge.SubmitChangeResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SubmitChange indicates an expected call of SubmitChange. +func (mr *MockWithThreadResolutionMockRecorder) SubmitChange(ctx, req any) *MockWithThreadResolutionSubmitChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitChange", reflect.TypeOf((*MockWithThreadResolution)(nil).SubmitChange), ctx, req) + return &MockWithThreadResolutionSubmitChangeCall{Call: call} +} + +// MockWithThreadResolutionSubmitChangeCall wrap *gomock.Call +type MockWithThreadResolutionSubmitChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionSubmitChangeCall) Return(arg0 forge.SubmitChangeResult, arg1 error) *MockWithThreadResolutionSubmitChangeCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionSubmitChangeCall) Do(f func(context.Context, forge.SubmitChangeRequest) (forge.SubmitChangeResult, error)) *MockWithThreadResolutionSubmitChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionSubmitChangeCall) DoAndReturn(f func(context.Context, forge.SubmitChangeRequest) (forge.SubmitChangeResult, error)) *MockWithThreadResolutionSubmitChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UnresolveThread mocks base method. +func (m *MockWithThreadResolution) UnresolveThread(ctx context.Context, threadID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UnresolveThread", ctx, threadID) + ret0, _ := ret[0].(error) + return ret0 +} + +// UnresolveThread indicates an expected call of UnresolveThread. +func (mr *MockWithThreadResolutionMockRecorder) UnresolveThread(ctx, threadID any) *MockWithThreadResolutionUnresolveThreadCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnresolveThread", reflect.TypeOf((*MockWithThreadResolution)(nil).UnresolveThread), ctx, threadID) + return &MockWithThreadResolutionUnresolveThreadCall{Call: call} +} + +// MockWithThreadResolutionUnresolveThreadCall wrap *gomock.Call +type MockWithThreadResolutionUnresolveThreadCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionUnresolveThreadCall) Return(arg0 error) *MockWithThreadResolutionUnresolveThreadCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionUnresolveThreadCall) Do(f func(context.Context, string) error) *MockWithThreadResolutionUnresolveThreadCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionUnresolveThreadCall) DoAndReturn(f func(context.Context, string) error) *MockWithThreadResolutionUnresolveThreadCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UpdateChangeComment mocks base method. +func (m *MockWithThreadResolution) UpdateChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateChangeComment", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateChangeComment indicates an expected call of UpdateChangeComment. +func (mr *MockWithThreadResolutionMockRecorder) UpdateChangeComment(arg0, arg1, arg2 any) *MockWithThreadResolutionUpdateChangeCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChangeComment", reflect.TypeOf((*MockWithThreadResolution)(nil).UpdateChangeComment), arg0, arg1, arg2) + return &MockWithThreadResolutionUpdateChangeCommentCall{Call: call} +} + +// MockWithThreadResolutionUpdateChangeCommentCall wrap *gomock.Call +type MockWithThreadResolutionUpdateChangeCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithThreadResolutionUpdateChangeCommentCall) Return(arg0 error) *MockWithThreadResolutionUpdateChangeCommentCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithThreadResolutionUpdateChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithThreadResolutionUpdateChangeCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithThreadResolutionUpdateChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithThreadResolutionUpdateChangeCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// MockWithCommentEdit is a mock of WithCommentEdit interface. +type MockWithCommentEdit struct { + ctrl *gomock.Controller + recorder *MockWithCommentEditMockRecorder + isgomock struct{} +} + +// MockWithCommentEditMockRecorder is the mock recorder for MockWithCommentEdit. +type MockWithCommentEditMockRecorder struct { + mock *MockWithCommentEdit +} + +// NewMockWithCommentEdit creates a new mock instance. +func NewMockWithCommentEdit(ctrl *gomock.Controller) *MockWithCommentEdit { + mock := &MockWithCommentEdit{ctrl: ctrl} + mock.recorder = &MockWithCommentEditMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockWithCommentEdit) EXPECT() *MockWithCommentEditMockRecorder { + return m.recorder +} + +// ChangeChecksState mocks base method. +func (m *MockWithCommentEdit) 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 *MockWithCommentEditMockRecorder) ChangeChecksState(ctx, id any) *MockWithCommentEditChangeChecksStateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeChecksState", reflect.TypeOf((*MockWithCommentEdit)(nil).ChangeChecksState), ctx, id) + return &MockWithCommentEditChangeChecksStateCall{Call: call} +} + +// MockWithCommentEditChangeChecksStateCall wrap *gomock.Call +type MockWithCommentEditChangeChecksStateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditChangeChecksStateCall) Return(arg0 forge.ChecksState, arg1 error) *MockWithCommentEditChangeChecksStateCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditChangeChecksStateCall) Do(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockWithCommentEditChangeChecksStateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditChangeChecksStateCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockWithCommentEditChangeChecksStateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ChangeStatuses mocks base method. +func (m *MockWithCommentEdit) ChangeStatuses(ctx context.Context, ids []forge.ChangeID) ([]forge.ChangeStatus, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChangeStatuses", ctx, ids) + ret0, _ := ret[0].([]forge.ChangeStatus) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ChangeStatuses indicates an expected call of ChangeStatuses. +func (mr *MockWithCommentEditMockRecorder) ChangeStatuses(ctx, ids any) *MockWithCommentEditChangeStatusesCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeStatuses", reflect.TypeOf((*MockWithCommentEdit)(nil).ChangeStatuses), ctx, ids) + return &MockWithCommentEditChangeStatusesCall{Call: call} +} + +// MockWithCommentEditChangeStatusesCall wrap *gomock.Call +type MockWithCommentEditChangeStatusesCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditChangeStatusesCall) Return(arg0 []forge.ChangeStatus, arg1 error) *MockWithCommentEditChangeStatusesCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditChangeStatusesCall) Do(f func(context.Context, []forge.ChangeID) ([]forge.ChangeStatus, error)) *MockWithCommentEditChangeStatusesCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditChangeStatusesCall) DoAndReturn(f func(context.Context, []forge.ChangeID) ([]forge.ChangeStatus, error)) *MockWithCommentEditChangeStatusesCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// CommentCountsByChange mocks base method. +func (m *MockWithCommentEdit) CommentCountsByChange(ctx context.Context, ids []forge.ChangeID) ([]*forge.CommentCounts, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CommentCountsByChange", ctx, ids) + ret0, _ := ret[0].([]*forge.CommentCounts) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CommentCountsByChange indicates an expected call of CommentCountsByChange. +func (mr *MockWithCommentEditMockRecorder) CommentCountsByChange(ctx, ids any) *MockWithCommentEditCommentCountsByChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommentCountsByChange", reflect.TypeOf((*MockWithCommentEdit)(nil).CommentCountsByChange), ctx, ids) + return &MockWithCommentEditCommentCountsByChangeCall{Call: call} +} + +// MockWithCommentEditCommentCountsByChangeCall wrap *gomock.Call +type MockWithCommentEditCommentCountsByChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditCommentCountsByChangeCall) Return(arg0 []*forge.CommentCounts, arg1 error) *MockWithCommentEditCommentCountsByChangeCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditCommentCountsByChangeCall) Do(f func(context.Context, []forge.ChangeID) ([]*forge.CommentCounts, error)) *MockWithCommentEditCommentCountsByChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditCommentCountsByChangeCall) DoAndReturn(f func(context.Context, []forge.ChangeID) ([]*forge.CommentCounts, error)) *MockWithCommentEditCommentCountsByChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// DeleteChangeComment mocks base method. +func (m *MockWithCommentEdit) DeleteChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteChangeComment", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteChangeComment indicates an expected call of DeleteChangeComment. +func (mr *MockWithCommentEditMockRecorder) DeleteChangeComment(arg0, arg1 any) *MockWithCommentEditDeleteChangeCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeComment", reflect.TypeOf((*MockWithCommentEdit)(nil).DeleteChangeComment), arg0, arg1) + return &MockWithCommentEditDeleteChangeCommentCall{Call: call} +} + +// MockWithCommentEditDeleteChangeCommentCall wrap *gomock.Call +type MockWithCommentEditDeleteChangeCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditDeleteChangeCommentCall) Return(arg0 error) *MockWithCommentEditDeleteChangeCommentCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditDeleteChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID) error) *MockWithCommentEditDeleteChangeCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditDeleteChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID) error) *MockWithCommentEditDeleteChangeCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// EditChange mocks base method. +func (m *MockWithCommentEdit) EditChange(ctx context.Context, id forge.ChangeID, opts forge.EditChangeOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EditChange", ctx, id, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// EditChange indicates an expected call of EditChange. +func (mr *MockWithCommentEditMockRecorder) EditChange(ctx, id, opts any) *MockWithCommentEditEditChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EditChange", reflect.TypeOf((*MockWithCommentEdit)(nil).EditChange), ctx, id, opts) + return &MockWithCommentEditEditChangeCall{Call: call} +} + +// MockWithCommentEditEditChangeCall wrap *gomock.Call +type MockWithCommentEditEditChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditEditChangeCall) Return(arg0 error) *MockWithCommentEditEditChangeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditEditChangeCall) Do(f func(context.Context, forge.ChangeID, forge.EditChangeOptions) error) *MockWithCommentEditEditChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditEditChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.EditChangeOptions) error) *MockWithCommentEditEditChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// EditComment mocks base method. +func (m *MockWithCommentEdit) EditComment(ctx context.Context, id forge.ChangeCommentID, body string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EditComment", ctx, id, body) + ret0, _ := ret[0].(error) + return ret0 +} + +// EditComment indicates an expected call of EditComment. +func (mr *MockWithCommentEditMockRecorder) EditComment(ctx, id, body any) *MockWithCommentEditEditCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EditComment", reflect.TypeOf((*MockWithCommentEdit)(nil).EditComment), ctx, id, body) + return &MockWithCommentEditEditCommentCall{Call: call} +} + +// MockWithCommentEditEditCommentCall wrap *gomock.Call +type MockWithCommentEditEditCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditEditCommentCall) Return(arg0 error) *MockWithCommentEditEditCommentCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditEditCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithCommentEditEditCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditEditCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithCommentEditEditCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// FindChangeByID mocks base method. +func (m *MockWithCommentEdit) FindChangeByID(ctx context.Context, id forge.ChangeID) (*forge.FindChangeItem, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindChangeByID", ctx, id) + ret0, _ := ret[0].(*forge.FindChangeItem) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindChangeByID indicates an expected call of FindChangeByID. +func (mr *MockWithCommentEditMockRecorder) FindChangeByID(ctx, id any) *MockWithCommentEditFindChangeByIDCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindChangeByID", reflect.TypeOf((*MockWithCommentEdit)(nil).FindChangeByID), ctx, id) + return &MockWithCommentEditFindChangeByIDCall{Call: call} +} + +// MockWithCommentEditFindChangeByIDCall wrap *gomock.Call +type MockWithCommentEditFindChangeByIDCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditFindChangeByIDCall) Return(arg0 *forge.FindChangeItem, arg1 error) *MockWithCommentEditFindChangeByIDCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditFindChangeByIDCall) Do(f func(context.Context, forge.ChangeID) (*forge.FindChangeItem, error)) *MockWithCommentEditFindChangeByIDCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditFindChangeByIDCall) DoAndReturn(f func(context.Context, forge.ChangeID) (*forge.FindChangeItem, error)) *MockWithCommentEditFindChangeByIDCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// FindChangesByBranch mocks base method. +func (m *MockWithCommentEdit) FindChangesByBranch(ctx context.Context, branch string, opts forge.FindChangesOptions) ([]*forge.FindChangeItem, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindChangesByBranch", ctx, branch, opts) + ret0, _ := ret[0].([]*forge.FindChangeItem) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindChangesByBranch indicates an expected call of FindChangesByBranch. +func (mr *MockWithCommentEditMockRecorder) FindChangesByBranch(ctx, branch, opts any) *MockWithCommentEditFindChangesByBranchCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindChangesByBranch", reflect.TypeOf((*MockWithCommentEdit)(nil).FindChangesByBranch), ctx, branch, opts) + return &MockWithCommentEditFindChangesByBranchCall{Call: call} +} + +// MockWithCommentEditFindChangesByBranchCall wrap *gomock.Call +type MockWithCommentEditFindChangesByBranchCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditFindChangesByBranchCall) Return(arg0 []*forge.FindChangeItem, arg1 error) *MockWithCommentEditFindChangesByBranchCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditFindChangesByBranchCall) Do(f func(context.Context, string, forge.FindChangesOptions) ([]*forge.FindChangeItem, error)) *MockWithCommentEditFindChangesByBranchCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditFindChangesByBranchCall) DoAndReturn(f func(context.Context, string, forge.FindChangesOptions) ([]*forge.FindChangeItem, error)) *MockWithCommentEditFindChangesByBranchCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Forge mocks base method. +func (m *MockWithCommentEdit) Forge() forge.Forge { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Forge") + ret0, _ := ret[0].(forge.Forge) + return ret0 +} + +// Forge indicates an expected call of Forge. +func (mr *MockWithCommentEditMockRecorder) Forge() *MockWithCommentEditForgeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Forge", reflect.TypeOf((*MockWithCommentEdit)(nil).Forge)) + return &MockWithCommentEditForgeCall{Call: call} +} + +// MockWithCommentEditForgeCall wrap *gomock.Call +type MockWithCommentEditForgeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditForgeCall) Return(arg0 forge.Forge) *MockWithCommentEditForgeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditForgeCall) Do(f func() forge.Forge) *MockWithCommentEditForgeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditForgeCall) DoAndReturn(f func() forge.Forge) *MockWithCommentEditForgeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ListChangeComments mocks base method. +func (m *MockWithCommentEdit) ListChangeComments(arg0 context.Context, arg1 forge.ChangeID, arg2 *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListChangeComments", arg0, arg1, arg2) + ret0, _ := ret[0].(iter.Seq2[*forge.ListChangeCommentItem, error]) + return ret0 +} + +// ListChangeComments indicates an expected call of ListChangeComments. +func (mr *MockWithCommentEditMockRecorder) ListChangeComments(arg0, arg1, arg2 any) *MockWithCommentEditListChangeCommentsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeComments", reflect.TypeOf((*MockWithCommentEdit)(nil).ListChangeComments), arg0, arg1, arg2) + return &MockWithCommentEditListChangeCommentsCall{Call: call} +} + +// MockWithCommentEditListChangeCommentsCall wrap *gomock.Call +type MockWithCommentEditListChangeCommentsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditListChangeCommentsCall) Return(arg0 iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithCommentEditListChangeCommentsCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditListChangeCommentsCall) Do(f func(context.Context, forge.ChangeID, *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithCommentEditListChangeCommentsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditListChangeCommentsCall) DoAndReturn(f func(context.Context, forge.ChangeID, *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithCommentEditListChangeCommentsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ListChangeTemplates mocks base method. +func (m *MockWithCommentEdit) ListChangeTemplates(arg0 context.Context) ([]*forge.ChangeTemplate, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListChangeTemplates", arg0) + ret0, _ := ret[0].([]*forge.ChangeTemplate) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListChangeTemplates indicates an expected call of ListChangeTemplates. +func (mr *MockWithCommentEditMockRecorder) ListChangeTemplates(arg0 any) *MockWithCommentEditListChangeTemplatesCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeTemplates", reflect.TypeOf((*MockWithCommentEdit)(nil).ListChangeTemplates), arg0) + return &MockWithCommentEditListChangeTemplatesCall{Call: call} +} + +// MockWithCommentEditListChangeTemplatesCall wrap *gomock.Call +type MockWithCommentEditListChangeTemplatesCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditListChangeTemplatesCall) Return(arg0 []*forge.ChangeTemplate, arg1 error) *MockWithCommentEditListChangeTemplatesCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditListChangeTemplatesCall) Do(f func(context.Context) ([]*forge.ChangeTemplate, error)) *MockWithCommentEditListChangeTemplatesCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditListChangeTemplatesCall) DoAndReturn(f func(context.Context) ([]*forge.ChangeTemplate, error)) *MockWithCommentEditListChangeTemplatesCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// MergeChange mocks base method. +func (m *MockWithCommentEdit) 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 *MockWithCommentEditMockRecorder) MergeChange(ctx, id, opts any) *MockWithCommentEditMergeChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MergeChange", reflect.TypeOf((*MockWithCommentEdit)(nil).MergeChange), ctx, id, opts) + return &MockWithCommentEditMergeChangeCall{Call: call} +} + +// MockWithCommentEditMergeChangeCall wrap *gomock.Call +type MockWithCommentEditMergeChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditMergeChangeCall) Return(arg0 error) *MockWithCommentEditMergeChangeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditMergeChangeCall) Do(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockWithCommentEditMergeChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditMergeChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockWithCommentEditMergeChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// NewChangeMetadata mocks base method. +func (m *MockWithCommentEdit) NewChangeMetadata(ctx context.Context, id forge.ChangeID) (forge.ChangeMetadata, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewChangeMetadata", ctx, id) + ret0, _ := ret[0].(forge.ChangeMetadata) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NewChangeMetadata indicates an expected call of NewChangeMetadata. +func (mr *MockWithCommentEditMockRecorder) NewChangeMetadata(ctx, id any) *MockWithCommentEditNewChangeMetadataCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewChangeMetadata", reflect.TypeOf((*MockWithCommentEdit)(nil).NewChangeMetadata), ctx, id) + return &MockWithCommentEditNewChangeMetadataCall{Call: call} +} + +// MockWithCommentEditNewChangeMetadataCall wrap *gomock.Call +type MockWithCommentEditNewChangeMetadataCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditNewChangeMetadataCall) Return(arg0 forge.ChangeMetadata, arg1 error) *MockWithCommentEditNewChangeMetadataCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditNewChangeMetadataCall) Do(f func(context.Context, forge.ChangeID) (forge.ChangeMetadata, error)) *MockWithCommentEditNewChangeMetadataCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditNewChangeMetadataCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChangeMetadata, error)) *MockWithCommentEditNewChangeMetadataCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// PostChangeComment mocks base method. +func (m *MockWithCommentEdit) PostChangeComment(arg0 context.Context, arg1 forge.ChangeID, arg2 string) (forge.ChangeCommentID, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PostChangeComment", arg0, arg1, arg2) + ret0, _ := ret[0].(forge.ChangeCommentID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// PostChangeComment indicates an expected call of PostChangeComment. +func (mr *MockWithCommentEditMockRecorder) PostChangeComment(arg0, arg1, arg2 any) *MockWithCommentEditPostChangeCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostChangeComment", reflect.TypeOf((*MockWithCommentEdit)(nil).PostChangeComment), arg0, arg1, arg2) + return &MockWithCommentEditPostChangeCommentCall{Call: call} +} + +// MockWithCommentEditPostChangeCommentCall wrap *gomock.Call +type MockWithCommentEditPostChangeCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditPostChangeCommentCall) Return(arg0 forge.ChangeCommentID, arg1 error) *MockWithCommentEditPostChangeCommentCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditPostChangeCommentCall) Do(f func(context.Context, forge.ChangeID, string) (forge.ChangeCommentID, error)) *MockWithCommentEditPostChangeCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditPostChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeID, string) (forge.ChangeCommentID, error)) *MockWithCommentEditPostChangeCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SubmitChange mocks base method. +func (m *MockWithCommentEdit) SubmitChange(ctx context.Context, req forge.SubmitChangeRequest) (forge.SubmitChangeResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubmitChange", ctx, req) + ret0, _ := ret[0].(forge.SubmitChangeResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SubmitChange indicates an expected call of SubmitChange. +func (mr *MockWithCommentEditMockRecorder) SubmitChange(ctx, req any) *MockWithCommentEditSubmitChangeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitChange", reflect.TypeOf((*MockWithCommentEdit)(nil).SubmitChange), ctx, req) + return &MockWithCommentEditSubmitChangeCall{Call: call} +} + +// MockWithCommentEditSubmitChangeCall wrap *gomock.Call +type MockWithCommentEditSubmitChangeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditSubmitChangeCall) Return(arg0 forge.SubmitChangeResult, arg1 error) *MockWithCommentEditSubmitChangeCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditSubmitChangeCall) Do(f func(context.Context, forge.SubmitChangeRequest) (forge.SubmitChangeResult, error)) *MockWithCommentEditSubmitChangeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditSubmitChangeCall) DoAndReturn(f func(context.Context, forge.SubmitChangeRequest) (forge.SubmitChangeResult, error)) *MockWithCommentEditSubmitChangeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UpdateChangeComment mocks base method. +func (m *MockWithCommentEdit) UpdateChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateChangeComment", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateChangeComment indicates an expected call of UpdateChangeComment. +func (mr *MockWithCommentEditMockRecorder) UpdateChangeComment(arg0, arg1, arg2 any) *MockWithCommentEditUpdateChangeCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChangeComment", reflect.TypeOf((*MockWithCommentEdit)(nil).UpdateChangeComment), arg0, arg1, arg2) + return &MockWithCommentEditUpdateChangeCommentCall{Call: call} +} + +// MockWithCommentEditUpdateChangeCommentCall wrap *gomock.Call +type MockWithCommentEditUpdateChangeCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithCommentEditUpdateChangeCommentCall) Return(arg0 error) *MockWithCommentEditUpdateChangeCommentCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithCommentEditUpdateChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithCommentEditUpdateChangeCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithCommentEditUpdateChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithCommentEditUpdateChangeCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/internal/forge/github/inline_comment.go b/internal/forge/github/inline_comment.go new file mode 100644 index 000000000..57018cf5e --- /dev/null +++ b/internal/forge/github/inline_comment.go @@ -0,0 +1,377 @@ +package github + +import ( + "context" + "fmt" + "time" + + "github.com/shurcooL/githubv4" + "go.abhg.dev/gs/internal/forge" +) + +var ( + _ forge.WithInlineComments = (*Repository)(nil) + _ forge.WithThreadResolution = (*Repository)(nil) + _ forge.WithCommentEdit = (*Repository)(nil) +) + +// ListInlineComments lists inline/review comments on a PR +// by querying the reviewThreads connection. +func (r *Repository) ListInlineComments( + ctx context.Context, + id forge.ChangeID, +) ([]*forge.InlineComment, error) { + pr := mustPR(id) + gqlID, err := r.graphQLID(ctx, pr) + if err != nil { + return nil, err + } + + type commentNode struct { + ID githubv4.ID `graphql:"id"` + Body string `graphql:"body"` + URL string `graphql:"url"` + Author struct { + Login string `graphql:"login"` + } `graphql:"author"` + CreatedAt githubv4.DateTime `graphql:"createdAt"` + Outdated bool `graphql:"outdated"` + } + + type threadNode struct { + ID githubv4.ID `graphql:"id"` + IsResolved bool `graphql:"isResolved"` + Path string `graphql:"path"` + Line *int `graphql:"line"` + Comments struct { + Nodes []commentNode `graphql:"nodes"` + } `graphql:"comments(first: 100)"` + } + + var q struct { + Node struct { + PullRequest struct { + ReviewThreads struct { + PageInfo struct { + HasNextPage bool `graphql:"hasNextPage"` + EndCursor githubv4.String `graphql:"endCursor"` + } `graphql:"pageInfo"` + Nodes []threadNode `graphql:"nodes"` + } `graphql:"reviewThreads(first: $first, after: $after)"` + } `graphql:"... on PullRequest"` + } `graphql:"node(id: $id)"` + } + + variables := map[string]any{ + "id": gqlID, + "first": githubv4.Int(100), + "after": (*githubv4.String)(nil), + } + + var comments []*forge.InlineComment + for { + if err := r.client.Query(ctx, &q, variables); err != nil { + return nil, fmt.Errorf("list inline comments: %w", err) + } + + for _, thread := range q.Node.PullRequest.ReviewThreads.Nodes { + threadID := fmt.Sprint(thread.ID) + line := 0 + if thread.Line != nil { + line = *thread.Line + } + + for _, c := range thread.Comments.Nodes { + comments = append(comments, &forge.InlineComment{ + ID: &PRComment{ + GQLID: c.ID, + URL: c.URL, + }, + ThreadID: threadID, + Path: thread.Path, + Line: line, + Body: c.Body, + Author: c.Author.Login, + Resolved: thread.IsResolved, + Outdated: c.Outdated, + CreatedAt: c.CreatedAt.Time, + }) + } + } + + pi := q.Node.PullRequest.ReviewThreads.PageInfo + if !pi.HasNextPage { + break + } + variables["after"] = pi.EndCursor + } + + return comments, nil +} + +// SubmitReview posts a batch of inline comments +// as a single review on a PR. +func (r *Repository) SubmitReview( + ctx context.Context, + id forge.ChangeID, + req forge.ReviewRequest, +) error { + pr := mustPR(id) + gqlID, err := r.graphQLID(ctx, pr) + if err != nil { + return err + } + + // Map review event to GitHub's enum. + var event githubv4.PullRequestReviewEvent + switch req.Event { + case forge.ReviewApprove: + event = githubv4.PullRequestReviewEventApprove + case forge.ReviewRequestChanges: + event = githubv4.PullRequestReviewEventRequestChanges + default: + event = githubv4.PullRequestReviewEventComment + } + + // Build thread inputs for inline comments. + var threads []*githubv4.DraftPullRequestReviewThread + for _, c := range req.Comments { + side := githubv4.DiffSideRight + if c.Side == "LEFT" { + side = githubv4.DiffSideLeft + } + threads = append(threads, + &githubv4.DraftPullRequestReviewThread{ + Path: new( + githubv4.String(c.Path), + ), + Line: new( + githubv4.Int(c.Line), + ), + Side: &side, + Body: githubv4.String(c.Body), + }) + } + + var m struct { + AddPullRequestReview struct { + PullRequestReview struct { + ID githubv4.ID `graphql:"id"` + } `graphql:"pullRequestReview"` + } `graphql:"addPullRequestReview(input: $input)"` + } + + input := githubv4.AddPullRequestReviewInput{ + PullRequestID: gqlID, + Event: &event, + Threads: &threads, + } + if req.Body != "" { + input.Body = new(githubv4.String(req.Body)) + } + + if err := r.client.Mutate(ctx, &m, input, nil); err != nil { + return fmt.Errorf("submit review: %w", err) + } + + r.log.Debug("Submitted review", + "pr", pr.Number, + "comments", len(req.Comments), + ) + return nil +} + +// PostInlineComment posts a single inline comment +// on a PR by creating a review thread. +func (r *Repository) PostInlineComment( + ctx context.Context, + id forge.ChangeID, + req forge.InlineCommentRequest, +) (*forge.InlineComment, error) { + pr := mustPR(id) + gqlID, err := r.graphQLID(ctx, pr) + if err != nil { + return nil, err + } + + // If replying to an existing thread, use addPullRequestReviewComment. + if req.ThreadID != "" { + return r.replyToThread(ctx, req) + } + + side := githubv4.DiffSideRight + if req.Side == "LEFT" { + side = githubv4.DiffSideLeft + } + + var m struct { + AddPullRequestReviewThread struct { + Thread struct { + ID githubv4.ID `graphql:"id"` + Comments struct { + Nodes []struct { + ID githubv4.ID `graphql:"id"` + URL string `graphql:"url"` + CreatedAt githubv4.DateTime `graphql:"createdAt"` + } `graphql:"nodes"` + } `graphql:"comments(first: 1)"` + } `graphql:"thread"` + } `graphql:"addPullRequestReviewThread(input: $input)"` + } + + input := githubv4.AddPullRequestReviewThreadInput{ + PullRequestID: &gqlID, + Path: new( + githubv4.String(req.Path), + ), + Line: new( + githubv4.Int(req.Line), + ), + Side: &side, + Body: githubv4.String(req.Body), + } + + if err := r.client.Mutate(ctx, &m, input, nil); err != nil { + return nil, fmt.Errorf("post inline comment: %w", err) + } + + thread := m.AddPullRequestReviewThread.Thread + threadID := fmt.Sprint(thread.ID) + + var commentID forge.ChangeCommentID + var createdAt time.Time + if len(thread.Comments.Nodes) > 0 { + n := thread.Comments.Nodes[0] + commentID = &PRComment{GQLID: n.ID, URL: n.URL} + createdAt = n.CreatedAt.Time + } + + r.log.Debug("Posted inline comment", + "pr", pr.Number, + "path", req.Path, + "line", req.Line, + ) + + return &forge.InlineComment{ + ID: commentID, + ThreadID: threadID, + Path: req.Path, + Line: req.Line, + Body: req.Body, + CreatedAt: createdAt, + }, nil +} + +// replyToThread adds a reply to an existing review thread. +func (r *Repository) replyToThread( + ctx context.Context, + req forge.InlineCommentRequest, +) (*forge.InlineComment, error) { + var m struct { + AddPullRequestReviewThreadReply struct { + Comment struct { + ID githubv4.ID `graphql:"id"` + URL string `graphql:"url"` + CreatedAt githubv4.DateTime `graphql:"createdAt"` + } `graphql:"comment"` + } `graphql:"addPullRequestReviewThreadReply(input: $input)"` + } + + input := githubv4.AddPullRequestReviewThreadReplyInput{ + PullRequestReviewThreadID: githubv4.ID(req.ThreadID), + Body: githubv4.String(req.Body), + } + + if err := r.client.Mutate(ctx, &m, input, nil); err != nil { + return nil, fmt.Errorf("reply to thread: %w", err) + } + + n := m.AddPullRequestReviewThreadReply.Comment + return &forge.InlineComment{ + ID: &PRComment{GQLID: n.ID, URL: n.URL}, + ThreadID: req.ThreadID, + Path: req.Path, + Line: req.Line, + Body: req.Body, + CreatedAt: n.CreatedAt.Time, + }, nil +} + +// ResolveThread marks a review thread as resolved. +func (r *Repository) ResolveThread( + ctx context.Context, + threadID string, +) error { + var m struct { + ResolveReviewThread struct { + Thread struct { + ID githubv4.ID `graphql:"id"` + } `graphql:"thread"` + } `graphql:"resolveReviewThread(input: $input)"` + } + + input := githubv4.ResolveReviewThreadInput{ + ThreadID: githubv4.ID(threadID), + } + + if err := r.client.Mutate(ctx, &m, input, nil); err != nil { + return fmt.Errorf("resolve thread: %w", err) + } + + r.log.Debug("Resolved thread", "threadID", threadID) + return nil +} + +// UnresolveThread marks a review thread as unresolved. +func (r *Repository) UnresolveThread( + ctx context.Context, + threadID string, +) error { + var m struct { + UnresolveReviewThread struct { + Thread struct { + ID githubv4.ID `graphql:"id"` + } `graphql:"thread"` + } `graphql:"unresolveReviewThread(input: $input)"` + } + + input := githubv4.UnresolveReviewThreadInput{ + ThreadID: githubv4.ID(threadID), + } + + if err := r.client.Mutate(ctx, &m, input, nil); err != nil { + return fmt.Errorf("unresolve thread: %w", err) + } + + r.log.Debug("Unresolved thread", "threadID", threadID) + return nil +} + +// EditComment updates the body of an existing review comment. +func (r *Repository) EditComment( + ctx context.Context, + id forge.ChangeCommentID, + body string, +) error { + cid := mustPRComment(id) + + var m struct { + UpdatePullRequestReviewComment struct { + PullRequestReviewComment struct { + ID githubv4.ID `graphql:"id"` + } `graphql:"pullRequestReviewComment"` + } `graphql:"updatePullRequestReviewComment(input: $input)"` + } + + input := githubv4.UpdatePullRequestReviewCommentInput{ + PullRequestReviewCommentID: cid.GQLID, + Body: githubv4.String(body), + } + + if err := r.client.Mutate(ctx, &m, input, nil); err != nil { + return fmt.Errorf("edit comment: %w", err) + } + + r.log.Debug("Edited comment", "url", cid.URL) + return nil +} diff --git a/internal/forge/gitlab/inline_comment.go b/internal/forge/gitlab/inline_comment.go new file mode 100644 index 000000000..cbfa86790 --- /dev/null +++ b/internal/forge/gitlab/inline_comment.go @@ -0,0 +1,418 @@ +package gitlab + +import ( + "context" + "fmt" + "strconv" + "time" + + "go.abhg.dev/gs/internal/forge" + "go.abhg.dev/gs/internal/gateway/gitlab" +) + +var ( + _ forge.WithInlineComments = (*Repository)(nil) + _ forge.WithThreadResolution = (*Repository)(nil) + _ forge.WithCommentEdit = (*Repository)(nil) +) + +// ListInlineComments lists inline/review comments on a MR +// by fetching discussions that have position information. +func (r *Repository) ListInlineComments( + ctx context.Context, + id forge.ChangeID, +) ([]*forge.InlineComment, error) { + mr := mustMR(id) + + opts := &gitlab.ListMergeRequestDiscussionsOptions{ + ListOptions: gitlab.ListOptions{PerPage: 100}, + } + + var comments []*forge.InlineComment + for { + discussions, resp, err := r.client.MergeRequestDiscussionList( + ctx, r.repoID, mr.Number, opts, + ) + if err != nil { + return nil, fmt.Errorf( + "list discussions: %w", err, + ) + } + + for _, disc := range discussions { + if len(disc.Notes) == 0 { + continue + } + // Only include discussions that are resolvable + // (i.e., code review / diff discussions). + root := disc.Notes[0] + if !root.Resolvable { + continue + } + + for _, note := range disc.Notes { + path := "" + var line int + if note.Position != nil { + path = note.Position.NewPath + if note.Position.NewLine != 0 { + line = int(note.Position.NewLine) + } + } + + createdAt := time.Time{} + if note.CreatedAt != nil { + createdAt = *note.CreatedAt + } + + comments = append(comments, + &forge.InlineComment{ + ID: &MRComment{ + Number: note.ID, + MRNumber: mr.Number, + }, + ThreadID: formatThreadID( + disc.ID, mr.Number, + ), + Path: path, + Line: line, + Body: note.Body, + Author: note.Author.Username, + Resolved: root.Resolved, + Outdated: note.Position != nil && note.Position.NewPath == "", + CreatedAt: createdAt, + }) + } + } + + if resp.NextPage == 0 { + break + } + opts.Page = int64(resp.NextPage) + } + + return comments, nil +} + +// SubmitReview posts a batch of inline comments +// as individual discussions on a MR. +// GitLab does not have a native batch review API, +// so each comment is posted as a separate discussion. +func (r *Repository) SubmitReview( + ctx context.Context, + id forge.ChangeID, + req forge.ReviewRequest, +) error { + mr := mustMR(id) + + // Get diff refs for positioning. + diffRefs, err := r.diffRefs(ctx, mr.Number) + if err != nil { + return err + } + + for _, c := range req.Comments { + if c.ThreadID != "" { + // Reply to existing thread. + discID, _, perr := parseThreadID(c.ThreadID) + if perr != nil { + return perr + } + body := c.Body + if _, _, err := r.client.MergeRequestDiscussionNoteCreate( + ctx, r.repoID, mr.Number, discID, + &gitlab.AddMergeRequestDiscussionNoteOptions{ + Body: &body, + }, + ); err != nil { + return fmt.Errorf( + "reply to thread %s: %w", + c.ThreadID, err, + ) + } + continue + } + + opts := newDiscussionOptions(c.Body, c.Path, c.Line, diffRefs) + if _, _, err := r.client.MergeRequestDiscussionCreate( + ctx, r.repoID, mr.Number, opts, + ); err != nil { + return fmt.Errorf( + "create discussion on %s:%d: %w", + c.Path, c.Line, err, + ) + } + } + + r.log.Debug("Submitted review", + "mr", mr.Number, + "comments", len(req.Comments), + ) + return nil +} + +// PostInlineComment posts a single inline comment +// on a MR as a new discussion. +func (r *Repository) PostInlineComment( + ctx context.Context, + id forge.ChangeID, + req forge.InlineCommentRequest, +) (*forge.InlineComment, error) { + mr := mustMR(id) + + // Reply to existing thread. + if req.ThreadID != "" { + discID, _, err := parseThreadID(req.ThreadID) + if err != nil { + return nil, err + } + body := req.Body + note, _, err := r.client.MergeRequestDiscussionNoteCreate( + ctx, r.repoID, mr.Number, discID, + &gitlab.AddMergeRequestDiscussionNoteOptions{ + Body: &body, + }, + ) + if err != nil { + return nil, fmt.Errorf( + "reply to thread: %w", err, + ) + } + + createdAt := time.Time{} + if note.CreatedAt != nil { + createdAt = *note.CreatedAt + } + return &forge.InlineComment{ + ID: &MRComment{ + Number: note.ID, + MRNumber: mr.Number, + }, + ThreadID: req.ThreadID, + Path: req.Path, + Line: req.Line, + Body: req.Body, + CreatedAt: createdAt, + }, nil + } + + // New discussion. + diffRefs, err := r.diffRefs(ctx, mr.Number) + if err != nil { + return nil, err + } + + disc, _, err := r.client.MergeRequestDiscussionCreate( + ctx, r.repoID, mr.Number, + newDiscussionOptions(req.Body, req.Path, req.Line, diffRefs), + ) + if err != nil { + return nil, fmt.Errorf("create discussion: %w", err) + } + + var noteID int64 + if len(disc.Notes) > 0 { + noteID = disc.Notes[0].ID + } + + r.log.Debug("Posted inline comment", + "mr", mr.Number, + "path", req.Path, + "line", req.Line, + ) + + return &forge.InlineComment{ + ID: &MRComment{ + Number: noteID, + MRNumber: mr.Number, + }, + ThreadID: formatThreadID(disc.ID, mr.Number), + Path: req.Path, + Line: req.Line, + Body: req.Body, + }, nil +} + +func newDiscussionOptions( + body, path string, line int, + refs *gitlab.MergeRequestDiffRefs, +) *gitlab.CreateMergeRequestDiscussionOptions { + textType := "text" + lineN := int64(line) + return &gitlab.CreateMergeRequestDiscussionOptions{ + Body: &body, + Position: &gitlab.PositionOptions{ + BaseSHA: &refs.BaseSha, + HeadSHA: &refs.HeadSha, + StartSHA: &refs.StartSha, + PositionType: &textType, + NewPath: &path, + OldPath: &path, + NewLine: &lineN, + }, + } +} + +// diffRefs fetches the diff refs for a MR, +// needed for positioning inline comments. +func (r *Repository) diffRefs( + ctx context.Context, + mrNumber int64, +) (*gitlab.MergeRequestDiffRefs, error) { + mr, _, err := r.client.MergeRequestGet( + ctx, r.repoID, mrNumber, nil, + ) + if err != nil { + return nil, fmt.Errorf("get merge request: %w", err) + } + return &mr.DiffRefs, nil +} + +// ResolveThread marks a discussion thread as resolved. +func (r *Repository) ResolveThread( + ctx context.Context, + threadID string, +) error { + // Thread ID format: "discussion_id:mr_number" + discID, mrNumber, err := parseThreadID(threadID) + if err != nil { + return err + } + + resolved := true + if _, _, err := r.client.MergeRequestDiscussionResolve( + ctx, r.repoID, mrNumber, discID, + &gitlab.ResolveMergeRequestDiscussionOptions{ + Resolved: &resolved, + }, + ); err != nil { + return fmt.Errorf("resolve thread: %w", err) + } + + r.log.Debug("Resolved thread", "threadID", threadID) + return nil +} + +// UnresolveThread marks a discussion thread as unresolved. +func (r *Repository) UnresolveThread( + ctx context.Context, + threadID string, +) error { + discID, mrNumber, err := parseThreadID(threadID) + if err != nil { + return err + } + + resolved := false + if _, _, err := r.client.MergeRequestDiscussionResolve( + ctx, r.repoID, mrNumber, discID, + &gitlab.ResolveMergeRequestDiscussionOptions{ + Resolved: &resolved, + }, + ); err != nil { + return fmt.Errorf("unresolve thread: %w", err) + } + + r.log.Debug("Unresolved thread", "threadID", threadID) + return nil +} + +// EditComment updates the body of an existing MR comment. +func (r *Repository) EditComment( + ctx context.Context, + id forge.ChangeCommentID, + body string, +) error { + cid := mustMRComment(id) + + // Find the discussion containing the note + // so we can use the discussion-level update API. + discID, err := r.findDiscussionForNote( + ctx, cid.MRNumber, cid.Number, + ) + if err != nil { + return err + } + + if _, _, err := r.client.MergeRequestDiscussionNoteUpdate( + ctx, r.repoID, cid.MRNumber, discID, cid.Number, + &gitlab.UpdateMergeRequestDiscussionNoteOptions{ + Body: &body, + }, + ); err != nil { + return fmt.Errorf("edit comment: %w", err) + } + + r.log.Debug("Edited comment", "noteID", cid.Number) + return nil +} + +// findDiscussionForNote finds the discussion ID +// that contains a specific note. +func (r *Repository) findDiscussionForNote( + ctx context.Context, + mrNumber, noteID int64, +) (string, error) { + opts := &gitlab.ListMergeRequestDiscussionsOptions{ + ListOptions: gitlab.ListOptions{PerPage: 100}, + } + + for { + discussions, resp, err := r.client.MergeRequestDiscussionList( + ctx, r.repoID, mrNumber, opts, + ) + if err != nil { + return "", fmt.Errorf( + "list discussions: %w", err, + ) + } + + for _, disc := range discussions { + for _, note := range disc.Notes { + if note.ID == noteID { + return disc.ID, nil + } + } + } + + if resp.NextPage == 0 { + break + } + opts.Page = int64(resp.NextPage) + } + + return "", fmt.Errorf( + "note %d not found in MR %d", noteID, mrNumber, + ) +} + +// threadID format for GitLab: "discussion_id:mr_number" +// This encodes both the discussion ID and MR number +// so resolve/unresolve can work without extra context. + +func formatThreadID(discID string, mrNumber int64) string { + return discID + ":" + strconv.FormatInt(mrNumber, 10) +} + +func parseThreadID(threadID string) ( + discID string, mrNumber int64, err error, +) { + for i := len(threadID) - 1; i >= 0; i-- { + if threadID[i] == ':' { + discID = threadID[:i] + mrNumber, err = strconv.ParseInt( + threadID[i+1:], 10, 64, + ) + if err != nil { + return "", 0, fmt.Errorf( + "parse thread ID %q: %w", + threadID, err, + ) + } + return discID, mrNumber, nil + } + } + return "", 0, fmt.Errorf( + "invalid thread ID format: %q", threadID, + ) +} diff --git a/internal/forge/shamhub/comment.go b/internal/forge/shamhub/comment.go index 9dfaf358a..899192c36 100644 --- a/internal/forge/shamhub/comment.go +++ b/internal/forge/shamhub/comment.go @@ -8,6 +8,7 @@ import ( "iter" "slices" "strconv" + "time" "go.abhg.dev/gs/internal/forge" ) @@ -135,11 +136,32 @@ type shamComment struct { Change int Body string - // Resolvable indicates this is a code review comment that can be resolved. + // Resolvable indicates this is a code review comment + // that can be resolved. Resolvable bool // Resolved indicates this comment has been resolved. Resolved bool + + // Inline comment fields (optional). + + // Path is the file path for inline comments. + Path string + + // Line is the line number for inline comments. + Line int + + // Side is "LEFT" or "RIGHT" for inline comments. + Side string + + // ThreadID groups inline comments into threads. + ThreadID string + + // Author is the comment author username. + Author string + + // CreatedAt is the comment creation timestamp. + CreatedAt time.Time } var ( diff --git a/internal/forge/shamhub/inline_comment.go b/internal/forge/shamhub/inline_comment.go new file mode 100644 index 000000000..b9d64781d --- /dev/null +++ b/internal/forge/shamhub/inline_comment.go @@ -0,0 +1,459 @@ +package shamhub + +import ( + "context" + "fmt" + "strconv" + "time" + + "go.abhg.dev/gs/internal/forge" +) + +var ( + _ forge.WithInlineComments = (*forgeRepository)(nil) + _ forge.WithThreadResolution = (*forgeRepository)(nil) + _ forge.WithCommentEdit = (*forgeRepository)(nil) +) + +// Inline comment handlers + +var ( + _ = shamhubRESTHandler( + "GET /{owner}/{repo}/inline-comments", + (*ShamHub).handleListInlineComments, + ) + _ = shamhubRESTHandler( + "POST /{owner}/{repo}/inline-comments", + (*ShamHub).handlePostInlineComment, + ) + _ = shamhubRESTHandler( + "POST /{owner}/{repo}/reviews", + (*ShamHub).handleSubmitReview, + ) + _ = shamhubRESTHandler( + "POST /{owner}/{repo}/threads/{threadID}/resolve", + (*ShamHub).handleResolveThread, + ) + _ = shamhubRESTHandler( + "POST /{owner}/{repo}/threads/{threadID}/unresolve", + (*ShamHub).handleUnresolveThread, + ) + _ = shamhubRESTHandler( + "PATCH /{owner}/{repo}/comments/{id}/edit", + (*ShamHub).handleEditComment, + ) +) + +// List inline comments + +type listInlineCommentsRequest struct { + Owner string `path:"owner" json:"-"` + Repo string `path:"repo" json:"-"` + Change int `form:"change,required" json:"-"` +} + +type listInlineCommentsResponse struct { + Items []inlineCommentItem `json:"items"` +} + +type inlineCommentItem struct { + ID int `json:"id"` + ThreadID string `json:"threadID"` + Path string `json:"path"` + Line int `json:"line"` + Body string `json:"body"` + Author string `json:"author"` + Resolved bool `json:"resolved"` + Outdated bool `json:"outdated"` + CreatedAt time.Time `json:"createdAt"` +} + +func (sh *ShamHub) handleListInlineComments( + _ context.Context, + req *listInlineCommentsRequest, +) (*listInlineCommentsResponse, error) { + sh.mu.RLock() + defer sh.mu.RUnlock() + + var items []inlineCommentItem + for _, c := range sh.comments { + if c.Change != req.Change || c.Path == "" { + continue + } + items = append(items, inlineCommentItem{ + ID: c.ID, + ThreadID: c.ThreadID, + Path: c.Path, + Line: c.Line, + Body: c.Body, + Author: c.Author, + Resolved: c.Resolved, + Outdated: false, + CreatedAt: c.CreatedAt, + }) + } + + return &listInlineCommentsResponse{Items: items}, nil +} + +func (r *forgeRepository) ListInlineComments( + ctx context.Context, + id forge.ChangeID, +) ([]*forge.InlineComment, error) { + u := r.apiURL.JoinPath(r.owner, r.repo, "inline-comments") + q := u.Query() + q.Set("change", strconv.Itoa(int(id.(ChangeID)))) + u.RawQuery = q.Encode() + + var res listInlineCommentsResponse + if err := r.client.Get(ctx, u.String(), &res); err != nil { + return nil, fmt.Errorf("list inline comments: %w", err) + } + + var comments []*forge.InlineComment + for _, item := range res.Items { + comments = append(comments, &forge.InlineComment{ + ID: ChangeCommentID(item.ID), + ThreadID: item.ThreadID, + Path: item.Path, + Line: item.Line, + Body: item.Body, + Author: item.Author, + Resolved: item.Resolved, + Outdated: item.Outdated, + CreatedAt: item.CreatedAt, + }) + } + return comments, nil +} + +// Post inline comment + +type postInlineCommentRequest struct { + Owner string `path:"owner" json:"-"` + Repo string `path:"repo" json:"-"` + + Change int `json:"change"` + Path string `json:"path"` + Line int `json:"line"` + Body string `json:"body"` + Side string `json:"side"` + ThreadID string `json:"threadID,omitempty"` +} + +type postInlineCommentResponse struct { + ID int `json:"id"` + ThreadID string `json:"threadID"` + CreatedAt time.Time `json:"createdAt"` +} + +func (sh *ShamHub) handlePostInlineComment( + _ context.Context, + req *postInlineCommentRequest, +) (*postInlineCommentResponse, error) { + sh.mu.Lock() + defer sh.mu.Unlock() + + threadID := req.ThreadID + if threadID == "" { + // New thread: generate a thread ID. + threadID = fmt.Sprintf("thread-%d", len(sh.comments)+1) + } + + now := time.Now() + comment := shamComment{ + ID: len(sh.comments) + 1, + Change: req.Change, + Body: req.Body, + Path: req.Path, + Line: req.Line, + Side: req.Side, + ThreadID: threadID, + Resolvable: true, + Author: "test-user", + CreatedAt: now, + } + sh.comments = append(sh.comments, comment) + + return &postInlineCommentResponse{ + ID: comment.ID, + ThreadID: threadID, + CreatedAt: now, + }, nil +} + +func (r *forgeRepository) PostInlineComment( + ctx context.Context, + id forge.ChangeID, + req forge.InlineCommentRequest, +) (*forge.InlineComment, error) { + u := r.apiURL.JoinPath( + r.owner, r.repo, "inline-comments", + ) + body := postInlineCommentRequest{ + Change: int(id.(ChangeID)), + Path: req.Path, + Line: req.Line, + Body: req.Body, + Side: req.Side, + ThreadID: req.ThreadID, + } + + var res postInlineCommentResponse + if err := r.client.Post( + ctx, u.String(), body, &res, + ); err != nil { + return nil, fmt.Errorf("post inline comment: %w", err) + } + + return &forge.InlineComment{ + ID: ChangeCommentID(res.ID), + ThreadID: res.ThreadID, + Path: req.Path, + Line: req.Line, + Body: req.Body, + CreatedAt: res.CreatedAt, + }, nil +} + +// Submit review (batch) + +type submitReviewRequest struct { + Owner string `path:"owner" json:"-"` + Repo string `path:"repo" json:"-"` + + Change int `json:"change"` + Body string `json:"body,omitempty"` + Event int `json:"event"` + Comments []submitReviewCommentRequest `json:"comments"` +} + +type submitReviewCommentRequest struct { + Path string `json:"path"` + Line int `json:"line"` + Body string `json:"body"` + Side string `json:"side,omitempty"` + ThreadID string `json:"threadID,omitempty"` +} + +type submitReviewResponse struct { + CommentIDs []int `json:"commentIDs"` +} + +func (sh *ShamHub) handleSubmitReview( + _ context.Context, + req *submitReviewRequest, +) (*submitReviewResponse, error) { + sh.mu.Lock() + defer sh.mu.Unlock() + + now := time.Now() + var ids []int + for _, c := range req.Comments { + threadID := c.ThreadID + if threadID == "" { + threadID = fmt.Sprintf( + "thread-%d", len(sh.comments)+1, + ) + } + + comment := shamComment{ + ID: len(sh.comments) + 1, + Change: req.Change, + Body: c.Body, + Path: c.Path, + Line: c.Line, + Side: c.Side, + ThreadID: threadID, + Resolvable: true, + Author: "test-user", + CreatedAt: now, + } + sh.comments = append(sh.comments, comment) + ids = append(ids, comment.ID) + } + + return &submitReviewResponse{CommentIDs: ids}, nil +} + +func (r *forgeRepository) SubmitReview( + ctx context.Context, + id forge.ChangeID, + req forge.ReviewRequest, +) error { + u := r.apiURL.JoinPath(r.owner, r.repo, "reviews") + + var comments []submitReviewCommentRequest + for _, c := range req.Comments { + comments = append(comments, submitReviewCommentRequest{ + Path: c.Path, + Line: c.Line, + Body: c.Body, + Side: c.Side, + ThreadID: c.ThreadID, + }) + } + + body := submitReviewRequest{ + Change: int(id.(ChangeID)), + Body: req.Body, + Event: int(req.Event), + Comments: comments, + } + + var res submitReviewResponse + if err := r.client.Post( + ctx, u.String(), body, &res, + ); err != nil { + return fmt.Errorf("submit review: %w", err) + } + + return nil +} + +// Resolve/unresolve threads + +type resolveThreadRequest struct { + Owner string `path:"owner" json:"-"` + Repo string `path:"repo" json:"-"` + ThreadID string `path:"threadID" json:"-"` +} + +type resolveThreadResponse struct{} + +func (sh *ShamHub) handleResolveThread( + _ context.Context, + req *resolveThreadRequest, +) (*resolveThreadResponse, error) { + sh.mu.Lock() + defer sh.mu.Unlock() + + found := false + for i, c := range sh.comments { + if c.ThreadID == req.ThreadID { + sh.comments[i].Resolved = true + found = true + } + } + if !found { + return nil, notFoundErrorf( + "thread %s not found", req.ThreadID, + ) + } + + return &resolveThreadResponse{}, nil +} + +func (sh *ShamHub) handleUnresolveThread( + _ context.Context, + req *resolveThreadRequest, +) (*resolveThreadResponse, error) { + sh.mu.Lock() + defer sh.mu.Unlock() + + found := false + for i, c := range sh.comments { + if c.ThreadID == req.ThreadID { + sh.comments[i].Resolved = false + found = true + } + } + if !found { + return nil, notFoundErrorf( + "thread %s not found", req.ThreadID, + ) + } + + return &resolveThreadResponse{}, nil +} + +func (r *forgeRepository) ResolveThread( + ctx context.Context, + threadID string, +) error { + u := r.apiURL.JoinPath( + r.owner, r.repo, "threads", threadID, "resolve", + ) + + var res resolveThreadResponse + if err := r.client.Post( + ctx, u.String(), struct{}{}, &res, + ); err != nil { + return fmt.Errorf("resolve thread: %w", err) + } + + return nil +} + +func (r *forgeRepository) UnresolveThread( + ctx context.Context, + threadID string, +) error { + u := r.apiURL.JoinPath( + r.owner, r.repo, "threads", threadID, "unresolve", + ) + + var res resolveThreadResponse + if err := r.client.Post( + ctx, u.String(), struct{}{}, &res, + ); err != nil { + return fmt.Errorf("unresolve thread: %w", err) + } + + return nil +} + +// Edit comment + +type editCommentRequest struct { + Owner string `path:"owner" json:"-"` + Repo string `path:"repo" json:"-"` + ID int `path:"id" json:"-"` + + Body string `json:"body"` +} + +type editCommentResponse struct { + ID int `json:"id"` +} + +func (sh *ShamHub) handleEditComment( + _ context.Context, + req *editCommentRequest, +) (*editCommentResponse, error) { + sh.mu.Lock() + defer sh.mu.Unlock() + + for i, c := range sh.comments { + if c.ID == req.ID { + sh.comments[i].Body = req.Body + return &editCommentResponse{ID: req.ID}, nil + } + } + + return nil, notFoundErrorf( + "comment %d not found", req.ID, + ) +} + +func (r *forgeRepository) EditComment( + ctx context.Context, + id forge.ChangeCommentID, + body string, +) error { + cid := int(id.(ChangeCommentID)) + u := r.apiURL.JoinPath( + r.owner, r.repo, "comments", + strconv.Itoa(cid), "edit", + ) + + req := editCommentRequest{Body: body} + var res editCommentResponse + if err := r.client.Patch( + ctx, u.String(), req, &res, + ); err != nil { + return fmt.Errorf("edit comment: %w", err) + } + + return nil +} diff --git a/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/UpdateComment/updated-comment b/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/UpdateComment/updated-comment index 85760ee02..dda3adda6 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/UpdateComment/updated-comment +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/UpdateComment/updated-comment @@ -1 +1 @@ -"uXAhcpF8V9XZWbQom2aI0nM6Q9fbiqpd" \ No newline at end of file +"YJgNsP025jRY5hQX6mh2mIfiwifvz6G8" \ 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 3d68dade2..0bc036d75 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/branch @@ -1 +1 @@ -"uO3v3Jiu" \ No newline at end of file +"pmwWlNhh" \ 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 e57864939..cb58610d5 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/comments +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangeComments/comments @@ -1,12 +1,12 @@ [ - "M9TCBnUn2veSjGnStFRLruw4FhpFbpPr", - "ooErWPQY4wHcWm8bJDNOeA2G2BHnMcl1", - "DU3TnJBDljtJOjrPNPgfJRo44fzPxWxZ", - "WeEXYW6yjMMf0jmnnze12omw5CmTHrDt", - "S4IQsdn1dgnUfOJEFb5JEm7kVxLd8oil", - "JNpsluBOeFN8cwri2EMfI8BrYjbArxPf", - "FgUJanBcocO1ablzVyYVjDh6fUZbZXyI", - "qp1FOZUVrehYPmU311YMEQDrHlJ2BJ40", - "sODVHSvcIOhqxyrkgurNH9HMl2b2LSg6", - "k7NLLLvg5wMj1tasfkFfqdbhqfa8Ah0E" + "K067WOW7dQdrliaKS0tKylcfDgP5GhVp", + "dsCMPgmyz0KVBG501PPi2ocxE5sq7UfQ", + "3zyUZ2FZcxkOgp4FBvJfBKTnh9fdpNa3", + "im86H34osfgrDc7E4gdx7gE3XXcTXmPX", + "fgt7AG4rAoQp1gGEw8G2U2lbe0qWrTmp", + "KMuajrgxFADVDZhIFdzUBVzpAm9ee7xR", + "6El2lmQr5Ea5Hq9L0fLVfCSATL6qaGJl", + "ha2n0xHKCbk6xogserVQ8vOR2o2gbNH8", + "Dr8DblxCuohfDzo0gUkdZdTuRxz8uIfz", + "lr6i3eENW1lJd9i6NNxcjZCditYNWUqF" ] \ 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 d616a2169..6f5fee334 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/closedBranch +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/closedBranch @@ -1 +1 @@ -"IEtiDhFs" \ No newline at end of file +"mzMsv5Rh" \ 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 2142ea6ab..3d9a25268 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/mergedBranch +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/mergedBranch @@ -1 +1 @@ -"C5hzQ5Ik" \ No newline at end of file +"gvgMWiD8" \ 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 7c13c61bf..7e77aa963 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/openBranch +++ b/internal/forge/shamhub/testdata/TestIntegration/ChangesStates/openBranch @@ -1 +1 @@ -"jMfwXkYK" \ No newline at end of file +"QohFltlh" \ 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 778cc9b7f..1b0a87a96 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/CommentCountsByChange/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/CommentCountsByChange/branch @@ -1 +1 @@ -"HQWHaq9z" \ No newline at end of file +"wleC7vBI" \ 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 3da52d175..305090d1d 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/ListChangeTemplates/TemplatesPresent/empty-template +++ b/internal/forge/shamhub/testdata/TestIntegration/ListChangeTemplates/TemplatesPresent/empty-template @@ -1 +1 @@ -"1HQqVNZV.md" \ No newline at end of file +"np6KTBsj.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 0c924f438..ef691a56a 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 @@ -"yE3Lj2v5.md" \ No newline at end of file +"aW2r2kGY.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 b8e719155..4d6f27de3 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/base-branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/base-branch @@ -1 +1 @@ -"9s9oMX6C" \ No newline at end of file +"ExQcEmr1" \ 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 02926e09f..a8a9575a0 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitBaseDoesNotExist/branch @@ -1 +1 @@ -"vY4xsORW" \ No newline at end of file +"bcKIEKS3" \ 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 b92100789..93c1210d2 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 @@ -"66MtCOhk" \ No newline at end of file +"4D8sFmyC" \ 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 e678e3903..97d4a3716 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 @@ -"Op9WQIRi" \ No newline at end of file +"lEG1MUxo" \ 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 d3f1200a7..6aba0ca56 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 @@ -"lE3mefp0" \ No newline at end of file +"UQDEDpcg" \ 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 5a0613317..bd79f7cc0 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/base +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/base @@ -1 +1 @@ -"t8XzNN0X" \ No newline at end of file +"P2inVOao" \ 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 133b93253..39462bd3d 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditBase/branch @@ -1 +1 @@ -"9YbzXae4" \ No newline at end of file +"mKnU8EV4" \ 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 879ccaf2e..d5094a646 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/branch @@ -1 +1 @@ -"RowsHzO8" \ No newline at end of file +"cI6Rfmnn" \ 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 68000fd15..7e986537e 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/firstCommitHash +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditChange/firstCommitHash @@ -1 +1 @@ -"1ee3894a24c031b5d053a0b8bb25a9182fd77604" \ No newline at end of file +"1e2c32dc4f5cfec9674dac2d9d7d0274a63c15b0" \ 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 5bfde7014..3bd5a7d4f 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditDraft/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditDraft/branch @@ -1 +1 @@ -"pCyU7Tpe" \ No newline at end of file +"R4gPQ4SL" \ 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 82678979f..d24723898 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/branch +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/branch @@ -1 +1 @@ -"jbBnJuHT" \ No newline at end of file +"4HOIehwu" \ 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 de5114824..ca667f6f4 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label1 +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label1 @@ -1 +1 @@ -"QcHb0icn" \ No newline at end of file +"2VGRqO7j" \ 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 7b3d9d81e..2939cac77 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label2 +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label2 @@ -1 +1 @@ -"820svnw8" \ No newline at end of file +"dF2bQUKv" \ 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 c09704b58..5a7982702 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label3 +++ b/internal/forge/shamhub/testdata/TestIntegration/SubmitEditLabels/label3 @@ -1 +1 @@ -"bUnh1ONJ" \ No newline at end of file +"bSgDWsqi" \ 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 876aafd30..d834b007c 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 @@ -"qS0oWVxR" \ No newline at end of file +"BXaFutk3" \ 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 df22e5ade..c34fa70ab 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 @@ -"sN0uOM0J" \ No newline at end of file +"EwqrlAsh" \ 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 9bf39d178..ad68d67bc 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 @@ -"4oj7KI1p" \ No newline at end of file +"df7WoDco" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/apiURL b/internal/forge/shamhub/testdata/TestIntegration/apiURL index 38ca6faef..4103c7885 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/apiURL +++ b/internal/forge/shamhub/testdata/TestIntegration/apiURL @@ -1 +1 @@ -"http://127.0.0.1:56373" \ No newline at end of file +"http://127.0.0.1:53569" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/gitURL b/internal/forge/shamhub/testdata/TestIntegration/gitURL index 0d906a389..01ae293af 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/gitURL +++ b/internal/forge/shamhub/testdata/TestIntegration/gitURL @@ -1 +1 @@ -"http://127.0.0.1:56374" \ No newline at end of file +"http://127.0.0.1:53570" \ No newline at end of file diff --git a/internal/forge/shamhub/testdata/TestIntegration/pushRepoURL b/internal/forge/shamhub/testdata/TestIntegration/pushRepoURL index 03fa24f07..ed207937f 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/pushRepoURL +++ b/internal/forge/shamhub/testdata/TestIntegration/pushRepoURL @@ -1 +1 @@ -"http://127.0.0.1:56374/abhinav-fork/test-repo.git" \ No newline at end of file +"http://127.0.0.1:53570/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 4551e0131..4c5e37538 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/repoURL +++ b/internal/forge/shamhub/testdata/TestIntegration/repoURL @@ -1 +1 @@ -"http://127.0.0.1:56374/abhinav/test-repo.git" \ No newline at end of file +"http://127.0.0.1:53570/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 a5ee830ce..8e0625d81 100644 --- a/internal/forge/shamhub/testdata/TestIntegration/token +++ b/internal/forge/shamhub/testdata/TestIntegration/token @@ -1 +1 @@ -"444a9baa5f8f8904" \ No newline at end of file +"1ec8a66d2ad7f057" \ 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 index 343a0d353..b345987f7 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Failed.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 88 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"subject":"Checks qP4Hn8gu","body":"Checks state test","base":"main","head":"qP4Hn8gu"}' - url: http://127.0.0.1:56373/abhinav/test-repo/changes + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -19,7 +19,7 @@ interactions: body: | { "number": 19, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/19" + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/19" } headers: Content-Length: @@ -35,9 +35,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 18 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"state":"failed"}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/19/checks + url: http://127.0.0.1:53569/abhinav/test-repo/change/19/checks method: POST response: proto: HTTP/1.1 @@ -60,8 +60,8 @@ interactions: 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 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/19/checks method: GET response: proto: HTTP/1.1 diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml index fc08268b0..aa5b9649a 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Passed.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 88 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"subject":"Checks f0XMOiaa","body":"Checks state test","base":"main","head":"f0XMOiaa"}' - url: http://127.0.0.1:56373/abhinav/test-repo/changes + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -19,7 +19,7 @@ interactions: body: | { "number": 9, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/9" + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/9" } headers: Content-Length: @@ -35,9 +35,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 18 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"state":"passed"}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/9/checks + url: http://127.0.0.1:53569/abhinav/test-repo/change/9/checks method: POST response: proto: HTTP/1.1 @@ -60,8 +60,8 @@ interactions: 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 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/9/checks method: GET response: proto: HTTP/1.1 diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml index 76558920f..5ed5de929 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeChecksState/Pending.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 88 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"subject":"Checks MGWUNTrV","body":"Checks state test","base":"main","head":"MGWUNTrV"}' - url: http://127.0.0.1:56373/abhinav/test-repo/changes + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -19,7 +19,7 @@ interactions: body: | { "number": 3, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/3" + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/3" } headers: Content-Length: @@ -35,9 +35,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 19 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"state":"pending"}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/3/checks + url: http://127.0.0.1:53569/abhinav/test-repo/change/3/checks method: POST response: proto: HTTP/1.1 @@ -60,8 +60,8 @@ interactions: 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 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/3/checks method: GET response: proto: HTTP/1.1 diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeComments.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangeComments.yaml index 889179595..edfe47a02 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: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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing pmwWlNhh","body":"Test PR for comments","base":"main","head":"pmwWlNhh"}' + url: http://127.0.0.1:53569/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:56374/abhinav/test-repo/change/4" + "number": 5, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/5" } headers: Content-Length: @@ -28,16 +28,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 20.3975ms + duration: 43.473041ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:56373 - body: '{"changeNumber":4,"body":"M9TCBnUn2veSjGnStFRLruw4FhpFbpPr"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments + host: 127.0.0.1:53569 + body: '{"changeNumber":5,"body":"K067WOW7dQdrliaKS0tKylcfDgP5GhVp"}' + url: http://127.0.0.1:53569/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -55,16 +55,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 123.292µs + duration: 345.417µs - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:56373 - body: '{"changeNumber":4,"body":"ooErWPQY4wHcWm8bJDNOeA2G2BHnMcl1"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments + host: 127.0.0.1:53569 + body: '{"changeNumber":5,"body":"dsCMPgmyz0KVBG501PPi2ocxE5sq7UfQ"}' + url: http://127.0.0.1:53569/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -82,16 +82,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 1.531375ms + duration: 158.667µs - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:56373 - body: '{"changeNumber":4,"body":"DU3TnJBDljtJOjrPNPgfJRo44fzPxWxZ"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments + host: 127.0.0.1:53569 + body: '{"changeNumber":5,"body":"3zyUZ2FZcxkOgp4FBvJfBKTnh9fdpNa3"}' + url: http://127.0.0.1:53569/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -109,16 +109,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 84.25µs + duration: 417.5µs - id: 4 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:56373 - body: '{"changeNumber":4,"body":"WeEXYW6yjMMf0jmnnze12omw5CmTHrDt"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments + host: 127.0.0.1:53569 + body: '{"changeNumber":5,"body":"im86H34osfgrDc7E4gdx7gE3XXcTXmPX"}' + url: http://127.0.0.1:53569/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -136,16 +136,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 482.875µs + duration: 224µs - id: 5 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:56373 - body: '{"changeNumber":4,"body":"S4IQsdn1dgnUfOJEFb5JEm7kVxLd8oil"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments + host: 127.0.0.1:53569 + body: '{"changeNumber":5,"body":"fgt7AG4rAoQp1gGEw8G2U2lbe0qWrTmp"}' + url: http://127.0.0.1:53569/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -163,16 +163,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 224.083µs + duration: 361.833µs - id: 6 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:56373 - body: '{"changeNumber":4,"body":"JNpsluBOeFN8cwri2EMfI8BrYjbArxPf"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments + host: 127.0.0.1:53569 + body: '{"changeNumber":5,"body":"KMuajrgxFADVDZhIFdzUBVzpAm9ee7xR"}' + url: http://127.0.0.1:53569/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -190,16 +190,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 103.5µs + duration: 699.25µs - id: 7 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:56373 - body: '{"changeNumber":4,"body":"FgUJanBcocO1ablzVyYVjDh6fUZbZXyI"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments + host: 127.0.0.1:53569 + body: '{"changeNumber":5,"body":"6El2lmQr5Ea5Hq9L0fLVfCSATL6qaGJl"}' + url: http://127.0.0.1:53569/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -217,16 +217,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 257.333µs + duration: 261.167µs - id: 8 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:56373 - body: '{"changeNumber":4,"body":"qp1FOZUVrehYPmU311YMEQDrHlJ2BJ40"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments + host: 127.0.0.1:53569 + body: '{"changeNumber":5,"body":"ha2n0xHKCbk6xogserVQ8vOR2o2gbNH8"}' + url: http://127.0.0.1:53569/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -244,16 +244,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 140.333µs + duration: 164.25µs - id: 9 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:56373 - body: '{"changeNumber":4,"body":"sODVHSvcIOhqxyrkgurNH9HMl2b2LSg6"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments + host: 127.0.0.1:53569 + body: '{"changeNumber":5,"body":"Dr8DblxCuohfDzo0gUkdZdTuRxz8uIfz"}' + url: http://127.0.0.1:53569/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -271,16 +271,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 121.5µs + duration: 562.292µs - id: 10 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 60 - host: 127.0.0.1:56373 - body: '{"changeNumber":4,"body":"k7NLLLvg5wMj1tasfkFfqdbhqfa8Ah0E"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments + host: 127.0.0.1:53569 + body: '{"changeNumber":5,"body":"lr6i3eENW1lJd9i6NNxcjZCditYNWUqF"}' + url: http://127.0.0.1:53569/abhinav/test-repo/comments method: POST response: proto: HTTP/1.1 @@ -298,16 +298,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 115.833µs + duration: 373.291µs - id: 11 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 43 - host: 127.0.0.1:56373 - body: '{"body":"uXAhcpF8V9XZWbQom2aI0nM6Q9fbiqpd"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments/1 + host: 127.0.0.1:53569 + body: '{"body":"YJgNsP025jRY5hQX6mh2mIfiwifvz6G8"}' + url: http://127.0.0.1:53569/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: 1.85ms + duration: 1.350167ms - id: 12 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/comments/2 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/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: 450µs + duration: 287.416µs - id: 13 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 22 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"body":"should fail"}' - url: http://127.0.0.1:56373/abhinav/test-repo/comments/2 + url: http://127.0.0.1:53569/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: 314.5µs + duration: 821.25µs - id: 14 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 form: change: - - "4" + - "5" limit: - "3" offset: - "0" - url: http://127.0.0.1:56373/abhinav/test-repo/comments?change=4&limit=3&offset=0 + url: http://127.0.0.1:53569/abhinav/test-repo/comments?change=5&limit=3&offset=0 method: GET response: proto: HTTP/1.1 @@ -401,15 +401,15 @@ interactions: "items": [ { "id": 1, - "body": "uXAhcpF8V9XZWbQom2aI0nM6Q9fbiqpd" + "body": "YJgNsP025jRY5hQX6mh2mIfiwifvz6G8" }, { "id": 3, - "body": "DU3TnJBDljtJOjrPNPgfJRo44fzPxWxZ" + "body": "3zyUZ2FZcxkOgp4FBvJfBKTnh9fdpNa3" }, { "id": 4, - "body": "WeEXYW6yjMMf0jmnnze12omw5CmTHrDt" + "body": "im86H34osfgrDc7E4gdx7gE3XXcTXmPX" } ], "offset": 3, @@ -422,22 +422,22 @@ interactions: - application/json status: 200 OK code: 200 - duration: 387.292µs + duration: 583.25µs - id: 15 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 form: change: - - "4" + - "5" limit: - "3" offset: - "3" - url: http://127.0.0.1:56373/abhinav/test-repo/comments?change=4&limit=3&offset=3 + url: http://127.0.0.1:53569/abhinav/test-repo/comments?change=5&limit=3&offset=3 method: GET response: proto: HTTP/1.1 @@ -449,15 +449,15 @@ interactions: "items": [ { "id": 5, - "body": "S4IQsdn1dgnUfOJEFb5JEm7kVxLd8oil" + "body": "fgt7AG4rAoQp1gGEw8G2U2lbe0qWrTmp" }, { "id": 6, - "body": "JNpsluBOeFN8cwri2EMfI8BrYjbArxPf" + "body": "KMuajrgxFADVDZhIFdzUBVzpAm9ee7xR" }, { "id": 7, - "body": "FgUJanBcocO1ablzVyYVjDh6fUZbZXyI" + "body": "6El2lmQr5Ea5Hq9L0fLVfCSATL6qaGJl" } ], "offset": 6, @@ -470,22 +470,22 @@ interactions: - application/json status: 200 OK code: 200 - duration: 1.042458ms + duration: 311.417µs - id: 16 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 form: change: - - "4" + - "5" limit: - "3" offset: - "6" - url: http://127.0.0.1:56373/abhinav/test-repo/comments?change=4&limit=3&offset=6 + url: http://127.0.0.1:53569/abhinav/test-repo/comments?change=5&limit=3&offset=6 method: GET response: proto: HTTP/1.1 @@ -497,15 +497,15 @@ interactions: "items": [ { "id": 8, - "body": "qp1FOZUVrehYPmU311YMEQDrHlJ2BJ40" + "body": "ha2n0xHKCbk6xogserVQ8vOR2o2gbNH8" }, { "id": 9, - "body": "sODVHSvcIOhqxyrkgurNH9HMl2b2LSg6" + "body": "Dr8DblxCuohfDzo0gUkdZdTuRxz8uIfz" }, { "id": 10, - "body": "k7NLLLvg5wMj1tasfkFfqdbhqfa8Ah0E" + "body": "lr6i3eENW1lJd9i6NNxcjZCditYNWUqF" } ], "offset": 9 @@ -517,22 +517,22 @@ interactions: - application/json status: 200 OK code: 200 - duration: 1.038417ms + duration: 210.416µs - id: 17 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 form: change: - - "4" + - "5" limit: - "10" offset: - "0" - url: http://127.0.0.1:56373/abhinav/test-repo/comments?change=4&limit=10&offset=0 + url: http://127.0.0.1:53569/abhinav/test-repo/comments?change=5&limit=10&offset=0 method: GET response: proto: HTTP/1.1 @@ -544,39 +544,39 @@ interactions: "items": [ { "id": 1, - "body": "uXAhcpF8V9XZWbQom2aI0nM6Q9fbiqpd" + "body": "YJgNsP025jRY5hQX6mh2mIfiwifvz6G8" }, { "id": 3, - "body": "DU3TnJBDljtJOjrPNPgfJRo44fzPxWxZ" + "body": "3zyUZ2FZcxkOgp4FBvJfBKTnh9fdpNa3" }, { "id": 4, - "body": "WeEXYW6yjMMf0jmnnze12omw5CmTHrDt" + "body": "im86H34osfgrDc7E4gdx7gE3XXcTXmPX" }, { "id": 5, - "body": "S4IQsdn1dgnUfOJEFb5JEm7kVxLd8oil" + "body": "fgt7AG4rAoQp1gGEw8G2U2lbe0qWrTmp" }, { "id": 6, - "body": "JNpsluBOeFN8cwri2EMfI8BrYjbArxPf" + "body": "KMuajrgxFADVDZhIFdzUBVzpAm9ee7xR" }, { "id": 7, - "body": "FgUJanBcocO1ablzVyYVjDh6fUZbZXyI" + "body": "6El2lmQr5Ea5Hq9L0fLVfCSATL6qaGJl" }, { "id": 8, - "body": "qp1FOZUVrehYPmU311YMEQDrHlJ2BJ40" + "body": "ha2n0xHKCbk6xogserVQ8vOR2o2gbNH8" }, { "id": 9, - "body": "sODVHSvcIOhqxyrkgurNH9HMl2b2LSg6" + "body": "Dr8DblxCuohfDzo0gUkdZdTuRxz8uIfz" }, { "id": 10, - "body": "k7NLLLvg5wMj1tasfkFfqdbhqfa8Ah0E" + "body": "lr6i3eENW1lJd9i6NNxcjZCditYNWUqF" } ], "offset": 9 @@ -588,4 +588,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 177.583µs + duration: 956.5µs diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangesStates.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangesStates.yaml index 32e610d37..63f60dabf 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangesStates.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ChangesStates.yaml @@ -7,37 +7,37 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 80 - 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 + host: 127.0.0.1:53569 + body: '{"subject":"Open QohFltlh","body":"Open change","base":"main","head":"QohFltlh"}' + url: http://127.0.0.1:53569/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": 15, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/15" + "number": 9, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/9" } headers: Content-Length: - - "82" + - "80" Content-Type: - application/json status: 200 OK code: 200 - duration: 13.188042ms + duration: 29.667375ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 84 - 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 + host: 127.0.0.1:53569 + body: '{"subject":"Merged gvgMWiD8","body":"Merged change","base":"main","head":"gvgMWiD8"}' + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -46,8 +46,8 @@ interactions: content_length: 82 body: | { - "number": 16, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/16" + "number": 11, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/11" } headers: Content-Length: @@ -56,16 +56,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 13.844667ms + duration: 29.907541ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 84 - 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 + host: 127.0.0.1:53569 + body: '{"subject":"Closed mzMsv5Rh","body":"Closed change","base":"main","head":"mzMsv5Rh"}' + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -74,8 +74,8 @@ interactions: content_length: 82 body: | { - "number": 18, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/18" + "number": 15, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/15" } headers: Content-Length: @@ -84,16 +84,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 14.069959ms + duration: 27.266959ms - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - 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 + content_length: 17 + host: 127.0.0.1:53569 + body: '{"ids":[9,11,15]}' + url: http://127.0.0.1:53569/abhinav/test-repo/change/states method: POST response: proto: HTTP/1.1 @@ -105,15 +105,15 @@ interactions: "statuses": [ { "state": "open", - "headHash": "84a9e994290ae89ccc93f7d2a03d009b39d103ea" + "headHash": "df17da0bd1722f06dbd75d8948417dded7a12d77" }, { "state": "merged", - "headHash": "25b03948515094aec6d2cf82537f16d56a1486dc" + "headHash": "fae1a4a757b2259632acb5eb5926849f125dc594" }, { "state": "closed", - "headHash": "0c32e505344f156f8aa70189cfd851a1a40765cd" + "headHash": "145f79d936fdcaf9ccd165ed6be52de6eaba9895" } ] } @@ -124,4 +124,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 10.51575ms + duration: 27.146958ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/CommentCountsByChange.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/CommentCountsByChange.yaml index a6c9cab53..b98cc5b46 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/CommentCountsByChange.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/CommentCountsByChange.yaml @@ -7,37 +7,37 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 98 - 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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing wleC7vBI","body":"Test PR for comment counts","base":"main","head":"wleC7vBI"}' + url: http://127.0.0.1:53569/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": 11, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/11" + "number": 1, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/1" } headers: Content-Length: - - "82" + - "80" Content-Type: - application/json status: 200 OK code: 200 - duration: 28.731083ms + duration: 46.254708ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 12 - host: 127.0.0.1:56373 - body: '{"ids":[11]}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/comment-counts + content_length: 11 + host: 127.0.0.1:53569 + body: '{"ids":[1]}' + url: http://127.0.0.1:53569/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: 1.628833ms + duration: 3.071583ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/FindChangesByBranchDoesNotExist.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/FindChangesByBranchDoesNotExist.yaml index 4673e14a0..931a943e7 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:56373 + host: 127.0.0.1:53569 form: limit: - "10" state: - all - url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/does-not-exist?limit=10&state=all + url: http://127.0.0.1:53569/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: 752.916µs + duration: 570µs diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/NoTemplates.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/NoTemplates.yaml index 4e2249722..970786aee 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:56373 - url: http://127.0.0.1:56373/abhinav/test-repo/change-template + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/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: 138.274667ms + duration: 270.632708ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/TemplatesPresent.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/ListChangeTemplates/TemplatesPresent.yaml index 2736a773b..490f41621 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:56373 - url: http://127.0.0.1:56373/abhinav/test-repo/change-template + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change-template method: GET response: proto: HTTP/1.1 @@ -18,12 +18,12 @@ interactions: body: | [ { - "filename": "1HQqVNZV.md", - "body": "\n" + "filename": "aW2r2kGY.md", + "body": "This is a test template\n" }, { - "filename": "yE3Lj2v5.md", - "body": "This is a test template\n" + "filename": "np6KTBsj.md", + "body": "\n" } ] headers: @@ -33,4 +33,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 149.63575ms + duration: 309.049ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitBaseDoesNotExist.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitBaseDoesNotExist.yaml index 4c536dd39..a9463e3d0 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: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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing bcKIEKS3","body":"Test PR with non-existent base","base":"ExQcEmr1","head":"bcKIEKS3"}' + url: http://127.0.0.1:53569/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: 9.87325ms + duration: 18.86725ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 29 - host: 127.0.0.1:56373 - body: '{"ref":"refs/heads/9s9oMX6C"}' - url: http://127.0.0.1:56373/abhinav/test-repo/ref/exists + host: 127.0.0.1:53569 + body: '{"ref":"refs/heads/ExQcEmr1"}' + url: http://127.0.0.1:53569/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: 10.2145ms + duration: 20.495625ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitChangeFromPushRepository.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitChangeFromPushRepository.yaml index be69f95da..7c6944ecc 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitChangeFromPushRepository.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitChangeFromPushRepository.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 138 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 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 + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -19,7 +19,7 @@ interactions: body: | { "number": 12, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/12" + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/12" } headers: Content-Length: @@ -35,8 +35,8 @@ interactions: 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/12 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/12 method: GET response: proto: HTTP/1.1 @@ -46,7 +46,7 @@ interactions: body: | { "number": 12, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/12", + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/12", "state": "open", "title": "Testing fork QDezbUVv", "body": "Test fork change request", @@ -81,7 +81,7 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 form: head_repo: - abhinav-fork/test-repo @@ -89,7 +89,7 @@ interactions: - "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 + url: http://127.0.0.1:53569/abhinav/test-repo/changes/by-branch/QDezbUVv?head_repo=abhinav-fork%2Ftest-repo&limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -100,7 +100,7 @@ interactions: [ { "number": 12, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/12", + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/12", "state": "open", "title": "Testing fork QDezbUVv", "body": "Test fork change request", @@ -136,13 +136,13 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 form: limit: - "10" state: - all - url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/QDezbUVv?limit=10&state=all + url: http://127.0.0.1:53569/abhinav/test-repo/changes/by-branch/QDezbUVv?limit=10&state=all method: GET response: proto: HTTP/1.1 diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssignee.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssignee.yaml index aeb06a334..fbafc7661 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: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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing 4D8sFmyC","body":"Test PR without assignees","base":"main","head":"4D8sFmyC"}' + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -19,7 +19,7 @@ interactions: body: | { "number": 10, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/10" + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/10" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 25.159916ms + duration: 29.755416ms - id: 1 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/10 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/10 method: GET response: proto: HTTP/1.1 @@ -46,9 +46,9 @@ interactions: body: | { "number": 10, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/10", + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/10", "state": "open", - "title": "Testing 66MtCOhk", + "title": "Testing 4D8sFmyC", "body": "Test PR without assignees", "base": { "repository": { @@ -56,15 +56,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "66MtCOhk", - "sha": "66a0c50cac60c34e761b18838932a3aab48deac9" + "ref": "4D8sFmyC", + "sha": "3dce9a05f05fb11263d1482ecd4125949e747389" } } headers: @@ -74,16 +74,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 22.786459ms + duration: 27.52675ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 39 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"assignees":["assignee1","assignee2"]}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/10 + url: http://127.0.0.1:53569/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: 696.167µs + duration: 224.75µs - id: 3 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/10 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/10 method: GET response: proto: HTTP/1.1 @@ -117,9 +117,9 @@ interactions: body: | { "number": 10, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/10", + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/10", "state": "open", - "title": "Testing 66MtCOhk", + "title": "Testing 4D8sFmyC", "body": "Test PR without assignees", "base": { "repository": { @@ -127,15 +127,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "66MtCOhk", - "sha": "66a0c50cac60c34e761b18838932a3aab48deac9" + "ref": "4D8sFmyC", + "sha": "3dce9a05f05fb11263d1482ecd4125949e747389" }, "assignees": [ "assignee1", @@ -149,4 +149,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 17.645625ms + duration: 29.249833ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne.yaml index 0f7dfd8b2..23e87958b 100644 --- a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne.yaml +++ b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/AddAssigneesOneByOne.yaml @@ -7,9 +7,9 @@ interactions: proto_major: 1 proto_minor: 1 content_length: 97 - 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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing lEG1MUxo","body":"Test PR without assignees","base":"main","head":"lEG1MUxo"}' + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 80 body: | { - "number": 5, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/5" + "number": 4, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/4" } headers: Content-Length: @@ -28,16 +28,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 21.201041ms + duration: 42.64775ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 27 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"assignees":["assignee1"]}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/5 + url: http://127.0.0.1:53569/abhinav/test-repo/change/4 method: PATCH response: proto: HTTP/1.1 @@ -53,16 +53,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 263.792µs + duration: 631.583µs - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 27 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"assignees":["assignee2"]}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/5 + url: http://127.0.0.1:53569/abhinav/test-repo/change/4 method: PATCH response: proto: HTTP/1.1 @@ -78,15 +78,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 2.75425ms + duration: 129.958µs - id: 3 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/5 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/4 method: GET response: proto: HTTP/1.1 @@ -95,10 +95,10 @@ interactions: content_length: 571 body: | { - "number": 5, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/5", + "number": 4, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/4", "state": "open", - "title": "Testing Op9WQIRi", + "title": "Testing lEG1MUxo", "body": "Test PR without assignees", "base": { "repository": { @@ -106,15 +106,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "Op9WQIRi", - "sha": "34d6de08ed0a392a6ec261c288d5516e65dc2614" + "ref": "lEG1MUxo", + "sha": "c95d303c96fd553536f0b20c74bbf7cb19087f37" }, "assignees": [ "assignee1", @@ -128,4 +128,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 21.133625ms + duration: 37.717625ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/SubmitWithAssignee.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditAssignees/SubmitWithAssignee.yaml index 1bd09cc14..9e3a5f5c2 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: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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing UQDEDpcg","body":"Test PR with assignee","base":"main","head":"UQDEDpcg","assignees":["assignee1","assignee2"]}' + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 80 body: | { - "number": 7, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/7" + "number": 2, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/2" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 21.594125ms + duration: 38.620583ms - id: 1 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/7 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/2 method: GET response: proto: HTTP/1.1 @@ -45,10 +45,10 @@ interactions: content_length: 567 body: | { - "number": 7, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/7", + "number": 2, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/2", "state": "open", - "title": "Testing lE3mefp0", + "title": "Testing UQDEDpcg", "body": "Test PR with assignee", "base": { "repository": { @@ -56,15 +56,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "lE3mefp0", - "sha": "1294690f93a2b746dbb81d60a23b512988633d14" + "ref": "UQDEDpcg", + "sha": "0970719d4527d7008b38d05e15c0e92f6acfb25b" }, "assignees": [ "assignee1", @@ -78,20 +78,20 @@ interactions: - application/json status: 200 OK code: 200 - duration: 17.238667ms + duration: 38.749042ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 form: limit: - "10" state: - all - url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/lE3mefp0?limit=10&state=all + url: http://127.0.0.1:53569/abhinav/test-repo/changes/by-branch/UQDEDpcg?limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -101,10 +101,10 @@ interactions: body: | [ { - "number": 7, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/7", + "number": 2, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/2", "state": "open", - "title": "Testing lE3mefp0", + "title": "Testing UQDEDpcg", "body": "Test PR with assignee", "base": { "repository": { @@ -112,15 +112,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "lE3mefp0", - "sha": "1294690f93a2b746dbb81d60a23b512988633d14" + "ref": "UQDEDpcg", + "sha": "0970719d4527d7008b38d05e15c0e92f6acfb25b" }, "assignees": [ "assignee1", @@ -135,4 +135,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 20.395ms + duration: 33.967333ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditBase.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditBase.yaml index ed56e8e18..33cf7f1c6 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: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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing mKnU8EV4","body":"Test PR with custom base","base":"P2inVOao","head":"mKnU8EV4"}' + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -19,7 +19,7 @@ interactions: body: | { "number": 8, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/8" + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/8" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 23.763167ms + duration: 41.197167ms - id: 1 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/8 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/8 method: GET response: proto: HTTP/1.1 @@ -46,25 +46,25 @@ interactions: body: | { "number": 8, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/8", + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/8", "state": "open", - "title": "Testing 9YbzXae4", + "title": "Testing mKnU8EV4", "body": "Test PR with custom base", "base": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "t8XzNN0X", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "ref": "P2inVOao", + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "9YbzXae4", - "sha": "a3fc1801625662da2cc43a337ee7ba729a73d732" + "ref": "mKnU8EV4", + "sha": "cd26b16c292f00fa0b6a5f5f710c461474950344" } } headers: @@ -74,16 +74,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 19.21925ms + duration: 44.502708ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 15 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"base":"main"}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/8 + url: http://127.0.0.1:53569/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: 485.75µs + duration: 129.75µs - id: 3 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/8 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/8 method: GET response: proto: HTTP/1.1 @@ -117,9 +117,9 @@ interactions: body: | { "number": 8, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/8", + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/8", "state": "open", - "title": "Testing 9YbzXae4", + "title": "Testing mKnU8EV4", "body": "Test PR with custom base", "base": { "repository": { @@ -127,15 +127,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "9YbzXae4", - "sha": "a3fc1801625662da2cc43a337ee7ba729a73d732" + "ref": "mKnU8EV4", + "sha": "cd26b16c292f00fa0b6a5f5f710c461474950344" } } headers: @@ -145,4 +145,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 17.355333ms + duration: 32.452916ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditChange.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditChange.yaml index e0876df1f..7faddd99f 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:56373 - body: '{"subject":"Testing RowsHzO8","body":"Test PR","base":"main","head":"RowsHzO8"}' - url: http://127.0.0.1:56373/abhinav/test-repo/changes + host: 127.0.0.1:53569 + body: '{"subject":"Testing cI6Rfmnn","body":"Test PR","base":"main","head":"cI6Rfmnn"}' + url: http://127.0.0.1:53569/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:56374/abhinav/test-repo/change/1" + "number": 7, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/7" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 22.12625ms + duration: 45.201167ms - id: 1 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/1 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/7 method: GET response: proto: HTTP/1.1 @@ -45,10 +45,10 @@ interactions: content_length: 498 body: | { - "number": 1, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/1", + "number": 7, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/7", "state": "open", - "title": "Testing RowsHzO8", + "title": "Testing cI6Rfmnn", "body": "Test PR", "base": { "repository": { @@ -56,15 +56,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "RowsHzO8", - "sha": "1ee3894a24c031b5d053a0b8bb25a9182fd77604" + "ref": "cI6Rfmnn", + "sha": "1e2c32dc4f5cfec9674dac2d9d7d0274a63c15b0" } } headers: @@ -74,20 +74,20 @@ interactions: - application/json status: 200 OK code: 200 - duration: 18.941208ms + duration: 39.789833ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 form: limit: - "10" state: - all - url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/RowsHzO8?limit=10&state=all + url: http://127.0.0.1:53569/abhinav/test-repo/changes/by-branch/cI6Rfmnn?limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -97,10 +97,10 @@ interactions: body: | [ { - "number": 1, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/1", + "number": 7, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/7", "state": "open", - "title": "Testing RowsHzO8", + "title": "Testing cI6Rfmnn", "body": "Test PR", "base": { "repository": { @@ -108,15 +108,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "RowsHzO8", - "sha": "1ee3894a24c031b5d053a0b8bb25a9182fd77604" + "ref": "cI6Rfmnn", + "sha": "1e2c32dc4f5cfec9674dac2d9d7d0274a63c15b0" } } ] @@ -127,4 +127,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 16.2305ms + duration: 40.238416ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditDraft.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditDraft.yaml index 5114cb40a..9371286e1 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: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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing R4gPQ4SL","body":"Test draft PR","base":"main","head":"R4gPQ4SL","draft":true}' + url: http://127.0.0.1:53569/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:56374/abhinav/test-repo/change/2" + "number": 3, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/3" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 22.713917ms + duration: 37.971ms - id: 1 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/2 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/3 method: GET response: proto: HTTP/1.1 @@ -45,11 +45,11 @@ interactions: content_length: 521 body: | { - "number": 2, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/2", + "number": 3, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/3", "draft": true, "state": "open", - "title": "Testing pCyU7Tpe", + "title": "Testing R4gPQ4SL", "body": "Test draft PR", "base": { "repository": { @@ -57,15 +57,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "pCyU7Tpe", - "sha": "7bd9a65f890645f1b36eb13dd6a622b6c4b32b13" + "ref": "R4gPQ4SL", + "sha": "965286a9aa45336455161a7b2a4db1e34f9ac98d" } } headers: @@ -75,16 +75,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 20.71025ms + duration: 36.908792ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 15 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"draft":false}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/2 + url: http://127.0.0.1:53569/abhinav/test-repo/change/3 method: PATCH response: proto: HTTP/1.1 @@ -100,15 +100,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 134.583µs + duration: 213.667µs - id: 3 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/2 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/3 method: GET response: proto: HTTP/1.1 @@ -117,10 +117,10 @@ interactions: content_length: 504 body: | { - "number": 2, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/2", + "number": 3, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/3", "state": "open", - "title": "Testing pCyU7Tpe", + "title": "Testing R4gPQ4SL", "body": "Test draft PR", "base": { "repository": { @@ -128,15 +128,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "pCyU7Tpe", - "sha": "7bd9a65f890645f1b36eb13dd6a622b6c4b32b13" + "ref": "R4gPQ4SL", + "sha": "965286a9aa45336455161a7b2a4db1e34f9ac98d" } } headers: @@ -146,16 +146,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 17.1405ms + duration: 43.281167ms - id: 4 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 14 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"draft":true}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/2 + url: http://127.0.0.1:53569/abhinav/test-repo/change/3 method: PATCH response: proto: HTTP/1.1 @@ -171,15 +171,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 1.807125ms + duration: 484.75µs - id: 5 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/2 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/3 method: GET response: proto: HTTP/1.1 @@ -188,11 +188,11 @@ interactions: content_length: 521 body: | { - "number": 2, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/2", + "number": 3, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/3", "draft": true, "state": "open", - "title": "Testing pCyU7Tpe", + "title": "Testing R4gPQ4SL", "body": "Test draft PR", "base": { "repository": { @@ -200,15 +200,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "pCyU7Tpe", - "sha": "7bd9a65f890645f1b36eb13dd6a622b6c4b32b13" + "ref": "R4gPQ4SL", + "sha": "965286a9aa45336455161a7b2a4db1e34f9ac98d" } } headers: @@ -218,4 +218,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 20.676166ms + duration: 37.233416ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditLabels.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditLabels.yaml index 7b515d983..351de0b08 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: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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing 4HOIehwu","body":"Test PR with labels","base":"main","head":"4HOIehwu","labels":["2VGRqO7j"]}' + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -19,7 +19,7 @@ interactions: body: | { "number": 6, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/6" + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/6" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 21.992708ms + duration: 41.998125ms - id: 1 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/6 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/6 method: GET response: proto: HTTP/1.1 @@ -46,9 +46,9 @@ interactions: body: | { "number": 6, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/6", + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/6", "state": "open", - "title": "Testing jbBnJuHT", + "title": "Testing 4HOIehwu", "body": "Test PR with labels", "base": { "repository": { @@ -56,18 +56,18 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "jbBnJuHT", - "sha": "c34dbee79699111d2299f1fd5737e5535ae1f643" + "ref": "4HOIehwu", + "sha": "b324fe0ca7ab1155f6db68bb6738b3a35c706c3f" }, "labels": [ - "QcHb0icn" + "2VGRqO7j" ] } headers: @@ -77,16 +77,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 15.358041ms + duration: 36.385333ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 23 - host: 127.0.0.1:56373 - body: '{"labels":["820svnw8"]}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/6 + host: 127.0.0.1:53569 + body: '{"labels":["dF2bQUKv"]}' + url: http://127.0.0.1:53569/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: 1.308292ms + duration: 398.042µs - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 34 - host: 127.0.0.1:56373 - body: '{"labels":["820svnw8","bUnh1ONJ"]}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/6 + host: 127.0.0.1:53569 + body: '{"labels":["dF2bQUKv","bSgDWsqi"]}' + url: http://127.0.0.1:53569/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: 242.25µs + duration: 421.083µs - id: 4 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 form: limit: - "10" state: - all - url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/jbBnJuHT?limit=10&state=all + url: http://127.0.0.1:53569/abhinav/test-repo/changes/by-branch/4HOIehwu?limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -151,9 +151,9 @@ interactions: [ { "number": 6, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/6", + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/6", "state": "open", - "title": "Testing jbBnJuHT", + "title": "Testing 4HOIehwu", "body": "Test PR with labels", "base": { "repository": { @@ -161,20 +161,20 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "jbBnJuHT", - "sha": "c34dbee79699111d2299f1fd5737e5535ae1f643" + "ref": "4HOIehwu", + "sha": "b324fe0ca7ab1155f6db68bb6738b3a35c706c3f" }, "labels": [ - "QcHb0icn", - "820svnw8", - "bUnh1ONJ" + "2VGRqO7j", + "dF2bQUKv", + "bSgDWsqi" ] } ] @@ -185,4 +185,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 20.795292ms + duration: 41.2895ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewer.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewer.yaml index a9ce1ed31..ca892789d 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: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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing BXaFutk3","body":"Test PR without reviewers","base":"main","head":"BXaFutk3"}' + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -18,8 +18,8 @@ interactions: content_length: 82 body: | { - "number": 17, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/17" + "number": 13, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/13" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 13.741459ms + duration: 30.130458ms - id: 1 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/17 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/13 method: GET response: proto: HTTP/1.1 @@ -45,10 +45,10 @@ interactions: content_length: 518 body: | { - "number": 17, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/17", + "number": 13, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/13", "state": "open", - "title": "Testing qS0oWVxR", + "title": "Testing BXaFutk3", "body": "Test PR without reviewers", "base": { "repository": { @@ -56,15 +56,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "qS0oWVxR", - "sha": "d10f53257e22f018a3d5d54780611749d959d3ed" + "ref": "BXaFutk3", + "sha": "4423dce906b5fddf7ddd3a536c3ffc2a2627a245" } } headers: @@ -74,16 +74,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 13.343458ms + duration: 27.700542ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 39 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"reviewers":["reviewer1","reviewer2"]}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/17 + url: http://127.0.0.1:53569/abhinav/test-repo/change/13 method: PATCH response: proto: HTTP/1.1 @@ -99,15 +99,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 20.163792ms + duration: 35.203875ms - id: 3 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/17 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/13 method: GET response: proto: HTTP/1.1 @@ -116,10 +116,10 @@ interactions: content_length: 583 body: | { - "number": 17, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/17", + "number": 13, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/13", "state": "open", - "title": "Testing qS0oWVxR", + "title": "Testing BXaFutk3", "body": "Test PR without reviewers", "base": { "repository": { @@ -127,15 +127,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "78e7fffc2e2f2b050db2efb7f3de43be063e31f3" + "sha": "935a1736c1d0abc559194d26342e46a76e102069" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "qS0oWVxR", - "sha": "d10f53257e22f018a3d5d54780611749d959d3ed" + "ref": "BXaFutk3", + "sha": "4423dce906b5fddf7ddd3a536c3ffc2a2627a245" }, "requested_reviewers": [ "reviewer1", @@ -149,4 +149,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 21.720042ms + duration: 55.48225ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewersOneByOne.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/AddReviewersOneByOne.yaml index e2a72c93e..567791f79 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: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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing EwqrlAsh","body":"Test PR without reviewers","base":"main","head":"EwqrlAsh"}' + url: http://127.0.0.1:53569/abhinav/test-repo/changes method: POST response: proto: HTTP/1.1 @@ -19,7 +19,7 @@ interactions: body: | { "number": 14, - "url": "http://127.0.0.1:56374/abhinav/test-repo/change/14" + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/14" } headers: Content-Length: @@ -28,15 +28,15 @@ interactions: - application/json status: 200 OK code: 200 - duration: 14.613166ms + duration: 30.532125ms - id: 1 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/14 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/14 method: GET response: proto: HTTP/1.1 @@ -46,9 +46,9 @@ interactions: body: | { "number": 14, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/14", + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/14", "state": "open", - "title": "Testing sN0uOM0J", + "title": "Testing EwqrlAsh", "body": "Test PR without reviewers", "base": { "repository": { @@ -56,15 +56,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "sN0uOM0J", - "sha": "fe1856b3db7f006918e699a1c316e92ad3342d93" + "ref": "EwqrlAsh", + "sha": "6ee3f5e3004c4d74580c42ea3b0f85d0fcf5f0f8" } } headers: @@ -74,16 +74,16 @@ interactions: - application/json status: 200 OK code: 200 - duration: 11.315875ms + duration: 27.463625ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 27 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"reviewers":["reviewer1"]}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/14 + url: http://127.0.0.1:53569/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: 415.5µs + duration: 35.209625ms - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 27 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 body: '{"reviewers":["reviewer2"]}' - url: http://127.0.0.1:56373/abhinav/test-repo/change/14 + url: http://127.0.0.1:53569/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: 102.334µs + duration: 26.211ms - id: 4 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/14 + host: 127.0.0.1:53569 + url: http://127.0.0.1:53569/abhinav/test-repo/change/14 method: GET response: proto: HTTP/1.1 @@ -142,9 +142,9 @@ interactions: body: | { "number": 14, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/14", + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/14", "state": "open", - "title": "Testing sN0uOM0J", + "title": "Testing EwqrlAsh", "body": "Test PR without reviewers", "base": { "repository": { @@ -152,15 +152,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "935a1736c1d0abc559194d26342e46a76e102069" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "sN0uOM0J", - "sha": "fe1856b3db7f006918e699a1c316e92ad3342d93" + "ref": "EwqrlAsh", + "sha": "6ee3f5e3004c4d74580c42ea3b0f85d0fcf5f0f8" }, "requested_reviewers": [ "reviewer1", @@ -174,4 +174,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 11.028083ms + duration: 28.57575ms diff --git a/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/SubmitWithReviewer.yaml b/internal/forge/shamhub/testdata/fixtures/TestIntegration/SubmitEditReviewers/SubmitWithReviewer.yaml index 0c837343b..6d9e90d43 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: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 + host: 127.0.0.1:53569 + body: '{"subject":"Testing df7WoDco","body":"Test PR with reviewer","base":"main","head":"df7WoDco","reviewers":["reviewer1","reviewer2"]}' + url: http://127.0.0.1:53569/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:56374/abhinav/test-repo/change/13" + "number": 12, + "url": "http://127.0.0.1:53570/abhinav/test-repo/change/12" } headers: Content-Length: @@ -28,20 +28,20 @@ interactions: - application/json status: 200 OK code: 200 - duration: 23.097875ms + duration: 30.764459ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 content_length: 0 - host: 127.0.0.1:56373 + host: 127.0.0.1:53569 form: limit: - "10" state: - all - url: http://127.0.0.1:56373/abhinav/test-repo/changes/by-branch/4oj7KI1p?limit=10&state=all + url: http://127.0.0.1:53569/abhinav/test-repo/changes/by-branch/df7WoDco?limit=10&state=all method: GET response: proto: HTTP/1.1 @@ -51,10 +51,10 @@ interactions: body: | [ { - "number": 13, - "html_url": "http://127.0.0.1:56374/abhinav/test-repo/change/13", + "number": 12, + "html_url": "http://127.0.0.1:53570/abhinav/test-repo/change/12", "state": "open", - "title": "Testing 4oj7KI1p", + "title": "Testing df7WoDco", "body": "Test PR with reviewer", "base": { "repository": { @@ -62,15 +62,15 @@ interactions: "name": "test-repo" }, "ref": "main", - "sha": "71012226be854d2a77b193ca779abba5cc84cca0" + "sha": "c17a304a06b281e76d193f8a86a8ab71585b64e3" }, "head": { "repository": { "owner": "abhinav", "name": "test-repo" }, - "ref": "4oj7KI1p", - "sha": "d42a7e9d935c9911190197ad4e04542af2500250" + "ref": "df7WoDco", + "sha": "6cca56449280db9fd8954bd6d01d3b30ca7a474c" }, "requested_reviewers": [ "reviewer1", @@ -85,4 +85,4 @@ interactions: - application/json status: 200 OK code: 200 - duration: 23.390833ms + duration: 28.513791ms diff --git a/internal/gateway/bitbucket/api.go b/internal/gateway/bitbucket/api.go index 9abc6cffe..199624148 100644 --- a/internal/gateway/bitbucket/api.go +++ b/internal/gateway/bitbucket/api.go @@ -77,6 +77,7 @@ type PullRequestListOptions struct { type Comment struct { ID int64 `json:"id"` Content Content `json:"content"` + User User `json:"user"` Inline *Inline `json:"inline,omitempty"` Resolution *Resolution `json:"resolution,omitempty"` } @@ -84,6 +85,25 @@ type Comment struct { // CommentCreateRequest is the request body for creating or updating a comment. type CommentCreateRequest struct { Content Content `json:"content"` + + // Inline, when set, posts a code-review (inline) comment + // on the given file path and line. + Inline *Inline `json:"inline,omitempty"` + + // Parent, when set, posts a reply on the given parent comment. + // Mutually exclusive with Inline. + Parent *CommentRef `json:"parent,omitempty"` +} + +// CommentRef identifies a comment by ID. +type CommentRef struct { + ID int64 `json:"id"` +} + +// CommentResolveRequest is the request body for resolving +// or unresolving an inline comment. +type CommentResolveRequest struct { + Resolution *Resolution `json:"resolution"` } // CommentList is the paginated response for listing comments. @@ -466,6 +486,32 @@ func (c *Client) CommitStatusCreate( return &response, resp, nil } +// CommentResolve resolves or unresolves a pull-request inline comment. +// +// Pass req.Resolution = nil to unresolve, non-nil to resolve. +func (c *Client) CommentResolve( + ctx context.Context, + workspace string, + repo string, + prID int64, + commentID int64, + req *CommentResolveRequest, +) (*Comment, *Response, error) { + var response Comment + resp, err := c.put( + ctx, + fmt.Sprintf( + "/repositories/%s/%s/pullrequests/%d/comments/%d", + workspace, repo, prID, commentID, + ), + 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/gitlab/api.go b/internal/gateway/gitlab/api.go index ba628d4f7..0badaf20d 100644 --- a/internal/gateway/gitlab/api.go +++ b/internal/gateway/gitlab/api.go @@ -7,6 +7,7 @@ import ( "net/url" "strconv" "strings" + "time" ) // ProjectGet fetches a single project by numeric ID or `group/project` path. @@ -326,6 +327,116 @@ func (c *Client) MergeRequestDiscussionList( return response, resp, nil } +// MergeRequestDiscussionCreate creates a new discussion (review thread) +// on a merge request. +// +// GitLab API: +// https://docs.gitlab.com/api/discussions/#create-new-merge-request-thread +func (c *Client) MergeRequestDiscussionCreate( + ctx context.Context, + projectID int64, + mergeRequest int64, + opt *CreateMergeRequestDiscussionOptions, +) (*Discussion, *Response, error) { + var response Discussion + resp, err := c.post( + ctx, + fmt.Sprintf( + "projects/%d/merge_requests/%d/discussions", + projectID, mergeRequest, + ), + nil, opt, &response, + ) + if err != nil { + return nil, resp, err + } + return &response, resp, nil +} + +// MergeRequestDiscussionResolve resolves or unresolves a discussion thread. +// +// GitLab API: +// https://docs.gitlab.com/api/discussions/#resolve-a-merge-request-thread +func (c *Client) MergeRequestDiscussionResolve( + ctx context.Context, + projectID int64, + mergeRequest int64, + discussionID string, + opt *ResolveMergeRequestDiscussionOptions, +) (*Discussion, *Response, error) { + var response Discussion + resp, err := c.put( + ctx, + fmt.Sprintf( + "projects/%d/merge_requests/%d/discussions/%s", + projectID, mergeRequest, + url.PathEscape(discussionID), + ), + nil, opt, &response, + ) + if err != nil { + return nil, resp, err + } + return &response, resp, nil +} + +// MergeRequestDiscussionNoteCreate adds a note to an existing discussion +// thread (i.e. reply). +// +// GitLab API: +// https://docs.gitlab.com/api/discussions/#add-note-to-existing-merge-request-thread +func (c *Client) MergeRequestDiscussionNoteCreate( + ctx context.Context, + projectID int64, + mergeRequest int64, + discussionID string, + opt *AddMergeRequestDiscussionNoteOptions, +) (*DiscussionNote, *Response, error) { + var response DiscussionNote + resp, err := c.post( + ctx, + fmt.Sprintf( + "projects/%d/merge_requests/%d/discussions/%s/notes", + projectID, mergeRequest, + url.PathEscape(discussionID), + ), + nil, opt, &response, + ) + if err != nil { + return nil, resp, err + } + return &response, resp, nil +} + +// MergeRequestDiscussionNoteUpdate edits the body of an existing +// discussion note. +// +// GitLab API: +// https://docs.gitlab.com/api/discussions/#modify-an-existing-merge-request-thread-note +func (c *Client) MergeRequestDiscussionNoteUpdate( + ctx context.Context, + projectID int64, + mergeRequest int64, + discussionID string, + noteID int64, + opt *UpdateMergeRequestDiscussionNoteOptions, +) (*DiscussionNote, *Response, error) { + var response DiscussionNote + resp, err := c.put( + ctx, + fmt.Sprintf( + "projects/%d/merge_requests/%d/discussions/%s/notes/%d", + projectID, mergeRequest, + url.PathEscape(discussionID), noteID, + ), + nil, opt, &response, + ) + if err != nil { + return nil, resp, err + } + return &response, resp, nil +} + // ProjectTemplateList lists project templates for a template type. // // GitLab API: @@ -504,7 +615,16 @@ type BasicMergeRequest struct { // https://docs.gitlab.com/api/merge_requests/ type MergeRequest struct { BasicMergeRequest - HeadPipeline *Pipeline `json:"head_pipeline,omitempty"` + HeadPipeline *Pipeline `json:"head_pipeline,omitempty"` + DiffRefs MergeRequestDiffRefs `json:"diff_refs"` +} + +// MergeRequestDiffRefs holds the SHAs needed +// to position inline comments on a merge request diff. +type MergeRequestDiffRefs struct { + BaseSha string `json:"base_sha"` + HeadSha string `json:"head_sha"` + StartSha string `json:"start_sha"` } // Pipeline is a GitLab CI pipeline status summary. @@ -567,8 +687,25 @@ type Discussion struct { // GitLab discussions API: // https://docs.gitlab.com/api/discussions/ type DiscussionNote struct { - Resolvable bool `json:"resolvable"` - Resolved bool `json:"resolved"` + ID int64 `json:"id"` + Body string `json:"body"` + Author DiscussionNoteUser `json:"author"` + Position *DiscussionPosition `json:"position,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + Resolvable bool `json:"resolvable"` + Resolved bool `json:"resolved"` +} + +// DiscussionNoteUser matches the author shape on a discussion note. +type DiscussionNoteUser struct { + Username string `json:"username"` +} + +// DiscussionPosition is the inline position of a code-review note. +type DiscussionPosition struct { + NewPath string `json:"new_path"` + OldPath string `json:"old_path"` + NewLine int64 `json:"new_line"` } // ProjectTemplate matches the subset of project template fields @@ -742,6 +879,42 @@ func (o *ListMergeRequestDiscussionsOptions) encodeQuery() url.Values { // ListProjectTemplatesOptions configures template-list requests. type ListProjectTemplatesOptions struct{} +// CreateMergeRequestDiscussionOptions configures the creation +// of a new merge request discussion thread. +type CreateMergeRequestDiscussionOptions struct { + Body *string `json:"body,omitempty"` + Position *PositionOptions `json:"position,omitempty"` +} + +// PositionOptions describes the inline position for +// a discussion-creation request. +type PositionOptions struct { + BaseSHA *string `json:"base_sha,omitempty"` + HeadSHA *string `json:"head_sha,omitempty"` + StartSHA *string `json:"start_sha,omitempty"` + PositionType *string `json:"position_type,omitempty"` + NewPath *string `json:"new_path,omitempty"` + OldPath *string `json:"old_path,omitempty"` + NewLine *int64 `json:"new_line,omitempty"` +} + +// ResolveMergeRequestDiscussionOptions configures resolve/unresolve. +type ResolveMergeRequestDiscussionOptions struct { + Resolved *bool `json:"resolved,omitempty"` +} + +// AddMergeRequestDiscussionNoteOptions configures replies on +// an existing discussion thread. +type AddMergeRequestDiscussionNoteOptions struct { + Body *string `json:"body,omitempty"` +} + +// UpdateMergeRequestDiscussionNoteOptions configures edits to +// an existing discussion note. +type UpdateMergeRequestDiscussionNoteOptions struct { + Body *string `json:"body,omitempty"` +} + func gitlabProjectResource(project any) (string, error) { switch v := project.(type) { case int: From dabcd6f7fba3ba993392992b3bc7b7af990de3b2 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Sat, 13 Jun 2026 20:44:38 -0700 Subject: [PATCH 2/3] forge: Type inline comments Inline comment operations now carry the thread identifier, line range, and diff side as named forge-domain types. The public inline-comment contract also owns thread resolution because all current inline-comment implementations support it. Inline comment editing is part of the base repository contract because every repository implementation already provides the operation. --- internal/forge/bitbucket/inline_comment.go | 79 +- internal/forge/bitbucket/operations_test.go | 24 +- internal/forge/forge.go | 98 +- internal/forge/forgetest/mocks.go | 1448 ++----------------- internal/forge/github/inline_comment.go | 50 +- internal/forge/gitlab/inline_comment.go | 73 +- internal/forge/shamhub/comment.go | 4 +- internal/forge/shamhub/inline_comment.go | 42 +- 8 files changed, 331 insertions(+), 1487 deletions(-) diff --git a/internal/forge/bitbucket/inline_comment.go b/internal/forge/bitbucket/inline_comment.go index 6772a091f..5b50ff6da 100644 --- a/internal/forge/bitbucket/inline_comment.go +++ b/internal/forge/bitbucket/inline_comment.go @@ -9,11 +9,7 @@ import ( "go.abhg.dev/gs/internal/gateway/bitbucket" ) -var ( - _ forge.WithInlineComments = (*Repository)(nil) - _ forge.WithThreadResolution = (*Repository)(nil) - _ forge.WithCommentEdit = (*Repository)(nil) -) +var _ forge.WithInlineComments = (*Repository)(nil) // ListInlineComments lists inline/review comments on a PR // by filtering comments that have inline position data. @@ -47,17 +43,17 @@ func (r *Repository) ListInlineComments( // Thread ID encodes comment ID and PR ID // for resolve/unresolve operations. - threadID := formatThreadID(c.ID, prID) + id := formatInlineCommentThreadID(c.ID, prID) comments = append(comments, &forge.InlineComment{ - ID: &PRComment{ + ID: id, + CommentID: &PRComment{ ID: c.ID, PRID: prID, }, - ThreadID: threadID, Path: c.Inline.Path, - Line: line, + Lines: forge.InlineCommentLine(line), Body: c.Content.Raw, Author: c.User.DisplayName, Resolved: c.Resolution != nil, @@ -104,10 +100,10 @@ func (r *Repository) submitOneComment( prID int64, c forge.InlineCommentRequest, ) error { - if c.ThreadID != "" { - parentID, _, err := parseThreadID(c.ThreadID) + if c.InReplyTo != "" { + parentID, _, err := parseInlineCommentThreadID(c.InReplyTo) if err != nil { - return fmt.Errorf("parse thread ID: %w", err) + return fmt.Errorf("parse inline comment ID: %w", err) } _, err = r.replyToComment( ctx, prID, parentID, c.Body, @@ -115,13 +111,13 @@ func (r *Repository) submitOneComment( return err } _, err := r.postInlineCommentAPI( - ctx, prID, c.Path, c.Line, c.Body, + ctx, prID, c.Path, c.Lines, c.Body, ) return err } // PostInlineComment posts a single inline comment on a PR. -// If req.ThreadID is set, posts a reply to that thread +// If req.InReplyTo is set, posts a reply to that thread // instead of creating a new inline comment. func (r *Repository) PostInlineComment( ctx context.Context, @@ -130,7 +126,7 @@ func (r *Repository) PostInlineComment( ) (*forge.InlineComment, error) { prID := mustPR(id).Number - if req.ThreadID != "" { + if req.InReplyTo != "" { return r.postReply(ctx, prID, req) } return r.postNewInlineComment(ctx, prID, req) @@ -142,22 +138,22 @@ func (r *Repository) postNewInlineComment( req forge.InlineCommentRequest, ) (*forge.InlineComment, error) { comment, err := r.postInlineCommentAPI( - ctx, prID, req.Path, req.Line, req.Body, + ctx, prID, req.Path, req.Lines, req.Body, ) if err != nil { return nil, err } return &forge.InlineComment{ - ID: &PRComment{ + ID: formatInlineCommentThreadID(comment.ID, prID), + CommentID: &PRComment{ ID: comment.ID, PRID: prID, }, - ThreadID: formatThreadID(comment.ID, prID), - Path: req.Path, - Line: req.Line, - Body: req.Body, - Author: comment.User.DisplayName, + Path: req.Path, + Lines: req.Lines, + Body: req.Body, + Author: comment.User.DisplayName, }, nil } @@ -166,9 +162,9 @@ func (r *Repository) postReply( prID int64, req forge.InlineCommentRequest, ) (*forge.InlineComment, error) { - parentID, _, err := parseThreadID(req.ThreadID) + parentID, _, err := parseInlineCommentThreadID(req.InReplyTo) if err != nil { - return nil, fmt.Errorf("parse thread ID: %w", err) + return nil, fmt.Errorf("parse inline comment ID: %w", err) } comment, err := r.replyToComment( @@ -179,13 +175,13 @@ func (r *Repository) postReply( } return &forge.InlineComment{ - ID: &PRComment{ + ID: req.InReplyTo, + CommentID: &PRComment{ ID: comment.ID, PRID: prID, }, - ThreadID: req.ThreadID, - Body: req.Body, - Author: comment.User.DisplayName, + Body: req.Body, + Author: comment.User.DisplayName, }, nil } @@ -214,10 +210,10 @@ func (r *Repository) postInlineCommentAPI( ctx context.Context, prID int64, filePath string, - line int, + lines forge.InlineCommentRange, body string, ) (*bitbucket.Comment, error) { - to := line + to := lines.StartLine comment, _, err := r.client.CommentCreate( ctx, r.workspace, r.repo, prID, &bitbucket.CommentCreateRequest{ @@ -231,7 +227,7 @@ func (r *Repository) postInlineCommentAPI( if err != nil { return nil, fmt.Errorf( "create inline comment on %s:%d: %w", - filePath, line, err, + filePath, lines.StartLine, err, ) } return comment, nil @@ -240,9 +236,9 @@ func (r *Repository) postInlineCommentAPI( // ResolveThread marks an inline comment as resolved. func (r *Repository) ResolveThread( ctx context.Context, - threadID string, + id forge.InlineCommentThreadID, ) error { - commentID, prID, err := parseThreadID(threadID) + commentID, prID, err := parseInlineCommentThreadID(id) if err != nil { return err } @@ -256,16 +252,16 @@ func (r *Repository) ResolveThread( return fmt.Errorf("resolve thread: %w", err) } - r.log.Debug("Resolved thread", "threadID", threadID) + r.log.Debug("Resolved thread", "id", id) return nil } // UnresolveThread marks an inline comment as unresolved. func (r *Repository) UnresolveThread( ctx context.Context, - threadID string, + id forge.InlineCommentThreadID, ) error { - commentID, prID, err := parseThreadID(threadID) + commentID, prID, err := parseInlineCommentThreadID(id) if err != nil { return err } @@ -279,7 +275,7 @@ func (r *Repository) UnresolveThread( return fmt.Errorf("unresolve thread: %w", err) } - r.log.Debug("Unresolved thread", "threadID", threadID) + r.log.Debug("Unresolved thread", "id", id) return nil } @@ -296,14 +292,15 @@ func (r *Repository) EditComment( // Thread ID encoding for Bitbucket: // "commentID:prID" -func formatThreadID(commentID, prID int64) string { - return strconv.FormatInt(commentID, 10) + - ":" + strconv.FormatInt(prID, 10) +func formatInlineCommentThreadID(commentID, prID int64) forge.InlineCommentThreadID { + return forge.InlineCommentThreadID(strconv.FormatInt(commentID, 10) + + ":" + strconv.FormatInt(prID, 10)) } -func parseThreadID(threadID string) ( +func parseInlineCommentThreadID(id forge.InlineCommentThreadID) ( commentID, prID int64, err error, ) { + threadID := string(id) for i := len(threadID) - 1; i >= 0; i-- { if threadID[i] == ':' { commentID, err = strconv.ParseInt( diff --git a/internal/forge/bitbucket/operations_test.go b/internal/forge/bitbucket/operations_test.go index 9f7b6845a..5591f238a 100644 --- a/internal/forge/bitbucket/operations_test.go +++ b/internal/forge/bitbucket/operations_test.go @@ -715,16 +715,16 @@ func TestPostInlineComment(t *testing.T) { t.Context(), &PR{Number: 1}, forge.InlineCommentRequest{ - Path: "file.go", - Line: 42, - Body: "new comment", + Path: "file.go", + Lines: forge.InlineCommentLine(42), + Body: "new comment", }, ) require.NoError(t, err) assert.Equal(t, "new comment", posted.Body) assert.Equal(t, "file.go", posted.Path) - assert.Equal(t, 42, posted.Line) + assert.Equal(t, forge.InlineCommentLine(42), posted.Lines) } func TestPostInlineComment_reply(t *testing.T) { @@ -771,14 +771,14 @@ func TestPostInlineComment_reply(t *testing.T) { t.Context(), &PR{Number: 1}, forge.InlineCommentRequest{ - Body: "reply body", - ThreadID: "99:1", // commentID:prID + Body: "reply body", + InReplyTo: "99:1", // commentID:prID }, ) require.NoError(t, err) assert.Equal(t, "reply body", posted.Body) - assert.Equal(t, "99:1", posted.ThreadID) + assert.Equal(t, forge.InlineCommentThreadID("99:1"), posted.ID) } func TestSubmitReview_withReply(t *testing.T) { @@ -811,13 +811,13 @@ func TestSubmitReview_withReply(t *testing.T) { forge.ReviewRequest{ Comments: []forge.InlineCommentRequest{ { - Path: "a.go", - Line: 10, - Body: "new comment", + Path: "a.go", + Lines: forge.InlineCommentLine(10), + Body: "new comment", }, { - Body: "thread reply", - ThreadID: "55:1", + Body: "thread reply", + InReplyTo: "55:1", }, }, }, diff --git a/internal/forge/forge.go b/internal/forge/forge.go index 0d36c94d6..5ededdbd7 100644 --- a/internal/forge/forge.go +++ b/internal/forge/forge.go @@ -143,7 +143,7 @@ type WithCommentFormat interface { CommentFormat() CommentFormat } -//go:generate mockgen -destination=forgetest/mocks.go -package forgetest -typed -write_package_comment=false . Forge,RepositoryID,Repository,WithInlineComments,WithThreadResolution,WithCommentEdit +//go:generate mockgen -destination=forgetest/mocks.go -package forgetest -typed -write_package_comment=false . Forge,RepositoryID,Repository,WithInlineComments // TODO: // Forge should become a struct with multiple interfaces or funcctions @@ -309,6 +309,9 @@ type Repository interface { UpdateChangeComment(context.Context, ChangeCommentID, string) error DeleteChangeComment(context.Context, ChangeCommentID) error + // EditComment updates the body of an existing inline comment. + EditComment(context.Context, ChangeCommentID, string) error + // List comments on a CR, optionally filtered per the given options. ListChangeComments(context.Context, ChangeID, *ListChangeCommentsOptions) iter.Seq2[*ListChangeCommentItem, error] @@ -764,41 +767,81 @@ func (s ChecksState) GoString() string { // Inline comment types and optional interfaces +// InlineCommentThreadID identifies an inline comment thread. +type InlineCommentThreadID string + +// InlineCommentSide identifies which side of a diff an inline comment targets. +type InlineCommentSide int + +const ( + // InlineCommentSideRight targets the new side of a diff. + InlineCommentSideRight InlineCommentSide = iota + + // InlineCommentSideLeft targets the old side of a diff. + InlineCommentSideLeft +) + +// String returns the forge-neutral spelling for the side. +func (s InlineCommentSide) String() string { + switch s { + case InlineCommentSideLeft: + return "left" + default: + return "right" + } +} + +// InlineCommentRange identifies an inclusive line range in a diff. +type InlineCommentRange struct { + // StartLine is the first line in the range, inclusive. + StartLine int + + // EndLine is the final line in the range, inclusive. + EndLine int +} + +// InlineCommentLine returns a range covering exactly one line. +func InlineCommentLine(line int) InlineCommentRange { + return InlineCommentRange{ + StartLine: line, + EndLine: line, + } +} + // InlineCommentRequest describes a new inline comment // to post on a change diff. type InlineCommentRequest struct { + // InReplyTo identifies the inline comment thread to reply to. + // + // Leave InReplyTo empty to start a new inline comment thread. + InReplyTo InlineCommentThreadID + // Path is the file path relative to the repository root. Path string - // Line is the line number in the new version of the file. - Line int + // Lines identifies the line range in the diff. + Lines InlineCommentRange // Body is the markdown body of the comment. Body string - // Side indicates which side of the diff the comment - // applies to. Use "LEFT" for the old version - // or "RIGHT" (default) for the new version. - Side string - - // ThreadID is set when replying to an existing thread. - // The format is forge-specific. - ThreadID string + // Side indicates which side of the diff the comment applies to. + Side InlineCommentSide } // InlineComment is a comment on a specific line of a diff. type InlineComment struct { - // ID is the forge-specific comment identifier. - ID ChangeCommentID + // ID is the inline comment thread identifier. + ID InlineCommentThreadID - // ThreadID is the forge-specific thread identifier. - ThreadID string + // CommentID is the forge-specific comment identifier. + CommentID ChangeCommentID // Path is the file path relative to the repository root. Path string - // Line is the line number in the diff. - Line int + // Lines identifies the line range in the diff. + Lines InlineCommentRange // Body is the markdown body of the comment. Body string @@ -868,27 +911,10 @@ type WithInlineComments interface { ctx context.Context, id ChangeID, req InlineCommentRequest, ) (*InlineComment, error) -} - -// WithThreadResolution is an optional interface -// for forges that support resolving comment threads. -type WithThreadResolution interface { - Repository // ResolveThread marks a comment thread as resolved. - ResolveThread(ctx context.Context, threadID string) error + ResolveThread(ctx context.Context, id InlineCommentThreadID) error // UnresolveThread marks a comment thread as unresolved. - UnresolveThread(ctx context.Context, threadID string) error -} - -// WithCommentEdit is an optional interface -// for forges that support editing existing comments. -type WithCommentEdit interface { - Repository - - // EditComment updates the body of an existing comment. - EditComment( - ctx context.Context, id ChangeCommentID, body string, - ) error + UnresolveThread(ctx context.Context, id InlineCommentThreadID) error } diff --git a/internal/forge/forgetest/mocks.go b/internal/forge/forgetest/mocks.go index b9ae2a647..d7dd5624a 100644 --- a/internal/forge/forgetest/mocks.go +++ b/internal/forge/forgetest/mocks.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: go.abhg.dev/gs/internal/forge (interfaces: Forge,RepositoryID,Repository,WithInlineComments,WithThreadResolution,WithCommentEdit) +// Source: go.abhg.dev/gs/internal/forge (interfaces: Forge,RepositoryID,Repository,WithInlineComments) // // Generated by this command: // -// mockgen -destination=forgetest/mocks.go -package forgetest -typed -write_package_comment=false . Forge,RepositoryID,Repository,WithInlineComments,WithThreadResolution,WithCommentEdit +// mockgen -destination=forgetest/mocks.go -package forgetest -typed -write_package_comment=false . Forge,RepositoryID,Repository,WithInlineComments // package forgetest @@ -901,6 +901,44 @@ func (c *MockRepositoryEditChangeCall) DoAndReturn(f func(context.Context, forge return c } +// EditComment mocks base method. +func (m *MockRepository) EditComment(arg0 context.Context, arg1 forge.ChangeCommentID, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EditComment", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// EditComment indicates an expected call of EditComment. +func (mr *MockRepositoryMockRecorder) EditComment(arg0, arg1, arg2 any) *MockRepositoryEditCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EditComment", reflect.TypeOf((*MockRepository)(nil).EditComment), arg0, arg1, arg2) + return &MockRepositoryEditCommentCall{Call: call} +} + +// MockRepositoryEditCommentCall wrap *gomock.Call +type MockRepositoryEditCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockRepositoryEditCommentCall) Return(arg0 error) *MockRepositoryEditCommentCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockRepositoryEditCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockRepositoryEditCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockRepositoryEditCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockRepositoryEditCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // FindChangeByID mocks base method. func (m *MockRepository) FindChangeByID(ctx context.Context, id forge.ChangeID) (*forge.FindChangeItem, error) { m.ctrl.T.Helper() @@ -1504,6 +1542,44 @@ func (c *MockWithInlineCommentsEditChangeCall) DoAndReturn(f func(context.Contex return c } +// EditComment mocks base method. +func (m *MockWithInlineComments) EditComment(arg0 context.Context, arg1 forge.ChangeCommentID, arg2 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EditComment", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// EditComment indicates an expected call of EditComment. +func (mr *MockWithInlineCommentsMockRecorder) EditComment(arg0, arg1, arg2 any) *MockWithInlineCommentsEditCommentCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EditComment", reflect.TypeOf((*MockWithInlineComments)(nil).EditComment), arg0, arg1, arg2) + return &MockWithInlineCommentsEditCommentCall{Call: call} +} + +// MockWithInlineCommentsEditCommentCall wrap *gomock.Call +type MockWithInlineCommentsEditCommentCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsEditCommentCall) Return(arg0 error) *MockWithInlineCommentsEditCommentCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsEditCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithInlineCommentsEditCommentCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsEditCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithInlineCommentsEditCommentCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // FindChangeByID mocks base method. func (m *MockWithInlineComments) FindChangeByID(ctx context.Context, id forge.ChangeID) (*forge.FindChangeItem, error) { m.ctrl.T.Helper() @@ -1891,6 +1967,44 @@ func (c *MockWithInlineCommentsPostInlineCommentCall) DoAndReturn(f func(context return c } +// ResolveThread mocks base method. +func (m *MockWithInlineComments) ResolveThread(ctx context.Context, id forge.InlineCommentThreadID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ResolveThread", ctx, id) + ret0, _ := ret[0].(error) + return ret0 +} + +// ResolveThread indicates an expected call of ResolveThread. +func (mr *MockWithInlineCommentsMockRecorder) ResolveThread(ctx, id any) *MockWithInlineCommentsResolveThreadCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveThread", reflect.TypeOf((*MockWithInlineComments)(nil).ResolveThread), ctx, id) + return &MockWithInlineCommentsResolveThreadCall{Call: call} +} + +// MockWithInlineCommentsResolveThreadCall wrap *gomock.Call +type MockWithInlineCommentsResolveThreadCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockWithInlineCommentsResolveThreadCall) Return(arg0 error) *MockWithInlineCommentsResolveThreadCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockWithInlineCommentsResolveThreadCall) Do(f func(context.Context, forge.InlineCommentThreadID) error) *MockWithInlineCommentsResolveThreadCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockWithInlineCommentsResolveThreadCall) DoAndReturn(f func(context.Context, forge.InlineCommentThreadID) error) *MockWithInlineCommentsResolveThreadCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // SubmitChange mocks base method. func (m *MockWithInlineComments) SubmitChange(ctx context.Context, req forge.SubmitChangeRequest) (forge.SubmitChangeResult, error) { m.ctrl.T.Helper() @@ -1968,1360 +2082,78 @@ func (c *MockWithInlineCommentsSubmitReviewCall) DoAndReturn(f func(context.Cont return c } -// UpdateChangeComment mocks base method. -func (m *MockWithInlineComments) UpdateChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID, arg2 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateChangeComment", arg0, arg1, arg2) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateChangeComment indicates an expected call of UpdateChangeComment. -func (mr *MockWithInlineCommentsMockRecorder) UpdateChangeComment(arg0, arg1, arg2 any) *MockWithInlineCommentsUpdateChangeCommentCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChangeComment", reflect.TypeOf((*MockWithInlineComments)(nil).UpdateChangeComment), arg0, arg1, arg2) - return &MockWithInlineCommentsUpdateChangeCommentCall{Call: call} -} - -// MockWithInlineCommentsUpdateChangeCommentCall wrap *gomock.Call -type MockWithInlineCommentsUpdateChangeCommentCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithInlineCommentsUpdateChangeCommentCall) Return(arg0 error) *MockWithInlineCommentsUpdateChangeCommentCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithInlineCommentsUpdateChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithInlineCommentsUpdateChangeCommentCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithInlineCommentsUpdateChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithInlineCommentsUpdateChangeCommentCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// MockWithThreadResolution is a mock of WithThreadResolution interface. -type MockWithThreadResolution struct { - ctrl *gomock.Controller - recorder *MockWithThreadResolutionMockRecorder - isgomock struct{} -} - -// MockWithThreadResolutionMockRecorder is the mock recorder for MockWithThreadResolution. -type MockWithThreadResolutionMockRecorder struct { - mock *MockWithThreadResolution -} - -// NewMockWithThreadResolution creates a new mock instance. -func NewMockWithThreadResolution(ctrl *gomock.Controller) *MockWithThreadResolution { - mock := &MockWithThreadResolution{ctrl: ctrl} - mock.recorder = &MockWithThreadResolutionMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockWithThreadResolution) EXPECT() *MockWithThreadResolutionMockRecorder { - return m.recorder -} - -// ChangeChecksState mocks base method. -func (m *MockWithThreadResolution) 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 *MockWithThreadResolutionMockRecorder) ChangeChecksState(ctx, id any) *MockWithThreadResolutionChangeChecksStateCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeChecksState", reflect.TypeOf((*MockWithThreadResolution)(nil).ChangeChecksState), ctx, id) - return &MockWithThreadResolutionChangeChecksStateCall{Call: call} -} - -// MockWithThreadResolutionChangeChecksStateCall wrap *gomock.Call -type MockWithThreadResolutionChangeChecksStateCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionChangeChecksStateCall) Return(arg0 forge.ChecksState, arg1 error) *MockWithThreadResolutionChangeChecksStateCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionChangeChecksStateCall) Do(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockWithThreadResolutionChangeChecksStateCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionChangeChecksStateCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockWithThreadResolutionChangeChecksStateCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// ChangeStatuses mocks base method. -func (m *MockWithThreadResolution) ChangeStatuses(ctx context.Context, ids []forge.ChangeID) ([]forge.ChangeStatus, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ChangeStatuses", ctx, ids) - ret0, _ := ret[0].([]forge.ChangeStatus) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ChangeStatuses indicates an expected call of ChangeStatuses. -func (mr *MockWithThreadResolutionMockRecorder) ChangeStatuses(ctx, ids any) *MockWithThreadResolutionChangeStatusesCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeStatuses", reflect.TypeOf((*MockWithThreadResolution)(nil).ChangeStatuses), ctx, ids) - return &MockWithThreadResolutionChangeStatusesCall{Call: call} -} - -// MockWithThreadResolutionChangeStatusesCall wrap *gomock.Call -type MockWithThreadResolutionChangeStatusesCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionChangeStatusesCall) Return(arg0 []forge.ChangeStatus, arg1 error) *MockWithThreadResolutionChangeStatusesCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionChangeStatusesCall) Do(f func(context.Context, []forge.ChangeID) ([]forge.ChangeStatus, error)) *MockWithThreadResolutionChangeStatusesCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionChangeStatusesCall) DoAndReturn(f func(context.Context, []forge.ChangeID) ([]forge.ChangeStatus, error)) *MockWithThreadResolutionChangeStatusesCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// CommentCountsByChange mocks base method. -func (m *MockWithThreadResolution) CommentCountsByChange(ctx context.Context, ids []forge.ChangeID) ([]*forge.CommentCounts, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CommentCountsByChange", ctx, ids) - ret0, _ := ret[0].([]*forge.CommentCounts) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CommentCountsByChange indicates an expected call of CommentCountsByChange. -func (mr *MockWithThreadResolutionMockRecorder) CommentCountsByChange(ctx, ids any) *MockWithThreadResolutionCommentCountsByChangeCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommentCountsByChange", reflect.TypeOf((*MockWithThreadResolution)(nil).CommentCountsByChange), ctx, ids) - return &MockWithThreadResolutionCommentCountsByChangeCall{Call: call} -} - -// MockWithThreadResolutionCommentCountsByChangeCall wrap *gomock.Call -type MockWithThreadResolutionCommentCountsByChangeCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionCommentCountsByChangeCall) Return(arg0 []*forge.CommentCounts, arg1 error) *MockWithThreadResolutionCommentCountsByChangeCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionCommentCountsByChangeCall) Do(f func(context.Context, []forge.ChangeID) ([]*forge.CommentCounts, error)) *MockWithThreadResolutionCommentCountsByChangeCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionCommentCountsByChangeCall) DoAndReturn(f func(context.Context, []forge.ChangeID) ([]*forge.CommentCounts, error)) *MockWithThreadResolutionCommentCountsByChangeCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// DeleteChangeComment mocks base method. -func (m *MockWithThreadResolution) DeleteChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID) error { +// UnresolveThread mocks base method. +func (m *MockWithInlineComments) UnresolveThread(ctx context.Context, id forge.InlineCommentThreadID) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteChangeComment", arg0, arg1) + ret := m.ctrl.Call(m, "UnresolveThread", ctx, id) ret0, _ := ret[0].(error) return ret0 } -// DeleteChangeComment indicates an expected call of DeleteChangeComment. -func (mr *MockWithThreadResolutionMockRecorder) DeleteChangeComment(arg0, arg1 any) *MockWithThreadResolutionDeleteChangeCommentCall { +// UnresolveThread indicates an expected call of UnresolveThread. +func (mr *MockWithInlineCommentsMockRecorder) UnresolveThread(ctx, id any) *MockWithInlineCommentsUnresolveThreadCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeComment", reflect.TypeOf((*MockWithThreadResolution)(nil).DeleteChangeComment), arg0, arg1) - return &MockWithThreadResolutionDeleteChangeCommentCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnresolveThread", reflect.TypeOf((*MockWithInlineComments)(nil).UnresolveThread), ctx, id) + return &MockWithInlineCommentsUnresolveThreadCall{Call: call} } -// MockWithThreadResolutionDeleteChangeCommentCall wrap *gomock.Call -type MockWithThreadResolutionDeleteChangeCommentCall struct { +// MockWithInlineCommentsUnresolveThreadCall wrap *gomock.Call +type MockWithInlineCommentsUnresolveThreadCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionDeleteChangeCommentCall) Return(arg0 error) *MockWithThreadResolutionDeleteChangeCommentCall { +func (c *MockWithInlineCommentsUnresolveThreadCall) Return(arg0 error) *MockWithInlineCommentsUnresolveThreadCall { c.Call = c.Call.Return(arg0) return c } // Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionDeleteChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID) error) *MockWithThreadResolutionDeleteChangeCommentCall { +func (c *MockWithInlineCommentsUnresolveThreadCall) Do(f func(context.Context, forge.InlineCommentThreadID) error) *MockWithInlineCommentsUnresolveThreadCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionDeleteChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID) error) *MockWithThreadResolutionDeleteChangeCommentCall { +func (c *MockWithInlineCommentsUnresolveThreadCall) DoAndReturn(f func(context.Context, forge.InlineCommentThreadID) error) *MockWithInlineCommentsUnresolveThreadCall { c.Call = c.Call.DoAndReturn(f) return c } -// EditChange mocks base method. -func (m *MockWithThreadResolution) EditChange(ctx context.Context, id forge.ChangeID, opts forge.EditChangeOptions) error { +// UpdateChangeComment mocks base method. +func (m *MockWithInlineComments) UpdateChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID, arg2 string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EditChange", ctx, id, opts) + ret := m.ctrl.Call(m, "UpdateChangeComment", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } -// EditChange indicates an expected call of EditChange. -func (mr *MockWithThreadResolutionMockRecorder) EditChange(ctx, id, opts any) *MockWithThreadResolutionEditChangeCall { +// UpdateChangeComment indicates an expected call of UpdateChangeComment. +func (mr *MockWithInlineCommentsMockRecorder) UpdateChangeComment(arg0, arg1, arg2 any) *MockWithInlineCommentsUpdateChangeCommentCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EditChange", reflect.TypeOf((*MockWithThreadResolution)(nil).EditChange), ctx, id, opts) - return &MockWithThreadResolutionEditChangeCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChangeComment", reflect.TypeOf((*MockWithInlineComments)(nil).UpdateChangeComment), arg0, arg1, arg2) + return &MockWithInlineCommentsUpdateChangeCommentCall{Call: call} } -// MockWithThreadResolutionEditChangeCall wrap *gomock.Call -type MockWithThreadResolutionEditChangeCall struct { +// MockWithInlineCommentsUpdateChangeCommentCall wrap *gomock.Call +type MockWithInlineCommentsUpdateChangeCommentCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionEditChangeCall) Return(arg0 error) *MockWithThreadResolutionEditChangeCall { +func (c *MockWithInlineCommentsUpdateChangeCommentCall) Return(arg0 error) *MockWithInlineCommentsUpdateChangeCommentCall { c.Call = c.Call.Return(arg0) return c } // Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionEditChangeCall) Do(f func(context.Context, forge.ChangeID, forge.EditChangeOptions) error) *MockWithThreadResolutionEditChangeCall { +func (c *MockWithInlineCommentsUpdateChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithInlineCommentsUpdateChangeCommentCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionEditChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.EditChangeOptions) error) *MockWithThreadResolutionEditChangeCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// FindChangeByID mocks base method. -func (m *MockWithThreadResolution) FindChangeByID(ctx context.Context, id forge.ChangeID) (*forge.FindChangeItem, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FindChangeByID", ctx, id) - ret0, _ := ret[0].(*forge.FindChangeItem) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FindChangeByID indicates an expected call of FindChangeByID. -func (mr *MockWithThreadResolutionMockRecorder) FindChangeByID(ctx, id any) *MockWithThreadResolutionFindChangeByIDCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindChangeByID", reflect.TypeOf((*MockWithThreadResolution)(nil).FindChangeByID), ctx, id) - return &MockWithThreadResolutionFindChangeByIDCall{Call: call} -} - -// MockWithThreadResolutionFindChangeByIDCall wrap *gomock.Call -type MockWithThreadResolutionFindChangeByIDCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionFindChangeByIDCall) Return(arg0 *forge.FindChangeItem, arg1 error) *MockWithThreadResolutionFindChangeByIDCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionFindChangeByIDCall) Do(f func(context.Context, forge.ChangeID) (*forge.FindChangeItem, error)) *MockWithThreadResolutionFindChangeByIDCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionFindChangeByIDCall) DoAndReturn(f func(context.Context, forge.ChangeID) (*forge.FindChangeItem, error)) *MockWithThreadResolutionFindChangeByIDCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// FindChangesByBranch mocks base method. -func (m *MockWithThreadResolution) FindChangesByBranch(ctx context.Context, branch string, opts forge.FindChangesOptions) ([]*forge.FindChangeItem, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FindChangesByBranch", ctx, branch, opts) - ret0, _ := ret[0].([]*forge.FindChangeItem) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FindChangesByBranch indicates an expected call of FindChangesByBranch. -func (mr *MockWithThreadResolutionMockRecorder) FindChangesByBranch(ctx, branch, opts any) *MockWithThreadResolutionFindChangesByBranchCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindChangesByBranch", reflect.TypeOf((*MockWithThreadResolution)(nil).FindChangesByBranch), ctx, branch, opts) - return &MockWithThreadResolutionFindChangesByBranchCall{Call: call} -} - -// MockWithThreadResolutionFindChangesByBranchCall wrap *gomock.Call -type MockWithThreadResolutionFindChangesByBranchCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionFindChangesByBranchCall) Return(arg0 []*forge.FindChangeItem, arg1 error) *MockWithThreadResolutionFindChangesByBranchCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionFindChangesByBranchCall) Do(f func(context.Context, string, forge.FindChangesOptions) ([]*forge.FindChangeItem, error)) *MockWithThreadResolutionFindChangesByBranchCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionFindChangesByBranchCall) DoAndReturn(f func(context.Context, string, forge.FindChangesOptions) ([]*forge.FindChangeItem, error)) *MockWithThreadResolutionFindChangesByBranchCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// Forge mocks base method. -func (m *MockWithThreadResolution) Forge() forge.Forge { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Forge") - ret0, _ := ret[0].(forge.Forge) - return ret0 -} - -// Forge indicates an expected call of Forge. -func (mr *MockWithThreadResolutionMockRecorder) Forge() *MockWithThreadResolutionForgeCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Forge", reflect.TypeOf((*MockWithThreadResolution)(nil).Forge)) - return &MockWithThreadResolutionForgeCall{Call: call} -} - -// MockWithThreadResolutionForgeCall wrap *gomock.Call -type MockWithThreadResolutionForgeCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionForgeCall) Return(arg0 forge.Forge) *MockWithThreadResolutionForgeCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionForgeCall) Do(f func() forge.Forge) *MockWithThreadResolutionForgeCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionForgeCall) DoAndReturn(f func() forge.Forge) *MockWithThreadResolutionForgeCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// ListChangeComments mocks base method. -func (m *MockWithThreadResolution) ListChangeComments(arg0 context.Context, arg1 forge.ChangeID, arg2 *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error] { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListChangeComments", arg0, arg1, arg2) - ret0, _ := ret[0].(iter.Seq2[*forge.ListChangeCommentItem, error]) - return ret0 -} - -// ListChangeComments indicates an expected call of ListChangeComments. -func (mr *MockWithThreadResolutionMockRecorder) ListChangeComments(arg0, arg1, arg2 any) *MockWithThreadResolutionListChangeCommentsCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeComments", reflect.TypeOf((*MockWithThreadResolution)(nil).ListChangeComments), arg0, arg1, arg2) - return &MockWithThreadResolutionListChangeCommentsCall{Call: call} -} - -// MockWithThreadResolutionListChangeCommentsCall wrap *gomock.Call -type MockWithThreadResolutionListChangeCommentsCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionListChangeCommentsCall) Return(arg0 iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithThreadResolutionListChangeCommentsCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionListChangeCommentsCall) Do(f func(context.Context, forge.ChangeID, *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithThreadResolutionListChangeCommentsCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionListChangeCommentsCall) DoAndReturn(f func(context.Context, forge.ChangeID, *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithThreadResolutionListChangeCommentsCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// ListChangeTemplates mocks base method. -func (m *MockWithThreadResolution) ListChangeTemplates(arg0 context.Context) ([]*forge.ChangeTemplate, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListChangeTemplates", arg0) - ret0, _ := ret[0].([]*forge.ChangeTemplate) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ListChangeTemplates indicates an expected call of ListChangeTemplates. -func (mr *MockWithThreadResolutionMockRecorder) ListChangeTemplates(arg0 any) *MockWithThreadResolutionListChangeTemplatesCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeTemplates", reflect.TypeOf((*MockWithThreadResolution)(nil).ListChangeTemplates), arg0) - return &MockWithThreadResolutionListChangeTemplatesCall{Call: call} -} - -// MockWithThreadResolutionListChangeTemplatesCall wrap *gomock.Call -type MockWithThreadResolutionListChangeTemplatesCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionListChangeTemplatesCall) Return(arg0 []*forge.ChangeTemplate, arg1 error) *MockWithThreadResolutionListChangeTemplatesCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionListChangeTemplatesCall) Do(f func(context.Context) ([]*forge.ChangeTemplate, error)) *MockWithThreadResolutionListChangeTemplatesCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionListChangeTemplatesCall) DoAndReturn(f func(context.Context) ([]*forge.ChangeTemplate, error)) *MockWithThreadResolutionListChangeTemplatesCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// MergeChange mocks base method. -func (m *MockWithThreadResolution) 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 *MockWithThreadResolutionMockRecorder) MergeChange(ctx, id, opts any) *MockWithThreadResolutionMergeChangeCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MergeChange", reflect.TypeOf((*MockWithThreadResolution)(nil).MergeChange), ctx, id, opts) - return &MockWithThreadResolutionMergeChangeCall{Call: call} -} - -// MockWithThreadResolutionMergeChangeCall wrap *gomock.Call -type MockWithThreadResolutionMergeChangeCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionMergeChangeCall) Return(arg0 error) *MockWithThreadResolutionMergeChangeCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionMergeChangeCall) Do(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockWithThreadResolutionMergeChangeCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionMergeChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockWithThreadResolutionMergeChangeCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// NewChangeMetadata mocks base method. -func (m *MockWithThreadResolution) NewChangeMetadata(ctx context.Context, id forge.ChangeID) (forge.ChangeMetadata, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NewChangeMetadata", ctx, id) - ret0, _ := ret[0].(forge.ChangeMetadata) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// NewChangeMetadata indicates an expected call of NewChangeMetadata. -func (mr *MockWithThreadResolutionMockRecorder) NewChangeMetadata(ctx, id any) *MockWithThreadResolutionNewChangeMetadataCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewChangeMetadata", reflect.TypeOf((*MockWithThreadResolution)(nil).NewChangeMetadata), ctx, id) - return &MockWithThreadResolutionNewChangeMetadataCall{Call: call} -} - -// MockWithThreadResolutionNewChangeMetadataCall wrap *gomock.Call -type MockWithThreadResolutionNewChangeMetadataCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionNewChangeMetadataCall) Return(arg0 forge.ChangeMetadata, arg1 error) *MockWithThreadResolutionNewChangeMetadataCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionNewChangeMetadataCall) Do(f func(context.Context, forge.ChangeID) (forge.ChangeMetadata, error)) *MockWithThreadResolutionNewChangeMetadataCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionNewChangeMetadataCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChangeMetadata, error)) *MockWithThreadResolutionNewChangeMetadataCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// PostChangeComment mocks base method. -func (m *MockWithThreadResolution) PostChangeComment(arg0 context.Context, arg1 forge.ChangeID, arg2 string) (forge.ChangeCommentID, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PostChangeComment", arg0, arg1, arg2) - ret0, _ := ret[0].(forge.ChangeCommentID) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// PostChangeComment indicates an expected call of PostChangeComment. -func (mr *MockWithThreadResolutionMockRecorder) PostChangeComment(arg0, arg1, arg2 any) *MockWithThreadResolutionPostChangeCommentCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostChangeComment", reflect.TypeOf((*MockWithThreadResolution)(nil).PostChangeComment), arg0, arg1, arg2) - return &MockWithThreadResolutionPostChangeCommentCall{Call: call} -} - -// MockWithThreadResolutionPostChangeCommentCall wrap *gomock.Call -type MockWithThreadResolutionPostChangeCommentCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionPostChangeCommentCall) Return(arg0 forge.ChangeCommentID, arg1 error) *MockWithThreadResolutionPostChangeCommentCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionPostChangeCommentCall) Do(f func(context.Context, forge.ChangeID, string) (forge.ChangeCommentID, error)) *MockWithThreadResolutionPostChangeCommentCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionPostChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeID, string) (forge.ChangeCommentID, error)) *MockWithThreadResolutionPostChangeCommentCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// ResolveThread mocks base method. -func (m *MockWithThreadResolution) ResolveThread(ctx context.Context, threadID string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResolveThread", ctx, threadID) - ret0, _ := ret[0].(error) - return ret0 -} - -// ResolveThread indicates an expected call of ResolveThread. -func (mr *MockWithThreadResolutionMockRecorder) ResolveThread(ctx, threadID any) *MockWithThreadResolutionResolveThreadCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveThread", reflect.TypeOf((*MockWithThreadResolution)(nil).ResolveThread), ctx, threadID) - return &MockWithThreadResolutionResolveThreadCall{Call: call} -} - -// MockWithThreadResolutionResolveThreadCall wrap *gomock.Call -type MockWithThreadResolutionResolveThreadCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionResolveThreadCall) Return(arg0 error) *MockWithThreadResolutionResolveThreadCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionResolveThreadCall) Do(f func(context.Context, string) error) *MockWithThreadResolutionResolveThreadCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionResolveThreadCall) DoAndReturn(f func(context.Context, string) error) *MockWithThreadResolutionResolveThreadCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// SubmitChange mocks base method. -func (m *MockWithThreadResolution) SubmitChange(ctx context.Context, req forge.SubmitChangeRequest) (forge.SubmitChangeResult, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubmitChange", ctx, req) - ret0, _ := ret[0].(forge.SubmitChangeResult) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SubmitChange indicates an expected call of SubmitChange. -func (mr *MockWithThreadResolutionMockRecorder) SubmitChange(ctx, req any) *MockWithThreadResolutionSubmitChangeCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitChange", reflect.TypeOf((*MockWithThreadResolution)(nil).SubmitChange), ctx, req) - return &MockWithThreadResolutionSubmitChangeCall{Call: call} -} - -// MockWithThreadResolutionSubmitChangeCall wrap *gomock.Call -type MockWithThreadResolutionSubmitChangeCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionSubmitChangeCall) Return(arg0 forge.SubmitChangeResult, arg1 error) *MockWithThreadResolutionSubmitChangeCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionSubmitChangeCall) Do(f func(context.Context, forge.SubmitChangeRequest) (forge.SubmitChangeResult, error)) *MockWithThreadResolutionSubmitChangeCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionSubmitChangeCall) DoAndReturn(f func(context.Context, forge.SubmitChangeRequest) (forge.SubmitChangeResult, error)) *MockWithThreadResolutionSubmitChangeCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// UnresolveThread mocks base method. -func (m *MockWithThreadResolution) UnresolveThread(ctx context.Context, threadID string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UnresolveThread", ctx, threadID) - ret0, _ := ret[0].(error) - return ret0 -} - -// UnresolveThread indicates an expected call of UnresolveThread. -func (mr *MockWithThreadResolutionMockRecorder) UnresolveThread(ctx, threadID any) *MockWithThreadResolutionUnresolveThreadCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnresolveThread", reflect.TypeOf((*MockWithThreadResolution)(nil).UnresolveThread), ctx, threadID) - return &MockWithThreadResolutionUnresolveThreadCall{Call: call} -} - -// MockWithThreadResolutionUnresolveThreadCall wrap *gomock.Call -type MockWithThreadResolutionUnresolveThreadCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionUnresolveThreadCall) Return(arg0 error) *MockWithThreadResolutionUnresolveThreadCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionUnresolveThreadCall) Do(f func(context.Context, string) error) *MockWithThreadResolutionUnresolveThreadCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionUnresolveThreadCall) DoAndReturn(f func(context.Context, string) error) *MockWithThreadResolutionUnresolveThreadCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// UpdateChangeComment mocks base method. -func (m *MockWithThreadResolution) UpdateChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID, arg2 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateChangeComment", arg0, arg1, arg2) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateChangeComment indicates an expected call of UpdateChangeComment. -func (mr *MockWithThreadResolutionMockRecorder) UpdateChangeComment(arg0, arg1, arg2 any) *MockWithThreadResolutionUpdateChangeCommentCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChangeComment", reflect.TypeOf((*MockWithThreadResolution)(nil).UpdateChangeComment), arg0, arg1, arg2) - return &MockWithThreadResolutionUpdateChangeCommentCall{Call: call} -} - -// MockWithThreadResolutionUpdateChangeCommentCall wrap *gomock.Call -type MockWithThreadResolutionUpdateChangeCommentCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithThreadResolutionUpdateChangeCommentCall) Return(arg0 error) *MockWithThreadResolutionUpdateChangeCommentCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithThreadResolutionUpdateChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithThreadResolutionUpdateChangeCommentCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithThreadResolutionUpdateChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithThreadResolutionUpdateChangeCommentCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// MockWithCommentEdit is a mock of WithCommentEdit interface. -type MockWithCommentEdit struct { - ctrl *gomock.Controller - recorder *MockWithCommentEditMockRecorder - isgomock struct{} -} - -// MockWithCommentEditMockRecorder is the mock recorder for MockWithCommentEdit. -type MockWithCommentEditMockRecorder struct { - mock *MockWithCommentEdit -} - -// NewMockWithCommentEdit creates a new mock instance. -func NewMockWithCommentEdit(ctrl *gomock.Controller) *MockWithCommentEdit { - mock := &MockWithCommentEdit{ctrl: ctrl} - mock.recorder = &MockWithCommentEditMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockWithCommentEdit) EXPECT() *MockWithCommentEditMockRecorder { - return m.recorder -} - -// ChangeChecksState mocks base method. -func (m *MockWithCommentEdit) 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 *MockWithCommentEditMockRecorder) ChangeChecksState(ctx, id any) *MockWithCommentEditChangeChecksStateCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeChecksState", reflect.TypeOf((*MockWithCommentEdit)(nil).ChangeChecksState), ctx, id) - return &MockWithCommentEditChangeChecksStateCall{Call: call} -} - -// MockWithCommentEditChangeChecksStateCall wrap *gomock.Call -type MockWithCommentEditChangeChecksStateCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditChangeChecksStateCall) Return(arg0 forge.ChecksState, arg1 error) *MockWithCommentEditChangeChecksStateCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditChangeChecksStateCall) Do(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockWithCommentEditChangeChecksStateCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditChangeChecksStateCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChecksState, error)) *MockWithCommentEditChangeChecksStateCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// ChangeStatuses mocks base method. -func (m *MockWithCommentEdit) ChangeStatuses(ctx context.Context, ids []forge.ChangeID) ([]forge.ChangeStatus, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ChangeStatuses", ctx, ids) - ret0, _ := ret[0].([]forge.ChangeStatus) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ChangeStatuses indicates an expected call of ChangeStatuses. -func (mr *MockWithCommentEditMockRecorder) ChangeStatuses(ctx, ids any) *MockWithCommentEditChangeStatusesCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeStatuses", reflect.TypeOf((*MockWithCommentEdit)(nil).ChangeStatuses), ctx, ids) - return &MockWithCommentEditChangeStatusesCall{Call: call} -} - -// MockWithCommentEditChangeStatusesCall wrap *gomock.Call -type MockWithCommentEditChangeStatusesCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditChangeStatusesCall) Return(arg0 []forge.ChangeStatus, arg1 error) *MockWithCommentEditChangeStatusesCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditChangeStatusesCall) Do(f func(context.Context, []forge.ChangeID) ([]forge.ChangeStatus, error)) *MockWithCommentEditChangeStatusesCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditChangeStatusesCall) DoAndReturn(f func(context.Context, []forge.ChangeID) ([]forge.ChangeStatus, error)) *MockWithCommentEditChangeStatusesCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// CommentCountsByChange mocks base method. -func (m *MockWithCommentEdit) CommentCountsByChange(ctx context.Context, ids []forge.ChangeID) ([]*forge.CommentCounts, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CommentCountsByChange", ctx, ids) - ret0, _ := ret[0].([]*forge.CommentCounts) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CommentCountsByChange indicates an expected call of CommentCountsByChange. -func (mr *MockWithCommentEditMockRecorder) CommentCountsByChange(ctx, ids any) *MockWithCommentEditCommentCountsByChangeCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommentCountsByChange", reflect.TypeOf((*MockWithCommentEdit)(nil).CommentCountsByChange), ctx, ids) - return &MockWithCommentEditCommentCountsByChangeCall{Call: call} -} - -// MockWithCommentEditCommentCountsByChangeCall wrap *gomock.Call -type MockWithCommentEditCommentCountsByChangeCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditCommentCountsByChangeCall) Return(arg0 []*forge.CommentCounts, arg1 error) *MockWithCommentEditCommentCountsByChangeCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditCommentCountsByChangeCall) Do(f func(context.Context, []forge.ChangeID) ([]*forge.CommentCounts, error)) *MockWithCommentEditCommentCountsByChangeCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditCommentCountsByChangeCall) DoAndReturn(f func(context.Context, []forge.ChangeID) ([]*forge.CommentCounts, error)) *MockWithCommentEditCommentCountsByChangeCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// DeleteChangeComment mocks base method. -func (m *MockWithCommentEdit) DeleteChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteChangeComment", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteChangeComment indicates an expected call of DeleteChangeComment. -func (mr *MockWithCommentEditMockRecorder) DeleteChangeComment(arg0, arg1 any) *MockWithCommentEditDeleteChangeCommentCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeComment", reflect.TypeOf((*MockWithCommentEdit)(nil).DeleteChangeComment), arg0, arg1) - return &MockWithCommentEditDeleteChangeCommentCall{Call: call} -} - -// MockWithCommentEditDeleteChangeCommentCall wrap *gomock.Call -type MockWithCommentEditDeleteChangeCommentCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditDeleteChangeCommentCall) Return(arg0 error) *MockWithCommentEditDeleteChangeCommentCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditDeleteChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID) error) *MockWithCommentEditDeleteChangeCommentCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditDeleteChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID) error) *MockWithCommentEditDeleteChangeCommentCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// EditChange mocks base method. -func (m *MockWithCommentEdit) EditChange(ctx context.Context, id forge.ChangeID, opts forge.EditChangeOptions) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EditChange", ctx, id, opts) - ret0, _ := ret[0].(error) - return ret0 -} - -// EditChange indicates an expected call of EditChange. -func (mr *MockWithCommentEditMockRecorder) EditChange(ctx, id, opts any) *MockWithCommentEditEditChangeCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EditChange", reflect.TypeOf((*MockWithCommentEdit)(nil).EditChange), ctx, id, opts) - return &MockWithCommentEditEditChangeCall{Call: call} -} - -// MockWithCommentEditEditChangeCall wrap *gomock.Call -type MockWithCommentEditEditChangeCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditEditChangeCall) Return(arg0 error) *MockWithCommentEditEditChangeCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditEditChangeCall) Do(f func(context.Context, forge.ChangeID, forge.EditChangeOptions) error) *MockWithCommentEditEditChangeCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditEditChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.EditChangeOptions) error) *MockWithCommentEditEditChangeCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// EditComment mocks base method. -func (m *MockWithCommentEdit) EditComment(ctx context.Context, id forge.ChangeCommentID, body string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EditComment", ctx, id, body) - ret0, _ := ret[0].(error) - return ret0 -} - -// EditComment indicates an expected call of EditComment. -func (mr *MockWithCommentEditMockRecorder) EditComment(ctx, id, body any) *MockWithCommentEditEditCommentCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EditComment", reflect.TypeOf((*MockWithCommentEdit)(nil).EditComment), ctx, id, body) - return &MockWithCommentEditEditCommentCall{Call: call} -} - -// MockWithCommentEditEditCommentCall wrap *gomock.Call -type MockWithCommentEditEditCommentCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditEditCommentCall) Return(arg0 error) *MockWithCommentEditEditCommentCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditEditCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithCommentEditEditCommentCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditEditCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithCommentEditEditCommentCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// FindChangeByID mocks base method. -func (m *MockWithCommentEdit) FindChangeByID(ctx context.Context, id forge.ChangeID) (*forge.FindChangeItem, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FindChangeByID", ctx, id) - ret0, _ := ret[0].(*forge.FindChangeItem) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FindChangeByID indicates an expected call of FindChangeByID. -func (mr *MockWithCommentEditMockRecorder) FindChangeByID(ctx, id any) *MockWithCommentEditFindChangeByIDCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindChangeByID", reflect.TypeOf((*MockWithCommentEdit)(nil).FindChangeByID), ctx, id) - return &MockWithCommentEditFindChangeByIDCall{Call: call} -} - -// MockWithCommentEditFindChangeByIDCall wrap *gomock.Call -type MockWithCommentEditFindChangeByIDCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditFindChangeByIDCall) Return(arg0 *forge.FindChangeItem, arg1 error) *MockWithCommentEditFindChangeByIDCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditFindChangeByIDCall) Do(f func(context.Context, forge.ChangeID) (*forge.FindChangeItem, error)) *MockWithCommentEditFindChangeByIDCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditFindChangeByIDCall) DoAndReturn(f func(context.Context, forge.ChangeID) (*forge.FindChangeItem, error)) *MockWithCommentEditFindChangeByIDCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// FindChangesByBranch mocks base method. -func (m *MockWithCommentEdit) FindChangesByBranch(ctx context.Context, branch string, opts forge.FindChangesOptions) ([]*forge.FindChangeItem, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FindChangesByBranch", ctx, branch, opts) - ret0, _ := ret[0].([]*forge.FindChangeItem) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FindChangesByBranch indicates an expected call of FindChangesByBranch. -func (mr *MockWithCommentEditMockRecorder) FindChangesByBranch(ctx, branch, opts any) *MockWithCommentEditFindChangesByBranchCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindChangesByBranch", reflect.TypeOf((*MockWithCommentEdit)(nil).FindChangesByBranch), ctx, branch, opts) - return &MockWithCommentEditFindChangesByBranchCall{Call: call} -} - -// MockWithCommentEditFindChangesByBranchCall wrap *gomock.Call -type MockWithCommentEditFindChangesByBranchCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditFindChangesByBranchCall) Return(arg0 []*forge.FindChangeItem, arg1 error) *MockWithCommentEditFindChangesByBranchCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditFindChangesByBranchCall) Do(f func(context.Context, string, forge.FindChangesOptions) ([]*forge.FindChangeItem, error)) *MockWithCommentEditFindChangesByBranchCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditFindChangesByBranchCall) DoAndReturn(f func(context.Context, string, forge.FindChangesOptions) ([]*forge.FindChangeItem, error)) *MockWithCommentEditFindChangesByBranchCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// Forge mocks base method. -func (m *MockWithCommentEdit) Forge() forge.Forge { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Forge") - ret0, _ := ret[0].(forge.Forge) - return ret0 -} - -// Forge indicates an expected call of Forge. -func (mr *MockWithCommentEditMockRecorder) Forge() *MockWithCommentEditForgeCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Forge", reflect.TypeOf((*MockWithCommentEdit)(nil).Forge)) - return &MockWithCommentEditForgeCall{Call: call} -} - -// MockWithCommentEditForgeCall wrap *gomock.Call -type MockWithCommentEditForgeCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditForgeCall) Return(arg0 forge.Forge) *MockWithCommentEditForgeCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditForgeCall) Do(f func() forge.Forge) *MockWithCommentEditForgeCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditForgeCall) DoAndReturn(f func() forge.Forge) *MockWithCommentEditForgeCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// ListChangeComments mocks base method. -func (m *MockWithCommentEdit) ListChangeComments(arg0 context.Context, arg1 forge.ChangeID, arg2 *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error] { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListChangeComments", arg0, arg1, arg2) - ret0, _ := ret[0].(iter.Seq2[*forge.ListChangeCommentItem, error]) - return ret0 -} - -// ListChangeComments indicates an expected call of ListChangeComments. -func (mr *MockWithCommentEditMockRecorder) ListChangeComments(arg0, arg1, arg2 any) *MockWithCommentEditListChangeCommentsCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeComments", reflect.TypeOf((*MockWithCommentEdit)(nil).ListChangeComments), arg0, arg1, arg2) - return &MockWithCommentEditListChangeCommentsCall{Call: call} -} - -// MockWithCommentEditListChangeCommentsCall wrap *gomock.Call -type MockWithCommentEditListChangeCommentsCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditListChangeCommentsCall) Return(arg0 iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithCommentEditListChangeCommentsCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditListChangeCommentsCall) Do(f func(context.Context, forge.ChangeID, *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithCommentEditListChangeCommentsCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditListChangeCommentsCall) DoAndReturn(f func(context.Context, forge.ChangeID, *forge.ListChangeCommentsOptions) iter.Seq2[*forge.ListChangeCommentItem, error]) *MockWithCommentEditListChangeCommentsCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// ListChangeTemplates mocks base method. -func (m *MockWithCommentEdit) ListChangeTemplates(arg0 context.Context) ([]*forge.ChangeTemplate, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListChangeTemplates", arg0) - ret0, _ := ret[0].([]*forge.ChangeTemplate) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ListChangeTemplates indicates an expected call of ListChangeTemplates. -func (mr *MockWithCommentEditMockRecorder) ListChangeTemplates(arg0 any) *MockWithCommentEditListChangeTemplatesCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeTemplates", reflect.TypeOf((*MockWithCommentEdit)(nil).ListChangeTemplates), arg0) - return &MockWithCommentEditListChangeTemplatesCall{Call: call} -} - -// MockWithCommentEditListChangeTemplatesCall wrap *gomock.Call -type MockWithCommentEditListChangeTemplatesCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditListChangeTemplatesCall) Return(arg0 []*forge.ChangeTemplate, arg1 error) *MockWithCommentEditListChangeTemplatesCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditListChangeTemplatesCall) Do(f func(context.Context) ([]*forge.ChangeTemplate, error)) *MockWithCommentEditListChangeTemplatesCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditListChangeTemplatesCall) DoAndReturn(f func(context.Context) ([]*forge.ChangeTemplate, error)) *MockWithCommentEditListChangeTemplatesCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// MergeChange mocks base method. -func (m *MockWithCommentEdit) 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 *MockWithCommentEditMockRecorder) MergeChange(ctx, id, opts any) *MockWithCommentEditMergeChangeCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MergeChange", reflect.TypeOf((*MockWithCommentEdit)(nil).MergeChange), ctx, id, opts) - return &MockWithCommentEditMergeChangeCall{Call: call} -} - -// MockWithCommentEditMergeChangeCall wrap *gomock.Call -type MockWithCommentEditMergeChangeCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditMergeChangeCall) Return(arg0 error) *MockWithCommentEditMergeChangeCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditMergeChangeCall) Do(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockWithCommentEditMergeChangeCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditMergeChangeCall) DoAndReturn(f func(context.Context, forge.ChangeID, forge.MergeChangeOptions) error) *MockWithCommentEditMergeChangeCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// NewChangeMetadata mocks base method. -func (m *MockWithCommentEdit) NewChangeMetadata(ctx context.Context, id forge.ChangeID) (forge.ChangeMetadata, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NewChangeMetadata", ctx, id) - ret0, _ := ret[0].(forge.ChangeMetadata) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// NewChangeMetadata indicates an expected call of NewChangeMetadata. -func (mr *MockWithCommentEditMockRecorder) NewChangeMetadata(ctx, id any) *MockWithCommentEditNewChangeMetadataCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewChangeMetadata", reflect.TypeOf((*MockWithCommentEdit)(nil).NewChangeMetadata), ctx, id) - return &MockWithCommentEditNewChangeMetadataCall{Call: call} -} - -// MockWithCommentEditNewChangeMetadataCall wrap *gomock.Call -type MockWithCommentEditNewChangeMetadataCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditNewChangeMetadataCall) Return(arg0 forge.ChangeMetadata, arg1 error) *MockWithCommentEditNewChangeMetadataCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditNewChangeMetadataCall) Do(f func(context.Context, forge.ChangeID) (forge.ChangeMetadata, error)) *MockWithCommentEditNewChangeMetadataCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditNewChangeMetadataCall) DoAndReturn(f func(context.Context, forge.ChangeID) (forge.ChangeMetadata, error)) *MockWithCommentEditNewChangeMetadataCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// PostChangeComment mocks base method. -func (m *MockWithCommentEdit) PostChangeComment(arg0 context.Context, arg1 forge.ChangeID, arg2 string) (forge.ChangeCommentID, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PostChangeComment", arg0, arg1, arg2) - ret0, _ := ret[0].(forge.ChangeCommentID) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// PostChangeComment indicates an expected call of PostChangeComment. -func (mr *MockWithCommentEditMockRecorder) PostChangeComment(arg0, arg1, arg2 any) *MockWithCommentEditPostChangeCommentCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostChangeComment", reflect.TypeOf((*MockWithCommentEdit)(nil).PostChangeComment), arg0, arg1, arg2) - return &MockWithCommentEditPostChangeCommentCall{Call: call} -} - -// MockWithCommentEditPostChangeCommentCall wrap *gomock.Call -type MockWithCommentEditPostChangeCommentCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditPostChangeCommentCall) Return(arg0 forge.ChangeCommentID, arg1 error) *MockWithCommentEditPostChangeCommentCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditPostChangeCommentCall) Do(f func(context.Context, forge.ChangeID, string) (forge.ChangeCommentID, error)) *MockWithCommentEditPostChangeCommentCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditPostChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeID, string) (forge.ChangeCommentID, error)) *MockWithCommentEditPostChangeCommentCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// SubmitChange mocks base method. -func (m *MockWithCommentEdit) SubmitChange(ctx context.Context, req forge.SubmitChangeRequest) (forge.SubmitChangeResult, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubmitChange", ctx, req) - ret0, _ := ret[0].(forge.SubmitChangeResult) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SubmitChange indicates an expected call of SubmitChange. -func (mr *MockWithCommentEditMockRecorder) SubmitChange(ctx, req any) *MockWithCommentEditSubmitChangeCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitChange", reflect.TypeOf((*MockWithCommentEdit)(nil).SubmitChange), ctx, req) - return &MockWithCommentEditSubmitChangeCall{Call: call} -} - -// MockWithCommentEditSubmitChangeCall wrap *gomock.Call -type MockWithCommentEditSubmitChangeCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditSubmitChangeCall) Return(arg0 forge.SubmitChangeResult, arg1 error) *MockWithCommentEditSubmitChangeCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditSubmitChangeCall) Do(f func(context.Context, forge.SubmitChangeRequest) (forge.SubmitChangeResult, error)) *MockWithCommentEditSubmitChangeCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditSubmitChangeCall) DoAndReturn(f func(context.Context, forge.SubmitChangeRequest) (forge.SubmitChangeResult, error)) *MockWithCommentEditSubmitChangeCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// UpdateChangeComment mocks base method. -func (m *MockWithCommentEdit) UpdateChangeComment(arg0 context.Context, arg1 forge.ChangeCommentID, arg2 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateChangeComment", arg0, arg1, arg2) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateChangeComment indicates an expected call of UpdateChangeComment. -func (mr *MockWithCommentEditMockRecorder) UpdateChangeComment(arg0, arg1, arg2 any) *MockWithCommentEditUpdateChangeCommentCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChangeComment", reflect.TypeOf((*MockWithCommentEdit)(nil).UpdateChangeComment), arg0, arg1, arg2) - return &MockWithCommentEditUpdateChangeCommentCall{Call: call} -} - -// MockWithCommentEditUpdateChangeCommentCall wrap *gomock.Call -type MockWithCommentEditUpdateChangeCommentCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockWithCommentEditUpdateChangeCommentCall) Return(arg0 error) *MockWithCommentEditUpdateChangeCommentCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockWithCommentEditUpdateChangeCommentCall) Do(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithCommentEditUpdateChangeCommentCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockWithCommentEditUpdateChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithCommentEditUpdateChangeCommentCall { +func (c *MockWithInlineCommentsUpdateChangeCommentCall) DoAndReturn(f func(context.Context, forge.ChangeCommentID, string) error) *MockWithInlineCommentsUpdateChangeCommentCall { c.Call = c.Call.DoAndReturn(f) return c } diff --git a/internal/forge/github/inline_comment.go b/internal/forge/github/inline_comment.go index 57018cf5e..37d7803ef 100644 --- a/internal/forge/github/inline_comment.go +++ b/internal/forge/github/inline_comment.go @@ -9,11 +9,7 @@ import ( "go.abhg.dev/gs/internal/forge" ) -var ( - _ forge.WithInlineComments = (*Repository)(nil) - _ forge.WithThreadResolution = (*Repository)(nil) - _ forge.WithCommentEdit = (*Repository)(nil) -) +var _ forge.WithInlineComments = (*Repository)(nil) // ListInlineComments lists inline/review comments on a PR // by querying the reviewThreads connection. @@ -83,13 +79,13 @@ func (r *Repository) ListInlineComments( for _, c := range thread.Comments.Nodes { comments = append(comments, &forge.InlineComment{ - ID: &PRComment{ + ID: forge.InlineCommentThreadID(threadID), + CommentID: &PRComment{ GQLID: c.ID, URL: c.URL, }, - ThreadID: threadID, Path: thread.Path, - Line: line, + Lines: forge.InlineCommentLine(line), Body: c.Body, Author: c.Author.Login, Resolved: thread.IsResolved, @@ -137,7 +133,7 @@ func (r *Repository) SubmitReview( var threads []*githubv4.DraftPullRequestReviewThread for _, c := range req.Comments { side := githubv4.DiffSideRight - if c.Side == "LEFT" { + if c.Side == forge.InlineCommentSideLeft { side = githubv4.DiffSideLeft } threads = append(threads, @@ -146,7 +142,7 @@ func (r *Repository) SubmitReview( githubv4.String(c.Path), ), Line: new( - githubv4.Int(c.Line), + githubv4.Int(c.Lines.StartLine), ), Side: &side, Body: githubv4.String(c.Body), @@ -195,12 +191,12 @@ func (r *Repository) PostInlineComment( } // If replying to an existing thread, use addPullRequestReviewComment. - if req.ThreadID != "" { + if req.InReplyTo != "" { return r.replyToThread(ctx, req) } side := githubv4.DiffSideRight - if req.Side == "LEFT" { + if req.Side == forge.InlineCommentSideLeft { side = githubv4.DiffSideLeft } @@ -225,7 +221,7 @@ func (r *Repository) PostInlineComment( githubv4.String(req.Path), ), Line: new( - githubv4.Int(req.Line), + githubv4.Int(req.Lines.StartLine), ), Side: &side, Body: githubv4.String(req.Body), @@ -249,14 +245,14 @@ func (r *Repository) PostInlineComment( r.log.Debug("Posted inline comment", "pr", pr.Number, "path", req.Path, - "line", req.Line, + "line", req.Lines.StartLine, ) return &forge.InlineComment{ - ID: commentID, - ThreadID: threadID, + ID: forge.InlineCommentThreadID(threadID), + CommentID: commentID, Path: req.Path, - Line: req.Line, + Lines: req.Lines, Body: req.Body, CreatedAt: createdAt, }, nil @@ -278,7 +274,7 @@ func (r *Repository) replyToThread( } input := githubv4.AddPullRequestReviewThreadReplyInput{ - PullRequestReviewThreadID: githubv4.ID(req.ThreadID), + PullRequestReviewThreadID: githubv4.ID(req.InReplyTo), Body: githubv4.String(req.Body), } @@ -288,10 +284,10 @@ func (r *Repository) replyToThread( n := m.AddPullRequestReviewThreadReply.Comment return &forge.InlineComment{ - ID: &PRComment{GQLID: n.ID, URL: n.URL}, - ThreadID: req.ThreadID, + ID: req.InReplyTo, + CommentID: &PRComment{GQLID: n.ID, URL: n.URL}, Path: req.Path, - Line: req.Line, + Lines: req.Lines, Body: req.Body, CreatedAt: n.CreatedAt.Time, }, nil @@ -300,7 +296,7 @@ func (r *Repository) replyToThread( // ResolveThread marks a review thread as resolved. func (r *Repository) ResolveThread( ctx context.Context, - threadID string, + id forge.InlineCommentThreadID, ) error { var m struct { ResolveReviewThread struct { @@ -311,21 +307,21 @@ func (r *Repository) ResolveThread( } input := githubv4.ResolveReviewThreadInput{ - ThreadID: githubv4.ID(threadID), + ThreadID: githubv4.ID(id), } if err := r.client.Mutate(ctx, &m, input, nil); err != nil { return fmt.Errorf("resolve thread: %w", err) } - r.log.Debug("Resolved thread", "threadID", threadID) + r.log.Debug("Resolved thread", "id", id) return nil } // UnresolveThread marks a review thread as unresolved. func (r *Repository) UnresolveThread( ctx context.Context, - threadID string, + id forge.InlineCommentThreadID, ) error { var m struct { UnresolveReviewThread struct { @@ -336,14 +332,14 @@ func (r *Repository) UnresolveThread( } input := githubv4.UnresolveReviewThreadInput{ - ThreadID: githubv4.ID(threadID), + ThreadID: githubv4.ID(id), } if err := r.client.Mutate(ctx, &m, input, nil); err != nil { return fmt.Errorf("unresolve thread: %w", err) } - r.log.Debug("Unresolved thread", "threadID", threadID) + r.log.Debug("Unresolved thread", "id", id) return nil } diff --git a/internal/forge/gitlab/inline_comment.go b/internal/forge/gitlab/inline_comment.go index cbfa86790..5cd6e9f29 100644 --- a/internal/forge/gitlab/inline_comment.go +++ b/internal/forge/gitlab/inline_comment.go @@ -10,11 +10,7 @@ import ( "go.abhg.dev/gs/internal/gateway/gitlab" ) -var ( - _ forge.WithInlineComments = (*Repository)(nil) - _ forge.WithThreadResolution = (*Repository)(nil) - _ forge.WithCommentEdit = (*Repository)(nil) -) +var _ forge.WithInlineComments = (*Repository)(nil) // ListInlineComments lists inline/review comments on a MR // by fetching discussions that have position information. @@ -67,15 +63,15 @@ func (r *Repository) ListInlineComments( comments = append(comments, &forge.InlineComment{ - ID: &MRComment{ + ID: formatInlineCommentThreadID( + disc.ID, mr.Number, + ), + CommentID: &MRComment{ Number: note.ID, MRNumber: mr.Number, }, - ThreadID: formatThreadID( - disc.ID, mr.Number, - ), Path: path, - Line: line, + Lines: forge.InlineCommentLine(line), Body: note.Body, Author: note.Author.Username, Resolved: root.Resolved, @@ -112,9 +108,9 @@ func (r *Repository) SubmitReview( } for _, c := range req.Comments { - if c.ThreadID != "" { + if c.InReplyTo != "" { // Reply to existing thread. - discID, _, perr := parseThreadID(c.ThreadID) + discID, _, perr := parseInlineCommentThreadID(c.InReplyTo) if perr != nil { return perr } @@ -127,19 +123,19 @@ func (r *Repository) SubmitReview( ); err != nil { return fmt.Errorf( "reply to thread %s: %w", - c.ThreadID, err, + c.InReplyTo, err, ) } continue } - opts := newDiscussionOptions(c.Body, c.Path, c.Line, diffRefs) + opts := newDiscussionOptions(c.Body, c.Path, c.Lines, diffRefs) if _, _, err := r.client.MergeRequestDiscussionCreate( ctx, r.repoID, mr.Number, opts, ); err != nil { return fmt.Errorf( "create discussion on %s:%d: %w", - c.Path, c.Line, err, + c.Path, c.Lines.StartLine, err, ) } } @@ -161,8 +157,8 @@ func (r *Repository) PostInlineComment( mr := mustMR(id) // Reply to existing thread. - if req.ThreadID != "" { - discID, _, err := parseThreadID(req.ThreadID) + if req.InReplyTo != "" { + discID, _, err := parseInlineCommentThreadID(req.InReplyTo) if err != nil { return nil, err } @@ -184,13 +180,13 @@ func (r *Repository) PostInlineComment( createdAt = *note.CreatedAt } return &forge.InlineComment{ - ID: &MRComment{ + ID: req.InReplyTo, + CommentID: &MRComment{ Number: note.ID, MRNumber: mr.Number, }, - ThreadID: req.ThreadID, Path: req.Path, - Line: req.Line, + Lines: req.Lines, Body: req.Body, CreatedAt: createdAt, }, nil @@ -204,7 +200,7 @@ func (r *Repository) PostInlineComment( disc, _, err := r.client.MergeRequestDiscussionCreate( ctx, r.repoID, mr.Number, - newDiscussionOptions(req.Body, req.Path, req.Line, diffRefs), + newDiscussionOptions(req.Body, req.Path, req.Lines, diffRefs), ) if err != nil { return nil, fmt.Errorf("create discussion: %w", err) @@ -218,27 +214,27 @@ func (r *Repository) PostInlineComment( r.log.Debug("Posted inline comment", "mr", mr.Number, "path", req.Path, - "line", req.Line, + "line", req.Lines.StartLine, ) return &forge.InlineComment{ - ID: &MRComment{ + ID: formatInlineCommentThreadID(disc.ID, mr.Number), + CommentID: &MRComment{ Number: noteID, MRNumber: mr.Number, }, - ThreadID: formatThreadID(disc.ID, mr.Number), - Path: req.Path, - Line: req.Line, - Body: req.Body, + Path: req.Path, + Lines: req.Lines, + Body: req.Body, }, nil } func newDiscussionOptions( - body, path string, line int, + body, path string, lines forge.InlineCommentRange, refs *gitlab.MergeRequestDiffRefs, ) *gitlab.CreateMergeRequestDiscussionOptions { textType := "text" - lineN := int64(line) + lineN := int64(lines.StartLine) return &gitlab.CreateMergeRequestDiscussionOptions{ Body: &body, Position: &gitlab.PositionOptions{ @@ -271,10 +267,10 @@ func (r *Repository) diffRefs( // ResolveThread marks a discussion thread as resolved. func (r *Repository) ResolveThread( ctx context.Context, - threadID string, + id forge.InlineCommentThreadID, ) error { // Thread ID format: "discussion_id:mr_number" - discID, mrNumber, err := parseThreadID(threadID) + discID, mrNumber, err := parseInlineCommentThreadID(id) if err != nil { return err } @@ -289,16 +285,16 @@ func (r *Repository) ResolveThread( return fmt.Errorf("resolve thread: %w", err) } - r.log.Debug("Resolved thread", "threadID", threadID) + r.log.Debug("Resolved thread", "id", id) return nil } // UnresolveThread marks a discussion thread as unresolved. func (r *Repository) UnresolveThread( ctx context.Context, - threadID string, + id forge.InlineCommentThreadID, ) error { - discID, mrNumber, err := parseThreadID(threadID) + discID, mrNumber, err := parseInlineCommentThreadID(id) if err != nil { return err } @@ -313,7 +309,7 @@ func (r *Repository) UnresolveThread( return fmt.Errorf("unresolve thread: %w", err) } - r.log.Debug("Unresolved thread", "threadID", threadID) + r.log.Debug("Unresolved thread", "id", id) return nil } @@ -390,13 +386,14 @@ func (r *Repository) findDiscussionForNote( // This encodes both the discussion ID and MR number // so resolve/unresolve can work without extra context. -func formatThreadID(discID string, mrNumber int64) string { - return discID + ":" + strconv.FormatInt(mrNumber, 10) +func formatInlineCommentThreadID(discID string, mrNumber int64) forge.InlineCommentThreadID { + return forge.InlineCommentThreadID(discID + ":" + strconv.FormatInt(mrNumber, 10)) } -func parseThreadID(threadID string) ( +func parseInlineCommentThreadID(id forge.InlineCommentThreadID) ( discID string, mrNumber int64, err error, ) { + threadID := string(id) for i := len(threadID) - 1; i >= 0; i-- { if threadID[i] == ':' { discID = threadID[:i] diff --git a/internal/forge/shamhub/comment.go b/internal/forge/shamhub/comment.go index 899192c36..6f7c4f3ba 100644 --- a/internal/forge/shamhub/comment.go +++ b/internal/forge/shamhub/comment.go @@ -151,8 +151,8 @@ type shamComment struct { // Line is the line number for inline comments. Line int - // Side is "LEFT" or "RIGHT" for inline comments. - Side string + // Side identifies which side of the diff the inline comment targets. + Side int // ThreadID groups inline comments into threads. ThreadID string diff --git a/internal/forge/shamhub/inline_comment.go b/internal/forge/shamhub/inline_comment.go index b9d64781d..ff685c4ea 100644 --- a/internal/forge/shamhub/inline_comment.go +++ b/internal/forge/shamhub/inline_comment.go @@ -9,11 +9,7 @@ import ( "go.abhg.dev/gs/internal/forge" ) -var ( - _ forge.WithInlineComments = (*forgeRepository)(nil) - _ forge.WithThreadResolution = (*forgeRepository)(nil) - _ forge.WithCommentEdit = (*forgeRepository)(nil) -) +var _ forge.WithInlineComments = (*forgeRepository)(nil) // Inline comment handlers @@ -113,10 +109,10 @@ func (r *forgeRepository) ListInlineComments( var comments []*forge.InlineComment for _, item := range res.Items { comments = append(comments, &forge.InlineComment{ - ID: ChangeCommentID(item.ID), - ThreadID: item.ThreadID, + ID: forge.InlineCommentThreadID(item.ThreadID), + CommentID: ChangeCommentID(item.ID), Path: item.Path, - Line: item.Line, + Lines: forge.InlineCommentLine(item.Line), Body: item.Body, Author: item.Author, Resolved: item.Resolved, @@ -137,7 +133,7 @@ type postInlineCommentRequest struct { Path string `json:"path"` Line int `json:"line"` Body string `json:"body"` - Side string `json:"side"` + Side int `json:"side"` ThreadID string `json:"threadID,omitempty"` } @@ -193,10 +189,10 @@ func (r *forgeRepository) PostInlineComment( body := postInlineCommentRequest{ Change: int(id.(ChangeID)), Path: req.Path, - Line: req.Line, + Line: req.Lines.StartLine, Body: req.Body, - Side: req.Side, - ThreadID: req.ThreadID, + Side: int(req.Side), + ThreadID: string(req.InReplyTo), } var res postInlineCommentResponse @@ -207,10 +203,10 @@ func (r *forgeRepository) PostInlineComment( } return &forge.InlineComment{ - ID: ChangeCommentID(res.ID), - ThreadID: res.ThreadID, + ID: forge.InlineCommentThreadID(res.ThreadID), + CommentID: ChangeCommentID(res.ID), Path: req.Path, - Line: req.Line, + Lines: req.Lines, Body: req.Body, CreatedAt: res.CreatedAt, }, nil @@ -232,7 +228,7 @@ type submitReviewCommentRequest struct { Path string `json:"path"` Line int `json:"line"` Body string `json:"body"` - Side string `json:"side,omitempty"` + Side int `json:"side,omitempty"` ThreadID string `json:"threadID,omitempty"` } @@ -287,10 +283,10 @@ func (r *forgeRepository) SubmitReview( for _, c := range req.Comments { comments = append(comments, submitReviewCommentRequest{ Path: c.Path, - Line: c.Line, + Line: c.Lines.StartLine, Body: c.Body, - Side: c.Side, - ThreadID: c.ThreadID, + Side: int(c.Side), + ThreadID: string(c.InReplyTo), }) } @@ -369,10 +365,10 @@ func (sh *ShamHub) handleUnresolveThread( func (r *forgeRepository) ResolveThread( ctx context.Context, - threadID string, + id forge.InlineCommentThreadID, ) error { u := r.apiURL.JoinPath( - r.owner, r.repo, "threads", threadID, "resolve", + r.owner, r.repo, "threads", string(id), "resolve", ) var res resolveThreadResponse @@ -387,10 +383,10 @@ func (r *forgeRepository) ResolveThread( func (r *forgeRepository) UnresolveThread( ctx context.Context, - threadID string, + id forge.InlineCommentThreadID, ) error { u := r.apiURL.JoinPath( - r.owner, r.repo, "threads", threadID, "unresolve", + r.owner, r.repo, "threads", string(id), "unresolve", ) var res resolveThreadResponse From 7ee17ba4a8d9d87564fabc1f3631f25155cd6c70 Mon Sep 17 00:00:00 2001 From: Edmund Kohlwey Date: Sat, 13 Jun 2026 20:45:36 -0700 Subject: [PATCH 3/3] state: Store staged inline comments The comments CLI needs a local representation for inline comments that have been prepared but not submitted to a forge yet. Staged comments now persist the target path, line range, body, diff side, and optional thread identifier in the spice state database. That gives command code a stable state boundary before it batches the comments into a forge review. Extracted from #1162 --- internal/spice/state/staged_comment.go | 121 ++++++++++++++++ internal/spice/state/staged_comment_test.go | 144 ++++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 internal/spice/state/staged_comment.go create mode 100644 internal/spice/state/staged_comment_test.go diff --git a/internal/spice/state/staged_comment.go b/internal/spice/state/staged_comment.go new file mode 100644 index 000000000..3ff7fbdd4 --- /dev/null +++ b/internal/spice/state/staged_comment.go @@ -0,0 +1,121 @@ +package state + +import ( + "context" + "errors" + "fmt" + "path" + + "go.abhg.dev/gs/internal/forge" + "go.abhg.dev/gs/internal/spice/state/storage" +) + +// _stagedCommentsDir is the directory holding staged comments +// for branches that have not yet been submitted as reviews. +const _stagedCommentsDir = "staged-comments" + +// StagedComment is a draft inline comment +// waiting to be batch-submitted as part of a review. +type StagedComment struct { + // LocalID is a local auto-increment identifier + // unique within the branch's staged comments. + LocalID int `json:"localID"` + + // File is the file path relative to the repository root. + File string `json:"file"` + + // Lines identifies the line range in the diff. + Lines forge.InlineCommentRange `json:"lines"` + + // Body is the markdown body of the comment. + Body string `json:"body"` + + // ID is set when replying to an existing inline comment thread. + ID forge.InlineCommentThreadID `json:"id,omitempty"` +} + +// StagedComments is the collection of staged comments +// for a branch. +type StagedComments struct { + // NextID is the next ID to assign + // to a new staged comment. + NextID int `json:"nextID"` + + // Comments are the staged comments. + Comments []StagedComment `json:"comments"` +} + +func (s *Store) stagedCommentsJSON(branch string) string { + return path.Join(_stagedCommentsDir, branch) +} + +// SaveStagedComments saves the staged comments +// for the given branch. +// If staged comments already exist for the branch, +// they will be overwritten. +func (s *Store) SaveStagedComments( + ctx context.Context, + branch string, + comments *StagedComments, +) error { + err := s.db.Set( + ctx, + s.stagedCommentsJSON(branch), + comments, + fmt.Sprintf( + "%v: save staged comments", branch, + ), + ) + if err != nil { + return fmt.Errorf( + "set staged comments: %w", err, + ) + } + return nil +} + +// LoadStagedComments retrieves staged comments +// for the given branch. +// Returns nil if no staged comments exist. +func (s *Store) LoadStagedComments( + ctx context.Context, + branch string, +) (*StagedComments, error) { + var comments StagedComments + err := s.db.Get( + ctx, + s.stagedCommentsJSON(branch), + &comments, + ) + if err != nil { + if errors.Is(err, storage.ErrNotExist) { + return nil, nil + } + return nil, fmt.Errorf( + "get staged comments: %w", err, + ) + } + return &comments, nil +} + +// ClearStagedComments removes staged comments +// for the given branch. +// This is a no-op if no staged comments exist. +func (s *Store) ClearStagedComments( + ctx context.Context, + branch string, +) error { + err := s.db.Delete( + ctx, + s.stagedCommentsJSON(branch), + fmt.Sprintf( + "%v: clear staged comments", branch, + ), + ) + if err != nil { + return fmt.Errorf( + "delete staged comments: %w", err, + ) + } + return nil +} diff --git a/internal/spice/state/staged_comment_test.go b/internal/spice/state/staged_comment_test.go new file mode 100644 index 000000000..23f4d38e2 --- /dev/null +++ b/internal/spice/state/staged_comment_test.go @@ -0,0 +1,144 @@ +package state_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.abhg.dev/gs/internal/forge" + "go.abhg.dev/gs/internal/silog/silogtest" + "go.abhg.dev/gs/internal/spice/state" + "go.abhg.dev/gs/internal/spice/state/storage" +) + +func TestStagedComments(t *testing.T) { + ctx := t.Context() + db := storage.NewDB(make(storage.MapBackend)) + + _, err := state.InitStore(ctx, state.InitStoreRequest{ + DB: db, + Trunk: "main", + }) + require.NoError(t, err) + + store, err := state.OpenStore(ctx, db, silogtest.New(t)) + require.NoError(t, err) + + t.Run("LoadEmpty", func(t *testing.T) { + got, err := store.LoadStagedComments(ctx, "feat") + require.NoError(t, err) + assert.Nil(t, got) + }) + + t.Run("SaveAndLoad", func(t *testing.T) { + comments := &state.StagedComments{ + NextID: 3, + Comments: []state.StagedComment{ + { + LocalID: 1, + File: "main.go", + Lines: forge.InlineCommentLine(42), + Body: "Consider using a const here.", + }, + { + LocalID: 2, + File: "handler.go", + Lines: forge.InlineCommentLine(15), + Body: "I agree with your suggestion.", + ID: "thread-abc", + }, + }, + } + + err := store.SaveStagedComments(ctx, "feat", comments) + require.NoError(t, err) + + got, err := store.LoadStagedComments(ctx, "feat") + require.NoError(t, err) + require.NotNil(t, got) + + assert.Equal(t, 3, got.NextID) + assert.Len(t, got.Comments, 2) + assert.Equal(t, "main.go", got.Comments[0].File) + assert.Equal(t, forge.InlineCommentLine(42), got.Comments[0].Lines) + assert.Equal(t, forge.InlineCommentThreadID("thread-abc"), got.Comments[1].ID) + }) + + t.Run("Overwrite", func(t *testing.T) { + comments := &state.StagedComments{ + NextID: 2, + Comments: []state.StagedComment{ + { + LocalID: 1, + File: "new.go", + Lines: forge.InlineCommentLine(1), + Body: "New comment", + }, + }, + } + + err := store.SaveStagedComments(ctx, "feat", comments) + require.NoError(t, err) + + got, err := store.LoadStagedComments(ctx, "feat") + require.NoError(t, err) + require.NotNil(t, got) + + assert.Len(t, got.Comments, 1) + assert.Equal(t, "new.go", got.Comments[0].File) + }) + + t.Run("Clear", func(t *testing.T) { + err := store.ClearStagedComments(ctx, "feat") + require.NoError(t, err) + + got, err := store.LoadStagedComments(ctx, "feat") + require.NoError(t, err) + assert.Nil(t, got) + }) + + t.Run("ClearNonExistent", func(t *testing.T) { + // Clearing a branch with no staged comments + // should not error. + err := store.ClearStagedComments(ctx, "nonexistent") + require.NoError(t, err) + }) + + t.Run("MultipleBranches", func(t *testing.T) { + commentsA := &state.StagedComments{ + NextID: 2, + Comments: []state.StagedComment{ + { + LocalID: 1, + File: "a.go", + Lines: forge.InlineCommentLine(1), + Body: "A", + }, + }, + } + commentsB := &state.StagedComments{ + NextID: 2, + Comments: []state.StagedComment{ + { + LocalID: 1, + File: "b.go", + Lines: forge.InlineCommentLine(2), + Body: "B", + }, + }, + } + + require.NoError(t, + store.SaveStagedComments(ctx, "branch-a", commentsA)) + require.NoError(t, + store.SaveStagedComments(ctx, "branch-b", commentsB)) + + gotA, err := store.LoadStagedComments(ctx, "branch-a") + require.NoError(t, err) + assert.Equal(t, "a.go", gotA.Comments[0].File) + + gotB, err := store.LoadStagedComments(ctx, "branch-b") + require.NoError(t, err) + assert.Equal(t, "b.go", gotB.Comments[0].File) + }) +}