Disable build history when maxEntries is zero

Skip build-history recording entirely when history.maxEntries is explicitly set to zero, while still closing progress for normal builds. Cover successful and failed builds across the integration worker matrix and document the configuration.

Closes moby/buildkit#3798.

Assisted-by: OpenAI Codex
Signed-off-by: Shurong Cao <170531907+CAOShurong@users.noreply.github.com>
This commit is contained in:
Shurong Cao committed 2026-08-13 17:10:34 +08:00
1 parent 30fe6a5116
commit 555e402bfd
6 files changed
+80 -1

No files matched your search

+37
View File
@@ -54,6 +54,37 @@ func testClientCustomGRPCOpts(t *testing.T, sb integration.Sandbox) {
require.Contains(t, interceptedMethods, "/moby.buildkit.v1.Control/Solve")
}
func testBuildHistoryDisabled(t *testing.T, sb integration.Sandbox) {
c, err := New(sb.Context(), sb.Address())
require.NoError(t, err)
defer c.Close()
successRef := identity.NewID()
successDef, err := llb.Scratch().File(llb.Mkfile("file", 0o644, nil)).Marshal(sb.Context())
require.NoError(t, err)
_, err = c.Solve(sb.Context(), successDef, SolveOpt{Ref: successRef}, nil)
require.NoError(t, err)
requireNoBuildHistory(t, c, sb, successRef)
failureRef := identity.NewID()
failureDef, err := llb.Scratch().File(llb.Rm("missing")).Marshal(sb.Context())
require.NoError(t, err)
_, err = c.Solve(sb.Context(), failureDef, SolveOpt{Ref: failureRef}, nil)
require.Error(t, err)
requireNoBuildHistory(t, c, sb, failureRef)
}
func requireNoBuildHistory(t *testing.T, c *Client, sb integration.Sandbox, ref string) {
t.Helper()
history, err := c.ControlClient().ListenBuildHistory(sb.Context(), &controlapi.BuildHistoryRequest{
Ref: ref,
EarlyExit: true,
})
require.NoError(t, err)
_, err = history.Recv()
require.ErrorIs(t, err, io.EOF)
}
func testListenBuildHistoryExcludesSoftDeletedRecords(t *testing.T, sb integration.Sandbox) {
c, err := New(sb.Context(), sb.Address())
require.NoError(t, err)
@@ -128,3 +159,9 @@ func testListenBuildHistoryExcludesSoftDeletedRecords(t *testing.T, sb integrati
}
}
}
type historyDisabled struct{}
func (*historyDisabled) UpdateConfigFile(in string) (string, func() error) {
return in + "\n\n[history]\n maxEntries = 0\n", nil
}
+6
View File
@@ -319,6 +319,12 @@ func testIntegration(t *testing.T, funcs ...func(t *testing.T, sb integration.Sa
tests = append(tests, diffOpTestCases()...)
integration.Run(t, tests, mirrors)
integration.Run(t, integration.TestFuncs(
testBuildHistoryDisabled,
), mirrors, integration.WithMatrix("history", map[string]any{
"disabled": &historyDisabled{},
}))
// the rest of the tests are meant for non-Windows, skipping on Windows.
integration.SkipOnPlatform(t, "windows")
+1
View File
@@ -65,6 +65,7 @@ provenanceEnvDir = "/etc/buildkit/provenance.d"
# maxAge is the maximum age of history entries to keep, in seconds.
maxAge = 172800
# maxEntries is the maximum number of history entries to keep.
# Setting this value to 0 disables build history.
maxEntries = 50
[worker.oci]
+6
View File
@@ -77,6 +77,12 @@ type StatusImportResult struct {
NumWarnings int
}
// Enabled reports whether completed build history should be recorded.
// A configured maximum of zero disables history recording entirely.
func (h *Queue) Enabled() bool {
return h.opt.CleanConfig.MaxEntries != 0
}
func NewQueue(opt QueueOpt) (*Queue, error) {
if opt.CleanConfig == nil {
opt.CleanConfig = &config.HistoryConfig{
@@ -0,0 +1,27 @@
package history
import (
"testing"
"github.com/moby/buildkit/cmd/buildkitd/config"
)
func TestQueueEnabled(t *testing.T) {
tests := []struct {
name string
maxEntries int64
want bool
}{
{name: "disabled", maxEntries: 0, want: false},
{name: "enabled", maxEntries: 50, want: true},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
q := &Queue{opt: QueueOpt{CleanConfig: &config.HistoryConfig{MaxEntries: tc.maxEntries}}}
if got := q.Enabled(); got != tc.want {
t.Fatalf("Enabled() = %v, want %v", got, tc.want)
}
})
}
}
+3 -1
View File
@@ -281,7 +281,7 @@ func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req fro
defer s.gatewayForwarder.UnregisterBuild(context.Background(), id)
}
if !internal {
if !internal && s.history.Enabled() {
rec, err1 := s.recordBuildHistory(ctx, id, req, exp, j, usage)
if err1 != nil {
defer j.CloseProgress()
@@ -290,6 +290,8 @@ func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req fro
defer func() {
err = rec(context.WithoutCancel(ctx), resProv, descrefs, err)
}()
} else if !internal {
defer j.CloseProgress()
}
if fwd != nil {