Skip to content

Commit

Permalink
Ensure config is created before executing any commands
Browse files Browse the repository at this point in the history
This will walk the user through setting up their token
unless otherwise configured, i.e. via flags

Diagnostic command prints out host, and if token is found.

Moved GQL call to Query command for testing.
  • Loading branch information
Zachary Scott committed May 31, 2018
1 parent d6df3a9 commit 2f78690
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 48 deletions.
55 changes: 13 additions & 42 deletions cmd/diagnostic.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package cmd

import (
"context"
"encoding/json"
"fmt"
"log"

"github.com/machinebox/graphql"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
Expand All @@ -18,46 +14,21 @@ var diagnosticCmd = &cobra.Command{
}

func diagnostic(cmd *cobra.Command, args []string) {
// TODO: Pass token once figure out how api-service uses it
host := viper.GetString("host") + "/graphql"
client := graphql.NewClient(host)
query := `
query IntrospectionQuery {
__schema {
queryType { name }
mutationType { name }
subscriptionType { name }
types {
...FullType
}
directives {
name
description
}
}
}
host := viper.GetString("host")
token := viper.GetString("token")

fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
}
}`
fmt.Printf("---\nCircleCI CLI Diagnostics\n---\n")
fmt.Printf("Config found: `%v`\n", viper.ConfigFileUsed())

req := graphql.NewRequest(query)
req.Header.Set("Authorization", viper.GetString("token"))

ctx := context.Background()
var resp map[string]interface{}

fmt.Println("Querying", host, "with:\n", query, "\n")
if err := client.Run(ctx, req, &resp); err != nil {
log.Fatal(err)
if host == "host" || host == "" {
fmt.Println("Please set a host!")
} else {
fmt.Printf("Host is: %s\n", host)
}

b, _ := json.MarshalIndent(resp, "", " ")
fmt.Println("Result: \n")
fmt.Println(string(b))
if token == "token" || token == "" {
fmt.Println("Please set a token!")
} else {
fmt.Println("OK, got a token.")
}
}
64 changes: 64 additions & 0 deletions cmd/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cmd

import (
"context"
"encoding/json"
"fmt"
"log"

"github.com/machinebox/graphql"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var queryCmd = &cobra.Command{
Use: "query",
Short: "Query the CircleCI GraphQL API.",
Run: query,
}

func query(cmd *cobra.Command, args []string) {
host := viper.GetString("host")
token := viper.GetString("token")
client := graphql.NewClient(host + "/graphql")

query := `
query IntrospectionQuery {
__schema {
queryType { name }
mutationType { name }
subscriptionType { name }
types {
...FullType
}
directives {
name
description
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
}
}`

req := graphql.NewRequest(query)
req.Header.Set("Authorization", token)

ctx := context.Background()
var resp map[string]interface{}

fmt.Println("Querying", host, "with:\n", query, "\n")
if err := client.Run(ctx, req, &resp); err != nil {
log.Fatal(err)
}

b, _ := json.MarshalIndent(resp, "", " ")
fmt.Println("Result: \n")
fmt.Println(string(b))
}
96 changes: 90 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ var RootCmd = &cobra.Command{
Long: `Use CircleCI from the command line.`,
}

var (
cfgFile string
cfgName = "cli"
configPathDefault = fmt.Sprintf("%s/.circleci/%s.yml", os.Getenv("HOME"), cfgName)
)

func AddCommands() {
RootCmd.AddCommand(diagnosticCmd)
RootCmd.AddCommand(queryCmd)
}

// TODO: This convention was carried over from admin-cli, do we still need it?
Expand All @@ -31,21 +38,98 @@ func Execute() {
func init() {
cobra.OnInitialize(initConfig)

RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.circleci/cli.yml)")
RootCmd.PersistentFlags().StringP("host", "H", "https://circleci.com", "the host of your CircleCI install")
RootCmd.PersistentFlags().StringP("token", "t", "", "your token for using CircleCI")

viper.BindPFlag("host", RootCmd.PersistentFlags().Lookup("host"))
viper.BindPFlag("token", RootCmd.PersistentFlags().Lookup("token"))
}

// TODO: move config stuff to it's own package
func initConfig() {
if err := readConfig(); err != nil {
if err = createConfig(); err != nil {
fmt.Println(err.Error())
os.Exit(-1)
}
cfgFile = configPathDefault
readConfig() // reload config after creating it
}
}

func readConfig() (err error) {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
}

if viper.ConfigFileUsed() == "" {
viper.SetConfigName("cli") // name of config file (without extension)
viper.AddConfigPath("$HOME/.circleci")
// If a config file is found, read it in.
viper.AutomaticEnv() // read in environment variables that match
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Failed to load config file...")
}
viper.SetConfigName(cfgName)
}

// read in environment variables that match
// set a prefix for config, i.e. CIRCLECI_CLI_HOST
viper.SetEnvPrefix("circleci_cli")
viper.AutomaticEnv()

// If a config file is found, read it in.
err = viper.ReadInConfig()
return err
}

func createConfig() (err error) {
// Don't support creating config at --config flag, only default
if cfgFile != "" {
fmt.Printf("Setting up default config at: %v\n", configPathDefault)
}

var host, token string

path := fmt.Sprintf("%s/.circleci", os.Getenv("HOME"))

if _, err := os.Stat(path); os.IsNotExist(err) {
os.Mkdir(path, 0777)
}

// Create default config file
if _, err := os.Create(configPathDefault); err != nil {
return err
}

// open file with read & write
file, err := os.OpenFile(configPathDefault, os.O_RDWR, 0644)
if err != nil {
fmt.Println(err.Error())
os.Exit(-1)
}

// read flag values
host = viper.GetString("host")
token = viper.GetString("token")

if host == "host" || host == "" {
fmt.Print("Please enter the HTTP(S) host of your CircleCI installation:")
fmt.Scanln(&host)
fmt.Println("OK.")
}

if token == "token" || token == "" {
fmt.Print("Please enter your CircleCI API token:")
fmt.Scanln(&token)
fmt.Println("OK.")
}

// format input
configValues := fmt.Sprintf("host: %v\ntoken: %v\n", host, token)

// write new config values to file
if _, err = file.WriteString(configValues); err != nil {
fmt.Println(err.Error())
os.Exit(-1)
}

fmt.Printf("Your configuration has been created in `%v`.\n", configPathDefault)
fmt.Println("It can edited manually for advanced settings.")
return err
}

0 comments on commit 2f78690

Please sign in to comment.