github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/review/git-review/change.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "os" 10 "regexp" 11 "strings" 12 ) 13 14 var changeQuick bool 15 16 func change(args []string) { 17 flags.BoolVar(&changeQuick, "q", false, "do not edit commit msg when updating commit") 18 flags.Parse(args) 19 if len(flags.Args()) > 1 { 20 fmt.Fprintf(os.Stderr, "Usage: %s change %s [branch]\n", os.Args[0], globalFlags) 21 os.Exit(2) 22 23 } 24 25 // Checkout or create branch, if specified. 26 target := flags.Arg(0) 27 if target != "" { 28 checkoutOrCreate(target) 29 } 30 31 // Create or amend change commit. 32 b := CurrentBranch() 33 if !b.IsLocalOnly() { 34 if target != "" { 35 // Permit "review change master". 36 return 37 } 38 dief("can't commit to %s branch (use '%s change branchname').", b.Name, os.Args[0]) 39 } 40 41 if b.ChangeID() == "" { 42 // No change commit on this branch, create one. 43 commitChanges(false) 44 return 45 } 46 if target != "" { 47 // If we switched to an existing branch, don't amend the 48 // commit. (The user can run 'review change' to do that.) 49 return 50 } 51 // Amend the commit. 52 commitChanges(true) 53 } 54 55 var testCommitMsg string 56 57 func commitChanges(amend bool) { 58 if !HasStagedChanges() { 59 printf("no staged changes. Did you forget to 'git add'?") 60 } 61 commit := func(amend bool) { 62 args := []string{"commit", "-q", "--allow-empty"} 63 if amend { 64 args = append(args, "--amend") 65 if changeQuick { 66 args = append(args, "--no-edit") 67 } 68 } 69 if testCommitMsg != "" { 70 args = append(args, "-m", testCommitMsg) 71 } 72 run("git", args...) 73 } 74 commit(amend) 75 for !commitMessageOK() { 76 fmt.Print("re-edit commit message (y/n)? ") 77 if !scanYes() { 78 break 79 } 80 commit(true) 81 } 82 printf("change updated.") 83 } 84 85 func checkoutOrCreate(target string) { 86 // If local branch exists, check it out. 87 for _, b := range LocalBranches() { 88 if b.Name == target { 89 run("git", "checkout", "-q", target) 90 printf("changed to branch %v.", target) 91 return 92 } 93 } 94 95 // If origin branch exists, create local branch tracking it. 96 for _, name := range OriginBranches() { 97 if name == "origin/"+target { 98 run("git", "checkout", "-q", "-t", "-b", target, name) 99 printf("created branch %v tracking %s.", target, name) 100 return 101 } 102 } 103 104 // Otherwise, this is a request to create a local work branch. 105 // Check for reserved names. We take everything with a dot. 106 if strings.Contains(target, ".") { 107 dief("invalid branch name %v: branch names with dots are reserved for git-review.", target) 108 } 109 110 // If the current branch has a pending commit, building 111 // on top of it will not help. Don't allow that. 112 // Otherwise, inherit HEAD and upstream from the current branch. 113 b := CurrentBranch() 114 if b.HasPendingCommit() { 115 dief("cannot branch from work branch; change back to %v first.", strings.TrimPrefix(b.OriginBranch(), "origin/")) 116 } 117 118 origin := b.OriginBranch() 119 120 // NOTE: This is different from git checkout -q -t -b branch. It does not move HEAD. 121 run("git", "checkout", "-q", "-b", target) 122 run("git", "branch", "-q", "--set-upstream-to", origin) 123 printf("created branch %v tracking %s.", target, origin) 124 } 125 126 var ( 127 messageRE = regexp.MustCompile(`^(\[[a-zA-Z0-9.-]+\] )?[a-zA-Z0-9-/, ]+: `) 128 oldFixesRE = regexp.MustCompile(`Fixes +(issue +#?)?([0-9]+)`) 129 ) 130 131 func commitMessageOK() bool { 132 body := getOutput("git", "log", "--format=format:%B", "-n", "1") 133 ok := true 134 if !messageRE.MatchString(body) { 135 fmt.Print(commitMessageWarning) 136 ok = false 137 } 138 if m := oldFixesRE.FindStringSubmatch(body); m != nil { 139 fmt.Printf(fixesIssueWarning, m[0], m[2]) 140 ok = false 141 } 142 return ok 143 } 144 145 const commitMessageWarning = ` 146 Your CL description appears not to use the standard form. 147 148 The first line of your change description is conventionally a one-line summary 149 of the change, prefixed by the primary affected package, and is used as the 150 subject for code review mail; the rest of the description elaborates. 151 152 Examples: 153 154 encoding/rot13: new package 155 156 math: add IsInf, IsNaN 157 158 net: fix cname in LookupHost 159 160 unicode: update to Unicode 5.0.2 161 162 ` 163 164 const fixesIssueWarning = ` 165 Your CL description contains the string %q, which is 166 the old Google Code way of linking commits to issues. 167 168 You should rewrite it to use the GitHub convention: "Fixes #%v". 169 170 ` 171 172 func scanYes() bool { 173 var s string 174 fmt.Scan(&s) 175 return strings.HasPrefix(strings.ToLower(s), "y") 176 }