Commit 4eaacc1

Eric Bower  ·  2026-05-08 10:34:18 -0400 EDT
parent 6048817
fix: timing issue
1 files changed,  +45, -38
M main.go
+45, -38
  1@@ -1075,6 +1075,10 @@ func monitorTick(cfg *Cfg, log *slog.Logger, output io.Writer, jobStates map[str
  2 					log.Error("publish final status", "err", err)
  3 				}
  4 			}
  5+			// Sync artifacts before writing sentinel — syncArtifacts skips jobs with published.json
  6+			if err := syncJobArtifacts(cfg, name, jobID, log); err != nil {
  7+				log.Error("sync artifacts", "err", err)
  8+			}
  9 			// Write sentinel so we don't re-publish on subsequent ticks
 10 			published := map[string]interface{}{
 11 				"status":      status,
 12@@ -1464,6 +1468,46 @@ func stageArtifact(dir, name, jobID, short, content, ext string) error {
 13 	return os.WriteFile(path, []byte(content), 0644)
 14 }
 15 
 16+// syncJobArtifacts syncs artifacts for a single job.
 17+func syncJobArtifacts(cfg *Cfg, repoName, jobID string, log *slog.Logger) error {
 18+	jobDir := filepath.Join(cfg.ArtifactDir, repoName, jobID)
 19+	eventPath := filepath.Join(jobDir, "event.json")
 20+	data, err := os.ReadFile(eventPath)
 21+	if err != nil {
 22+		return fmt.Errorf("read event: %w", err)
 23+	}
 24+	var event Event
 25+	if err := json.Unmarshal(data, &event); err != nil || event.ArtifactDest == "" {
 26+		return fmt.Errorf("invalid event")
 27+	}
 28+	log.Debug("syncing artifacts", "repo", repoName, "job_id", jobID, "dest", event.ArtifactDest)
 29+	var sshArgs string
 30+	if cfg.KeyLocation != "" {
 31+		certFile := ""
 32+		if cfg.CertificateLocation != "" {
 33+			certFile = fmt.Sprintf(" -o CertificateFile %s", cfg.CertificateLocation)
 34+		}
 35+		sshArgs = fmt.Sprintf("-F ~/.ssh/config -i %s%s", cfg.KeyLocation, certFile)
 36+	}
 37+	// Append "/" so rsync copies into the destination directory,
 38+	// not as a subdirectory named after the source.
 39+	dest := event.ArtifactDest
 40+	if !strings.HasSuffix(dest, "/") {
 41+		dest += "/"
 42+	}
 43+	var cmd *exec.Cmd
 44+	if sshArgs != "" {
 45+		cmd = exec.Command("rsync", "-e", sshArgs, "-rv", jobDir+"/", dest)
 46+	} else {
 47+		cmd = exec.Command("rsync", "-rv", jobDir+"/", dest)
 48+	}
 49+	rsyncCmd := fmt.Sprintf("rsync %s %s %s",
 50+		strings.TrimLeft(cmd.Args[1], "-"),
 51+		jobDir+"/", dest)
 52+	log.Info("rsync", "cmd", rsyncCmd)
 53+	return runCmd(cmd, log)
 54+}
 55+
 56 func syncArtifacts(cfg *Cfg, log *slog.Logger) error {
 57 	entries, err := os.ReadDir(cfg.ArtifactDir)
 58 	if err != nil {
 59@@ -1484,7 +1528,6 @@ func syncArtifacts(cfg *Cfg, log *slog.Logger) error {
 60 				continue
 61 			}
 62 			jobDir := filepath.Join(cfg.ArtifactDir, entry.Name(), repoEntry.Name())
 63-			eventPath := filepath.Join(jobDir, "event.json")
 64 			publishedPath := filepath.Join(jobDir, "published.json")
 65 
 66 			// Skip if already published (job is complete)
 67@@ -1492,43 +1535,7 @@ func syncArtifacts(cfg *Cfg, log *slog.Logger) error {
 68 				continue
 69 			}
 70 
 71-			data, err := os.ReadFile(eventPath)
 72-			if err != nil {
 73-				continue // no event yet, skip
 74-			}
 75-			var event Event
 76-			if err := json.Unmarshal(data, &event); err != nil || event.ArtifactDest == "" {
 77-				continue
 78-			}
 79-			log.Debug("syncing artifacts", "repo", entry.Name(), "job_id", repoEntry.Name(), "dest", event.ArtifactDest)
 80-			var sshArgs string
 81-			if cfg.KeyLocation != "" {
 82-				certFile := ""
 83-				if cfg.CertificateLocation != "" {
 84-					certFile = fmt.Sprintf(" -o CertificateFile %s", cfg.CertificateLocation)
 85-				}
 86-				sshArgs = fmt.Sprintf("-F ~/.ssh/config -i %s%s", cfg.KeyLocation, certFile)
 87-			}
 88-			srcDir := jobDir
 89-			// Append "/" so rsync copies into the destination directory,
 90-			// not as a subdirectory named after the source.
 91-			dest := event.ArtifactDest
 92-			if !strings.HasSuffix(dest, "/") {
 93-				dest += "/"
 94-			}
 95-
 96-			// Build rsync command, omitting -e if no ssh args
 97-			var cmd *exec.Cmd
 98-			if sshArgs != "" {
 99-				cmd = exec.Command("rsync", "-e", sshArgs, "-rv", srcDir+"/", dest)
100-			} else {
101-				cmd = exec.Command("rsync", "-rv", srcDir+"/", dest)
102-			}
103-			rsyncCmd := fmt.Sprintf("rsync %s %s %s",
104-				strings.TrimLeft(cmd.Args[1], "-"),
105-				srcDir+"/", dest)
106-			log.Info("rsync", "cmd", rsyncCmd)
107-			if err := runCmd(cmd, log); err != nil {
108+			if err := syncJobArtifacts(cfg, entry.Name(), repoEntry.Name(), log); err != nil {
109 				log.Error("sync artifacts", "repo", entry.Name(), "job_id", repoEntry.Name(), "err", err)
110 			}
111 		}