diff --git a/README.md b/README.md index 4165461f..85050f1b 100644 --- a/README.md +++ b/README.md @@ -278,18 +278,19 @@ UDS CLI includes a vendored version of Zarf inside of its binary. To use Zarf, s ## Dev Mode > [!NOTE] -> Dev mode is a BETA feature and currently only works with local bundles +> Dev mode is a BETA feature Dev mode facilitates faster dev cycles when developing and testing bundles ``` -uds dev deploy +uds dev deploy | ``` The `dev deploy` command performs the following operations -- Creates Zarf packages for all local packages in a bundle + +- If local bundle: Creates Zarf packages for all local packages in a bundle - Creates the Zarf tarball in the same directory as the `zarf.yaml` - Will only create the Zarf tarball if one does not already exist - Ignores any `kind: ZarfInitConfig` packages in the bundle -- Creates a bundle from the newly created Zarf packages + - Creates a bundle from the newly created Zarf packages - Deploys the bundle in [YOLO](https://docs.zarf.dev/faq/#what-is-yolo-mode-and-why-would-i-use-it) mode, eliminating the need to do a `zarf init` diff --git a/src/cmd/dev.go b/src/cmd/dev.go index 3f266993..5b7fc8e5 100644 --- a/src/cmd/dev.go +++ b/src/cmd/dev.go @@ -5,8 +5,7 @@ package cmd import ( - "os" - + "github.com/defenseunicorns/pkg/helpers" "github.com/defenseunicorns/uds-cli/src/config" "github.com/defenseunicorns/uds-cli/src/config/lang" "github.com/defenseunicorns/zarf/src/pkg/message" @@ -25,26 +24,25 @@ var devDeployCmd = &cobra.Command{ Args: cobra.MaximumNArgs(1), Short: lang.CmdDevDeployShort, Long: lang.CmdDevDeployLong, - PreRun: func(_ *cobra.Command, args []string) { - setBundleFile(args) - }, Run: func(_ *cobra.Command, args []string) { + config.Dev = true - // Create Bundle - srcDir, err := os.Getwd() - if err != nil { - message.Fatalf(err, "error reading the current working directory") - } + // Get bundle source + src := "" if len(args) > 0 { - srcDir = args[0] + src = args[0] } - if len(srcDir) != 0 && srcDir[len(srcDir)-1] != '/' { - srcDir = srcDir + "/" - } + // Check if source is a local bundle + localBundle := helpers.IsDir(src) + + if localBundle { + // Create Bundle + setBundleFile(args) - config.CommonOptions.Confirm = true - bundleCfg.CreateOpts.SourceDirectory = srcDir + config.CommonOptions.Confirm = true + bundleCfg.CreateOpts.SourceDirectory = src + } configureZarf() @@ -59,18 +57,24 @@ var devDeployCmd = &cobra.Command{ bndlClient := bundle.NewOrDie(&bundleCfg) defer bndlClient.ClearPaths() - // Check if local zarf packages need to be created - bndlClient.CreateZarfPkgs() - // Create dev bundle - config.Dev = true - if err := bndlClient.Create(); err != nil { - bndlClient.ClearPaths() - message.Fatalf(err, "Failed to create bundle: %s", err.Error()) + if localBundle { + // Check if local zarf packages need to be created + bndlClient.CreateZarfPkgs() + + if err := bndlClient.Create(); err != nil { + message.Fatalf(err, "Failed to create bundle: %s", err.Error()) + } + } + + // Set dev source + if localBundle { + bndlClient.SetDeploySource(src) + } else { + bundleCfg.DeployOpts.Source = src } - // Deploy dev bundle - bndlClient.SetDevSource(srcDir) + // Deploy bundle deploy(bndlClient) }, } @@ -80,4 +84,6 @@ func init() { rootCmd.AddCommand(devCmd) devCmd.AddCommand(devDeployCmd) devDeployCmd.Flags().StringArrayVarP(&bundleCfg.DeployOpts.Packages, "packages", "p", []string{}, lang.CmdBundleDeployFlagPackages) + devDeployCmd.Flags().BoolVarP(&config.CommonOptions.Confirm, "confirm", "c", false, lang.CmdBundleDeployFlagConfirm) + devDeployCmd.Flags().StringToStringVar(&bundleCfg.DeployOpts.SetVariables, "set", nil, lang.CmdBundleDeployFlagSet) } diff --git a/src/pkg/bundle/dev.go b/src/pkg/bundle/dev.go index c36aa4dd..64d2d10f 100644 --- a/src/pkg/bundle/dev.go +++ b/src/pkg/bundle/dev.go @@ -58,13 +58,8 @@ func (b *Bundle) CreateZarfPkgs() { } } -// SetDevSource sets the source for the bundle when in dev mode -func (b *Bundle) SetDevSource(srcDir string) { - srcDir = filepath.Dir(srcDir) - // Add a trailing slash if it's missing - if len(srcDir) != 0 && srcDir[len(srcDir)-1] != '/' { - srcDir = srcDir + "/" - } +// SetDeploySource sets the source for the bundle when in dev mode +func (b *Bundle) SetDeploySource(srcDir string) { filename := fmt.Sprintf("%s%s-%s-%s.tar.zst", config.BundlePrefix, b.bundle.Metadata.Name, b.bundle.Metadata.Architecture, b.bundle.Metadata.Version) b.cfg.DeployOpts.Source = filepath.Join(srcDir, filename) } diff --git a/src/pkg/sources/common.go b/src/pkg/sources/common.go index 21ee1e04..7f47b252 100644 --- a/src/pkg/sources/common.go +++ b/src/pkg/sources/common.go @@ -4,7 +4,9 @@ // Package sources contains Zarf packager sources package sources -import zarfTypes "github.com/defenseunicorns/zarf/src/types" +import ( + zarfTypes "github.com/defenseunicorns/zarf/src/types" +) // addNamespaceOverrides checks if pkg components have charts with namespace overrides and adds them func addNamespaceOverrides(pkg *zarfTypes.ZarfPackage, nsOverrides NamespaceOverrideMap) { @@ -21,3 +23,13 @@ func addNamespaceOverrides(pkg *zarfTypes.ZarfPackage, nsOverrides NamespaceOver } } } + +// setAsYOLO sets the YOLO flag on a package and strips out all images and repos +func setAsYOLO(pkg *zarfTypes.ZarfPackage) { + pkg.Metadata.YOLO = true + // strip out all images and repos + for idx := range pkg.Components { + pkg.Components[idx].Images = []string{} + pkg.Components[idx].Repos = []string{} + } +} diff --git a/src/pkg/sources/remote.go b/src/pkg/sources/remote.go index 2b280c03..6641a173 100644 --- a/src/pkg/sources/remote.go +++ b/src/pkg/sources/remote.go @@ -52,6 +52,11 @@ func (r *RemoteBundle) LoadPackage(dst *layout.PackagePaths, filter filters.Comp return zarfTypes.ZarfPackage{}, nil, err } + // if in dev mode and package is a zarf init config, return an empty package + if config.Dev && pkg.Kind == zarfTypes.ZarfInitConfig { + return zarfTypes.ZarfPackage{}, nil, nil + } + pkg.Components, err = filter.Apply(pkg) if err != nil { return pkg, nil, err @@ -85,6 +90,11 @@ func (r *RemoteBundle) LoadPackage(dst *layout.PackagePaths, filter filters.Comp } } addNamespaceOverrides(&pkg, r.nsOverrides) + + if config.Dev { + setAsYOLO(&pkg) + } + // ensure we're using the correct package name as specified by the bundle pkg.Metadata.Name = r.PkgName return pkg, nil, err diff --git a/src/pkg/sources/tarball.go b/src/pkg/sources/tarball.go index dcd22a5a..68d33b6f 100644 --- a/src/pkg/sources/tarball.go +++ b/src/pkg/sources/tarball.go @@ -96,12 +96,7 @@ func (t *TarballBundle) LoadPackage(dst *layout.PackagePaths, filter filters.Com addNamespaceOverrides(&pkg, t.nsOverrides) if config.Dev { - pkg.Metadata.YOLO = true - // strip out all images and repos - for idx := range pkg.Components { - pkg.Components[idx].Images = []string{} - pkg.Components[idx].Repos = []string{} - } + setAsYOLO(&pkg) } packageSpinner.Successf("Loaded bundled Zarf package: %s", t.PkgName) diff --git a/src/test/e2e/commands_test.go b/src/test/e2e/commands_test.go index 891cf145..b840f9cf 100644 --- a/src/test/e2e/commands_test.go +++ b/src/test/e2e/commands_test.go @@ -112,8 +112,8 @@ func deploy(t *testing.T, tarballPath string) (stdout string, stderr string) { return stdout, stderr } -func devDeploy(t *testing.T, tarballPath string) (stdout string, stderr string) { - cmd := strings.Split(fmt.Sprintf("dev deploy %s", tarballPath), " ") +func devDeploy(t *testing.T, bundlePath string) (stdout string, stderr string) { + cmd := strings.Split(fmt.Sprintf("dev deploy %s --confirm", bundlePath), " ") stdout, stderr, err := e2e.UDS(cmd...) require.NoError(t, err) return stdout, stderr diff --git a/src/test/e2e/dev_test.go b/src/test/e2e/dev_test.go index c01fe8dd..4ff3254a 100644 --- a/src/test/e2e/dev_test.go +++ b/src/test/e2e/dev_test.go @@ -49,4 +49,26 @@ func TestDevDeploy(t *testing.T) { remove(t, bundlePath) }) + + t.Run("Test dev deploy with remote bundle", func(t *testing.T) { + + bundle := "oci://ghcr.io/defenseunicorns/packages/uds-cli/test/publish/ghcr-test:0.0.1" + + devDeploy(t, bundle) + + deployments, _, _ := e2e.UDS(cmd...) + require.Contains(t, deployments, "podinfo") + require.Contains(t, deployments, "nginx") + + remove(t, bundle) + }) + + t.Run("Test dev deploy with --set flag", func(t *testing.T) { + bundleDir := "src/test/bundles/02-variables" + bundleTarballPath := filepath.Join(bundleDir, fmt.Sprintf("uds-bundle-variables-%s-0.0.1.tar.zst", e2e.Arch)) + _, stderr := runCmd(t, "dev deploy "+bundleDir+" --set ANIMAL=Longhorns --set COUNTRY=Texas --confirm -l=debug") + require.Contains(t, stderr, "This fun-fact was imported: Longhorns are the national animal of Texas") + require.NotContains(t, stderr, "This fun-fact was imported: Unicorns are the national animal of Scotland") + remove(t, bundleTarballPath) + }) }