summaryrefslogtreecommitdiff
path: root/internal/api/stories.go
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-04-04 09:30:13 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-04-04 09:30:13 +0000
commit940a5bab031bfe81cea9c90d64e6ebc804c366f9 (patch)
tree34f41c4675f0e238c5acd9665790d256ea39a041 /internal/api/stories.go
parent2917c580ae3eab093e9e655ccdf210030b7b9d1f (diff)
feat: story ship gate — explicit POST /api/stories/{id}/ship; remove auto-deploy
- checkStoryCompletion now guards against re-running on already-SHIPPABLE stories and no longer auto-triggers triggerStoryDeploy on completion - New Pool.ShipStory method validates SHIPPABLE state then fires triggerStoryDeploy - POST /api/stories/{id}/ship route registered and handleShipStory handler added - Two new tests: 202 for SHIPPABLE story, 409 for non-SHIPPABLE story Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/api/stories.go')
-rw-r--r--internal/api/stories.go11
1 files changed, 11 insertions, 0 deletions
diff --git a/internal/api/stories.go b/internal/api/stories.go
index 629ea7a..1743dbe 100644
--- a/internal/api/stories.go
+++ b/internal/api/stories.go
@@ -322,6 +322,17 @@ func (s *Server) handleApproveStory(w http.ResponseWriter, r *http.Request) {
})
}
+// handleShipStory triggers the merge + deploy for a SHIPPABLE story.
+// POST /api/stories/{id}/ship
+func (s *Server) handleShipStory(w http.ResponseWriter, r *http.Request) {
+ id := r.PathValue("id")
+ if err := s.pool.ShipStory(r.Context(), id); err != nil {
+ writeJSON(w, http.StatusConflict, map[string]string{"error": err.Error()})
+ return
+ }
+ writeJSON(w, http.StatusAccepted, map[string]string{"message": "story shipping initiated", "story_id": id})
+}
+
// handleStoryDeploymentStatus aggregates the deployment status across all tasks in a story.
// GET /api/stories/{id}/deployment-status
func (s *Server) handleStoryDeploymentStatus(w http.ResponseWriter, r *http.Request) {