github.com/adevinta/maiao@v0.0.0-20240318133227-b6f9656b5e07/pkg/credentials/git.go (about)

     1  package credentials
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"os/exec"
     7  	"strings"
     8  )
     9  
    10  var run = realRun
    11  
    12  type runOpts struct {
    13  	path  string
    14  	args  []string
    15  	stdin string
    16  }
    17  
    18  func realRun(opts runOpts) (string, error) {
    19  	cmd := exec.Command(opts.path, opts.args...)
    20  	b := bytes.Buffer{}
    21  	cmd.Stdout = &b
    22  	if opts.stdin != "" {
    23  		cmd.Stdin = strings.NewReader(opts.stdin)
    24  	}
    25  	return b.String(), nil
    26  }
    27  
    28  type GitCredentials struct {
    29  	GitPath string
    30  }
    31  
    32  func (c *GitCredentials) CredentialForHost(host string) (*Credentials, error) {
    33  	// this should be better included with the actual git remotes.
    34  	out, err := run(runOpts{path: c.GitPath, args: []string{"credential", "fill"}, stdin: "protocol=https\nhost=" + host})
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	if out != "" {
    39  		kv := map[string]string{}
    40  		for _, line := range strings.Split(out, "\n") {
    41  			keyAndValue := strings.SplitN(line, "=", 2)
    42  			if len(keyAndValue) == 2 {
    43  				kv[strings.TrimSpace(keyAndValue[0])] = strings.TrimSuffix(keyAndValue[1], "\n")
    44  			}
    45  		}
    46  		if _, ok := kv["password"]; ok {
    47  			return &Credentials{Username: kv["username"], Password: kv["password"]}, nil
    48  		}
    49  		return nil, errors.New("unable to find username and password from git credential")
    50  	}
    51  	return nil, errors.New("not found")
    52  }