Skip to content

Commit

Permalink
Allow reference as positional arg to explain/inspect (getporter#2247)
Browse files Browse the repository at this point in the history
* Allow reference as positional arg to explain/inspect

Since the inspect and explain commands operate directly on a bundle, it
makes sense to let the user specify it as a positional argument. I have
updated both commands to accept either the existing --reference flag
(for consistency with other commands and backwards compatibility) and
alow support passing the reference as the first positional argument.

So either of the following now work:

porter explain REFERENCE
porter explain --reference

I've updated the docs to prefer the form without the flag, since it's
shorter.

Signed-off-by: Carolyn Van Slyck <[email protected]>

* Update docs to use explain/inspect with positional argument

Signed-off-by: Carolyn Van Slyck <[email protected]>

* Review feedback

Signed-off-by: Carolyn Van Slyck <[email protected]>
  • Loading branch information
carolynvs authored Jul 25, 2022
1 parent 84d77e0 commit 17f1195
Show file tree
Hide file tree
Showing 21 changed files with 84 additions and 50 deletions.
6 changes: 3 additions & 3 deletions cmd/porter/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions cmd/porter/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ 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.
If you would like more information about the bundle, the porter explain command will provide additional information,
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
`,
Expand Down
2 changes: 1 addition & 1 deletion docs/content/archive-bundles.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions docs/content/bundle/create.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions docs/content/cli/bundles_explain.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions docs/content/cli/bundles_inspect.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions docs/content/cli/explain.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions docs/content/cli/inspect.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/content/examine-bundles.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/content/examples/hello.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions docs/content/inspect-bundles.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/content/plugin-tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/.
Expand Down
4 changes: 2 additions & 2 deletions docs/content/quickstart/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/content/quickstart/credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/content/quickstart/desired-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/content/quickstart/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/content/slides/cnab-unpacked/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 6 additions & 4 deletions pkg/porter/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
22 changes: 22 additions & 0 deletions pkg/porter/explain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,35 @@ 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"
"github.com/stretchr/testify/assert"
"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()
Expand Down
4 changes: 4 additions & 0 deletions pkg/printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
30 changes: 18 additions & 12 deletions pkg/printer/printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
})
}
Expand Down

0 comments on commit 17f1195

Please sign in to comment.