/
git.go
111 lines (87 loc) · 2.48 KB
/
git.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package main
import (
"fmt"
"regexp"
"strings"
"github.com/streamingfast/cli"
"go.uber.org/zap"
)
func ensureGitSync() {
state := fetchGitSyncState()
switch state {
case gitSyncUpToDate:
case gitSyncNeedPull:
if yes, _ := cli.PromptConfirm("It seems you need to 'git pull', do it now?"); yes {
run("git pull")
}
case gitSyncNeedPush:
fmt.Println("Pushing our changes to Git so it knowns about our commit(s)")
run("git push")
case gitSyncDiverged:
fmt.Println("Your branch has diverged from remote, cannot continue")
run("git status")
cli.Quit("")
}
}
type gitSyncState string
var (
gitSyncUpToDate gitSyncState = "up-to-date"
gitSyncNeedPull gitSyncState = "need-pull"
gitSyncNeedPush gitSyncState = "need-push"
gitSyncDiverged gitSyncState = "diverged"
)
// See https://stackoverflow.com/a/3278427/697930
func fetchGitSyncState() gitSyncState {
upstream := "'@{u}'"
local := resultOf("git rev-parse @")
remote, info, err := maybeResultOf("git rev-parse", upstream)
if err != nil {
if strings.Contains(remote, "no upstream configured") {
remote = ""
} else {
cli.NoError(err, "Command %q failed with %q", info, remote)
}
}
base, info, err := maybeResultOf("git merge-base @", upstream)
if strings.Contains(base, "no upstream configured") {
base = ""
} else {
cli.NoError(err, "Command %q failed with %q", info, base)
}
if local == remote {
return gitSyncUpToDate
}
if local == base {
return gitSyncNeedPull
}
if remote == base {
return gitSyncNeedPush
}
return gitSyncDiverged
}
func ensureGitNotDirty() {
if isGitDirty() {
fmt.Println("Your git repository is dirty, refusing to release (use --allow-dirty to continue even if Git is dirty)")
run("git status")
cli.Exit(1)
}
}
func isGitDirty() bool {
return resultOf("git status --porcelain") != ""
}
var remoteTagRegex = regexp.MustCompile(`refs/tags/(v?[0-9]+\.[0-9]+\.[0-9]+[^\s]*)`)
func latestTag() (latestTag string) {
defer func() {
zlog.Debug("latest tag", zap.String("found", latestTag))
}()
// We use `maybeResultOf` but ignore error so no error is printed
output, _, _ := maybeResultOf("git -c 'versionsort.suffix=-' ls-remote --exit-code --refs --sort='version:refname' --tags origin '*.*.*'")
lines := getLines(output)
if len(lines) == 0 {
return "'Never released yet'"
}
lastLine := lines[len(lines)-1]
groups := remoteTagRegex.FindStringSubmatch(lastLine)
cli.Ensure(len(groups) > 1, "Unable to extract tag regex from line %q", lastLine)
return groups[1]
}