Skip to content

Commit

Permalink
cli: rpkg push surface renderstatus (#3645)
Browse files Browse the repository at this point in the history
  • Loading branch information
droot authored Nov 1, 2022
1 parent 971cb4c commit 0da1e20
Show file tree
Hide file tree
Showing 13 changed files with 153 additions and 88 deletions.
80 changes: 78 additions & 2 deletions commands/alpha/rpkg/push/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import (
"os"
"path"
"path/filepath"
"strings"

"github.com/GoogleContainerTools/kpt/internal/docs/generated/rpkgdocs"
"github.com/GoogleContainerTools/kpt/internal/errors"
"github.com/GoogleContainerTools/kpt/internal/fnruntime"
"github.com/GoogleContainerTools/kpt/internal/printer"
"github.com/GoogleContainerTools/kpt/internal/util/porch"
porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1"
Expand Down Expand Up @@ -117,7 +119,7 @@ func (r *runner) runE(cmd *cobra.Command, args []string) error {
return errors.E(op, err)
}

if err := r.client.Update(r.ctx, &porchapi.PackageRevisionResources{
pkgResources := porchapi.PackageRevisionResources{
TypeMeta: metav1.TypeMeta{
Kind: "PackageRevisionResources",
APIVersion: porchapi.SchemeGroupVersion.Identifier(),
Expand All @@ -129,12 +131,86 @@ func (r *runner) runE(cmd *cobra.Command, args []string) error {
Spec: porchapi.PackageRevisionResourcesSpec{
Resources: resources,
},
}); err != nil {
}
if err := r.client.Update(r.ctx, &pkgResources); err != nil {
return errors.E(op, err)
}
rs := pkgResources.Status.RenderStatus
if rs.Err != "" {
r.printer.Printf("Package is updated, but failed to render the package.\n")
r.printer.Printf("Error: %s\n", rs.Err)
}
if len(rs.Result.Items) > 0 {
for _, result := range rs.Result.Items {
r.printer.Printf("[RUNNING] %q \n", result.Image)
printOpt := printer.NewOpt()
if result.ExitCode != 0 {
r.printer.OptPrintf(printOpt, "[FAIL] %q\n", result.Image)
} else {
r.printer.OptPrintf(printOpt, "[PASS] %q\n", result.Image)
}
r.printFnResult(result, printOpt)
}
}
return nil
}

// printFnResult prints given function result in a user friendly
// format on kpt CLI.
func (r *runner) printFnResult(fnResult *porchapi.Result, opt *printer.Options) {
if len(fnResult.Results) > 0 {
// function returned structured results
var lines []string
for _, item := range fnResult.Results {
lines = append(lines, str(item))
}
ri := &fnruntime.MultiLineFormatter{
Title: "Results",
Lines: lines,
TruncateOutput: printer.TruncateOutput,
}
r.printer.OptPrintf(opt, "%s", ri.String())
}
}

// String provides a human-readable message for the result item
func str(i porchapi.ResultItem) string {
identifier := i.ResourceRef
var idStringList []string
if identifier != nil {
if identifier.APIVersion != "" {
idStringList = append(idStringList, identifier.APIVersion)
}
if identifier.Kind != "" {
idStringList = append(idStringList, identifier.Kind)
}
if identifier.Namespace != "" {
idStringList = append(idStringList, identifier.Namespace)
}
if identifier.Name != "" {
idStringList = append(idStringList, identifier.Name)
}
}
formatString := "[%s]"
severity := i.Severity
// We default Severity to Info when converting a result to a message.
if i.Severity == "" {
severity = "info"
}
list := []interface{}{severity}
if len(idStringList) > 0 {
formatString += " %s"
list = append(list, strings.Join(idStringList, "/"))
}
if i.Field != nil {
formatString += " %s"
list = append(list, i.Field.Path)
}
formatString += ": %s"
list = append(list, i.Message)
return fmt.Sprintf(formatString, list...)
}

func readFromDir(dir string) (map[string]string, error) {
resources := map[string]string{}
if err := filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/GoogleContainerTools/kpt
go 1.18

require (
github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20221027171429-622c0141f3d7
github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20221028161857-aa271f292cc0
github.com/bytecodealliance/wasmtime-go v0.39.0
github.com/cpuguy83/go-md2man/v2 v2.0.2
github.com/go-errors/errors v1.4.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20221027171429-622c0141f3d7 h1:WKfyM9TDvHaGJ0n98rO/U7qkPL8wAWPvLKQYNT7TNvY=
github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20221027171429-622c0141f3d7/go.mod h1:ASrhnLAL4ahTuiUJyepqcpVRXIoRMJyDs8/eSxwhgZM=
github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20221028161857-aa271f292cc0 h1:Nay/s1StXHUKyIxerpXb8o0hZUkRjrbteLO6ardI26Y=
github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20221028161857-aa271f292cc0/go.mod h1:ASrhnLAL4ahTuiUJyepqcpVRXIoRMJyDs8/eSxwhgZM=
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU=
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
Expand Down
2 changes: 1 addition & 1 deletion internal/fnruntime/fnerrors.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type ExecError struct {
func (fe *ExecError) String() string {
var b strings.Builder

errLines := &multiLineFormatter{
errLines := &MultiLineFormatter{
Title: "Stderr",
Lines: strings.Split(fe.Stderr, "\n"),
UseQuote: true,
Expand Down
17 changes: 11 additions & 6 deletions internal/fnruntime/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,10 +295,15 @@ func (fr *FunctionRunner) do(input []*yaml.RNode) (output []*yaml.RNode, err err
}
if err != nil {
var execErr *ExecError
// set exitCode to non-zero by default in case of an error.
// It will be overridden with appropriate exitCode if the function runtime returns execError.
// builtinruntime and podEvaluator function runtime do not return execError so having
// a default is important.
fnResult.ExitCode = 1
fr.fnResults.ExitCode = 1
if goerrors.As(err, &execErr) {
fnResult.ExitCode = execErr.ExitCode
fnResult.Stderr = execErr.Stderr
fr.fnResults.ExitCode = 1
}
// accumulate the results
fr.fnResults.Items = append(fr.fnResults.Items, *fnResult)
Expand Down Expand Up @@ -427,7 +432,7 @@ func printFnResult(ctx context.Context, fnResult *fnresult.Result, opt *printer.
for _, item := range fnResult.Results {
lines = append(lines, item.String())
}
ri := &multiLineFormatter{
ri := &MultiLineFormatter{
Title: "Results",
Lines: lines,
TruncateOutput: printer.TruncateOutput,
Expand All @@ -448,7 +453,7 @@ func printFnExecErr(ctx context.Context, fnErr *ExecError) {
func printFnStderr(ctx context.Context, stdErr string) {
pr := printer.FromContextOrDie(ctx)
if len(stdErr) > 0 {
errLines := &multiLineFormatter{
errLines := &MultiLineFormatter{
Title: "Stderr",
Lines: strings.Split(stdErr, "\n"),
UseQuote: true,
Expand Down Expand Up @@ -492,9 +497,9 @@ func enforcePathInvariants(nodes []*yaml.RNode) error {
return nil
}

// multiLineFormatter knows how to format multiple lines in pretty format
// MultiLineFormatter knows how to format multiple lines in pretty format
// that can be displayed to an end user.
type multiLineFormatter struct {
type MultiLineFormatter struct {
// Title under which lines need to be printed
Title string

Expand All @@ -512,7 +517,7 @@ type multiLineFormatter struct {
}

// String returns multiline string.
func (ri *multiLineFormatter) String() string {
func (ri *MultiLineFormatter) String() string {
if ri.MaxLines == 0 {
ri.MaxLines = FnExecErrorTruncateLines
}
Expand Down
6 changes: 3 additions & 3 deletions internal/fnruntime/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,13 @@ data: {foo: bar}

func TestMultilineFormatter(t *testing.T) {
type testcase struct {
ml *multiLineFormatter
ml *MultiLineFormatter
expected string
}

testcases := map[string]testcase{
"multiline should format lines and truncate": {
ml: &multiLineFormatter{
ml: &MultiLineFormatter{
Title: "Results",
Lines: []string{
"line-1",
Expand All @@ -127,7 +127,7 @@ func TestMultilineFormatter(t *testing.T) {
`,
},
"multiline should format without truncate": {
ml: &multiLineFormatter{
ml: &MultiLineFormatter{
Title: "Results",
Lines: []string{
"line-1",
Expand Down
14 changes: 7 additions & 7 deletions porch/api/generated/clientset/versioned/fake/register.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions porch/api/generated/clientset/versioned/scheme/register.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 21 additions & 22 deletions porch/api/porch/types_packagerevisions.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,27 +347,6 @@ const (
ConditionUnknown ConditionStatus = "Unknown"
)

// Result contains the structured result from an individual function
type Result struct {
// Image is the full name of the image that generates this result
// Image and Exec are mutually exclusive
Image string `json:"image,omitempty"`
// ExecPath is the the absolute os-specific path to the executable file
// If user provides an executable file with commands, ExecPath should
// contain the entire input string.
ExecPath string `json:"exec,omitempty"`
// TODO(droot): This is required for making structured results subpackage aware.
// Enable this once test harness supports filepath based assertions.
// Pkg is OS specific Absolute path to the package.
// Pkg string `yaml:"pkg,omitempty"`
// Stderr is the content in function stderr
Stderr string `json:"stderr,omitempty"`
// ExitCode is the exit code from running the function
ExitCode int `json:"exitCode"`
// Results is the list of results for the function
Results []ResultItem `json:"results,omitempty"`
}

const (
// Deprecated: prefer ResultListGVK
ResultListKind = "FunctionResultList"
Expand All @@ -380,7 +359,6 @@ const (
)

// ResultList contains aggregated results from multiple functions
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type ResultList struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand All @@ -390,6 +368,27 @@ type ResultList struct {
Items []*Result `json:"items,omitempty"`
}

// Result contains the structured result from an individual function
type Result struct {
// Image is the full name of the image that generates this result
// Image and Exec are mutually exclusive
Image string `json:"image,omitempty"`
// ExecPath is the the absolute os-specific path to the executable file
// If user provides an executable file with commands, ExecPath should
// contain the entire input string.
ExecPath string `json:"exec,omitempty"`
// TODO(droot): This is required for making structured results subpackage aware.
// Enable this once test harness supports filepath based assertions.
// Pkg is OS specific Absolute path to the package.
// Pkg string `yaml:"pkg,omitempty"`
// Stderr is the content in function stderr
Stderr string `json:"stderr,omitempty"`
// ExitCode is the exit code from running the function
ExitCode int `json:"exitCode"`
// Results is the list of results for the function
Results []ResultItem `json:"results,omitempty"`
}

// ResultItem defines a validation result
type ResultItem struct {
// Message is a human readable message. This field is required.
Expand Down
43 changes: 21 additions & 22 deletions porch/api/porch/v1alpha1/types_packagerevisions.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,27 +358,6 @@ const (
ConditionUnknown ConditionStatus = "Unknown"
)

// Result contains the structured result from an individual function
type Result struct {
// Image is the full name of the image that generates this result
// Image and Exec are mutually exclusive
Image string `json:"image,omitempty"`
// ExecPath is the the absolute os-specific path to the executable file
// If user provides an executable file with commands, ExecPath should
// contain the entire input string.
ExecPath string `json:"exec,omitempty"`
// TODO(droot): This is required for making structured results subpackage aware.
// Enable this once test harness supports filepath based assertions.
// Pkg is OS specific Absolute path to the package.
// Pkg string `yaml:"pkg,omitempty"`
// Stderr is the content in function stderr
Stderr string `json:"stderr,omitempty"`
// ExitCode is the exit code from running the function
ExitCode int `json:"exitCode"`
// Results is the list of results for the function
Results []ResultItem `json:"results,omitempty"`
}

const (
// Deprecated: prefer ResultListGVK
ResultListKind = "FunctionResultList"
Expand All @@ -391,7 +370,6 @@ const (
)

// ResultList contains aggregated results from multiple functions
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type ResultList struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand All @@ -401,6 +379,27 @@ type ResultList struct {
Items []*Result `json:"items,omitempty"`
}

// Result contains the structured result from an individual function
type Result struct {
// Image is the full name of the image that generates this result
// Image and Exec are mutually exclusive
Image string `json:"image,omitempty"`
// ExecPath is the the absolute os-specific path to the executable file
// If user provides an executable file with commands, ExecPath should
// contain the entire input string.
ExecPath string `json:"exec,omitempty"`
// TODO(droot): This is required for making structured results subpackage aware.
// Enable this once test harness supports filepath based assertions.
// Pkg is OS specific Absolute path to the package.
// Pkg string `yaml:"pkg,omitempty"`
// Stderr is the content in function stderr
Stderr string `json:"stderr,omitempty"`
// ExitCode is the exit code from running the function
ExitCode int `json:"exitCode"`
// Results is the list of results for the function
Results []ResultItem `json:"results,omitempty"`
}

// ResultItem defines a validation result
type ResultItem struct {
// Message is a human readable message. This field is required.
Expand Down
Loading

0 comments on commit 0da1e20

Please sign in to comment.