Monorepo for Tangled tangled.org

appview/state: trigger site redeploy on git push to configured branch

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.org>

anirudh.fi f93c5f2d 5938fdf6

verified
+74 -5
+74 -5
appview/state/knotstream.go
··· 8 8 "slices" 9 9 "time" 10 10 11 + "tangled.org/core/appview/cloudflare" 11 12 "tangled.org/core/appview/notify" 12 13 13 14 "tangled.org/core/api/tangled" ··· 15 16 "tangled.org/core/appview/config" 16 17 "tangled.org/core/appview/db" 17 18 "tangled.org/core/appview/models" 19 + "tangled.org/core/appview/sites" 18 20 ec "tangled.org/core/eventconsumer" 19 21 "tangled.org/core/eventconsumer/cursor" 20 22 "tangled.org/core/log" ··· 27 29 "github.com/posthog/posthog-go" 28 30 ) 29 31 30 - func Knotstream(ctx context.Context, c *config.Config, d *db.DB, enforcer *rbac.Enforcer, posthog posthog.Client, notifier notify.Notifier) (*ec.Consumer, error) { 32 + func Knotstream(ctx context.Context, c *config.Config, d *db.DB, enforcer *rbac.Enforcer, posthog posthog.Client, notifier notify.Notifier, cfClient *cloudflare.Client) (*ec.Consumer, error) { 31 33 logger := log.FromContext(ctx) 32 34 logger = log.SubLogger(logger, "knotstream") 33 35 ··· 50 52 51 53 cfg := ec.ConsumerConfig{ 52 54 Sources: srcs, 53 - ProcessFunc: knotIngester(d, enforcer, posthog, notifier, c.Core.Dev), 55 + ProcessFunc: knotIngester(d, enforcer, posthog, notifier, c.Core.Dev, c, cfClient), 54 56 RetryInterval: c.Knotstream.RetryInterval, 55 57 MaxRetryInterval: c.Knotstream.MaxRetryInterval, 56 58 ConnectionTimeout: c.Knotstream.ConnectionTimeout, ··· 64 66 return ec.NewConsumer(cfg), nil 65 67 } 66 68 67 - func knotIngester(d *db.DB, enforcer *rbac.Enforcer, posthog posthog.Client, notifier notify.Notifier, dev bool) ec.ProcessFunc { 69 + func knotIngester(d *db.DB, enforcer *rbac.Enforcer, posthog posthog.Client, notifier notify.Notifier, dev bool, c *config.Config, cfClient *cloudflare.Client) ec.ProcessFunc { 68 70 return func(ctx context.Context, source ec.Source, msg ec.Message) error { 69 71 switch msg.Nsid { 70 72 case tangled.GitRefUpdateNSID: 71 - return ingestRefUpdate(d, enforcer, posthog, notifier, dev, source, msg, ctx) 73 + return ingestRefUpdate(ctx, d, enforcer, posthog, notifier, dev, c, cfClient, source, msg) 72 74 case tangled.PipelineNSID: 73 75 return ingestPipeline(d, source, msg) 74 76 } ··· 77 79 } 78 80 } 79 81 80 - func ingestRefUpdate(d *db.DB, enforcer *rbac.Enforcer, pc posthog.Client, notifier notify.Notifier, dev bool, source ec.Source, msg ec.Message, ctx context.Context) error { 82 + func ingestRefUpdate(ctx context.Context, d *db.DB, enforcer *rbac.Enforcer, pc posthog.Client, notifier notify.Notifier, dev bool, c *config.Config, cfClient *cloudflare.Client, source ec.Source, msg ec.Message) error { 81 83 logger := log.FromContext(ctx) 82 84 83 85 var record tangled.GitRefUpdate ··· 126 128 }) 127 129 } 128 130 131 + // Trigger a sites redeploy if this push is to the configured sites branch. 132 + if cfClient.Enabled() { 133 + go triggerSitesDeployIfNeeded(ctx, d, cfClient, c, record, source) 134 + } 135 + 129 136 return errors.Join(errWebhook, errPunchcard, errLanguages, errPosthog) 137 + } 138 + 139 + // triggerSitesDeployIfNeeded checks whether the pushed ref matches the sites 140 + // branch configured for this repo and, if so, syncs the site to R2 141 + func triggerSitesDeployIfNeeded(ctx context.Context, d *db.DB, cfClient *cloudflare.Client, c *config.Config, record tangled.GitRefUpdate, source ec.Source) { 142 + logger := log.FromContext(ctx) 143 + 144 + ref := plumbing.ReferenceName(record.Ref) 145 + if !ref.IsBranch() { 146 + return 147 + } 148 + pushedBranch := ref.Short() 149 + 150 + repos, err := db.GetRepos( 151 + d, 152 + 0, 153 + orm.FilterEq("did", record.RepoDid), 154 + orm.FilterEq("name", record.RepoName), 155 + ) 156 + if err != nil || len(repos) != 1 { 157 + return 158 + } 159 + repo := repos[0] 160 + 161 + siteConfig, err := db.GetRepoSiteConfig(d, repo.RepoAt().String()) 162 + if err != nil || siteConfig == nil { 163 + return 164 + } 165 + if siteConfig.Branch != pushedBranch { 166 + return 167 + } 168 + 169 + scheme := "https" 170 + if c.Core.Dev { 171 + scheme = "http" 172 + } 173 + knotHost := fmt.Sprintf("%s://%s", scheme, source.Key()) 174 + 175 + deploy := &models.SiteDeploy{ 176 + RepoAt: repo.RepoAt().String(), 177 + Branch: siteConfig.Branch, 178 + Dir: siteConfig.Dir, 179 + CommitSHA: record.NewSha, 180 + Trigger: models.SiteDeployTriggerPush, 181 + } 182 + 183 + deployErr := sites.Deploy(ctx, cfClient, knotHost, record.RepoDid, record.RepoName, siteConfig.Branch, siteConfig.Dir) 184 + if deployErr != nil { 185 + logger.Error("sites: R2 sync failed on push", "repo", record.RepoDid+"/"+record.RepoName, "err", deployErr) 186 + deploy.Status = models.SiteDeployStatusFailure 187 + deploy.Error = deployErr.Error() 188 + } else { 189 + deploy.Status = models.SiteDeployStatusSuccess 190 + } 191 + 192 + if err := db.AddSiteDeploy(d, deploy); err != nil { 193 + logger.Error("sites: failed to record deploy", "repo", record.RepoDid+"/"+record.RepoName, "err", err) 194 + } 195 + 196 + if deployErr == nil { 197 + logger.Info("site deployed to r2", "repo", record.RepoDid+"/"+record.RepoName) 198 + } 130 199 } 131 200 132 201 func populatePunchcard(d *db.DB, record tangled.GitRefUpdate) error {