Add a flag --init to write a default config (#81)

## Summary:
Steve pointed out (#73) that having genqlient with no arguments silently
use a default config file was a bit confusing, and changed it to use
`genqlient.yaml` by default (#74).  Mark pointed out (#76) that this
makes it a bit less convenient when you're starting from scratch; you
have to go create a config file.  In this commit I add a new init flag
that creates you a config file before using it.

Originally the suggestion was to use subcommands, e.g. we'd have
`genqlient init` and `genqlient generate` and so on.  But I couldn't
think of anything else we might want subcommands for in the future, and
it felt a little silly to make you type `generate` each time.  So
instead, I made it a flag, which has the nice property that you can do
`genqlient --init` and it will generate and then use a config file.  (I
mean, maybe it will immediately crash because you don't have a schema,
but hopefully that's still a useful clue as to what to do next!)  The
implmentation was fairly trivial.

Since we now have a nice way to generate a default config, I removed the
default values for most of the options; I've always felt they were
probably more confusing than helpful.  (And indeed, all the users I know
of (Khan/webapp, and the much smaller project Steve was working on, are
setting those options explicitly.)  This required a slight change to
the syntax to say "don't use context", which is probably also net clearer.

I decided this is also a good time to pull in a proper CLI parser (#31);
see ADR-504 for more on that choice.  This also adds some nice help
messages!

Fixes #76, #31.

Issue: https://github.com/Khan/genqlient/issues/76

## Test plan:
```
go run .
go run . --init
go run . --init example/genqlient.yaml     # refuses to clobber
go run . --init example/newgenqlient.yaml
```


Author: benjaminjkraft

Reviewers: dnerdy, aberkan, MiguelCastillo, StevenACoffman

Required Reviewers: 

Approved By: dnerdy

Checks:  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Lint,  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Lint

Pull Request URL: https://github.com/Khan/genqlient/pull/81
This commit is contained in:
Ben Kraft
2021-09-10 15:49:54 -07:00
committed by GitHub
parent 9e1c98488e
commit dc38360d9d
10 changed files with 108 additions and 64 deletions
+30 -16
View File
@@ -10,6 +10,7 @@ import (
"testing"
"github.com/Khan/genqlient/internal/testutil"
"gopkg.in/yaml.v2"
)
const (
@@ -80,6 +81,7 @@ func TestGenerate(t *testing.T) {
Package: "test",
Generated: goFilename,
ExportOperations: queriesFilename,
ContextType: "-",
Bindings: map[string]*TypeBinding{
"ID": {Type: "github.com/Khan/genqlient/internal/testutil.ID"},
"DateTime": {Type: "time.Time"},
@@ -120,6 +122,22 @@ func TestGenerate(t *testing.T) {
}
}
func defaultConfig(t *testing.T) *Config {
// Parse the config that `genqlient --init` generates, to make sure that
// works.
var config Config
b, err := ioutil.ReadFile("default_genqlient.yaml")
if err != nil {
t.Fatal(err)
}
err = yaml.UnmarshalStrict(b, &config)
if err != nil {
t.Fatal(err)
}
return &config
}
// TestGenerateWithConfig tests several configuration options that affect
// generated code but don't require particular query structures to test.
//
@@ -131,24 +149,20 @@ func TestGenerateWithConfig(t *testing.T) {
fakeConfigFilename string
config *Config // omits Schema and Operations, set below.
}{
{"DefaultConfig", "genqlient.yaml", defaultConfig},
{"DefaultConfig", "genqlient.yaml", defaultConfig(t)},
{"Subpackage", "genqlient.yaml", &Config{
Generated: "mypkg/myfile.go",
ContextType: "context.Context", // (from defaultConfig)
Generated: "mypkg/myfile.go",
}},
{"SubpackageConfig", "mypkg/genqlient.yaml", &Config{
Generated: "myfile.go", // (relative to genqlient.yaml)
ContextType: "context.Context",
Generated: "myfile.go", // (relative to genqlient.yaml)
}},
{"PackageName", "genqlient.yaml", &Config{
Generated: "myfile.go",
Package: "mypkg",
ContextType: "context.Context",
Generated: "myfile.go",
Package: "mypkg",
}},
{"ExportOperations", "genqlient.yaml", &Config{
Generated: "generated.go",
ExportOperations: "operations.json",
ContextType: "context.Context",
}},
{"CustomContext", "genqlient.yaml", &Config{
Generated: "generated.go",
@@ -156,12 +170,11 @@ func TestGenerateWithConfig(t *testing.T) {
}},
{"NoContext", "genqlient.yaml", &Config{
Generated: "generated.go",
ContextType: "",
ContextType: "-",
}},
{"ClientGetter", "genqlient.yaml", &Config{
Generated: "generated.go",
ClientGetter: "github.com/Khan/genqlient/internal/testutil.GetClientFromContext",
ContextType: "context.Context",
}},
{"ClientGetterCustomContext", "genqlient.yaml", &Config{
Generated: "generated.go",
@@ -171,7 +184,7 @@ func TestGenerateWithConfig(t *testing.T) {
{"ClientGetterNoContext", "genqlient.yaml", &Config{
Generated: "generated.go",
ClientGetter: "github.com/Khan/genqlient/internal/testutil.GetClientFromNowhere",
ContextType: "",
ContextType: "-",
}},
}
@@ -240,10 +253,11 @@ func TestGenerateErrors(t *testing.T) {
t.Run(sourceFilename, func(t *testing.T) {
_, err := Generate(&Config{
Schema: filepath.Join(errorsDir, schemaFilename),
Operations: []string{filepath.Join(errorsDir, sourceFilename)},
Package: "test",
Generated: os.DevNull,
Schema: filepath.Join(errorsDir, schemaFilename),
Operations: []string{filepath.Join(errorsDir, sourceFilename)},
Package: "test",
Generated: os.DevNull,
ContextType: "context.Context",
Bindings: map[string]*TypeBinding{
"ValidScalar": {Type: "string"},
"InvalidScalar": {Type: "bogus"},