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 }