- Add pass/fail/needs-fix CLI commands to cmd/sdlc/cmd_artifact.go
- Add 3 new methods to SDLCExecutor interface in internal/port
- Implement methods in kubernetes adapter
- Add service methods to SDLCService
- Add HTTP handlers for POST .../artifacts/{type}/pass|fail|needs-fix
- Update 6 skeleton commands to evaluate and set artifact status
- Update test mocks
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
169 lines
4.6 KiB
Go
169 lines
4.6 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/orchard9/rdev/internal/sdlc"
|
|
"github.com/orchard9/rdev/pkg/api"
|
|
)
|
|
|
|
// GetArtifactStatus returns artifact statuses for a feature.
|
|
// GET /projects/{id}/sdlc/features/{slug}/artifacts
|
|
func (h *SDLCHandler) GetArtifactStatus(w http.ResponseWriter, r *http.Request) {
|
|
projectID := chi.URLParam(r, "id")
|
|
slug := chi.URLParam(r, "slug")
|
|
|
|
ctx, cancel := context.WithTimeout(r.Context(), TimeoutStandard)
|
|
defer cancel()
|
|
|
|
artifacts, err := h.sdlcService.GetArtifactStatus(ctx, projectID, slug)
|
|
if err != nil {
|
|
writeSDLCError(w, r, err)
|
|
return
|
|
}
|
|
|
|
api.WriteSuccess(w, r, artifacts)
|
|
}
|
|
|
|
// ApproveArtifact approves a feature artifact.
|
|
// POST /projects/{id}/sdlc/features/{slug}/artifacts/{type}/approve
|
|
func (h *SDLCHandler) ApproveArtifact(w http.ResponseWriter, r *http.Request) {
|
|
projectID := chi.URLParam(r, "id")
|
|
slug := chi.URLParam(r, "slug")
|
|
artTypeStr := chi.URLParam(r, "type")
|
|
|
|
artType := sdlc.ArtifactType(artTypeStr)
|
|
if !sdlc.IsValidArtifactType(artType) {
|
|
api.WriteBadRequest(w, r, "invalid artifact type: "+artTypeStr)
|
|
return
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(r.Context(), TimeoutHeavyWrite)
|
|
defer cancel()
|
|
|
|
if err := h.sdlcService.ApproveArtifact(ctx, projectID, slug, artType); err != nil {
|
|
writeSDLCError(w, r, err)
|
|
return
|
|
}
|
|
|
|
api.WriteSuccess(w, r, map[string]any{
|
|
"feature": slug,
|
|
"artifact": artTypeStr,
|
|
"status": "approved",
|
|
})
|
|
}
|
|
|
|
// RejectArtifact rejects a feature artifact.
|
|
// POST /projects/{id}/sdlc/features/{slug}/artifacts/{type}/reject
|
|
func (h *SDLCHandler) RejectArtifact(w http.ResponseWriter, r *http.Request) {
|
|
projectID := chi.URLParam(r, "id")
|
|
slug := chi.URLParam(r, "slug")
|
|
artTypeStr := chi.URLParam(r, "type")
|
|
|
|
artType := sdlc.ArtifactType(artTypeStr)
|
|
if !sdlc.IsValidArtifactType(artType) {
|
|
api.WriteBadRequest(w, r, "invalid artifact type: "+artTypeStr)
|
|
return
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(r.Context(), TimeoutHeavyWrite)
|
|
defer cancel()
|
|
|
|
if err := h.sdlcService.RejectArtifact(ctx, projectID, slug, artType); err != nil {
|
|
writeSDLCError(w, r, err)
|
|
return
|
|
}
|
|
|
|
api.WriteSuccess(w, r, map[string]any{
|
|
"feature": slug,
|
|
"artifact": artTypeStr,
|
|
"status": "rejected",
|
|
})
|
|
}
|
|
|
|
// PassArtifact marks a feature artifact as passed (for execution artifacts).
|
|
// POST /projects/{id}/sdlc/features/{slug}/artifacts/{type}/pass
|
|
func (h *SDLCHandler) PassArtifact(w http.ResponseWriter, r *http.Request) {
|
|
projectID := chi.URLParam(r, "id")
|
|
slug := chi.URLParam(r, "slug")
|
|
artTypeStr := chi.URLParam(r, "type")
|
|
|
|
artType := sdlc.ArtifactType(artTypeStr)
|
|
if !sdlc.IsValidArtifactType(artType) {
|
|
api.WriteBadRequest(w, r, "invalid artifact type: "+artTypeStr)
|
|
return
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(r.Context(), TimeoutHeavyWrite)
|
|
defer cancel()
|
|
|
|
if err := h.sdlcService.PassArtifact(ctx, projectID, slug, artType); err != nil {
|
|
writeSDLCError(w, r, err)
|
|
return
|
|
}
|
|
|
|
api.WriteSuccess(w, r, map[string]any{
|
|
"feature": slug,
|
|
"artifact": artTypeStr,
|
|
"status": "passed",
|
|
})
|
|
}
|
|
|
|
// FailArtifact marks a feature artifact as failed (for execution artifacts).
|
|
// POST /projects/{id}/sdlc/features/{slug}/artifacts/{type}/fail
|
|
func (h *SDLCHandler) FailArtifact(w http.ResponseWriter, r *http.Request) {
|
|
projectID := chi.URLParam(r, "id")
|
|
slug := chi.URLParam(r, "slug")
|
|
artTypeStr := chi.URLParam(r, "type")
|
|
|
|
artType := sdlc.ArtifactType(artTypeStr)
|
|
if !sdlc.IsValidArtifactType(artType) {
|
|
api.WriteBadRequest(w, r, "invalid artifact type: "+artTypeStr)
|
|
return
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(r.Context(), TimeoutHeavyWrite)
|
|
defer cancel()
|
|
|
|
if err := h.sdlcService.FailArtifact(ctx, projectID, slug, artType); err != nil {
|
|
writeSDLCError(w, r, err)
|
|
return
|
|
}
|
|
|
|
api.WriteSuccess(w, r, map[string]any{
|
|
"feature": slug,
|
|
"artifact": artTypeStr,
|
|
"status": "failed",
|
|
})
|
|
}
|
|
|
|
// NeedsFixArtifact marks a feature artifact as needing fixes.
|
|
// POST /projects/{id}/sdlc/features/{slug}/artifacts/{type}/needs-fix
|
|
func (h *SDLCHandler) NeedsFixArtifact(w http.ResponseWriter, r *http.Request) {
|
|
projectID := chi.URLParam(r, "id")
|
|
slug := chi.URLParam(r, "slug")
|
|
artTypeStr := chi.URLParam(r, "type")
|
|
|
|
artType := sdlc.ArtifactType(artTypeStr)
|
|
if !sdlc.IsValidArtifactType(artType) {
|
|
api.WriteBadRequest(w, r, "invalid artifact type: "+artTypeStr)
|
|
return
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(r.Context(), TimeoutHeavyWrite)
|
|
defer cancel()
|
|
|
|
if err := h.sdlcService.NeedsFixArtifact(ctx, projectID, slug, artType); err != nil {
|
|
writeSDLCError(w, r, err)
|
|
return
|
|
}
|
|
|
|
api.WriteSuccess(w, r, map[string]any{
|
|
"feature": slug,
|
|
"artifact": artTypeStr,
|
|
"status": "needs_fix",
|
|
})
|
|
}
|