98 lines
3.0 KiB
Go
98 lines
3.0 KiB
Go
package gitops
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/forgeo/forgebucket/internal/events"
|
|
"github.com/forgeo/forgebucket/internal/models"
|
|
)
|
|
|
|
// TriggerSync creates a Deployment record in "pending" state and fires
|
|
// deployment.started — the same path as a manually-triggered deployment.
|
|
// GitOps is just the trigger; actual execution is handled externally (or via CI).
|
|
func (c *Controller) TriggerSync(cfg models.GitOpsConfig, desiredSHA string) {
|
|
var env models.Environment
|
|
if found, _ := c.db.ID(cfg.EnvID).Get(&env); !found {
|
|
log.Printf("gitops: sync env %d not found", cfg.EnvID)
|
|
return
|
|
}
|
|
|
|
now := time.Now().UTC()
|
|
deploy := &models.Deployment{
|
|
EnvID: cfg.EnvID,
|
|
RepoID: cfg.RepoID,
|
|
SHA: desiredSHA,
|
|
Ref: "refs/heads/" + cfg.Branch,
|
|
Status: models.DeployStatusPending,
|
|
TriggeredBy: "gitops",
|
|
Description: "GitOps auto-sync",
|
|
StartedAt: &now,
|
|
}
|
|
if _, err := c.db.Insert(deploy); err != nil {
|
|
log.Printf("gitops: create deployment: %v", err)
|
|
return
|
|
}
|
|
|
|
cfg.SyncStatus = "syncing"
|
|
c.db.ID(cfg.ID).Cols("sync_status").Update(&cfg) //nolint:errcheck
|
|
|
|
c.bus.Publish(events.SubjectDeploymentStarted, events.DeploymentEvent{ //nolint:errcheck
|
|
DeploymentID: deploy.ID,
|
|
EnvID: env.ID,
|
|
EnvName: env.Name,
|
|
RepoID: deploy.RepoID,
|
|
SHA: deploy.SHA,
|
|
Ref: deploy.Ref,
|
|
Status: string(deploy.Status),
|
|
TriggeredBy: deploy.TriggeredBy,
|
|
})
|
|
|
|
log.Printf("gitops: triggered sync deploy %d for env %d (%s)", deploy.ID, cfg.EnvID, desiredSHA[:7])
|
|
}
|
|
|
|
// handleDeploymentSucceeded is called when any deployment.succeeded event fires.
|
|
// If the deployment was GitOps-triggered, it marks the config as synced.
|
|
func (c *Controller) handleDeploymentSucceeded(data []byte) {
|
|
var evt events.DeploymentEvent
|
|
if err := json.Unmarshal(data, &evt); err != nil {
|
|
return
|
|
}
|
|
|
|
// Only act on deployments triggered by gitops.
|
|
if evt.TriggeredBy != "gitops" {
|
|
// Still update ActualSHA and resolve drift if this env has a GitOps config —
|
|
// manual deployments also advance the state.
|
|
var cfg models.GitOpsConfig
|
|
if found, _ := c.db.Where("env_id = ?", evt.EnvID).Get(&cfg); found {
|
|
markSynced(c.db, evt.EnvID, evt.SHA)
|
|
log.Printf("gitops: env %d synced via manual deploy (%s)", evt.EnvID, sha7(evt.SHA))
|
|
}
|
|
return
|
|
}
|
|
|
|
markSynced(c.db, evt.EnvID, evt.SHA)
|
|
log.Printf("gitops: env %d synced (%s)", evt.EnvID, sha7(evt.SHA))
|
|
}
|
|
|
|
// handleDeploymentFailed is called when deployment.failed fires.
|
|
// If the deployment was GitOps-triggered, it reverts SyncStatus back to drifted.
|
|
func (c *Controller) handleDeploymentFailed(data []byte) {
|
|
var evt events.DeploymentEvent
|
|
if err := json.Unmarshal(data, &evt); err != nil {
|
|
return
|
|
}
|
|
if evt.TriggeredBy != "gitops" {
|
|
return
|
|
}
|
|
|
|
var cfg models.GitOpsConfig
|
|
if found, _ := c.db.Where("env_id = ?", evt.EnvID).Get(&cfg); !found {
|
|
return
|
|
}
|
|
cfg.SyncStatus = "drifted"
|
|
c.db.ID(cfg.ID).Cols("sync_status").Update(&cfg) //nolint:errcheck
|
|
log.Printf("gitops: env %d sync failed — reverting to drifted", evt.EnvID)
|
|
}
|