Tag built images with the commit's short hash (closes #239)
Check / check (pull_request) Skipped
Check / check (pull_request) Skipped
Builds are tagged upaas-<app>:<short hash>, git's own short form of the commit checked out, instead of the deployment number. A redeploy of a commit gives the tag to the new image. The cleanup after a deploy now also finds the app's untagged images among those its deployments recorded, and removes them by ID once the app neither runs them nor would roll back to them. It keeps every image any app uses, since apps that build the same commit can share one. The clone reads the commits from git's output after removing Docker's log headers, which had hidden the COMMIT: line; commit_sha is now saved on update so manual deploys keep the commit they recorded. Model: opus-5-5
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
controlapi "github.com/moby/buildkit/api/services/control"
|
||||
)
|
||||
|
||||
@@ -203,6 +205,8 @@ func TestPerformCloneRemovesContainerVolumes(t *testing.T) {
|
||||
<-r.Context().Done()
|
||||
case strings.HasSuffix(r.URL.Path, "/wait"):
|
||||
_, _ = fmt.Fprintf(w, `{"StatusCode":%d}`, tt.exitCode)
|
||||
case strings.HasSuffix(r.URL.Path, "/logs"):
|
||||
writeCloneOutput(w)
|
||||
default:
|
||||
_, _ = w.Write([]byte(`{}`))
|
||||
}
|
||||
@@ -244,6 +248,62 @@ func TestPerformCloneRemovesContainerVolumes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// cloneCommit is the commit the fake clones in these tests check out.
|
||||
const cloneCommit = "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b"
|
||||
|
||||
// writeCloneOutput writes the output of a git clone of cloneCommit as
|
||||
// Docker sends a container's log: each line after a header.
|
||||
func writeCloneOutput(w io.Writer) {
|
||||
stdout := stdcopy.NewStdWriter(w, stdcopy.Stdout)
|
||||
stderr := stdcopy.NewStdWriter(w, stdcopy.Stderr)
|
||||
|
||||
_, _ = stderr.Write([]byte("Cloning into '/repo'...\n"))
|
||||
_, _ = stdout.Write([]byte("COMMIT:" + cloneCommit + "\n"))
|
||||
_, _ = stdout.Write([]byte("SHORT_SHA:1a2b3c4\n"))
|
||||
}
|
||||
|
||||
// TestCloneRepoReadsCommit runs a clone against a fake Docker API and
|
||||
// checks that the commit checked out is read from the clone's output, in
|
||||
// full and in git's short form.
|
||||
func TestCloneRepoReadsCommit(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.URL.Path, "/containers/create"):
|
||||
_, _ = w.Write([]byte(`{"Id":"gitcontainer"}`))
|
||||
case strings.HasSuffix(r.URL.Path, "/logs"):
|
||||
writeCloneOutput(w)
|
||||
default:
|
||||
_, _ = w.Write([]byte(`{}`))
|
||||
}
|
||||
},
|
||||
))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
dockerAPI, err := client.NewClientWithOpts(
|
||||
client.WithHost("tcp://" + srv.Listener.Addr().String()),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := &Client{docker: dockerAPI, log: slog.Default()}
|
||||
|
||||
result, err := c.CloneRepo(
|
||||
t.Context(), "git@example.com:repo.git", mainBranch, "", "fake-key",
|
||||
t.TempDir(), t.TempDir(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if result.CommitSHA != cloneCommit || result.ShortSHA != "1a2b3c4" {
|
||||
t.Errorf("got commit %q, short %q", result.CommitSHA, result.ShortSHA)
|
||||
}
|
||||
}
|
||||
|
||||
// TestPerformBuildUsesBuildKit runs a build against a fake Docker API and
|
||||
// checks that it asks for BuildKit and that BuildKit's progress reaches the
|
||||
// build log as plain text.
|
||||
|
||||
Reference in New Issue
Block a user