// Push pushes the current branch to Gerrit. func Push(run *runutil.Run, clOpts CLOpts) error { remote := clOpts.Remote if remote == "" { var err error remote, err = getRemoteURL(run, clOpts) if err != nil { return err } } refspec := "HEAD:" + Reference(clOpts) args := []string{"push", remote, refspec} // TODO(jamesr): This should really reuse gitutil/git.go's Push which knows // how to set this option but doesn't yet know how to pipe stdout/stderr the way // this function wants. if clOpts.Verify { args = append(args, "--verify") } else { args = append(args, "--no-verify") } var stdout, stderr bytes.Buffer opts := run.Opts() opts.Stdout = &stdout opts.Stderr = &stderr if err := run.CommandWithOpts(opts, "git", args...); err != nil { return gitutil.Error(stdout.String(), stderr.String(), args...) } for _, line := range strings.Split(stderr.String(), "\n") { if remoteRE.MatchString(line) { fmt.Println(line) } } return nil }
// getRemoteURL returns the URL of the Gerrit project with respect to the // project identified by the current working directory. func getRemoteURL(run *runutil.Run, clOpts CLOpts) (string, error) { args := []string{"config", "--get", "remote.origin.url"} var stdout, stderr bytes.Buffer opts := run.Opts() opts.Stdout = &stdout opts.Stderr = &stderr if err := run.CommandWithOpts(opts, "git", args...); err != nil { return "", gitutil.Error(stdout.String(), stderr.String(), args...) } baseUrl := clOpts.Host if !strings.HasSuffix(baseUrl, "/") { baseUrl = baseUrl + "/" } return baseUrl + filepath.Base(strings.TrimSpace(stdout.String())), nil }
// hostCredentials returns credentials for the given Gerrit host. The // function uses best effort to scan common locations where the // credentials could exist. func hostCredentials(run *runutil.Run, host string) (_ *credentials, e error) { // Check the host URL is valid. url, err := url.Parse(host) if err != nil { return nil, fmt.Errorf("Parse(%q) failed: %v", host, err) } if url.Host == "" { return nil, fmt.Errorf("%q has no host", host) } // Look for the host credentials in the .netrc file. netrcPath := filepath.Join(os.Getenv("HOME"), ".netrc") file, err := run.Open(netrcPath) if err != nil { if !os.IsNotExist(err) { return nil, err } } else { defer collect.Error(func() error { return file.Close() }, &e) credsMap, err := parseNetrcFile(file) if err != nil { return nil, err } creds, ok := credsMap[url.Host] if ok { return creds, nil } } // Look for the host credentials in the git cookie file. args := []string{"config", "--get", "http.cookiefile"} var stdout, stderr bytes.Buffer opts := run.Opts() opts.Stdout = &stdout opts.Stderr = &stderr if err := run.CommandWithOpts(opts, "git", args...); err == nil { cookieFilePath := strings.TrimSpace(stdout.String()) file, err := run.Open(cookieFilePath) if err != nil { if !os.IsNotExist(err) { return nil, err } } else { defer collect.Error(func() error { return file.Close() }, &e) credsMap, err := parseGitCookieFile(file) if err != nil { return nil, err } creds, ok := credsMap[url.Host] if ok { return creds, nil } // Account for site-wide credentials. Namely, the git cookie // file can contain credentials of the form ".<name>", which // should match any host "*.<name>". for host, creds := range credsMap { if strings.HasPrefix(host, ".") && strings.HasSuffix(url.Host, host) { return creds, nil } } } } return nil, fmt.Errorf("cannot find credentials for %q", host) }