Skip to content

Commit

Permalink
Remove adhoc config system
Browse files Browse the repository at this point in the history
  • Loading branch information
marcomorain committed Jun 13, 2018
1 parent b001566 commit 555aa13
Show file tree
Hide file tree
Showing 97 changed files with 10,920 additions and 186 deletions.
45 changes: 44 additions & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@
[prune]
go-tests = true
unused-packages = true

[[constraint]]
name = "github.com/manifoldco/promptui"
version = "0.3.0"
121 changes: 121 additions & 0 deletions cmd/configure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package cmd

import (
"fmt"
"strings"

"github.com/spf13/viper"

"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
)

var configureCommand = &cobra.Command{
Use: "configure",
Short: "Configure the tool with your credentials",
Run: configure,
}

var testing = false

func init() {
configureCommand.Flags().BoolVar(&testing, "testing", false, "Enable test mode to bypass interactive UI.")
if err := configureCommand.Flags().MarkHidden("testing"); err != nil {
panic(err)
}
}

// We can't properly run integration tests on code that calls PromptUI.
// This is because the first call to PromptUI reads from stdin correctly,
// but subsequent calls return EOF.
// The `userInterface` is created here to allow us to pass a mock user
// interface for testing.
type userInterface interface {
readStringFromUser(message string, defaultValue string) string
askUserToConfirm(message string) bool
}

type interactiveUI struct {
}

func (interactiveUI) readStringFromUser(message string, defaultValue string) string {
prompt := promptui.Prompt{
Label: message,
}

if defaultValue != "" {
prompt.Default = defaultValue
}

token, err := prompt.Run()

if err != nil {
panic(err)
}

return token
}

func (interactiveUI) askUserToConfirm(message string) bool {
prompt := promptui.Prompt{
Label: message,
IsConfirm: true,
}

result, err := prompt.Run()
return err == nil && strings.ToLower(result) == "y"
}

type testingUI struct {
input string
confirm bool
}

func (ui testingUI) readStringFromUser(message string, defaultValue string) string {
fmt.Println(message)
return ui.input
}

func (ui testingUI) askUserToConfirm(message string) bool {
fmt.Println(message)
return ui.confirm
}

func shouldAskForToken(token string, ui userInterface) bool {

if token == "" {
return true
}

return ui.askUserToConfirm("A CircleCI token is already set. Do you want to change it")
}

func configure(cmd *cobra.Command, args []string) {
token := viper.GetString("token")

var ui userInterface = interactiveUI{}

if testing {
ui = testingUI{
confirm: true,
input: "boondoggle",
}
}

if shouldAskForToken(token, ui) {
viper.Set("token", ui.readStringFromUser("CircleCI API Token", ""))
fmt.Println("API token has been set.")
}
viper.Set("endpoint", ui.readStringFromUser("CircleCI API End Point", viper.GetString("endpoint")))
fmt.Println("API endpoint has been set.")

// Marc: I can't find a way to prevent the verbose flag from
// being written to the config file, so set it to false in
// the config file.
viper.Set("verbose", false)

if err := viper.WriteConfig(); err != nil {
panic(err)
}
fmt.Println("Configuration has been saved.")
}
97 changes: 97 additions & 0 deletions cmd/configure_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package cmd_test

import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
"github.com/onsi/gomega/gexec"
)

var _ = Describe("Configure", func() {
var (
tempHome string
command *exec.Cmd
)

BeforeEach(func() {
var err error
tempHome, err = ioutil.TempDir("", "circleci-cli-test-")
Expect(err).ToNot(HaveOccurred())

command = exec.Command(pathCLI, "configure", "--testing")
command.Env = append(os.Environ(),
fmt.Sprintf("HOME=%s", tempHome),
fmt.Sprintf("USERPROFILE=%s", tempHome), // windows
)
})

AfterEach(func() {
Expect(os.RemoveAll(tempHome)).To(Succeed())
})

Describe("existing config file", func() {
var config *os.File

BeforeEach(func() {
const (
configDir = ".circleci"
configFile = "cli.yml"
)

Expect(os.Mkdir(filepath.Join(tempHome, configDir), 0700)).To(Succeed())

var err error
config, err = os.OpenFile(
filepath.Join(tempHome, configDir, configFile),
os.O_RDWR|os.O_CREATE,
0600,
)
Expect(err).ToNot(HaveOccurred())
})

Describe("token and endpoint set in config file", func() {

It("print success", func() {
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
Expect(err).ShouldNot(HaveOccurred())
Eventually(session.Err.Contents()).Should(BeEmpty())

Eventually(session.Out).Should(gbytes.Say("CircleCI API Token"))
Eventually(session.Out).Should(gbytes.Say("API token has been set."))
Eventually(session.Out).Should(gbytes.Say("CircleCI API End Point"))
Eventually(session.Out).Should(gbytes.Say("API endpoint has been set."))
Eventually(session.Out).Should(gbytes.Say("Configuration has been saved."))
Eventually(session).Should(gexec.Exit(0))
})
})

Context("token set to some string in config file", func() {
BeforeEach(func() {
_, err := config.Write([]byte(`
endpoint: https://example.com/graphql
token: fooBarBaz
`))
Expect(err).ToNot(HaveOccurred())
Expect(config.Close()).To(Succeed())
})

It("print error", func() {
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
Expect(err).ShouldNot(HaveOccurred())
Eventually(session.Out).Should(gbytes.Say("A CircleCI token is already set. Do you want to change it"))
Eventually(session.Out).Should(gbytes.Say("CircleCI API Token"))
Eventually(session.Out).Should(gbytes.Say("API token has been set."))
Eventually(session.Out).Should(gbytes.Say("CircleCI API End Point"))
Eventually(session.Out).Should(gbytes.Say("API endpoint has been set."))
Eventually(session.Out).Should(gbytes.Say("Configuration has been saved."))
Eventually(session).Should(gexec.Exit(0))
})
})
})
})
19 changes: 0 additions & 19 deletions cmd/diagnostic_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cmd_test

import (
"bytes"
"fmt"
"io/ioutil"
"os"
Expand Down Expand Up @@ -35,24 +34,6 @@ var _ = Describe("Diagnostic", func() {
Expect(os.RemoveAll(tempHome)).To(Succeed())
})

Describe("no config file", func() {
BeforeEach(func() {
var stdin bytes.Buffer
stdin.Write([]byte(`mytoken`))
command.Stdin = &stdin
})

It("prompt for token and use default endpoint", func() {
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
Expect(err).ShouldNot(HaveOccurred())
Eventually(session.Err.Contents()).Should(BeEmpty())
Eventually(session.Out).Should(gbytes.Say("Please enter your CircleCI API token:"))
Eventually(session.Out).Should(gbytes.Say("GraphQL API endpoint: https://circleci.com/graphql"))
Eventually(session.Out).Should(gbytes.Say("OK, got a token."))
Eventually(session).Should(gexec.Exit(0))
})
})

Describe("existing config file", func() {
var config *os.File

Expand Down
Loading

0 comments on commit 555aa13

Please sign in to comment.