github.com/fredbi/git-chglog@v0.0.0-20190706071416-d35c598eac81/cmd/git-chglog/questioner.go (about)

     1  package main
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	gitcmd "github.com/tsuyoshiwada/go-gitcmd"
    10  	survey "gopkg.in/AlecAivazis/survey.v1"
    11  )
    12  
    13  // Answer ...
    14  type Answer struct {
    15  	RepositoryURL       string `survey:"repository_url"`
    16  	Style               string `survey:"style"`
    17  	CommitMessageFormat string `survey:"commit_message_format"`
    18  	Template            string `survey:"template"`
    19  	IncludeMerges       bool   `survey:"include_merges"`
    20  	IncludeReverts      bool   `survey:"include_reverts"`
    21  	ConfigDir           string `survey:"config_dir"`
    22  }
    23  
    24  // Questioner ...
    25  type Questioner interface {
    26  	Ask() (*Answer, error)
    27  }
    28  
    29  type questionerImpl struct {
    30  	client gitcmd.Client
    31  	fs     FileSystem
    32  }
    33  
    34  // NewQuestioner ...
    35  func NewQuestioner(client gitcmd.Client, fs FileSystem) Questioner {
    36  	return &questionerImpl{
    37  		client: client,
    38  		fs:     fs,
    39  	}
    40  }
    41  
    42  // Ask ...
    43  func (q *questionerImpl) Ask() (*Answer, error) {
    44  	ans, err := q.ask()
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	config := filepath.Join(ans.ConfigDir, defaultConfigFilename)
    50  	tpl := filepath.Join(ans.ConfigDir, defaultTemplateFilename)
    51  	c := q.fs.Exists(config)
    52  	t := q.fs.Exists(tpl)
    53  	msg := ""
    54  
    55  	if c && t {
    56  		msg = fmt.Sprintf("\"%s\" and \"%s\" already exists. Do you want to overwrite?", config, tpl)
    57  	} else if c {
    58  		msg = fmt.Sprintf("\"%s\" already exists. Do you want to overwrite?", config)
    59  	} else if t {
    60  		msg = fmt.Sprintf("\"%s\" already exists. Do you want to overwrite?", tpl)
    61  	}
    62  
    63  	if msg != "" {
    64  		overwrite := false
    65  		err = survey.AskOne(&survey.Confirm{
    66  			Message: msg,
    67  			Default: true,
    68  		}, &overwrite, nil)
    69  
    70  		if err != nil || !overwrite {
    71  			return nil, errors.New("creation of the file was interrupted")
    72  		}
    73  	}
    74  
    75  	return ans, nil
    76  }
    77  
    78  func (q *questionerImpl) ask() (*Answer, error) {
    79  	ans := &Answer{}
    80  	fmts := q.getPreviewableList(formats)
    81  	tpls := q.getPreviewableList(templates)
    82  
    83  	var previewableTransform = func(ans interface{}) (newAns interface{}) {
    84  		if s, ok := ans.(string); ok {
    85  			newAns = q.parsePreviewableList(s)
    86  		}
    87  		return
    88  	}
    89  
    90  	questions := []*survey.Question{
    91  		{
    92  			Name: "repository_url",
    93  			Prompt: &survey.Input{
    94  				Message: "What is the URL of your repository?",
    95  				Default: q.getRepositoryURL(),
    96  			},
    97  		},
    98  		{
    99  			Name: "style",
   100  			Prompt: &survey.Select{
   101  				Message: "What is your favorite style?",
   102  				Options: styles,
   103  				Default: styles[0],
   104  			},
   105  		},
   106  		{
   107  			Name: "commit_message_format",
   108  			Prompt: &survey.Select{
   109  				Message: "Choose the format of your favorite commit message",
   110  				Options: fmts,
   111  				Default: fmts[0],
   112  			},
   113  			Transform: previewableTransform,
   114  		},
   115  		{
   116  			Name: "template",
   117  			Prompt: &survey.Select{
   118  				Message: "What is your favorite template style?",
   119  				Options: tpls,
   120  				Default: tpls[0],
   121  			},
   122  			Transform: previewableTransform,
   123  		},
   124  		{
   125  			Name: "include_merges",
   126  			Prompt: &survey.Confirm{
   127  				Message: "Do you include Merge Commit in CHANGELOG?",
   128  				Default: true,
   129  			},
   130  		},
   131  		{
   132  			Name: "include_reverts",
   133  			Prompt: &survey.Confirm{
   134  				Message: "Do you include Revert Commit in CHANGELOG?",
   135  				Default: true,
   136  			},
   137  		},
   138  		{
   139  			Name: "config_dir",
   140  			Prompt: &survey.Input{
   141  				Message: "In which directory do you output configuration files and templates?",
   142  				Default: defaultConfigDir,
   143  			},
   144  		},
   145  	}
   146  
   147  	err := survey.Ask(questions, ans)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  
   152  	return ans, nil
   153  }
   154  
   155  func (*questionerImpl) getPreviewableList(list []Previewable) []string {
   156  	arr := make([]string, len(list))
   157  	max := 0
   158  
   159  	for _, p := range list {
   160  		l := len(p.Display())
   161  		if max < l {
   162  			max = l
   163  		}
   164  	}
   165  
   166  	for i, p := range list {
   167  		arr[i] = fmt.Sprintf(
   168  			"%s -- %s",
   169  			p.Display()+strings.Repeat(" ", max-len(p.Display())),
   170  			p.Preview(),
   171  		)
   172  	}
   173  
   174  	return arr
   175  }
   176  
   177  func (*questionerImpl) parsePreviewableList(input string) string {
   178  	return strings.TrimSpace(strings.Split(input, "--")[0])
   179  }
   180  
   181  func (q *questionerImpl) getRepositoryURL() string {
   182  	if q.client.CanExec() != nil || q.client.InsideWorkTree() != nil {
   183  		return ""
   184  	}
   185  
   186  	rawurl, err := q.client.Exec("config", "--get", "remote.origin.url")
   187  	if err != nil {
   188  		return ""
   189  	}
   190  
   191  	return remoteOriginURLToHTTP(rawurl)
   192  }