-
Notifications
You must be signed in to change notification settings - Fork 370
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
Add index add command #545
Conversation
cmd/krew/cmd/index.go
Outdated
Example: | ||
kubectl krew index add index-name index-url`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
if len(args) != 2 { |
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.
Cobra supports this natively. You can set minargs 2
cmd/krew/cmd/index.go
Outdated
|
||
err := indexoperations.AddIndex(paths.IndexBase(), args[0], args[1]) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to add index %s: %s", args[0], args[1]) |
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.
No need to print args back again
cmd/krew/cmd/index.go
Outdated
var indexAddCmd = &cobra.Command{ | ||
Use: "add", | ||
Short: "Add a new index", | ||
Long: `Configure a new index to install plugins from. |
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.
See if you can name the positional args.
Like NAME GIT_URL.
Cobra probably has facilities to do that.
Please add CLI integration tests to ./integration_test. |
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.
It's really great that you take small steps. This makes reviewing so much easier 👍!
integration_test/index_test.go
Outdated
} | ||
|
||
indexName := "foo" | ||
test.Krew("index", "add", indexName, constants.IndexURI).RunOrFail() |
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.
Add/list should have separate tests ideally.
But for this you can merge them but make sure test name reflects that. Refer to other integration tests for an idea on how to develop. We test cli scenario and behavior here.
For example you don’t test 0 args fails case here :)
integration_test/testutil_test.go
Outdated
@@ -171,6 +173,13 @@ func (it *ITest) WithIndex() *ITest { | |||
return it | |||
} | |||
|
|||
// WithMigratedIndex initializes the index and performs the index migration. |
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.
Add TODO for deletion, ditto migrateIndex.
Why don’t we use the env variable for behavior change in initializeIndex instead? Simple if can solve this but you added 2 methods to be removed for it. :)
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.
That's a good idea, I'll change it
@chriskim06 does the code handle this case?
we need sanity checks around names to ensure they don't serve path escapes. |
I didn't think about that, I'll add those checks. |
cmd/krew/cmd/index.go
Outdated
err := indexoperations.AddIndex(paths.IndexBase(), args[0], args[1]) | ||
if err != nil { | ||
return errors.Wrap(err, "failed to add index") | ||
} | ||
klog.Infoln("Successfully added index") | ||
return nil |
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.
honestly this entire func can be 1 line :)
we'd know the success from the command execution anyway, so no need to log that.
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 thought that it seemed a little nicer with some explicit validation (similar to index/receipt migration) but am fine either way. I'll remove it.
|
||
// AddIndex initializes a new index to install plugins from. | ||
func AddIndex(path, name, url string) error { | ||
if strings.ContainsAny(name, "./") { |
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.
as you might imagine this won't work on Windows
please use os.PathSeparator
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.
consider extracting this to IsValidIndexName
method and check for further things, like spaces, \
/
, .
... + add unit tests + reuse everywhere (add, delete, ...)
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.
Even easier, we could simply restrict index names to k8s resource names (see https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names). Hopefully, there is a k8s tool that we can just use?
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.
Like IsValidPathSegmentName
? Although that doesn't check \
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 start restrictive, we can relax as we need.
Honestly, something like [A-Za-z0-9_-]
is good enough and safest for now. Let's make it a method regardless as I'm intending to reuse in other places.
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.
Ah, finally found it: https://github.com/kubernetes/kubernetes/blob/fdb2cb4c8832da1499069bda918c014762d8ac05/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go#L203
If we can, let's use it. Then we get all the goodness with names starting with alpha characters.
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.
Are you 100% sure that string supports all repo names on github. If so, let's use it. If not, let's stick to something more relevant.
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.
Looks like GitHub also allows dots in repo names, i.e. [A-Za-z0-9_-.]+
. And it does not care whether a repo name starts with an alpha character or _-.
. So if we want to support everything that GitHub does, the current pattern is better.
|
||
// AddIndex initializes a new index to install plugins from. | ||
func AddIndex(path, name, url string) error { | ||
if strings.ContainsAny(name, "./") { |
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.
Even easier, we could simply restrict index names to k8s resource names (see https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names). Hopefully, there is a k8s tool that we can just use?
|
||
if err := AddIndex(tmpDir.Path("index"), indexName, localRepo); err != nil { | ||
t.Errorf("error adding index: %v", err) | ||
} |
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.
IMHO, you should also test that AddIndex
has actually done something.
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.
To do that, you can have a combined Add+List scenario.
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.
That way you can also move away from doing manual mkdir/clone in the test code.
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.
@chriskim06 What's your opinion about using the ListIndex
machinery for the assertion?
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.
Sure I can change it to use that.
cmd/krew/cmd/index.go
Outdated
if len(indexes) == 0 { | ||
klog.Info(indexoperations.NoIndexMessage) | ||
return nil | ||
} |
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 not do this here.
We can do that when user tries to query a plugin (krew install
, krew update
, krew upgrade
etc) but there's no plugins installed.
Furthermore klog isn't good for this. we probably should use fmt.Fprintf or something like that with color pkg.
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.
Also I think this command should still print an "empty table".
We need to print the output properly to stderr so it doesn't get mixed up with other stuff.
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.
Do you mean it should still print:
INDEX URL
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.
Yeah. That’s expected. Like krew list.
integration_test/index_test.go
Outdated
if !strings.Contains(string(out), indexoperations.NoIndexMessage) { | ||
t.Fatalf("expected index list to be empty:\n%s", string(out)) | ||
} |
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.
testing with messages isn't good practice, let's not do that.
the previous test was good.
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.
Ok I'll change it back
) | ||
|
||
var ( | ||
NoIndexMessage = "No index configured, run kubectl krew index add default " + constants.IndexURI + " to get started" |
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 not do this here. We should ideally implement this in cmd/krew pkg as a func PrintDefaultIndexSuggestion()
.
Index commands are for pro-users, so most users should be realizing they miss an index while using main user cmds (install, search, update etc). "index" cmds are mgmt cmds, so they ideally shouldn't print these.
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 just remove this for now then since I'm not covering the main user cmds in this PR.
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.
Yeah sgtm. We’ll handle the scenario later.
if IsValidIndexName(" ") { | ||
t.Error("name cannot contain spaces") | ||
} | ||
if IsValidIndexName("foo/bar") { | ||
t.Error("name cannot contain forward slashes") | ||
} | ||
if IsValidIndexName("foo\\bar") { | ||
t.Error("name cannot contain back slashes") | ||
} | ||
if IsValidIndexName("foo.bar") { | ||
t.Error("name cannot contain forward periods") | ||
} | ||
if !IsValidIndexName("foo") { | ||
t.Error("expected valid index name: foo") | ||
} |
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 actually would be the perfect use case for tabular tests :)
if os.IsNotExist(err) { | ||
return nil, nil |
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.
nit: now that we ensure that index/
is present on startup, this error case no longer needs to be treated in a special way.
// AddIndex initializes a new index to install plugins from. | ||
func AddIndex(path, name, url string) error { | ||
if !IsValidIndexName(name) { | ||
return errors.New("index name cannot contain path characters") |
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.
That error is no longer accurate.
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.
What about something like "index name can only contain alphanumeric characters, -, and _"
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 should just say “invalid index name”.
In a separate PR you can return an error from the validation func and wrap it here :)
|
||
if err := AddIndex(tmpDir.Path("index"), indexName, localRepo); err != nil { | ||
t.Errorf("error adding index: %v", err) | ||
} |
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.
@chriskim06 What's your opinion about using the ListIndex
machinery for the assertion?
|
||
// AddIndex initializes a new index to install plugins from. | ||
func AddIndex(path, name, url string) error { | ||
if strings.ContainsAny(name, "./") { |
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.
Looks like GitHub also allows dots in repo names, i.e. [A-Za-z0-9_-.]+
. And it does not care whether a repo name starts with an alpha character or _-.
. So if we want to support everything that GitHub does, the current pattern is better.
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.
Nice, I think we are almost there. Just smaller final nits from my side. 👍
Add success case to unit test and add initial integration test for index command
Remove test table to make it easier to read and split into separate tests for failure and success cases
Print empty index list and convert valid index name to use test tables
Co-Authored-By: Cornelius Weig <[email protected]>
Use ListIndexes in add test and fix error message
/lgtm Thanks @chriskim06 for pushing it through. I'll be making several followup PRs to clean up a few things! |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: ahmetb, chriskim06 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 |
Relatively small change. The majority of it is the test I added. I wasn't sure how to test the case where an index is added since it relies on git to clone the repo, so the only test cases I have are negative ones where the index with a name has already been configured and an invalid url is provided for the clone operation. I was thinking of using
constants.IndexURI
in a test case but didn't like that the unit test would need to be able to reach github so I didn't add it.Related issue: #483