-
Notifications
You must be signed in to change notification settings - Fork 372
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
Make files in spec.platforms[]
optional
#261
Make files in spec.platforms[]
optional
#261
Conversation
Codecov Report
@@ Coverage Diff @@
## master #261 +/- ##
==========================================
+ Coverage 54.98% 55.66% +0.67%
==========================================
Files 19 19
Lines 902 918 +16
==========================================
+ Hits 496 511 +15
- Misses 354 355 +1
Partials 52 52
Continue to review full report at Codecov.
|
docs/DEVELOPER_GUIDE.md
Outdated
the root of your plugin, use the default: | ||
|
||
```yaml | ||
files: [] # same as [{from: "*", to: "."}] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. I think empty list should not be treated as unspecified (nil
) field.
Empty means do nothing, which a valid operation, but it shouldn't be allowed since it does not make sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the differentiation between empty and nil a programming language subtlety? From a user's perspective both cases mean "no rules given". And here I think we are complicating things if we make that distinction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll move this to main thread.
docs/DEVELOPER_GUIDE.md
Outdated
files: [] # same as [{from: "*", to: "."}] | ||
``` | ||
|
||
The resulting installation directory would eventually contain: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would copy out binaries for both platforms to the installation directory on user’s machine, despite only one of them will be used.
pkg/index/validate.go
Outdated
@@ -90,8 +90,13 @@ func (p Platform) Validate() error { | |||
if p.Bin == "" { | |||
return errors.New("bin has to be set") | |||
} | |||
if len(p.Files) == 0 { | |||
return errors.New("can't have a plugin without specifying file operations") | |||
for _, fo := range p.Files { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's extract this to a new method that we can unit-test, just like ValidatePlatform above.
pkg/index/validate.go
Outdated
@@ -90,8 +90,13 @@ func (p Platform) Validate() error { | |||
if p.Bin == "" { | |||
return errors.New("bin has to be set") | |||
} | |||
if len(p.Files) == 0 { | |||
return errors.New("can't have a plugin without specifying file operations") | |||
for _, fo := range p.Files { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let’s add a check that verifies nil
is ok for p.Files (you should make this Files
field a pointer like *[]FileOperaton first I think to distinguish between nil
and empty []
) AND validate that empty is not allowed and should not be defaulted.
pkg/installation/util.go
Outdated
return version, uri, p.Files, p.Bin, nil | ||
files := p.Files | ||
if len(files) == 0 { | ||
files = []index.FileOperation{{From: "*", To: "."}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
worth adding a glog.V(4) here saying file operation not specified, assuming %v
pkg/installation/util_test.go
Outdated
wantBin: "kubectl-foo", | ||
wantErr: false, | ||
}, { | ||
name: "Find Matching Platform with default files", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...with FileOperations unspecified
or ...defaulted
Overall looks good. I think we just need to distinguish clearly between unspecified (null) and empty ([]) while allowing one and failing on another. |
Sadly, no. This is independent of programming language. More obvious examples of this can be seen in Kubernetes API design. For example, in Kubernetes NetworkPolicy API, specifying Let's play safe in this case and (1) distinguish nil and default on that (2) validate error on empty array. Here's another reason to play safe: We can start with defaulting on just I prefer to err on being more restrictive and being more lenient only if there's a need. |
Ok, that forward compatibility argument is convincing. I'll address the nil vs empty issue, but I'll need a few days due to other obligations. |
Haha sorry I caused merge conflicts everywhere. Now that we have proper validation on |
b9a58c3
to
dfc1a2e
Compare
/hold |
dfc1a2e
to
946b1bf
Compare
/hold cancel |
Rebase is finally done. I added a new validation case which forbids empty file operations now. The difference between empty and unspecified is quite subtle though (this comes from our yaml library): ...
bin: foo-amd64
files: # present, but no values is equivalent to ...
bin: foo-amd64
# files: <- not present Whereas this triggers the error case: ...
bin: foo-amd64
files: [] |
I think it's ok to treat unspecified and |
docs/DEVELOPER_GUIDE.md
Outdated
└── krew-foo-windows.exe | ||
``` | ||
- To copy all files in the `bin/` directory of the extracted archive to | ||
the root of your plugin, use the default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, to use the default, maybe they shouldn't need to specify files:
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, my thinking was to keep the two examples as similar as possible. But I agree that this looks odd. I changed the wording.
pkg/index/validation/validate.go
Outdated
} | ||
for _, op := range fops { | ||
if op.From == "" { | ||
return errors.New("from field has to be set") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we say "from" and "to" (below) to distinguish field names from the rest of the error message. especially below it says to ... to be set
so it's a bit confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I enclosed field names in backticks. To be consistent, I did the same for other error messages.
@@ -190,8 +190,8 @@ func TestValidatePlatform(t *testing.T) { | |||
wantErr: true, | |||
}, | |||
{ | |||
name: "no file operations", | |||
platform: testutil.NewPlatform().WithFiles(nil).V(), | |||
name: "empty file operations", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you also add WithFiles(nil) case (wantErr:false
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those test cases are covered by Test_validateFiles
. I only included this error case in this test, to check if files are validated at all. Do you think this is not enough?
pkg/installation/util.go
Outdated
uri = p.URI | ||
sha256sum = p.Sha256 | ||
|
||
files := p.Files | ||
if len(files) == 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm removing this method (getDownloadTarget
) soon as part of #293.
I think we should consider a method like func applyDefaults(*index.Platform)
to achieve defaulting on the FileOperations. Are you open to such a method, that's easily testable etc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In principle, I like the idea. However, I didn't find a good spot for this. The best place is close to validation, but there we pass in a copy of the plugin object which loses any mutations. And I didn't want to put this into ReadPluginFile
.
So I ended up, putting it in moveToInstallDir
. Not ideal, though..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's why we should call applyDefaults(&plugin)
right before we do moveToInstallDir. Then we can do moveToInstallDir(..., plugin.Files)
.
Don't move inside moveToInstallDir
as the name indicates, it's not expected to do defaulting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I moved the logic one level up into install
. Also, I added a unit test for applyDefaults
.
If unspecified, default to `{From: "*", To: "."}`. When `files` is given, but empty, an error is produced instead. Also validate that files specification has both fields set.
946b1bf
to
e9e84d0
Compare
- Improve readability of error messages.
e9e84d0
to
f357807
Compare
}, | ||
{ | ||
name: "no defaults for other fields", | ||
platform: testutil.NewPlatform().WithBin("").WithOS("").WithSelector(nil).WithSHA256("").WithURI("").V(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh boy this test is gonna be a problem in the future.
because we will keep adding defaults to testutil.NewPlatform(), and we will keep adding new WithXxx.
let's keep it until it breaks.
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: ahmetb, corneliusweig The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Many plugins use the pattern to copy all files from the archive into the installation directory. Those plugins always have to specify a file copy operation such as
This PR makes the files field completely optional and defaults to the above copy specifier. As discussed in #135, the default copy spec may install too many files. The plugin developer docs therefore explicitly show such an antipattern example.
Close #135