Skip to content

Commit

Permalink
[#136] (fix) issue displaying token url when entering credentials
Browse files Browse the repository at this point in the history
Also removes the old gitconfig based config and tests the newer lab.hcl
configuration
  • Loading branch information
zaquestion committed Apr 22, 2018
1 parent f5dcd02 commit db6bffb
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 78 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ internal-test:
dep ensure
rm coverage-* 2>&1 > /dev/null || true
mv testdata/test.git testdata/.git
go test -coverprofile=coverage-main.out -covermode=count -coverpkg ./... -run=$(run) github.com/zaquestion/lab/cmd
go test -coverprofile=coverage-main.out -covermode=count -coverpkg ./... -run=$(run) github.com/zaquestion/lab/cmd github.com/zaquestion/lab/internal/...
mv testdata/.git testdata/test.git
go get github.com/wadey/gocovmerge
gocovmerge coverage-*.out > coverage.txt && rm coverage-*.out
Expand Down
73 changes: 73 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package config

import (
"bufio"
"errors"
"fmt"
"io"
"net/url"
"strings"
"syscall"

"github.com/spf13/viper"
"golang.org/x/crypto/ssh/terminal"
)

const defaultGitLabHost = "https://gitlab.com"

// New prompts the user for the default config values to use with lab, and save
// them to the provided confpath (default: ~/.config/lab.hcl)
func New(confpath string, r io.Reader) error {
var (
reader = bufio.NewReader(r)
host, user, token string
err error
)
fmt.Printf("Enter default GitLab host (default: %s): ", defaultGitLabHost)
host, err = reader.ReadString('\n')
host = strings.TrimSpace(host)
if err != nil {
return err
}
if host == "" {
host = defaultGitLabHost
}

fmt.Print("Enter default GitLab user: ")
user, err = reader.ReadString('\n')
user = strings.TrimSpace(user)
if err != nil {
return err
}
if user == "" {
return errors.New("lab.hcl config core.user must be set")
}

tokenURL, err := url.Parse(host)
if err != nil {
return err
}
tokenURL.Path = "profile/personal_access_tokens"

fmt.Printf("Create a token here: %s\nEnter default GitLab token (scope: api): ", tokenURL.String())
token, err = readPassword()
if err != nil {
return err
}

viper.Set("core.host", host)
viper.Set("core.user", user)
viper.Set("core.token", token)
if err := viper.WriteConfigAs(confpath); err != nil {
return err
}
return nil
}

var readPassword = func() (string, error) {
byteToken, err := terminal.ReadPassword(int(syscall.Stdin))
if err != nil {
return "", err
}
return strings.TrimSpace(string(byteToken)), nil
}
78 changes: 78 additions & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package config

import (
"bytes"
"fmt"
"io"
"io/ioutil"
"math/rand"
"os"
"path"
"strconv"
"testing"

"github.com/stretchr/testify/assert"
)

func TestNewConfig(t *testing.T) {
testconf := "/tmp/testconf-" + strconv.Itoa(int(rand.Uint64()))
os.Mkdir(testconf, os.FileMode(0700))

t.Run("create config", func(t *testing.T) {
old := os.Stdout // keep backup of the real stdout
r, w, _ := os.Pipe()
os.Stdout = w

var buf bytes.Buffer
fmt.Fprintln(&buf, "https://gitlab.zaquestion.io")
fmt.Fprintln(&buf, "zaq")

oldreadPassword := readPassword
readPassword = func() (string, error) {
return "abcde12345", nil
}
defer func() {
readPassword = oldreadPassword
}()

err := New(path.Join(testconf, "lab.hcl"), &buf)
if err != nil {
t.Fatal(err)
}

outC := make(chan string)
// copy the output in a separate goroutine so printing can't block indefinitely
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
outC <- buf.String()
}()

// back to normal state
w.Close()
os.Stdout = old // restoring the real stdout
out := <-outC

assert.Contains(t, out, "Enter default GitLab host (default: https://gitlab.com): ")
assert.Contains(t, out, "Enter default GitLab user:")
assert.Contains(t, out, "Create a token here: https://gitlab.zaquestion.io/profile/personal_access_tokens\nEnter default GitLab token (scope: api):")

cfg, err := os.Open(path.Join(testconf, "lab.hcl"))
if err != nil {
t.Fatal(err)
}

cfgData, err := ioutil.ReadAll(cfg)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, string(cfgData), `"core" = {
"host" = "https://gitlab.zaquestion.io"
"token" = "abcde12345"
"user" = "zaq"
}`)
})
os.RemoveAll(testconf)
}
98 changes: 21 additions & 77 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
package main

