This commit is contained in:
2026-06-22 08:55:57 +08:00
parent dbb87823e8
commit 6ade6e8fa9
325 changed files with 41131 additions and 855 deletions
+55 -5
View File
@@ -13,12 +13,18 @@ import (
// CredentialResolver 是 service 共享的解密回调,避免 GitOpsService 直接持有 *crypto.Encryptor。
type CredentialResolver func(ctx context.Context, wsID uuid.UUID) (*git.Credential, error)
// CommitSummaryHook is a best-effort callback fired after a successful commit to
// enqueue auto-doc/PR-summary generation. Injected from app.go via
// SetCommitSummaryHook to avoid a workspace→docs import cycle. May be nil.
type CommitSummaryHook func(ctx context.Context, wsID uuid.UUID, worktreeID *uuid.UUID, branch, commitSHA string) error
type gitOpsService struct {
repo Repository
rec audit.Recorder
gitr git.Runner
pa ProjectAccess
cred CredentialResolver
repo Repository
rec audit.Recorder
gitr git.Runner
pa ProjectAccess
cred CredentialResolver
summaryHook CommitSummaryHook
}
// NewGitOpsService 构造 GitOpsService。cred 由 WorkspaceService.loadDecryptedCredential 适配过来。
@@ -26,6 +32,9 @@ func NewGitOpsService(repo Repository, rec audit.Recorder, gitr git.Runner, pa P
return &gitOpsService{repo: repo, rec: rec, gitr: gitr, pa: pa, cred: cred}
}
// SetCommitSummaryHook injects the auto-doc enqueue callback (app wiring).
func (s *gitOpsService) SetCommitSummaryHook(h CommitSummaryHook) { s.summaryHook = h }
// ===== Main =====
func (s *gitOpsService) StatusOnMain(ctx context.Context, c Caller, wsID uuid.UUID) ([]git.FileStatus, error) {
@@ -50,6 +59,7 @@ func (s *gitOpsService) CommitOnMain(ctx context.Context, c Caller, wsID uuid.UU
return "", errs.Wrap(err, errs.CodeGitCmdFailed, "git commit")
}
s.auditCommit(ctx, &c.UserID, wsID.String(), "main", in.Message, sha)
s.fireCommitSummary(ctx, &c.UserID, wsID, nil, ws.DefaultBranch, sha)
if in.Push {
cred, err := s.cred(ctx, wsID)
if err != nil {
@@ -63,6 +73,20 @@ func (s *gitOpsService) CommitOnMain(ctx context.Context, c Caller, wsID uuid.UU
return sha, nil
}
// fireCommitSummary invokes the auto-doc hook best-effort; failures are audited
// but never surfaced to the commit caller.
func (s *gitOpsService) fireCommitSummary(ctx context.Context, userID *uuid.UUID, wsID uuid.UUID, worktreeID *uuid.UUID, branch, sha string) {
if s.summaryHook == nil || sha == "" {
return
}
if herr := s.summaryHook(ctx, wsID, worktreeID, branch, sha); herr != nil {
_ = s.rec.Record(ctx, audit.Entry{
UserID: userID, Action: "docs.summary_enqueue_failed", TargetType: "workspace",
TargetID: wsID.String(), Metadata: map[string]any{"err": herr.Error()},
})
}
}
func (s *gitOpsService) PushOnMain(ctx context.Context, c Caller, wsID uuid.UUID) error {
ws, err := s.guardWorkspaceWrite(ctx, c, wsID)
if err != nil {
@@ -91,6 +115,18 @@ func (s *gitOpsService) LogOnMain(ctx context.Context, c Caller, wsID uuid.UUID,
return commits, nil
}
func (s *gitOpsService) DiffOnMain(ctx context.Context, c Caller, wsID uuid.UUID, opts git.DiffOptions) (git.DiffResult, error) {
ws, err := s.guardWorkspaceRead(ctx, c, wsID)
if err != nil {
return git.DiffResult{}, err
}
res, err := s.gitr.Diff(ctx, ws.MainPath, opts)
if err != nil {
return git.DiffResult{}, errs.Wrap(err, errs.CodeGitCmdFailed, "git diff")
}
return res, nil
}
// ===== Worktree =====
func (s *gitOpsService) StatusOnWorktree(ctx context.Context, c Caller, wtID uuid.UUID) ([]git.FileStatus, error) {
@@ -116,6 +152,8 @@ func (s *gitOpsService) CommitOnWorktree(ctx context.Context, c Caller, wtID uui
return "", errs.Wrap(err, errs.CodeGitCmdFailed, "git commit")
}
s.auditCommit(ctx, &c.UserID, ws.ID.String(), wt.Branch, in.Message, sha)
wtIDCopy := wt.ID
s.fireCommitSummary(ctx, &c.UserID, ws.ID, &wtIDCopy, wt.Branch, sha)
if in.Push {
cred, err := s.cred(ctx, ws.ID)
if err != nil {
@@ -157,6 +195,18 @@ func (s *gitOpsService) LogOnWorktree(ctx context.Context, c Caller, wtID uuid.U
return commits, nil
}
func (s *gitOpsService) DiffOnWorktree(ctx context.Context, c Caller, wtID uuid.UUID, opts git.DiffOptions) (git.DiffResult, error) {
wt, _, err := s.guardWorktreeRead(ctx, c, wtID)
if err != nil {
return git.DiffResult{}, err
}
res, err := s.gitr.Diff(ctx, wt.Path, opts)
if err != nil {
return git.DiffResult{}, errs.Wrap(err, errs.CodeGitCmdFailed, "git diff")
}
return res, nil
}
// ===== guards =====
func (s *gitOpsService) guardWorkspaceRead(ctx context.Context, c Caller, wsID uuid.UUID) (*Workspace, error) {