From 217d029083a0853ab26457a26418a63935d9f15c Mon Sep 17 00:00:00 2001 From: decleaver <85503726+decleaver@users.noreply.github.com> Date: Thu, 4 Apr 2024 12:20:16 -0600 Subject: [PATCH] feat: uds dev deploy (#536) Co-authored-by: UncleGedd <42304551+UncleGedd@users.noreply.github.com> --- README.md | 8 ++- src/cmd/common.go | 101 +++++++++++++++++++++++++++++ src/cmd/dev.go | 81 +++++++++++++++++++++++ src/cmd/root.go | 31 +-------- src/cmd/uds.go | 51 +-------------- src/cmd/version.go | 4 +- src/config/config.go | 3 + src/config/lang/lang.go | 4 ++ src/pkg/bundle/dev.go | 69 ++++++++++++++++++++ src/pkg/bundle/tui/deploy/model.go | 1 - src/pkg/sources/tarball.go | 17 +++++ src/pkg/utils/utils.go | 7 +- src/test/common.go | 14 ++++ src/test/e2e/commands_test.go | 17 +++++ src/test/e2e/dev_test.go | 52 +++++++++++++++ 15 files changed, 373 insertions(+), 87 deletions(-) create mode 100644 src/cmd/common.go create mode 100644 src/cmd/dev.go create mode 100644 src/pkg/bundle/dev.go create mode 100644 src/test/e2e/dev_test.go diff --git a/README.md b/README.md index aa9ee465..ee15f6c4 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ 1. [Bundle Overrides](docs/overrides.md) 1. [Bundle Anatomy](docs/anatomy.md) 1. [Runner](docs/runner.md) +1. [Dev Mode](#dev-mode) ## Install Recommended installation method is with Brew: @@ -130,7 +131,7 @@ As an example: `uds remove uds-bundle-.tar.zst --packages init,nginx` ### Logs -> [!NOTE] +> Note: > Only works with `uds deploy` for now, may work for other operations but isn't guaranteed. The `uds logs` command can be used to view the most recent logs of a bundle operation. Note that depending on your OS temporary directory and file settings, recent logs are purged after a certain amount of time, so this command may return an error if the logs are no longer available. @@ -223,3 +224,8 @@ That is to say, variables set using the `--set` flag take precedence over all ot ## Zarf Integration UDS CLI includes a vendored version of Zarf inside of its binary. To use Zarf, simply run `uds zarf `. For example, to create a Zarf package, run `uds zarf create `, or to use the [airgap tooling](https://docs.zarf.dev/docs/the-zarf-cli/cli-commands/zarf_tools) that Zarf provides, run `uds zarf tools `. + +## Dev Mode +Dev mode allows you to speed up dev cycles when developing and testing bundles. `uds dev deploy` allows you to deploy a UDS bundle in dev mode. If you are missing a local zarf package, this command will create that zarf package for you assuming that your `zarf.yaml` file and zarf package are expected in the same directory. It will then create your bundle and deploy your zarf packages in [YOLO](https://docs.zarf.dev/docs/faq#what-is-yolo-mode-and-why-would-i-use-it) mode, eliminating the need to do a `zarf init` + +> Note: currently dev mode only works with local bundles diff --git a/src/cmd/common.go b/src/cmd/common.go new file mode 100644 index 00000000..c5dfcc39 --- /dev/null +++ b/src/cmd/common.go @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The UDS Authors + +// Package cmd contains the CLI commands for UDS. +package cmd + +import ( + "os" + "path/filepath" + "strings" + + tea "github.com/charmbracelet/bubbletea" + "github.com/defenseunicorns/uds-cli/src/config" + "github.com/defenseunicorns/uds-cli/src/config/lang" + "github.com/defenseunicorns/uds-cli/src/pkg/bundle" + "github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui/deploy" + "github.com/defenseunicorns/uds-cli/src/pkg/utils" + zarfConfig "github.com/defenseunicorns/zarf/src/config" + "github.com/defenseunicorns/zarf/src/pkg/message" + "github.com/defenseunicorns/zarf/src/pkg/utils/helpers" + zarfTypes "github.com/defenseunicorns/zarf/src/types" + "github.com/spf13/cobra" +) + +// configureZarf copies configs from UDS-CLI to Zarf +func configureZarf() { + zarfConfig.CommonOptions = zarfTypes.ZarfCommonOptions{ + Insecure: config.CommonOptions.Insecure, + TempDirectory: config.CommonOptions.TempDirectory, + OCIConcurrency: config.CommonOptions.OCIConcurrency, + Confirm: config.CommonOptions.Confirm, + CachePath: config.CommonOptions.CachePath, // use uds-cache instead of zarf-cache + } +} + +func deployWithoutTea(bndlClient *bundle.Bundle) { + _, _, _, err := bndlClient.PreDeployValidation() + if err != nil { + message.Fatalf(err, "Failed to validate bundle: %s", err.Error()) + } + // confirm deployment + if ok := bndlClient.ConfirmBundleDeploy(); !ok { + message.Fatal(nil, "bundle deployment cancelled") + } + // create an empty program and kill it, this makes Program.Send a no-op + deploy.Program = tea.NewProgram(nil) + deploy.Program.Kill() + + // deploy the bundle + if err := bndlClient.Deploy(); err != nil { + bndlClient.ClearPaths() + message.Fatalf(err, "Failed to deploy bundle: %s", err.Error()) + } +} + +func setBundleFile(args []string) { + pathToBundleFile := "" + if len(args) > 0 { + if !helpers.IsDir(args[0]) { + message.Fatalf(nil, "(%q) is not a valid path to a directory", args[0]) + } + pathToBundleFile = filepath.Join(args[0]) + } + // Handle .yaml or .yml + bundleYml := strings.Replace(config.BundleYAML, ".yaml", ".yml", 1) + if _, err := os.Stat(filepath.Join(pathToBundleFile, config.BundleYAML)); err == nil { + bundleCfg.CreateOpts.BundleFile = config.BundleYAML + } else if _, err = os.Stat(filepath.Join(pathToBundleFile, bundleYml)); err == nil { + bundleCfg.CreateOpts.BundleFile = bundleYml + } else { + message.Fatalf(err, "Neither %s or %s found", config.BundleYAML, bundleYml) + } +} + +func cliSetup(cmd *cobra.Command) { + match := map[string]message.LogLevel{ + "warn": message.WarnLevel, + "info": message.InfoLevel, + "debug": message.DebugLevel, + "trace": message.TraceLevel, + } + + printViperConfigUsed() + + // No log level set, so use the default + if logLevel != "" { + if lvl, ok := match[logLevel]; ok { + message.SetLogLevel(lvl) + message.Debug("Log level set to " + logLevel) + } else { + message.Warn(lang.RootCmdErrInvalidLogLevel) + } + } + + if !config.SkipLogFile && !config.ListTasks { + err := utils.ConfigureLogs(cmd) + if err != nil { + message.Fatalf(err, "Error configuring logs") + } + } +} diff --git a/src/cmd/dev.go b/src/cmd/dev.go new file mode 100644 index 00000000..232c4eb1 --- /dev/null +++ b/src/cmd/dev.go @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The UDS Authors + +// Package cmd contains the CLI commands for UDS. +package cmd + +import ( + "os" + + "github.com/defenseunicorns/uds-cli/src/config" + "github.com/defenseunicorns/uds-cli/src/config/lang" + "github.com/defenseunicorns/zarf/src/pkg/message" + + "github.com/defenseunicorns/uds-cli/src/pkg/bundle" + "github.com/spf13/cobra" +) + +var devCmd = &cobra.Command{ + Use: "dev", + Short: lang.CmdDevShort, +} + +var devDeployCmd = &cobra.Command{ + Use: "deploy", + Args: cobra.MaximumNArgs(1), + Short: lang.CmdDevDeployShort, + PreRun: func(_ *cobra.Command, args []string) { + setBundleFile(args) + }, + Run: func(_ *cobra.Command, args []string) { + + // Create Bundle + srcDir, err := os.Getwd() + if err != nil { + message.Fatalf(err, "error reading the current working directory") + } + if len(args) > 0 { + srcDir = args[0] + } + + if len(srcDir) != 0 && srcDir[len(srcDir)-1] != '/' { + srcDir = srcDir + "/" + } + + config.CommonOptions.Confirm = true + bundleCfg.CreateOpts.SourceDirectory = srcDir + configureZarf() + + // load uds-config if it exists + if v.ConfigFileUsed() != "" { + if err := loadViperConfig(); err != nil { + message.Fatalf(err, "Failed to load uds-config: %s", err.Error()) + return + } + } + + 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()) + } + + // Deploy dev bundle + bndlClient.SetDevSource(srcDir) + + deployWithoutTea(bndlClient) + }, +} + +func init() { + initViper() + rootCmd.AddCommand(devCmd) + devCmd.AddCommand(devDeployCmd) +} diff --git a/src/cmd/root.go b/src/cmd/root.go index 754b44d6..123f0a03 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -10,7 +10,6 @@ import ( "github.com/defenseunicorns/uds-cli/src/config" "github.com/defenseunicorns/uds-cli/src/config/lang" - "github.com/defenseunicorns/uds-cli/src/pkg/utils" "github.com/defenseunicorns/uds-cli/src/types" "github.com/defenseunicorns/zarf/src/cmd/common" zarfCommon "github.com/defenseunicorns/zarf/src/cmd/common" @@ -42,7 +41,7 @@ var rootCmd = &cobra.Command{ // don't load log configs for the logs command if cmd.Use != "logs" { - cliSetup(cmd.Use) + cliSetup(cmd) } }, Short: lang.RootCmdShort, @@ -91,31 +90,3 @@ func init() { rootCmd.PersistentFlags().IntVar(&config.CommonOptions.OCIConcurrency, "oci-concurrency", v.GetInt(V_BNDL_OCI_CONCURRENCY), lang.CmdBundleFlagConcurrency) rootCmd.PersistentFlags().BoolVar(&config.CommonOptions.NoTea, "no-tea", v.GetBool(V_NO_TEA), lang.RootCmdNoTea) } - -func cliSetup(op string) { - match := map[string]message.LogLevel{ - "warn": message.WarnLevel, - "info": message.InfoLevel, - "debug": message.DebugLevel, - "trace": message.TraceLevel, - } - - printViperConfigUsed() - - // No log level set, so use the default - if logLevel != "" { - if lvl, ok := match[logLevel]; ok { - message.SetLogLevel(lvl) - message.Debug("Log level set to " + logLevel) - } else { - message.Warn(lang.RootCmdErrInvalidLogLevel) - } - } - - if !config.SkipLogFile && !config.ListTasks { - err := utils.ConfigureLogs(op) - if err != nil { - message.Fatalf(err, "Error configuring logs") - } - } -} diff --git a/src/cmd/uds.go b/src/cmd/uds.go index 0ca88107..808dbea2 100644 --- a/src/cmd/uds.go +++ b/src/cmd/uds.go @@ -18,10 +18,7 @@ import ( "github.com/defenseunicorns/uds-cli/src/config/lang" "github.com/defenseunicorns/uds-cli/src/pkg/bundle" "github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui/deploy" - zarfConfig "github.com/defenseunicorns/zarf/src/config" "github.com/defenseunicorns/zarf/src/pkg/message" - "github.com/defenseunicorns/zarf/src/pkg/utils/helpers" - zarfTypes "github.com/defenseunicorns/zarf/src/types" goyaml "github.com/goccy/go-yaml" "github.com/spf13/cobra" "golang.org/x/term" @@ -33,22 +30,7 @@ var createCmd = &cobra.Command{ Args: cobra.MaximumNArgs(1), Short: lang.CmdBundleCreateShort, PreRun: func(_ *cobra.Command, args []string) { - pathToBundleFile := "" - if len(args) > 0 { - if !helpers.IsDir(args[0]) { - message.Fatalf(nil, "(%q) is not a valid path to a directory", args[0]) - } - pathToBundleFile = filepath.Join(args[0]) - } - // Handle .yaml or .yml - bundleYml := strings.Replace(config.BundleYAML, ".yaml", ".yml", 1) - if _, err := os.Stat(filepath.Join(pathToBundleFile, config.BundleYAML)); err == nil { - bundleCfg.CreateOpts.BundleFile = config.BundleYAML - } else if _, err = os.Stat(filepath.Join(pathToBundleFile, bundleYml)); err == nil { - bundleCfg.CreateOpts.BundleFile = bundleYml - } else { - message.Fatalf(err, "Neither %s or %s found", config.BundleYAML, bundleYml) - } + setBundleFile(args) }, Run: func(_ *cobra.Command, args []string) { srcDir, err := os.Getwd() @@ -301,17 +283,6 @@ func init() { rootCmd.AddCommand(logsCmd) } -// configureZarf copies configs from UDS-CLI to Zarf -func configureZarf() { - zarfConfig.CommonOptions = zarfTypes.ZarfCommonOptions{ - Insecure: config.CommonOptions.Insecure, - TempDirectory: config.CommonOptions.TempDirectory, - OCIConcurrency: config.CommonOptions.OCIConcurrency, - Confirm: config.CommonOptions.Confirm, - CachePath: config.CommonOptions.CachePath, // use uds-cache instead of zarf-cache - } -} - // chooseBundle provides a file picker when users don't specify a file func chooseBundle(args []string) string { if len(args) > 0 { @@ -337,23 +308,3 @@ func chooseBundle(args []string) string { return path } - -func deployWithoutTea(bndlClient *bundle.Bundle) { - _, _, _, err := bndlClient.PreDeployValidation() - if err != nil { - message.Fatalf(err, "Failed to validate bundle: %s", err.Error()) - } - // confirm deployment - if ok := bndlClient.ConfirmBundleDeploy(); !ok { - message.Fatal(nil, "bundle deployment cancelled") - } - // create an empty program and kill it, this makes Program.Send a no-op - deploy.Program = tea.NewProgram(nil) - deploy.Program.Kill() - - // deploy the bundle - if err := bndlClient.Deploy(); err != nil { - bndlClient.ClearPaths() - message.Fatalf(err, "Failed to deploy bundle: %s", err.Error()) - } -} diff --git a/src/cmd/version.go b/src/cmd/version.go index 926c2a3d..daf40e8b 100644 --- a/src/cmd/version.go +++ b/src/cmd/version.go @@ -15,9 +15,9 @@ import ( var versionCmd = &cobra.Command{ Use: "version", Aliases: []string{"v"}, - PersistentPreRun: func(_ *cobra.Command, _ []string) { + PersistentPreRun: func(cmd *cobra.Command, _ []string) { config.SkipLogFile = true - cliSetup("") + cliSetup(cmd) }, Short: lang.CmdVersionShort, Long: lang.CmdVersionLong, diff --git a/src/config/config.go b/src/config/config.go index 83866f84..d2f70e41 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -77,6 +77,9 @@ var ( // HelmTimeout is the default timeout for helm deploys HelmTimeout = 15 * time.Minute + + // Dev specifies if we are running in dev mode + Dev = false ) // GetArch returns the arch based on a priority list with options for overriding. diff --git a/src/config/lang/lang.go b/src/config/lang/lang.go index 03e17d4f..42eb1786 100644 --- a/src/config/lang/lang.go +++ b/src/config/lang/lang.go @@ -80,4 +80,8 @@ const ( // uds zarf CmdZarfShort = "Run a zarf command" + + // uds dev + CmdDevShort = "Commands useful for developing bundles" + CmdDevDeployShort = "Creates and deploys a dev UDS bundle from a given directory" ) diff --git a/src/pkg/bundle/dev.go b/src/pkg/bundle/dev.go new file mode 100644 index 00000000..a93f35ee --- /dev/null +++ b/src/pkg/bundle/dev.go @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The UDS Authors + +// Package bundle contains functions for interacting with, managing and deploying UDS packages +package bundle + +import ( + "fmt" + "os" + "path/filepath" + "regexp" + + "github.com/defenseunicorns/uds-cli/src/config" + + zarfCLI "github.com/defenseunicorns/zarf/src/cmd" + "github.com/defenseunicorns/zarf/src/pkg/message" + zarfUtils "github.com/defenseunicorns/zarf/src/pkg/utils" +) + +// CreateZarfPkgs creates a zarf package if its missing when in dev mode +func (b *Bundle) CreateZarfPkgs() { + srcDir := b.cfg.CreateOpts.SourceDirectory + path := filepath.Join(srcDir, b.cfg.CreateOpts.BundleFile) + if err := zarfUtils.ReadYaml(path, &b.bundle); err != nil { + message.Fatalf(err, "Failed to read bundle.yaml: %s", err.Error()) + } + + zarfPackagePattern := `^zarf-.*\.tar\.zst$` + for _, pkg := range b.bundle.Packages { + // if pkg is a local zarf package, attempt to create it if it doesn't exist + if pkg.Path != "" { + path := srcDir + pkg.Path + // get files in directory + files, err := os.ReadDir(path) + if err != nil { + message.Fatalf(err, "Failed to obtain package %s: %s", pkg.Name, err.Error()) + } + regex := regexp.MustCompile(zarfPackagePattern) + + // check if package exists + packageFound := false + for _, file := range files { + if regex.MatchString(file.Name()) { + packageFound = true + break + } + } + // create local zarf package if it doesn't exist + if !packageFound { + os.Args = []string{"zarf", "package", "create", path, "--confirm", "-o", path} + zarfCLI.Execute() + if err != nil { + message.Fatalf(err, "Failed to create package %s: %s", pkg.Name, err.Error()) + } + } + } + } +} + +// 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 + "/" + } + 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/bundle/tui/deploy/model.go b/src/pkg/bundle/tui/deploy/model.go index d9c0f29c..c354205d 100644 --- a/src/pkg/bundle/tui/deploy/model.go +++ b/src/pkg/bundle/tui/deploy/model.go @@ -64,7 +64,6 @@ type pkgState struct { percDownloaded int downloaded bool verified bool - isRemote bool } // Model contains the state of the TUI diff --git a/src/pkg/sources/tarball.go b/src/pkg/sources/tarball.go index 426e62aa..388605ea 100644 --- a/src/pkg/sources/tarball.go +++ b/src/pkg/sources/tarball.go @@ -20,6 +20,7 @@ import ( "github.com/defenseunicorns/zarf/src/pkg/packager/sources" zarfUtils "github.com/defenseunicorns/zarf/src/pkg/utils" "github.com/defenseunicorns/zarf/src/pkg/utils/helpers" + "github.com/defenseunicorns/zarf/src/types" zarfTypes "github.com/defenseunicorns/zarf/src/types" av4 "github.com/mholt/archiver/v4" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -44,6 +45,7 @@ type TarballBundle struct { // LoadPackage loads a Zarf package from a local tarball bundle func (t *TarballBundle) LoadPackage(dst *layout.PackagePaths, filter filters.ComponentFilterStrategy, unarchiveAll bool) (zarfTypes.ZarfPackage, []string, error) { + packageSpinner := message.NewProgressSpinner("Loading bundled Zarf package: %s", t.PkgName) defer packageSpinner.Stop() @@ -57,6 +59,11 @@ func (t *TarballBundle) LoadPackage(dst *layout.PackagePaths, filter filters.Com 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 == types.ZarfInitConfig { + return zarfTypes.ZarfPackage{}, nil, nil + } + pkg.Components, err = filter.Apply(pkg) if err != nil { return pkg, nil, err @@ -93,6 +100,16 @@ 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{} + } + } + packageSpinner.Successf("Loaded bundled Zarf package: %s", t.PkgName) // ensure we're using the correct package name as specified by the bundle pkg.Metadata.Name = t.PkgName diff --git a/src/pkg/utils/utils.go b/src/pkg/utils/utils.go index 2f941205..762d95c7 100644 --- a/src/pkg/utils/utils.go +++ b/src/pkg/utils/utils.go @@ -21,6 +21,7 @@ import ( "github.com/defenseunicorns/zarf/src/pkg/utils/helpers" av4 "github.com/mholt/archiver/v4" "github.com/pterm/pterm" + "github.com/spf13/cobra" ) // GracefulPanic in the event of a panic, attempt to reset the terminal using the 'reset' command. @@ -53,9 +54,9 @@ func IsValidTarballPath(path string) bool { } // ConfigureLogs sets up the log file, log cache and output for the CLI -func ConfigureLogs(op string) error { +func ConfigureLogs(cmd *cobra.Command) error { // don't configure UDS logs for vendored cmds - if strings.HasPrefix(op, "zarf") || strings.HasPrefix(op, "run") { + if strings.HasPrefix(cmd.Use, "zarf") || strings.HasPrefix(cmd.Use, "run") { return nil } writer, err := message.UseLogFile("") @@ -83,7 +84,7 @@ func ConfigureLogs(op string) error { // use Zarf pterm output if no-tea flag is set // todo: as more bundle ops use BubbleTea, need to also check them alongside 'deploy' - if !strings.Contains(op, "deploy") || config.CommonOptions.NoTea { + if !(strings.HasPrefix(cmd.Parent().Use, "uds") && strings.HasPrefix(cmd.Use, "deploy")) || config.CommonOptions.NoTea { message.Notef("Saving log file to %s", tmpLogLocation) logWriter = io.MultiWriter(os.Stderr, logFile) pterm.SetDefaultOutput(logWriter) diff --git a/src/test/common.go b/src/test/common.go index 6cc34a85..fcae281c 100644 --- a/src/test/common.go +++ b/src/test/common.go @@ -174,6 +174,20 @@ func (e2e *UDSE2ETest) CreateZarfPkg(t *testing.T, path string, forceCreate bool require.NoError(t, err) } +func (e2e *UDSE2ETest) DeleteZarfPkg(t *testing.T, path string) { + // check if pkg already exists + pattern := fmt.Sprintf("%s/*-%s-*.tar.zst", path, e2e.Arch) + matches, err := filepath.Glob(pattern) + require.NoError(t, err) + if len(matches) > 0 { + fmt.Println("Deleting Zarf pkg") + for _, match := range matches { + os.Remove(match) + } + return + } +} + func downloadFile(url string, outputDir string) error { response, err := http.Get(url) if err != nil { diff --git a/src/test/e2e/commands_test.go b/src/test/e2e/commands_test.go index a89e99bb..b4a36a70 100644 --- a/src/test/e2e/commands_test.go +++ b/src/test/e2e/commands_test.go @@ -16,6 +16,7 @@ import ( "testing" "github.com/defenseunicorns/uds-cli/src/config" + "github.com/defenseunicorns/zarf/src/pkg/message" "github.com/defenseunicorns/zarf/src/pkg/utils/helpers" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/stretchr/testify/assert" @@ -112,6 +113,13 @@ func deployWithTUI(t *testing.T, source 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 --no-tea", tarballPath), " ") + stdout, stderr, err := e2e.UDS(cmd...) + require.NoError(t, err) + return stdout, stderr +} + func runCmd(t *testing.T, input string) (stdout string, stderr string) { cmd := strings.Split(input, " ") stdout, stderr, err := e2e.UDS(cmd...) @@ -274,3 +282,12 @@ func queryIndex(t *testing.T, registryURL, bundlePath string) (ocispec.Index, er err = json.Unmarshal(body, &index) return index, err } + +func removeZarfInit() { + cmd := strings.Split("zarf tools kubectl delete namespace zarf", " ") + _, _, err := e2e.UDS(cmd...) + message.WarnErr(err, "Failed to delete zarf namespace") + cmd = strings.Split("zarf tools kubectl delete mutatingwebhookconfiguration.admissionregistration.k8s.io/zarf", " ") + _, _, err = e2e.UDS(cmd...) + message.WarnErr(err, "Failed to delete zarf webhook") +} diff --git a/src/test/e2e/dev_test.go b/src/test/e2e/dev_test.go new file mode 100644 index 00000000..f2b39fc4 --- /dev/null +++ b/src/test/e2e/dev_test.go @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The UDS Authors + +// Package test provides e2e tests for UDS. +package test + +import ( + "fmt" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDevDeploy(t *testing.T) { + + removeZarfInit() + cmd := strings.Split("zarf tools kubectl get deployments -A -o=jsonpath='{.items[*].metadata.name}'", " ") + + t.Run("Test dev deploy with local and remote pkgs", func(t *testing.T) { + + e2e.CreateZarfPkg(t, "src/test/packages/podinfo", false) + + bundleDir := "src/test/bundles/03-local-and-remote" + bundlePath := filepath.Join(bundleDir, fmt.Sprintf("uds-bundle-test-local-and-remote-%s-0.0.1.tar.zst", e2e.Arch)) + + devDeploy(t, bundleDir) + + deployments, _, _ := e2e.UDS(cmd...) + require.Contains(t, deployments, "podinfo") + require.Contains(t, deployments, "nginx") + + remove(t, bundlePath) + }) + + t.Run("Test dev deploy with CreateLocalPkgs", func(t *testing.T) { + + e2e.DeleteZarfPkg(t, "src/test/packages/podinfo") + + bundleDir := "src/test/bundles/03-local-and-remote" + bundlePath := filepath.Join(bundleDir, fmt.Sprintf("uds-bundle-test-local-and-remote-%s-0.0.1.tar.zst", e2e.Arch)) + + devDeploy(t, bundleDir) + + deployments, _, _ := e2e.UDS(cmd...) + require.Contains(t, deployments, "podinfo") + require.Contains(t, deployments, "nginx") + + remove(t, bundlePath) + }) +}