iop/packages/go/agenttask/review.go

124 lines
4.3 KiB
Go

package agenttask
import (
"context"
"fmt"
)
func (m *Manager) reviewSubmission(
ctx context.Context,
project ProjectRecord,
work WorkRecord,
submission Submission,
) (bool, error) {
result, err := m.reviewer.Review(ctx, ReviewRequest{
Project: project, Work: work, Submission: submission,
IdempotencyKey: reviewKey(project.ProjectID, work.Unit.ID, work.Attempt, submission.ArtifactID),
})
if err != nil {
m.blockWork(ctx, project.ProjectID, work.Unit.ID, WorkStateBlocked, Blocker{
Code: BlockerReviewFailed, Message: err.Error(), Retryable: true,
})
return false, nil
}
if result.ProjectID != project.ProjectID || result.WorkUnitID != work.Unit.ID ||
result.AttemptID != work.AttemptID || result.ArtifactID != submission.ArtifactID {
m.blockWork(ctx, project.ProjectID, work.Unit.ID, WorkStateBlocked, Blocker{
Code: BlockerArtifactMismatch, Message: "official review result identity mismatch",
})
return false, nil
}
var cmdID CommandID
var wfRev WorkflowRevision
if project.Intent != nil {
cmdID = project.Intent.CommandID
wfRev = project.Intent.WorkflowRevision
}
m.emit(ctx, Event{
Type: EventReviewResult, ProjectID: project.ProjectID, WorkspaceID: project.WorkspaceID,
WorkUnitID: work.Unit.ID, CommandID: cmdID, WorkflowRevision: wfRev, AttemptID: work.AttemptID, Ordinal: work.DispatchOrdinal,
Detail: string(result.Verdict),
})
switch result.Verdict {
case ReviewVerdictPass:
if result.ChangeSet == nil || result.ChangeSet.ArtifactID != submission.ArtifactID {
m.blockWork(ctx, project.ProjectID, work.Unit.ID, WorkStateBlocked, Blocker{
Code: BlockerArtifactMismatch, Message: "PASS review is missing an exact artifact change-set identity",
})
return false, nil
}
if err := validateIdentity("change_set", string(result.ChangeSet.ID)); err != nil {
m.blockWork(ctx, project.ProjectID, work.Unit.ID, WorkStateBlocked, Blocker{
Code: BlockerArtifactMismatch, Message: err.Error(),
})
return false, nil
}
if err := validateIdentity("change_set_revision", result.ChangeSet.Revision); err != nil {
m.blockWork(ctx, project.ProjectID, work.Unit.ID, WorkStateBlocked, Blocker{
Code: BlockerArtifactMismatch, Message: err.Error(),
})
return false, nil
}
err := m.changeWork(ctx, project.ProjectID, work.Unit.ID, func(work *WorkRecord) error {
if err := transitionWork(work, WorkStatePendingIntegration); err != nil {
return err
}
work.Review = &result
changeSet := *result.ChangeSet
work.ChangeSet = &changeSet
work.Blocker = nil
return nil
})
return false, err
case ReviewVerdictWarn, ReviewVerdictFail:
if result.Rework && work.Attempt < m.config.MaxReworkAttempts {
err := m.changeWork(ctx, project.ProjectID, work.Unit.ID, func(work *WorkRecord) error {
if err := transitionWork(work, WorkStateReady); err != nil {
return err
}
work.Review = &result
work.Attempt++
work.AttemptID = attemptID(work.Unit.ID, work.Attempt)
work.Target = nil
work.Isolation = nil
work.Submission = nil
work.ChangeSet = nil
work.Blocker = nil
return nil
})
m.emit(ctx, Event{
Type: EventFollowup, ProjectID: project.ProjectID, WorkspaceID: project.WorkspaceID,
WorkUnitID: work.Unit.ID, CommandID: cmdID, WorkflowRevision: wfRev, AttemptID: attemptID(work.Unit.ID, work.Attempt+1),
Ordinal: work.DispatchOrdinal, Detail: string(result.Verdict),
})
return err == nil, err
}
code := BlockerReviewFailed
if result.Rework {
code = BlockerReviewReworkExhausted
}
_ = m.changeWork(ctx, project.ProjectID, work.Unit.ID, func(work *WorkRecord) error {
work.Review = &result
return nil
})
m.blockWork(ctx, project.ProjectID, work.Unit.ID, WorkStateBlocked, Blocker{
Code: code,
Message: fmt.Sprintf("official review ended with %s: %s", result.Verdict, result.Message),
})
return false, nil
case ReviewVerdictUserReview:
_ = m.changeWork(ctx, project.ProjectID, work.Unit.ID, func(work *WorkRecord) error {
work.Review = &result
return nil
})
m.blockWork(ctx, project.ProjectID, work.Unit.ID, WorkStateTerminalDeferred, Blocker{
Code: BlockerUserReview, Message: result.Message,
})
return false, nil
default:
m.blockWork(ctx, project.ProjectID, work.Unit.ID, WorkStateBlocked, Blocker{
Code: BlockerReviewFailed, Message: "official review returned an unknown verdict",
})
return false, nil
}
}