Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set non-zero exit code for invalid manifests #62

Closed
wants to merge 2 commits into from

Conversation

MaGaroo
Copy link
Contributor

@MaGaroo MaGaroo commented Jul 6, 2023

Hi!
This PR is supposed to resolve #61

I also refactored a small part of the code in order to remove redundancy in the print section.
I'd be glad if you could review these changes.

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: MaGaroo
Once this PR has been reviewed and has the lgtm label, please assign richabanker for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Jul 6, 2023
@k8s-ci-robot k8s-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Jul 6, 2023
@@ -10,6 +9,6 @@ import (
func main() {
rootCmd := cmd.NewRootCommand()
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that we're not going to print the errors anymore?

Copy link
Contributor Author

@MaGaroo MaGaroo Jul 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cobra prints the error itself. I think we should either print the error manually and set SilenceError attribute in cobra.Command or not print the error explicitly and let cobra print it for us.

pkg/cmd/validate.go Show resolved Hide resolved
data, e := json.MarshalIndent(res, "", " ")
if e != nil {
return fmt.Errorf("failed to render results into JSON: %w", e)
if err := printJsonErrors(filesErrors, cmd.OutOrStdout(), cmd.ErrOrStderr()); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

json.Marshal is stable since it sorts the keys, so this is not going to change the behavior, but printHumanErrors is now going to show files in a random order. Not sure how much it matters but I wanted to point that out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently not sure about the best approach, but wanted to note another change in behavior of human formatter.
Previously, if a file had occurred twice in the args, human output printed it twice too. Now, it only prints its errors once.

Comment on lines +208 to +212
if filesErrors.hasError() {
return errors.New("found some errors in the manifests")
} else {
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super excited about that.

Something you could do is:

  1. Give FilesErrors a "Append" function that supports self being nil
  2. return the instance here without checking for nil, nor creating a dummy error

So probably something like this:

type Error struct {
    path string
    err error
}

type FilesErrors []Error

func (e *FilesError) Append(path string, err error) *FilesError {
    if err == nil {
        return e
    } 
    return append(e, Error{path: path, err: err})
}

func (e *FilesError) Error(format string) string {
    // print according to format, can call separate functions if needed.
}

... // In Run()
var errs *FileErrors // Get a nil pointer to errors
for _, path := range files {
    errs = errs.Append(path, ValidateFile(path, factory))
}
...
return errs // Will be null if we've never added any error.

... // in main()
if err := rootCmd.Execute(); err != nil {
    fmt.Fprintln(os.Stderr, err.Error(rootCmd.outputFormat))
    os.Exit(1)
}

I think this has a lot less conditions to keep track of.

Copy link
Contributor Author

@MaGaroo MaGaroo Jul 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I generally agree, but there are some concerns. I start with two of them which are the most important ones:

First, each file can contain multiple documents.1 ValidateFile function generates an error (possibly nil) for each document and returns a list of errors. 2 So, it's important to keep track of nil errors as json formatter needs it.

Second, in order for the FilesErrors type to be considered a golang error, we have to implement Error method without any arguments. So, what's your opinion about declaring FilesErrors as a struct with errors and outputFormat fields, and using outputFormat field to implement the logic of Error() method?

Footnotes

  1. It runs ValidateDocument over all documents of the file, which returns exactly one error per document. So, ValidateFile returns a slice containing those errors, i'th error for the i'th document.

  2. I think the human output is a little ambiguous when a file contains multiple documents. For example, if the first and third documents in a file have an error and the second document is sane, the human formatter prints the first and third errors and prints nothing about the sanity of the second document. However, this issue is out of scope and I intended to address it in another issue/pr.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, code freeze in k/k is approaching and I lost track of that.

Yeah, I made the invalid assumption that we weren't printing anything if there was no error.
Considering that, I don't see how we can return a relevant error out of the Run method, maybe it's fine to just os.Exit directly from it, and always return nil when no errors occur?

Copy link
Contributor

@alexzielenski alexzielenski Jul 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer for the cobra command to return an errors.Join of a slice of the Error type @apelisse posted above, then in main we can exit if the execution returns non-nil error.

@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 28, 2023
@k8s-ci-robot
Copy link
Contributor

PR needs rebase.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@alexzielenski
Copy link
Contributor

I've opened up #63 since this PR has gotten stale and this change is super high priority.

after that merges you may like it keep working on your refactoring, or close this PR

@MaGaroo
Copy link
Contributor Author

MaGaroo commented Aug 24, 2023

Sorry for the delay, for some reason I didn't receive any notification about this PR.
So, if it is completed, should we close this PR, or is there anything I can do?

@apelisse apelisse closed this Aug 24, 2023
@apelisse
Copy link
Contributor

I think we can close, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

invalid manifest doesn't return non-zero exit code
4 participants