diff --git a/cmd/porter/explain.go b/cmd/porter/explain.go index 39fcedfdb..d7500e10e 100644 --- a/cmd/porter/explain.go +++ b/cmd/porter/explain.go @@ -9,12 +9,12 @@ func buildBundleExplainCommand(p *porter.Porter) *cobra.Command { opts := porter.ExplainOpts{} cmd := cobra.Command{ - Use: "explain", + Use: "explain REFERENCE", Short: "Explain a bundle", Long: "Explain how to use a bundle by printing the parameters, credentials, outputs, actions.", Example: ` porter bundle explain - porter bundle explain --reference ghcr.io/getporter/examples/porter-hello:v0.2.0 - porter bundle explain --reference localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force + porter bundle explain ghcr.io/getporter/examples/porter-hello:v0.2.0 + porter bundle explain localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force porter bundle explain --file another/porter.yaml porter bundle explain --cnab-file some/bundle.json porter bundle explain --action install diff --git a/cmd/porter/inspect.go b/cmd/porter/inspect.go index 238c3db0e..6315eb67c 100644 --- a/cmd/porter/inspect.go +++ b/cmd/porter/inspect.go @@ -8,7 +8,7 @@ import ( func buildBundleInspectCommand(p *porter.Porter) *cobra.Command { opts := porter.ExplainOpts{} cmd := cobra.Command{ - Use: "inspect", + Use: "inspect REFERENCE", Short: "Inspect a bundle", Long: `Inspect a bundle by printing the invocation images and any related images images. @@ -16,8 +16,8 @@ If you would like more information about the bundle, the porter explain command like parameters, credentials, outputs and custom actions available. `, Example: ` porter bundle inspect - porter bundle inspect --reference ghcr.io/getporter/examples/porter-hello:v0.2.0 - porter bundle inspect --reference localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force + porter bundle inspect ghcr.io/getporter/examples/porter-hello:v0.2.0 + porter bundle inspect localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force porter bundle inspect --file another/porter.yaml porter bundle inspect --cnab-file some/bundle.json `, diff --git a/docs/content/archive-bundles.md b/docs/content/archive-bundles.md index 63ed609e2..8af458c0d 100644 --- a/docs/content/archive-bundles.md +++ b/docs/content/archive-bundles.md @@ -74,7 +74,7 @@ Bundle tag jrrporter.azurecr.io/do-porter-from-archive:1.0.0 pushed successfully This command will expand the bundle archive and copy each image up to the new registry. Once complete, you can use the bundle like any other published bundle: ``` -porter explain --reference jrrporter.azurecr.io/do-porter-from-archive:1.0.0 +porter explain jrrporter.azurecr.io/do-porter-from-archive:1.0.0 Name: spring-music Description: Run the Spring Music Service on Kubernetes and Digital Ocean PostgreSQL Version: 0.5.0 diff --git a/docs/content/bundle/create.md b/docs/content/bundle/create.md index 5242ad636..936a85e0d 100644 --- a/docs/content/bundle/create.md +++ b/docs/content/bundle/create.md @@ -165,8 +165,8 @@ version: 0.3.0 Once you have figured out the reference to your published bundle, the best way to verify that it was published successfully is with the [porter explain] command: ```console -# porter explain --reference|-r REFERENCE -$ porter explain -r ghcr.io/getporter/porter-hello:v0.2.0 +# porter explain REFERENCE +$ porter explain ghcr.io/getporter/porter-hello:v0.2.0 ``` ## Next Steps diff --git a/docs/content/cli/bundles_explain.md b/docs/content/cli/bundles_explain.md index ee5a47586..12ec07488 100644 --- a/docs/content/cli/bundles_explain.md +++ b/docs/content/cli/bundles_explain.md @@ -12,15 +12,15 @@ Explain a bundle Explain how to use a bundle by printing the parameters, credentials, outputs, actions. ``` -porter bundles explain [flags] +porter bundles explain REFERENCE [flags] ``` ### Examples ``` porter bundle explain - porter bundle explain --reference ghcr.io/getporter/examples/porter-hello:v0.2.0 - porter bundle explain --reference localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force + porter bundle explain ghcr.io/getporter/examples/porter-hello:v0.2.0 + porter bundle explain localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force porter bundle explain --file another/porter.yaml porter bundle explain --cnab-file some/bundle.json porter bundle explain --action install diff --git a/docs/content/cli/bundles_inspect.md b/docs/content/cli/bundles_inspect.md index 955223421..0c9d788b4 100644 --- a/docs/content/cli/bundles_inspect.md +++ b/docs/content/cli/bundles_inspect.md @@ -16,15 +16,15 @@ like parameters, credentials, outputs and custom actions available. ``` -porter bundles inspect [flags] +porter bundles inspect REFERENCE [flags] ``` ### Examples ``` porter bundle inspect - porter bundle inspect --reference ghcr.io/getporter/examples/porter-hello:v0.2.0 - porter bundle inspect --reference localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force + porter bundle inspect ghcr.io/getporter/examples/porter-hello:v0.2.0 + porter bundle inspect localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force porter bundle inspect --file another/porter.yaml porter bundle inspect --cnab-file some/bundle.json diff --git a/docs/content/cli/explain.md b/docs/content/cli/explain.md index 47d09fe63..200ea78da 100644 --- a/docs/content/cli/explain.md +++ b/docs/content/cli/explain.md @@ -12,15 +12,15 @@ Explain a bundle Explain how to use a bundle by printing the parameters, credentials, outputs, actions. ``` -porter explain [flags] +porter explain REFERENCE [flags] ``` ### Examples ``` porter explain - porter explain --reference ghcr.io/getporter/examples/porter-hello:v0.2.0 - porter explain --reference localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force + porter explain ghcr.io/getporter/examples/porter-hello:v0.2.0 + porter explain localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force porter explain --file another/porter.yaml porter explain --cnab-file some/bundle.json porter explain --action install diff --git a/docs/content/cli/inspect.md b/docs/content/cli/inspect.md index 11fb85bfc..7737eada3 100644 --- a/docs/content/cli/inspect.md +++ b/docs/content/cli/inspect.md @@ -16,15 +16,15 @@ like parameters, credentials, outputs and custom actions available. ``` -porter inspect [flags] +porter inspect REFERENCE [flags] ``` ### Examples ``` porter inspect - porter inspect --reference ghcr.io/getporter/examples/porter-hello:v0.2.0 - porter inspect --reference localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force + porter inspect ghcr.io/getporter/examples/porter-hello:v0.2.0 + porter inspect localhost:5000/ghcr.io/getporter/examples/porter-hello:v0.2.0 --insecure-registry --force porter inspect --file another/porter.yaml porter inspect --cnab-file some/bundle.json diff --git a/docs/content/examine-bundles.md b/docs/content/examine-bundles.md index 32213430f..3202c8f4e 100644 --- a/docs/content/examine-bundles.md +++ b/docs/content/examine-bundles.md @@ -8,7 +8,7 @@ aliases: Once a bundle has been built, how do users of the bundle figure out how to actually _use_ it? A user could read the `porter.yaml` or the `bundle.json` if they have the bundle locally, but this won't work for a bundle that has been published to an OCI registry. Even when you have them locally, the `bundle.json` and `porter.yaml` aren't the best way to figure out how to use a bundle. How should a user examine the bundle then? Porter has a command called `explain` to help with this! ```bash -$ porter explain --reference jeremyrickard/porter-do-bundle:v1.0.0 +$ porter explain jeremyrickard/porter-do-bundle:v1.0.0 Name: spring-music Description: Run the Spring Music Service on Kubernetes and Digital Ocean PostgreSQL Version: 1.0.0 diff --git a/docs/content/examples/hello.md b/docs/content/examples/hello.md index 998013435..9d5bc0a88 100644 --- a/docs/content/examples/hello.md +++ b/docs/content/examples/hello.md @@ -14,7 +14,7 @@ This is the default bundle generated for you when you run `porter create`. 1. Use `porter explain` to see what is included in the bundle and how to use it. ```console - porter explain --reference ghcr.io/getporter/examples/porter-hello:v0.2.0 + porter explain ghcr.io/getporter/examples/porter-hello:v0.2.0 ``` 1. Install the bundle diff --git a/docs/content/inspect-bundles.md b/docs/content/inspect-bundles.md index 1fe51b9b2..a079d7f0b 100644 --- a/docs/content/inspect-bundles.md +++ b/docs/content/inspect-bundles.md @@ -10,8 +10,8 @@ You've found a bundle that you'd like to use, but you'd like to what images will When a bundle is published, the images that it will use are copied into the location of the published bundle. This simplifies access control and management of artifacts in the repository. The `inspect` command will show the invocation images, as well as any referenced images, that will be used as a result of performing actions like install nad upgrade. For each image, you will see the image reference that will be used, along with the original image reference that the image was copied from. -```bash -$ porter inspect --reference jeremyrickard/porter-do-bundle:v1.0.0 +```console +$ porter inspect jeremyrickard/porter-do-bundle:v1.0.0 Name: spring-music Description: Run the Spring Music Service on Kubernetes and Digital Ocean PostgreSQL Version: 1.0.0 @@ -27,8 +27,8 @@ spring-music docker jeremyrickard/porter-do-bundle@sha256:8f1133d81f1b078c86 With the image information above, you can use existing tooling to pull, inspect and vet the images before you run the bundle. If you copy or archive and then republish a bundle, the image information will reflect the new locations of the images, allowing you to compare between the source and the new bundle as well. This is especially useful when used with bundles that have been re-published from an archive: -``` -porter inspect --reference jrrporter.azurecr.io/do-porter-from-archive:1.0.0 +```console +$ porter inspect jrrporter.azurecr.io/do-porter-from-archive:1.0.0 Name: spring-music Description: Run the Spring Music Service on Kubernetes and Digital Ocean PostgreSQL Version: 1.0.0 diff --git a/docs/content/plugin-tutorial.md b/docs/content/plugin-tutorial.md index 767ecf12b..1f11d7515 100644 --- a/docs/content/plugin-tutorial.md +++ b/docs/content/plugin-tutorial.md @@ -219,7 +219,7 @@ We will use the `ghcr.io/getporter/examples/plugins-tutorial:v0.2.0` bundle, let explain` to see what credentials are necessary. ```console -$ porter explain --reference ghcr.io/getporter/examples/plugins-tutorial:v0.2.0 +$ porter explain ghcr.io/getporter/examples/plugins-tutorial:v0.2.0 Name: plugins-tutorial Description: Example of porter resolving credentials from a secrets store using a plugin. This bundle is a companion for the plugin tutorial at https://getporter.org/plugins/tutorial/. diff --git a/docs/content/quickstart/_index.md b/docs/content/quickstart/_index.md index 14e342ee0..c68b62c45 100644 --- a/docs/content/quickstart/_index.md +++ b/docs/content/quickstart/_index.md @@ -37,7 +37,7 @@ Use this command to see: * dependencies of the bundle ```console -$ porter explain --reference getporter/wordpress:v0.1.3 +$ porter explain getporter/wordpress:v0.1.3 Name: wordpress Description: Version: 0.1.3 @@ -64,7 +64,7 @@ mysql getporter/mysql:v0.1.3 For this quickstart we are going to use the hello world bundle which is a bit simpler: ```console -$ porter explain --reference ghcr.io/getporter/examples/porter-hello:v0.2.0 +$ porter explain ghcr.io/getporter/examples/porter-hello:v0.2.0 Name: HELLO Description: An example Porter configuration Version: 0.1.0 diff --git a/docs/content/quickstart/credentials.md b/docs/content/quickstart/credentials.md index e4c20a124..2b459d409 100644 --- a/docs/content/quickstart/credentials.md +++ b/docs/content/quickstart/credentials.md @@ -24,7 +24,7 @@ Depending on the bundle, a credential can apply to all actions (install/upgrade/ Let's look at a bundle with credentials: ```console -$ porter explain --reference ghcr.io/ghcr.io/getporter/examples/credentials-tutorial:v0.3.0 +$ porter explain ghcr.io/ghcr.io/getporter/examples/credentials-tutorial:v0.3.0 Name: examples/credentials-tutorial Description: An example Porter bundle with credentials. Uses your GitHub token to retrieve your public user profile from GitHub. Version: 0.3.0 diff --git a/docs/content/quickstart/desired-state.md b/docs/content/quickstart/desired-state.md index 1033d18fc..2009bbb73 100644 --- a/docs/content/quickstart/desired-state.md +++ b/docs/content/quickstart/desired-state.md @@ -14,7 +14,7 @@ This QuickStart walks you through how to manage credential sets, parameter sets First, let's look at the bundle used in this QuickStart. ```console -$ porter explain --reference ghcr.io/getporter/examples/credentials-tutorial:v0.3.0 +$ porter explain ghcr.io/getporter/examples/credentials-tutorial:v0.3.0 Name: examples/credentials-tutorial Description: An example Porter bundle with credentials. Uses your GitHub token to retrieve your public user profile from GitHub. Version: 0.3.0 diff --git a/docs/content/quickstart/parameters.md b/docs/content/quickstart/parameters.md index 824c26087..2071f025d 100644 --- a/docs/content/quickstart/parameters.md +++ b/docs/content/quickstart/parameters.md @@ -18,7 +18,7 @@ For optional parameters, bundles set a default value that is used when the user Let's look at a bundle with parameters: ```console -$ porter explain --reference getporter/hello-llama:v0.1.1 +$ porter explain getporter/hello-llama:v0.1.1 Name: hello-llama Description: An example Porter bundle with parameters Version: 0.1.0 diff --git a/docs/content/slides/cnab-unpacked/index.md b/docs/content/slides/cnab-unpacked/index.md index 28b1f7460..38009aaa9 100644 --- a/docs/content/slides/cnab-unpacked/index.md +++ b/docs/content/slides/cnab-unpacked/index.md @@ -114,7 +114,7 @@ class: middle # Get ready... ``` -$ porter explain --reference deislabs/tron:v1.0 +$ porter explain deislabs/tron:v1.0 name: Tron description: The classic game of light cycles and disc wars diff --git a/pkg/porter/explain.go b/pkg/porter/explain.go index 68f9d09dd..61c561661 100644 --- a/pkg/porter/explain.go +++ b/pkg/porter/explain.go @@ -130,12 +130,14 @@ func (s SortPrintableAction) Swap(i, j int) { } func (o *ExplainOpts) Validate(args []string, pctx *portercontext.Context) error { - err := o.validateInstallationName(args) - if err != nil { - return err + // Allow reference to be specified as a positional argument, or using --reference + if len(args) == 1 { + o.Reference = args[0] + } else if len(args) > 1 { + return fmt.Errorf("only one positional argument may be specified, the bundle reference, but multiple were received: %s", args) } - err = o.bundleFileOptions.Validate(pctx) + err := o.bundleFileOptions.Validate(pctx) if err != nil { return err } diff --git a/pkg/porter/explain_test.go b/pkg/porter/explain_test.go index 8a7c58845..d1023454e 100644 --- a/pkg/porter/explain_test.go +++ b/pkg/porter/explain_test.go @@ -6,6 +6,7 @@ import ( "get.porter.sh/porter/pkg/cnab" depsv1 "get.porter.sh/porter/pkg/cnab/dependencies/v1" + "get.porter.sh/porter/pkg/portercontext" "get.porter.sh/porter/pkg/test" "github.com/cnabio/cnab-go/bundle" "github.com/cnabio/cnab-go/bundle/definition" @@ -13,6 +14,27 @@ import ( "github.com/stretchr/testify/require" ) +func TestExplain_ValidateReference(t *testing.T) { + const ref = "ghcr.io/getporter/examples/porter-hello:v0.2.0" + t.Run("--reference specified", func(t *testing.T) { + porterCtx := portercontext.NewTestContext(t) + opts := ExplainOpts{} + opts.Reference = ref + + err := opts.Validate(nil, porterCtx.Context) + require.NoError(t, err, "Validate failed") + assert.Equal(t, ref, opts.Reference) + }) + t.Run("reference positional argument specified", func(t *testing.T) { + porterCtx := portercontext.NewTestContext(t) + opts := ExplainOpts{} + + err := opts.Validate([]string{ref}, porterCtx.Context) + require.NoError(t, err, "Validate failed") + assert.Equal(t, ref, opts.Reference) + }) +} + func TestExplain_validateBadFormat(t *testing.T) { p := NewTestPorter(t) defer p.Close() diff --git a/pkg/printer/printer.go b/pkg/printer/printer.go index a035752b1..95dae3328 100644 --- a/pkg/printer/printer.go +++ b/pkg/printer/printer.go @@ -32,6 +32,10 @@ func (p *PrintOptions) ParseFormat() error { case FormatJson, FormatYaml, FormatPlaintext: p.Format = format return nil + case "": + // This helps us out in our unit tests, defaulting the output to plaintext + p.Format = FormatPlaintext + return nil default: return fmt.Errorf("invalid format: %s", p.RawFormat) } diff --git a/pkg/printer/printer_test.go b/pkg/printer/printer_test.go index bc4f9597c..18b062213 100644 --- a/pkg/printer/printer_test.go +++ b/pkg/printer/printer_test.go @@ -3,30 +3,36 @@ package printer import ( "testing" + "get.porter.sh/porter/tests" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestParseFormat(t *testing.T) { - testcases := map[string]bool{ - "plaintext": true, - "json": true, - "human": false, + testcases := []struct { + rawFormat string + wantFormat Format + wantErr string + }{ + {rawFormat: "plaintext", wantFormat: FormatPlaintext}, + {rawFormat: "json", wantFormat: FormatJson}, + {rawFormat: "yaml", wantFormat: FormatYaml}, + {rawFormat: "", wantFormat: FormatPlaintext}, + {rawFormat: "human", wantErr: "invalid format"}, } - for name, valid := range testcases { - t.Run(name, func(t *testing.T) { + for _, tc := range testcases { + t.Run(tc.rawFormat, func(t *testing.T) { opts := PrintOptions{ - RawFormat: name, + RawFormat: tc.rawFormat, } err := opts.ParseFormat() - if valid { - require.Nil(t, err) - require.Equal(t, name, string(opts.Format)) + if tc.wantErr == "" { + require.NoError(t, err) + require.Equal(t, tc.wantFormat, opts.Format, "incorrect format was returned by ParseFormat") } else { - require.NotNil(t, err) - require.Contains(t, err.Error(), "invalid format") + tests.RequireErrorContains(t, err, tc.wantErr, "unexpected error returned by ParseFormat") } }) }