Skip to content

Issue 16 empty envvars#18

Merged
rakyll merged 8 commits into
rakyll:masterfrom
johnlockwood-wf:issue-16-empty-envvars
Sep 19, 2016
Merged

Issue 16 empty envvars#18
rakyll merged 8 commits into
rakyll:masterfrom
johnlockwood-wf:issue-16-empty-envvars

Conversation

@johnlockwood-wf

Copy link
Copy Markdown
Contributor

Previously, If you set an environmental variable that matches an ENVPREFIX_FLAG_NAME to an empty string, it would not overwrite the flag_name in the INI file. This uses os.LookupEnv to overwrite the flag if it is set at all.

Addresses #16

Comment thread globalconf.go
// If the flags are already set, values are overwritten
// by the values in the config file. Defaults are not set
// if the flag is not in the file.
func (g *GlobalConf) ParseSet(flagSetName string, set *flag.FlagSet) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Does ParseSet need to exist at all? It is not tested and It looks like Parse will do the work as long as the flagset is registered.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Parse works on the default flag set, ParseSet works on a particular one. I don't know why Parse doesn't use ParseSet though.

I will try to rewrite a bunch of things after this PR. Thanks for pointing them out.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I stared at TestParse_GlobalAndCustom for a while to figure out how parse, which calls ParseAll was processing the custom FlagSet. Register adds the set to the flags map , which already has the default flag.CommandLine in it, and then ParseAll iterates over all the sets and parses them.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Globally registering a flagset is not always what users can do. We should leave the decision to the user. We should maybe remove registration and ParseAll rather than removing the fundamental flagset-scoped ParseSet.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't feel safe breaking the API without existing releases with semantic versioning in place, especially since I have code using globalconf in production. I think ParseSet is fine to keep, I was just a little uneasy about making a change to it without existing tests, so was looking to save the work of adding tests. Would you prefer I add tests proving it does what it says in the comment block? Now that I read that, It has a different behavior than what happens in Parse. It will overwrite already set flags.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Would you prefer I add tests proving it does what it says in the comment block?

Yes, please. I don't think this PR is where we should discuss ParseSet. It is beyond the scope. Could you please file another issue if you have more questions?

@johnlockwood-wf

johnlockwood-wf commented Sep 15, 2016

Copy link
Copy Markdown
Contributor Author

I take, from the failing ci, it that os.LookupEnv doesn't exist in Go 1.2.2.

Comment thread globalconf.go Outdated
set.VisitAll(func(f *flag.Flag) {
val := getEnv(g.EnvPrefix, flagSetName, f.Name)
if val != "" {
val, exists := getEnv(g.EnvPrefix, flagSetName, f.Name)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The second bool argument is usually called ok.

if val, ok := getEnv(...); ok {
    set.Set(f.Name, val)
    return
}

Comment thread globalconf.go Outdated

val := getEnv(g.EnvPrefix, name, f.Name)
if val != "" {
val, exists := getEnv(g.EnvPrefix, name, f.Name)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Here again. s/exists/ok.

Comment thread globalconf_test.go Outdated
}

func TestParse_GlobalWithEmptyValue(t *testing.T) {
t.Log("Given the need to test overwriting a flag with an environmental variable set to an empty string")

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Don't log this.

Use a comment block to explain.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I picked up this test explaining style from Go In Action. I saw a number of benefits to it such as when you go test -v the output looks like:

=== RUN   TestParse_GlobalWithEmptyValue
--- PASS: TestParse_GlobalWithEmptyValue (0.00s)
        globalconf_test.go:100: Given the need to test overwriting a flag with an environmental variable set to an empty string
        globalconf_test.go:101:         Reset the flags and clear the env
        globalconf_test.go:106:         Set the env var for the c flag to an empty string
        globalconf_test.go:108:         Define the c flag and parse the INI file
        globalconf_test.go:113:                 Expect flagC to an empty string and not be the value Hello World from the INI file

This helped me see where failures were happening more quickly along with educating me on what the test was doing.

Comment thread globalconf_test.go Outdated
resetForTesting("")
}

t.Log("\tSet the env var for the c flag to an empty string")

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Same here.

Comment thread globalconf_test.go Outdated
flagC := flag.String("c", "", "")

parse(t, "./testdata/global.ini", envTestPrefix)
t.Log("\t\tExpect flagC to an empty string and not be the value Hello World from the INI file")

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

same here.

Comment thread globalconf_test.go Outdated
parse(t, "./testdata/global.ini", envTestPrefix)
t.Log("\t\tExpect flagC to an empty string and not be the value Hello World from the INI file")
if *flagC != "" {
t.Errorf("\t\tflagC found %v, expected an empty string", *flagC)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

don't add \t\t. Test log is formatted nicely by the tool already.

Comment thread globalconf_test.go Outdated
parse(t, "./testdata/global.ini", envTestPrefix)
t.Log("\t\tExpect flagC to an empty string and not be the value Hello World from the INI file")
if *flagC != "" {
t.Errorf("\t\tflagC found %v, expected an empty string", *flagC)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Let's use the defacto go test formatting here.

if got, want := *flagC, ""; got != want {
    t.Errorf("got flag = %q, want empty string", got)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is nice. By the time I joined the Go projects I'm working on, the testify package was already adopted and I'm used to seeing require.Equal(t, expected, got)

Use defacto go test formatting

Move test explaination to comment block
@johnlockwood-wf

Copy link
Copy Markdown
Contributor Author

It is weird that github does not mark your comments as addressed anymore.

@rakyll

rakyll commented Sep 18, 2016

Copy link
Copy Markdown
Owner

@johnlockwood-wf, is this your first time contributing to a Google project? If so, could you review the Google CLA underneath https://cla.developers.google.com/clas and sign? Thanks!

@johnlockwood-wf

Copy link
Copy Markdown
Contributor Author

I did the individual CLA for now and am looking into if we have one of those google groups registered that I can add myself to.
I've run tests on this branch merged with the branch from #19 and the tests still pass, so I feel good about this one.

@rakyll rakyll merged commit 7afbf15 into rakyll:master Sep 19, 2016
@rakyll

rakyll commented Sep 19, 2016

Copy link
Copy Markdown
Owner

Thanks!

Looking at #19 shortly.

@johnlockwood-wf johnlockwood-wf deleted the issue-16-empty-envvars branch September 20, 2016 20:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants