You've already forked agentic-coding-workflow
120 lines
3.8 KiB
Go
120 lines
3.8 KiB
Go
// Package changerequest models the change_requests entity and the server-side
|
|
// merge gate. A change request links a project/workspace/(requirement|issue)
|
|
// and a source->target branch to an external (Gitea) pull request, carrying a
|
|
// review verdict + CI state. The crux is Service.Merge, which hard-blocks the
|
|
// host-side merge unless review_verdict=='approved' (and optionally
|
|
// ci_state=='success'): an agent can open and merge PRs via MCP, but cannot
|
|
// self-approve — approval is HTTP/web-only by policy.
|
|
//
|
|
// Layout mirrors internal/workspace (single package, service + repository +
|
|
// handler + sqlc) to keep the aggregate cohesive.
|
|
package changerequest
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// State mirrors the change_requests.state CHECK constraint.
|
|
type State string
|
|
|
|
// State enum values.
|
|
const (
|
|
StateOpen State = "open"
|
|
StateMerged State = "merged"
|
|
StateClosed State = "closed"
|
|
)
|
|
|
|
// Verdict mirrors the change_requests.review_verdict CHECK constraint.
|
|
type Verdict string
|
|
|
|
// Verdict enum values.
|
|
const (
|
|
VerdictPending Verdict = "pending"
|
|
VerdictApproved Verdict = "approved"
|
|
VerdictChangesRequested Verdict = "changes_requested"
|
|
VerdictRejected Verdict = "rejected"
|
|
)
|
|
|
|
// IsValid reports whether v is in the enum set.
|
|
func (v Verdict) IsValid() bool {
|
|
switch v {
|
|
case VerdictPending, VerdictApproved, VerdictChangesRequested, VerdictRejected:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// CIState mirrors the change_requests.ci_state CHECK constraint.
|
|
type CIState string
|
|
|
|
// CIState enum values.
|
|
const (
|
|
CIUnknown CIState = "unknown"
|
|
CIPending CIState = "pending"
|
|
CISuccess CIState = "success"
|
|
CIFailure CIState = "failure"
|
|
)
|
|
|
|
// ChangeRequest is the change_requests row projection.
|
|
type ChangeRequest struct {
|
|
ID uuid.UUID
|
|
ProjectID uuid.UUID
|
|
WorkspaceID uuid.UUID
|
|
RequirementID *uuid.UUID
|
|
IssueID *uuid.UUID
|
|
Number int
|
|
Title string
|
|
Description string
|
|
SourceBranch string
|
|
TargetBranch string
|
|
State State
|
|
ReviewVerdict Verdict
|
|
CIState CIState
|
|
Provider string
|
|
ExternalID *int64
|
|
ExternalURL string
|
|
MergeCommitSHA string
|
|
ReviewedBy *uuid.UUID
|
|
ReviewedAt *time.Time
|
|
CreatedBy uuid.UUID
|
|
MergedAt *time.Time
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
// Caller mirrors workspace.Caller: the user context driving auth + audit.
|
|
type Caller struct {
|
|
UserID uuid.UUID
|
|
IsAdmin bool
|
|
SessionID *uuid.UUID
|
|
}
|
|
|
|
// CreateInput carries the fields to open a change request (and host PR).
|
|
type CreateInput struct {
|
|
SourceBranch string
|
|
TargetBranch string // empty => workspace default branch
|
|
Title string
|
|
Description string
|
|
RequirementID *uuid.UUID
|
|
IssueID *uuid.UUID
|
|
}
|
|
|
|
// Service is the change-request application service.
|
|
type Service interface {
|
|
Create(ctx context.Context, c Caller, wsID uuid.UUID, in CreateInput) (*ChangeRequest, error)
|
|
Get(ctx context.Context, c Caller, id uuid.UUID) (*ChangeRequest, error)
|
|
GetByNumber(ctx context.Context, c Caller, projectSlug string, number int) (*ChangeRequest, error)
|
|
ListByWorkspace(ctx context.Context, c Caller, wsID uuid.UUID) ([]*ChangeRequest, error)
|
|
// Review records a human verdict (owner/admin only). It is intentionally NOT
|
|
// exposed as an MCP tool so agents cannot self-approve their own PRs.
|
|
Review(ctx context.Context, c Caller, id uuid.UUID, verdict Verdict, note string) (*ChangeRequest, error)
|
|
// Merge is the gate: requires review_verdict=='approved' (+ ci success when
|
|
// RequireCIPass), then merges the host PR and persists merged state.
|
|
Merge(ctx context.Context, c Caller, id uuid.UUID, method string) (*ChangeRequest, error)
|
|
// SyncStatus refreshes ci_state/state from the host (provider.GetPR).
|
|
SyncStatus(ctx context.Context, c Caller, id uuid.UUID) (*ChangeRequest, error)
|
|
}
|