From c9e462cbfaad3c7fc6e250a1ed5e24554713f40d Mon Sep 17 00:00:00 2001 From: Paul Mars Date: Fri, 24 Jul 2026 11:17:51 +0200 Subject: [PATCH 1/3] 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/3] 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" From fce22b5fc2ca6b199ad5ea4a721b39c71e044f76 Mon Sep 17 00:00:00 2001 From: Paul Mars Date: Tue, 18 Aug 2026 09:08:00 +0200 Subject: [PATCH 3/3] fix: review --- cmd/chisel/cmd_debug_validate_release.go | 17 +++++++++-------- cmd/chisel/cmd_debug_validate_release_test.go | 8 +++++++- tests/debug-validate-release/task.yaml | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/cmd/chisel/cmd_debug_validate_release.go b/cmd/chisel/cmd_debug_validate_release.go index bddc7c667..accb09b95 100644 --- a/cmd/chisel/cmd_debug_validate_release.go +++ b/cmd/chisel/cmd_debug_validate_release.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "github.com/jessevdk/go-flags" ) @@ -10,12 +8,15 @@ 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. +release, checking the slice definition files (SDFs) and the chisel.yaml file +for structural issues without downloading any package. + +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. -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. +This command, as any other command under debug, is unstable and will likely be +removed inside a major release with no warnings. Do not build scripts on it. ` ) @@ -41,6 +42,6 @@ func (cmd *cmdDebugValidateRelease) Execute(args []string) error { return err } - fmt.Fprintln(Stdout, "Release is valid") + logf("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 index efb40907d..7b7e8a4f5 100644 --- a/cmd/chisel/cmd_debug_validate_release_test.go +++ b/cmd/chisel/cmd_debug_validate_release_test.go @@ -1,6 +1,7 @@ package main_test import ( + "log" "os" "path/filepath" @@ -29,6 +30,10 @@ func writeRelease(c *C, files map[string]string) string { func (s *ChiselSuite) TestValidateReleaseSuccess(c *C) { s.ResetStdStreams() + logger := log.New(s.stderr, "", 0) + chisel.SetLogger(logger) + defer chisel.SetLogger(nil) + dir := writeRelease(c, map[string]string{ "chisel.yaml": testutil.DefaultChiselYaml, "slices/mydir/pkg-a.yaml": ` @@ -43,7 +48,8 @@ func (s *ChiselSuite) TestValidateReleaseSuccess(c *C) { []string{"debug", "validate-release", "--release", dir}, ) c.Assert(err, IsNil) - c.Assert(s.Stdout(), Equals, "Release is valid\n") + c.Assert(s.Stdout(), Equals, "") + c.Assert(s.Stderr(), Equals, "Release is valid.\n") } func (s *ChiselSuite) TestValidateReleaseErrorPropagation(c *C) { diff --git a/tests/debug-validate-release/task.yaml b/tests/debug-validate-release/task.yaml index 16316e957..0c3bfe545 100644 --- a/tests/debug-validate-release/task.yaml +++ b/tests/debug-validate-release/task.yaml @@ -1,4 +1,4 @@ summary: Validate a Chisel release statically execute: | - chisel debug validate-release --release ${OS}-${RELEASE} 2>&1 | MATCH "Release is valid" + chisel debug validate-release --release ${OS}-${RELEASE} 2>&1 | MATCH "Release is valid."