Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions cmd/chisel/cmd_debug_validate_release.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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.

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:"<branch|dir>"`
}

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")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a convention established for such messages? Lower/upper? Punctuation?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not find one for this type of message but looking again for it made me realize displaying this message in stdout looks inconsistent with other commands. So this is now using logf (sending to stderr by default) and I added a period at the end of the message. This is more consistent with the behavior of check-release-archives. Output of a successful execution looks like this:

# go run ./cmd/chisel debug validate-release --release ubuntu-24.04
2026/08/18 09:12:26 Consulting release repository...
2026/08/18 09:12:27 Cached ubuntu-24.04 release is still up-to-date.
2026/08/18 09:12:27 Processing ubuntu-24.04 release...
2026/08/18 09:12:35 Release is valid.

return nil
}
93 changes: 93 additions & 0 deletions cmd/chisel/cmd_debug_validate_release_test.go
Original file line number Diff line number Diff line change
@@ -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`)
}
4 changes: 4 additions & 0 deletions tests/debug-validate-release/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
summary: Validate a Chisel release statically

execute: |
chisel debug validate-release --release ${OS}-${RELEASE} 2>&1 | MATCH "Release is valid"
Loading