feat(zli): add config list/show/get/set/reset and isolate deprecated syntax (#4037)

* feat(zli): add config list/show/get/set/reset and isolate deprecated syntax

Introduce first-class subcommands for listing profiles, showing a profile,
getting and setting keys, and resetting optional keys (alongside existing add/remove).
The parent command now resolves ~/.zot via zliUserConfigPath(),
documents that profile names must not clash with subcommand names,
and states that positional/--list/--reset usage is deprecated and will be removed soon.

Legacy behavior is delegated to config_cmd_deprecated.go with stderr warnings for old flags and positional get/set.
Examples and inline help point users at the new commands.
FormatNames/FormatListedVars comments reference config list/show.

Tests are split so config_cmd_test.go exercises the supported subcommands
while config_cmd_deprecated_test.go retains coverage for the deprecated
paths under renamed TestConfigCmdDeprecated* entries.

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>

* test: stabilize retention check tests

See https://github.com/project-zot/zot/actions/runs/25361779632/job/74362802944?pr=4037

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>

---------

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
This commit is contained in:
Andrei Aaron
2026-05-08 20:19:26 +03:00
committed by GitHub
parent b89d10834c
commit c7ddbe2e36
7 changed files with 1108 additions and 267 deletions
+54
View File
@@ -1445,6 +1445,10 @@ func TestRetentionCheckWithSubpaths(t *testing.T) {
},
}
// The command returns after its timeout; ensure we have all expected decisions in the log
// before validating, to avoid flakes from buffered writes.
logContent = readLogUntilRetentionDecisions(t, logFile, len(expectedResults), 2*time.Second)
logStr = string(logContent)
validateRetentionDecisions(t, logContent, expectedResults)
})
}
@@ -1714,6 +1718,56 @@ func validateRetentionDecisions(t *testing.T, logContent []byte, expectedResults
}
}
func readLogUntilRetentionDecisions(
t *testing.T,
logFile string,
expectedCount int,
timeout time.Duration,
) []byte {
t.Helper()
deadline := time.Now().Add(timeout)
var (
lastContent []byte
lastReadErr error
)
for time.Now().Before(deadline) {
content, err := os.ReadFile(logFile)
if err != nil {
lastReadErr = err
time.Sleep(50 * time.Millisecond)
continue
}
lastReadErr = nil
lastContent = content
if len(parseRetentionDecisions(content)) >= expectedCount {
return content
}
time.Sleep(50 * time.Millisecond)
}
if lastContent == nil && lastReadErr != nil {
t.Fatalf("failed to read log file %q: %v", logFile, lastReadErr)
}
if lastReadErr != nil {
t.Logf("last log read error for %q: %v", logFile, lastReadErr)
}
observed := len(parseRetentionDecisions(lastContent))
if observed < expectedCount {
t.Fatalf("timed out waiting for retention decisions in %q: observed=%d expected>=%d",
logFile, observed, expectedCount)
}
return lastContent
}
func logRetentionDecisions(t *testing.T, actualDecisions []RetentionDecision) {
t.Helper()