get.porter.sh/porter@v1.3.0/cmd/porter/bundle.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"get.porter.sh/porter/pkg/porter"
     8  	"github.com/spf13/cobra"
     9  )
    10  
    11  func buildBundleCommands(p *porter.Porter) *cobra.Command {
    12  	cmd := &cobra.Command{
    13  		Use:     "bundles",
    14  		Aliases: []string{"bundle"},
    15  		Short:   "Bundle commands",
    16  		Long:    "Commands for working with bundles. These all have shortcuts so that you can call these commands without the bundle resource prefix. For example, porter bundle build is available as porter build as well.",
    17  	}
    18  	cmd.Annotations = map[string]string{
    19  		"group": "resource",
    20  	}
    21  
    22  	cmd.AddCommand(buildBundleCreateCommand(p))
    23  	cmd.AddCommand(buildBundleBuildCommand(p))
    24  	cmd.AddCommand(buildBundleLintCommand(p))
    25  	cmd.AddCommand(buildBundleArchiveCommand(p))
    26  	cmd.AddCommand(buildBundleExplainCommand(p))
    27  	cmd.AddCommand(buildBundleCopyCommand(p))
    28  	cmd.AddCommand(buildBundleInspectCommand(p))
    29  
    30  	return cmd
    31  }
    32  
    33  func buildBundleCreateCommand(p *porter.Porter) *cobra.Command {
    34  	return &cobra.Command{
    35  		Use:   "create [bundle-name]",
    36  		Short: "Create a bundle",
    37  		Long: "Create a bundle. This command creates a new porter bundle with the specified bundle-name, in the directory with the specified bundle-name." +
    38  			" The directory will be created if it doesn't already exist. If no bundle-name is provided, the bundle will be created in current directory and the bundle name will be 'porter-hello'.",
    39  		Args: cobra.MaximumNArgs(1), // Expect at most one argument for the bundle name
    40  		RunE: func(cmd *cobra.Command, args []string) error {
    41  			if len(args) > 0 {
    42  				bundleName := args[0]
    43  				return p.CreateInDir(bundleName)
    44  			}
    45  			return p.Create()
    46  		},
    47  	}
    48  }
    49  
    50  func buildBundleBuildCommand(p *porter.Porter) *cobra.Command {
    51  	opts := porter.BuildOptions{}
    52  
    53  	cmd := &cobra.Command{
    54  		Use:   "build",
    55  		Short: "Build a bundle",
    56  		Long: `Builds the bundle in the current directory by generating a Dockerfile and a CNAB bundle.json, and then building the bundle image.
    57  
    58  The docker driver builds the bundle image using the local Docker host. To use a remote Docker host, set the following environment variables:
    59    DOCKER_HOST (required)
    60    DOCKER_TLS_VERIFY (optional)
    61    DOCKER_CERT_PATH (optional)
    62  '
    63  `,
    64  		Example: `  porter build
    65    porter build --name newbuns
    66    porter build --version 0.1.0
    67    porter build --file path/to/porter.yaml
    68    porter build --dir path/to/build/context
    69    porter build --custom version=0.2.0 --custom myapp.version=0.1.2
    70  `,
    71  		PreRunE: func(cmd *cobra.Command, args []string) error {
    72  			return opts.Validate(p)
    73  		},
    74  		RunE: func(cmd *cobra.Command, args []string) error {
    75  			return p.Build(cmd.Context(), opts)
    76  		},
    77  	}
    78  
    79  	f := cmd.Flags()
    80  	f.BoolVar(&opts.NoLint, "no-lint", false, "Do not run the linter")
    81  	f.StringVar(&opts.Name, "name", "", "Override the bundle name")
    82  	f.StringVar(&opts.Version, "version", "", "Override the bundle version")
    83  	f.StringVarP(&opts.File, "file", "f", "",
    84  		"Path to the Porter manifest. The path is relative to the build context directory. Defaults to porter.yaml in the current directory.")
    85  	f.StringVarP(&opts.Dir, "dir", "d", "",
    86  		"Path to the build context directory where all bundle assets are located. Defaults to the current directory.")
    87  	f.StringVar(&opts.Driver, "driver", porter.BuildDriverDefault,
    88  		fmt.Sprintf("Driver for building the bundle image. Allowed values are: %s", strings.Join(porter.BuildDriverAllowedValues, ", ")))
    89  	_ = f.MarkHidden("driver") // Hide the driver flag since there aren't any choices to make right now
    90  	f.StringArrayVar(&opts.BuildArgs, "build-arg", nil,
    91  		"Set build arguments in the template Dockerfile (format: NAME=VALUE). May be specified multiple times. Max length is 5,000 characters.")
    92  	f.StringArrayVar(&opts.BuildContexts, "build-context", nil,
    93  		"Define additional build context with specified contents (format: NAME=PATH). May be specified multiple times.")
    94  	f.StringArrayVar(&opts.SSH, "ssh", nil,
    95  		"SSH agent socket or keys to expose to the build (format: default|<id>[=<socket>|<key>[,<key>]]). May be specified multiple times.")
    96  	f.StringArrayVar(&opts.Secrets, "secret", nil,
    97  		"Secret file to expose to the build (format: id=mysecret,src=/local/secret). Custom values are accessible as build arguments in the template Dockerfile and in the manifest using template variables. May be specified multiple times.")
    98  	f.BoolVar(&opts.NoCache, "no-cache", false,
    99  		"Do not use the Docker cache when building the bundle image.")
   100  	f.StringArrayVar(&opts.Customs, "custom", nil,
   101  		"Define an individual key-value pair for the custom section in the form of NAME=VALUE. Use dot notation to specify a nested custom field. May be specified multiple times. Max length is 5,000 characters when used as a build argument.")
   102  	f.BoolVar(&opts.InsecureRegistry, "insecure-registry", false,
   103  		"Don't require TLS when pulling referenced images")
   104  	f.BoolVar(&opts.PreserveTags, "preserve-tags", false, "Preserve the original tag name on referenced images")
   105  
   106  	// Allow configuring the --driver flag with build-driver, to avoid conflicts with other commands
   107  	cmd.Flag("driver").Annotations = map[string][]string{
   108  		"viper-key": {"build-driver"},
   109  	}
   110  
   111  	return cmd
   112  }
   113  
   114  func buildBundleLintCommand(p *porter.Porter) *cobra.Command {
   115  	var opts porter.LintOptions
   116  	cmd := &cobra.Command{
   117  		Use:   "lint",
   118  		Short: "Lint a bundle",
   119  		Long: `Check the bundle for problems and adherence to best practices by running linters for porter and the mixins used in the bundle.
   120  
   121  The lint command is run automatically when you build a bundle. The command is available separately so that you can just lint your bundle without also building it.`,
   122  		Example: `  porter lint
   123    porter lint --file path/to/porter.yaml
   124    porter lint --output plaintext
   125  `,
   126  		PreRunE: func(cmd *cobra.Command, args []string) error {
   127  			return opts.Validate(p.Context)
   128  		},
   129  		RunE: func(cmd *cobra.Command, args []string) error {
   130  			return p.PrintLintResults(cmd.Context(), opts)
   131  		},
   132  	}
   133  
   134  	f := cmd.Flags()
   135  	f.StringVarP(&opts.File, "file", "f", "",
   136  		"Path to the porter manifest file. Defaults to the bundle in the current directory.")
   137  	f.StringVarP(&opts.RawFormat, "output", "o", string(porter.LintDefaultFormats),
   138  		"Specify an output format.  Allowed values: "+porter.LintAllowFormats.String())
   139  
   140  	return cmd
   141  }
   142  
   143  func buildBundlePublishCommand(p *porter.Porter) *cobra.Command {
   144  
   145  	opts := porter.PublishOptions{}
   146  	cmd := cobra.Command{
   147  		Use:   "publish",
   148  		Short: "Publish a bundle",
   149  		Long: `Publishes a bundle by pushing the bundle image and bundle to a registry.
   150  
   151  Note: if overrides for registry/tag/reference are provided, this command only re-tags the bundle image and bundle; it does not re-build the bundle.`,
   152  		Example: `  porter bundle publish
   153    porter bundle publish --file myapp/porter.yaml
   154    porter bundle publish --dir myapp
   155    porter bundle publish --archive /tmp/mybuns.tgz --reference myrepo/my-buns:0.1.0
   156    porter bundle publish --tag latest
   157    porter bundle publish --registry myregistry.com/myorg
   158    porter bundle publish --autobuild-disabled
   159  		`,
   160  		PreRunE: func(cmd *cobra.Command, args []string) error {
   161  			return opts.Validate(p.Config)
   162  		},
   163  		RunE: func(cmd *cobra.Command, args []string) error {
   164  			return p.Publish(cmd.Context(), opts)
   165  		},
   166  	}
   167  
   168  	f := cmd.Flags()
   169  	f.StringVarP(&opts.File, "file", "f", "", "Path to the Porter manifest. Defaults to `porter.yaml` in the current directory.")
   170  	f.StringVarP(&opts.Dir, "dir", "d", "",
   171  		"Path to the build context directory where all bundle assets are located.")
   172  	f.StringVarP(&opts.ArchiveFile, "archive", "a", "", "Path to the bundle archive in .tgz format")
   173  	f.StringVar(&opts.Tag, "tag", "", "Override the Docker tag portion of the bundle reference, e.g. latest, v0.1.1")
   174  	f.StringVar(&opts.Registry, "registry", "", "Override the registry portion of the bundle reference, e.g. docker.io, myregistry.com/myorg")
   175  	addReferenceFlag(f, &opts.BundlePullOptions)
   176  	addInsecureRegistryFlag(f, &opts.BundlePullOptions)
   177  	f.BoolVar(&opts.Force, "force", false, "Force push the bundle to overwrite the previously published bundle")
   178  	// Allow configuring the --force flag with "force-overwrite" in the configuration file
   179  	cmd.Flag("force").Annotations = map[string][]string{
   180  		"viper-key": {"force-overwrite"},
   181  	}
   182  	f.BoolVar(&opts.AutoBuildDisabled, "autobuild-disabled", false, "Do not automatically build the bundle from source when the last build is out-of-date.")
   183  	f.BoolVar(&opts.SignBundle, "sign-bundle", false, "Sign the bundle using the configured signing plugin")
   184  	f.BoolVar(&opts.PreserveTags, "preserve-tags", false, "Preserve the original tag name on referenced images")
   185  
   186  	return &cmd
   187  }
   188  
   189  func buildBundleArchiveCommand(p *porter.Porter) *cobra.Command {
   190  
   191  	opts := porter.ArchiveOptions{}
   192  	cmd := cobra.Command{
   193  		Use:   "archive FILENAME --reference PUBLISHED_BUNDLE",
   194  		Short: "Archive a bundle from a reference",
   195  		Long:  "Archives a bundle by generating a gzipped tar archive containing the bundle, bundle image and any referenced images.",
   196  		Example: `  porter bundle archive mybun.tgz --reference ghcr.io/getporter/examples/porter-hello:v0.2.0
   197    porter bundle archive mybun.tgz --reference localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --force
   198    porter bundle archive mybun.tgz --compression NoCompression --reference ghcr.io/getporter/examples/porter-hello:v0.2.0
   199  `,
   200  		PreRunE: func(cmd *cobra.Command, args []string) error {
   201  			return opts.Validate(cmd.Context(), args, p)
   202  		},
   203  		RunE: func(cmd *cobra.Command, args []string) error {
   204  			return p.Archive(cmd.Context(), opts)
   205  		},
   206  	}
   207  
   208  	f := cmd.Flags()
   209  	addBundlePullFlags(f, &opts.BundlePullOptions)
   210  	f.StringVarP(&opts.CompressionLevel, "compression", "c", opts.GetCompressionLevelDefault(),
   211  		fmt.Sprintf("Compression level to use when creating the gzipped tar archive. Allowed values are: %s", strings.Join(opts.GetCompressionLevelAllowedValues(), ", ")))
   212  	return &cmd
   213  }