fix: cancel in-progress deploy when webhook triggers new deploy (closes #38)

When a webhook-triggered deploy starts for an app that already has a deploy
in progress, the existing deploy is now cancelled via context cancellation
before the new deploy begins. This prevents silently lost webhook deploys.

Changes:
- Add per-app active deploy tracking with cancel func and done channel
- Deploy() accepts cancelExisting param: true for webhook, false for manual
- Cancelled deployments are marked with new 'cancelled' status
- Add ErrDeployCancelled sentinel error
- Add DeploymentStatusCancelled model constant
- Add comprehensive tests for cancellation mechanics
This commit is contained in:
2026-02-15 22:12:03 -08:00
parent 9a284d40fd
commit 3f499163a7
6 changed files with 275 additions and 20 deletions

View File

@@ -0,0 +1,33 @@
package deploy
import (
"context"
"log/slog"
)
// NewTestService creates a Service with minimal dependencies for testing.
func NewTestService(log *slog.Logger) *Service {
return &Service{
log: log,
}
}
// CancelActiveDeploy exposes cancelActiveDeploy for testing.
func (svc *Service) CancelActiveDeploy(appID string) {
svc.cancelActiveDeploy(appID)
}
// RegisterActiveDeploy registers an active deploy for testing.
func (svc *Service) RegisterActiveDeploy(appID string, cancel context.CancelFunc, done chan struct{}) {
svc.activeDeploys.Store(appID, &activeDeploy{cancel: cancel, done: done})
}
// TryLockApp exposes tryLockApp for testing.
func (svc *Service) TryLockApp(appID string) bool {
return svc.tryLockApp(appID)
}
// UnlockApp exposes unlockApp for testing.
func (svc *Service) UnlockApp(appID string) {
svc.unlockApp(appID)
}