import (
"bufio"
"fmt"
"log"
"os"
"path"
"strings"
"syscall"

homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
gitconfig "github.com/tcnksm/go-gitconfig"
"github.com/zaquestion/lab/cmd"
"github.com/zaquestion/lab/internal/config"
lab "github.com/zaquestion/lab/internal/gitlab"
"golang.org/x/crypto/ssh/terminal"
)

// version gets set on releases during build by goreleaser.
Expand All @@ -38,90 +33,39 @@ func main() {
viper.AddConfigPath(".")
viper.AddConfigPath(confpath)
viper.AutomaticEnv()
err = viper.ReadInConfig()
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
host, user, token := legacyLoadConfig()
writeConfig(confpath, host, user, token)
err = viper.ReadInConfig()
if err != nil {
if _, ok := viper.ReadInConfig().(viper.ConfigFileNotFoundError); ok {
if err := config.New(confpath, os.Stdin); err != nil {
log.Fatal(err)
}

if err := viper.ReadInConfig(); err != nil {
log.Fatal(err)
}
}

c := viper.AllSettings()["core"]
var config map[string]interface{}
var cfg map[string]interface{}
switch v := c.(type) {
// Most run this is the type
case []map[string]interface{}:
config = v[0]
// On the first run when the config is created it comes in as this type
cfg = v[0]
// On the first run when the cfg is created it comes in as this type
// for whatever reason
case map[string]interface{}:
config = v
cfg = v
}

lab.Init(
config["host"].(string),
config["user"].(string),
config["token"].(string))

cmd.Execute()
}

func writeConfig(confpath, host, user, token string) {
viper.Set("core.host", host)
viper.Set("core.user", user)
viper.Set("core.token", token)
err := viper.WriteConfigAs(path.Join(confpath, "lab.hcl"))
if err != nil {
log.Fatal(err)
}
}

const defaultGitLabHost = "https://gitlab.com"

// legacyLoadConfig handles all of the credential setup and prompts for user
// input when not present
func legacyLoadConfig() (host, user, token string) {
reader := bufio.NewReader(os.Stdin)
var err error
host, err = gitconfig.Entire("gitlab.host")
if err != nil {
fmt.Printf("Enter default GitLab host (default: %s): ", defaultGitLabHost)
host, err = reader.ReadString('\n')
host = strings.TrimSpace(host)
if err != nil {
log.Fatal(err)
}
if host == "" {
host = defaultGitLabHost
for _, v := range []string{"host", "user", "token"} {
if cv, ok := cfg[v]; !ok {
log.Println(cv)
log.Fatalf("missing config value core.%s in %s", v, viper.ConfigFileUsed())
}
}
var errt error
user, err = gitconfig.Entire("gitlab.user")
token, errt = gitconfig.Entire("gitlab.token")
if err != nil {
fmt.Print("Enter default GitLab user: ")
user, err = reader.ReadString('\n')
user = strings.TrimSpace(user)
if err != nil {
log.Fatal(err)
}
if user == "" {
log.Fatal("git config gitlab.user must be set")
}
tokenURL := path.Join(host, "profile/personal_access_tokens")

// If the default user is being set this is the first time lab
// is being run.
if errt != nil {
fmt.Printf("Create a token here: %s\nEnter default GitLab token (scope: api): ", tokenURL)
byteToken, err := terminal.ReadPassword(int(syscall.Stdin))
if err != nil {
log.Fatal(err)
}
token = strings.TrimSpace(string(byteToken))
}
}
return
lab.Init(
cfg["host"].(string),
cfg["user"].(string),
cfg["token"].(string))

cmd.Execute()
}

0 comments on commit db6bffb

Please sign in to comment.