1245f5b90006c35abc163268590d932b5e322102

Author
TheEdgeOfRage <git@theedgeofrage.com>
Committer
TheEdgeOfRage <git@theedgeofrage.com>
Date

Message

feat: publish tagged builds

Diff

 1diff --git a/http.go b/http.go
 2index 8f71ca0fbc38ace2dca02c41dc64bb47f072b4b3..312a62e71fc1c99b2985757856980895d6df97eb 100644
 3--- a/http.go
 4+++ b/http.go
 5@@ -19,11 +19,15 @@ const (
 6 	maxStatusRepositories    = 100
 7 )
 8 
 9-var commitSHA = regexp.MustCompile(`^[0-9a-f]{40}([0-9a-f]{24})?$`)
10+var (
11+	commitSHA = regexp.MustCompile(`^[0-9a-f]{40}([0-9a-f]{24})?$`)
12+	dockerTag = regexp.MustCompile(`^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$`)
13+)
14 
15 type buildRequest struct {
16 	Repository string `json:"repository"`
17 	SHA        string `json:"sha"`
18+	Ref        string `json:"ref"`
19 }
20 
21 type buildStatus struct {
22@@ -122,6 +126,11 @@ func buildHandler(jobs chan<- buildJob, statuses *buildStatuses) http.HandlerFun
23 			http.Error(writer, "invalid build request", http.StatusBadRequest)
24 			return
25 		}
26+		if !isBuildRef(buildRequest.Ref) {
27+			slog.Info("build ignored", "repository", buildRequest.Repository, "sha", buildRequest.SHA, "ref", buildRequest.Ref)
28+			writer.WriteHeader(http.StatusNoContent)
29+			return
30+		}
31 
32 		job, err := newBuildJob(buildRequest)
33 		if err != nil {
34@@ -172,7 +181,18 @@ func buildStatusHandler(statuses *buildStatuses) http.HandlerFunc {
35 }
36 
37 func validBuildRequest(request buildRequest) bool {
38-	return validRepository(request.Repository) && commitSHA.MatchString(request.SHA)
39+	return validRepository(request.Repository) && commitSHA.MatchString(request.SHA) && validBuildRef(request.Ref)
40+}
41+
42+func validBuildRef(ref string) bool {
43+	if strings.HasPrefix(ref, "refs/heads/") {
44+		return strings.TrimPrefix(ref, "refs/heads/") != ""
45+	}
46+	return strings.HasPrefix(ref, "refs/tags/") && dockerTag.MatchString(strings.TrimPrefix(ref, "refs/tags/"))
47+}
48+
49+func isBuildRef(ref string) bool {
50+	return ref == "refs/heads/main" || strings.HasPrefix(ref, "refs/tags/")
51 }
52 
53 func validBuildStatusRequest(request buildStatusRequest) bool {
54diff --git a/worker.go b/worker.go
55index 776bc588c04eec87bc5c0a7521a1dc2ebfb4ccab..9b69771baf6e0f342862863cf46e77353776008a 100644
56--- a/worker.go
57+++ b/worker.go
58@@ -74,7 +74,7 @@ func build(ctx context.Context, config config, request buildRequest) error {
59 	}
60 
61 	image := imageName(config.registry, request.Repository)
62-	output := fmt.Sprintf("type=image,\"name=%s:%s,%s:main\",push=true", image, request.SHA, image)
63+	output := fmt.Sprintf("type=image,\"name=%s\",push=true", strings.Join(imageTags(image, request), ","))
64 	if err := run(
65 		ctx,
66 		"buildctl", "--addr", config.buildkitAddress,
67@@ -118,6 +118,14 @@ func imageName(registry, repository string) string {
68 	return registry + "/" + filepath.Base(repository)
69 }
70 
71+func imageTags(image string, request buildRequest) []string {
72+	tags := []string{image + ":" + request.SHA}
73+	if request.Ref == "refs/heads/main" {
74+		return append(tags, image+":main")
75+	}
76+	return append(tags, image+":"+strings.TrimPrefix(request.Ref, "refs/tags/"))
77+}
78+
79 func run(ctx context.Context, name string, arguments ...string) error {
80 	output, err := exec.CommandContext(ctx, name, arguments...).CombinedOutput()
81 	if err == nil {