From c9e462cbfaad3c7fc6e250a1ed5e24554713f40d Mon Sep 17 00:00:00 2001 From: Paul Mars Date: Fri, 24 Jul 2026 11:17:51 +0200 Subject: [PATCH 1/2] feat: validation debug command --- cmd/chisel/cmd_debug_validate_release.go | 51 ++++++++++ cmd/chisel/cmd_debug_validate_release_test.go | 93 +++++++++++++++++++ tests/debug-validate-release/task.yaml | 7 ++ 3 files changed, 151 insertions(+) create mode 100644 cmd/chisel/cmd_debug_validate_release.go create mode 100644 cmd/chisel/cmd_debug_validate_release_test.go create mode 100644 tests/debug-validate-release/task.yaml diff --git a/cmd/chisel/cmd_debug_validate_release.go b/cmd/chisel/cmd_debug_validate_release.go new file mode 100644 index 000000000..b87f6fdb4 --- /dev/null +++ b/cmd/chisel/cmd_debug_validate_release.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + + "github.com/jessevdk/go-flags" +) + +var ( + shortValidateReleaseHelp = "Validate a Chisel release" + longValidateReleaseHelp = ` +The validate-release command performs the static validation of a Chisel +release, checking the slice definition files (SDFs) and the chisel.yaml +file for structural issues without downloading any package. + +It is a lightweight way to ensure that a release being authored or +modified is well formed. For a deeper validation that also downloads +packages and checks for content conflicts, see the +"check-release-archives" command. + +By default it fetches the slices for the same Ubuntu version as the +current host, unless the --release flag is used. Pointing --release to a +local directory avoids any network access. +` +) + +var validateReleaseDescs = map[string]string{ + "release": "Chisel release name or directory (e.g. ubuntu-22.04)", +} + +type cmdDebugValidateRelease struct { + Release string `long:"release" value-name:""` +} + +func init() { + addDebugCommand("validate-release", shortValidateReleaseHelp, longValidateReleaseHelp, func() flags.Commander { return &cmdDebugValidateRelease{} }, validateReleaseDescs, nil) +} + +func (cmd *cmdDebugValidateRelease) Execute(args []string) error { + if len(args) > 0 { + return ErrExtraArgs + } + + _, err := obtainRelease(cmd.Release) + if err != nil { + return err + } + + fmt.Fprintln(Stdout, "Release is valid") + return nil +} diff --git a/cmd/chisel/cmd_debug_validate_release_test.go b/cmd/chisel/cmd_debug_validate_release_test.go new file mode 100644 index 000000000..efb40907d --- /dev/null +++ b/cmd/chisel/cmd_debug_validate_release_test.go @@ -0,0 +1,93 @@ +package main_test + +import ( + "os" + "path/filepath" + + . "gopkg.in/check.v1" + + chisel "github.com/canonical/chisel/cmd/chisel" + "github.com/canonical/chisel/internal/testutil" +) + +// writeRelease writes the provided release files into a temporary directory +// and returns its path. +func writeRelease(c *C, files map[string]string) string { + dir := c.MkDir() + for path, data := range files { + fpath := filepath.Join(dir, path) + err := os.MkdirAll(filepath.Dir(fpath), 0o755) + c.Assert(err, IsNil) + err = os.WriteFile(fpath, testutil.Reindent(data), 0o644) + c.Assert(err, IsNil) + } + err := os.MkdirAll(filepath.Join(dir, "slices"), 0o755) + c.Assert(err, IsNil) + return dir +} + +func (s *ChiselSuite) TestValidateReleaseSuccess(c *C) { + s.ResetStdStreams() + + dir := writeRelease(c, map[string]string{ + "chisel.yaml": testutil.DefaultChiselYaml, + "slices/mydir/pkg-a.yaml": ` + package: pkg-a + slices: + myslice: + contents: + /file/path: + `, + }) + _, err := chisel.Parser().ParseArgs( + []string{"debug", "validate-release", "--release", dir}, + ) + c.Assert(err, IsNil) + c.Assert(s.Stdout(), Equals, "Release is valid\n") +} + +func (s *ChiselSuite) TestValidateReleaseErrorPropagation(c *C) { + s.ResetStdStreams() + + dir := writeRelease(c, map[string]string{ + "chisel.yaml": testutil.DefaultChiselYaml, + "slices/mydir/pkg-a.yaml": ` + package: pkg-a + slices: + myslice: + contents: + /path1: + `, + "slices/mydir/pkg-b.yaml": ` + package: pkg-b + slices: + myslice: + contents: + /path1: + `, + }) + _, err := chisel.Parser().ParseArgs( + []string{"debug", "validate-release", "--release", dir}, + ) + c.Assert(err, ErrorMatches, `slices pkg-a_myslice and pkg-b_myslice conflict on /path1`) + c.Assert(s.Stdout(), Equals, "") +} + +func (s *ChiselSuite) TestValidateReleaseExtraArgs(c *C) { + s.ResetStdStreams() + + dir := writeRelease(c, map[string]string{ + "chisel.yaml": testutil.DefaultChiselYaml, + "slices/mydir/pkg-a.yaml": ` + package: pkg-a + slices: + myslice: + contents: + /file/path: + `, + }) + _, err := chisel.Parser().ParseArgs( + []string{"debug", "validate-release", "--release", dir, "extra"}, + ) + c.Assert(err, ErrorMatches, `too many arguments for command`) +} diff --git a/tests/debug-validate-release/task.yaml b/tests/debug-validate-release/task.yaml new file mode 100644 index 000000000..7e2e9d6f4 --- /dev/null +++ b/tests/debug-validate-release/task.yaml @@ -0,0 +1,7 @@ +summary: Validate a Chisel release statically + +execute: | + chisel debug validate-release --release ${OS}-${RELEASE} 2> stderr.out + + # The command must complete successfully for a published release. + grep -q "Release is valid" stdout.txt 2>/dev/null || cat stderr.out From 032872bae2cb5df6236ec12950547dae201775e2 Mon Sep 17 00:00:00 2001 From: Paul Mars Date: Fri, 24 Jul 2026 12:01:47 +0200 Subject: [PATCH 2/2] fix: review --- cmd/chisel/cmd_debug_validate_release.go | 5 ----- tests/debug-validate-release/task.yaml | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/cmd/chisel/cmd_debug_validate_release.go b/cmd/chisel/cmd_debug_validate_release.go index b87f6fdb4..bddc7c667 100644 --- a/cmd/chisel/cmd_debug_validate_release.go +++ b/cmd/chisel/cmd_debug_validate_release.go @@ -13,11 +13,6 @@ The validate-release command performs the static validation of a Chisel release, checking the slice definition files (SDFs) and the chisel.yaml file for structural issues without downloading any package. -It is a lightweight way to ensure that a release being authored or -modified is well formed. For a deeper validation that also downloads -packages and checks for content conflicts, see the -"check-release-archives" command. - By default it fetches the slices for the same Ubuntu version as the current host, unless the --release flag is used. Pointing --release to a local directory avoids any network access. diff --git a/tests/debug-validate-release/task.yaml b/tests/debug-validate-release/task.yaml index 7e2e9d6f4..16316e957 100644 --- a/tests/debug-validate-release/task.yaml +++ b/tests/debug-validate-release/task.yaml @@ -1,7 +1,4 @@ summary: Validate a Chisel release statically execute: | - chisel debug validate-release --release ${OS}-${RELEASE} 2> stderr.out - - # The command must complete successfully for a published release. - grep -q "Release is valid" stdout.txt 2>/dev/null || cat stderr.out + chisel debug validate-release --release ${OS}-${RELEASE} 2>&1 | MATCH "Release is valid"