blob: 0bd5b8327ad08f1d0653ab9513104a69bf1c4ffe [file] [log] [blame]
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"flag"
"fmt"
"os"
"regexp"
"strings"
)
var uploadFlags struct {
flag.FlagSet
diff bool
force bool
rList string
ccList string
}
func init() {
f := &uploadFlags
f.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s [-n] [-v] upload [-r reviewer,...] [-cc mail,...]\n", os.Args[0])
}
f.BoolVar(&f.diff, "diff", false, "show change commit diff and don't upload")
f.BoolVar(&f.force, "f", false, "upload even if there are staged changes")
f.StringVar(&f.rList, "r", "", "comma-separated list of reviewers")
f.StringVar(&f.ccList, "cc", "", "comma-separated list of people to CC:")
}
func upload(args []string) {
f := &uploadFlags
if f.Parse(args) != nil || len(f.Args()) != 0 {
f.Usage()
os.Exit(2)
}
branch := CurrentBranch()
if branch.Name == "master" {
dief("on master branch; can't upload.")
}
if branch.ChangeID == "" {
dief("no pending change; can't upload.")
}
if f.diff {
run("git", "diff", "master..HEAD")
return
}
if !f.force && hasStagedChanges() {
dief("there are staged changes; aborting.\n" +
"Use 'review change' to include them or 'review upload -f' to force upload.")
}
refSpec := "HEAD:refs/for/master"
start := "%"
if f.rList != "" {
refSpec += mailList(start, "r", f.rList)
start = ","
}
if f.ccList != "" {
refSpec += mailList(start, "cc", f.ccList)
}
run("git", "push", "-q", "origin", refSpec)
}
// mailAddressRE matches the mail addresses we admit. It's restrictive but admits
// all the addresses in the Go CONTRIBUTORS file at time of writing (tested separately).
var mailAddressRE = regexp.MustCompile(`^[a-zA-Z0-9][-_.a-zA-Z0-9]*@[-_.a-zA-Z0-9]+$`)
// mailList turns the list of mail addresses from the flag value into the format
// expected by gerrit. The start argument is a % or , depending on where we
// are in the processing sequence.
func mailList(start, tag string, flagList string) string {
spec := start
for i, addr := range strings.Split(flagList, ",") {
if !mailAddressRE.MatchString(addr) {
dief("%q is not a valid reviewer mail address", addr)
}
if i > 0 {
spec += ","
}
spec += tag + "=" + addr
}
return spec
}