-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
133 lines (110 loc) · 3.38 KB
/
main.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package main
import (
"bufio"
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
)
var gitmodRegex = regexp.MustCompile(`path\s*=\s*(.*)`)
var vgnVersionRegex = regexp.MustCompile(`go\.kwusen\.ca\/vgn\s+(v.*)`)
var vgnReplaceRegex = regexp.MustCompile(`^\s*(replace)\s+go\.kwusen\.ca\/vgn.*`)
func findMatches(f *os.File, regexes ...*regexp.Regexp) [][]string {
var found [][]string
scanner := bufio.NewScanner(f)
for scanner.Scan() {
ln := scanner.Text()
for _, r := range regexes {
matches := r.FindStringSubmatch(ln)
if len(matches) >= 2 {
found = append(found, matches)
}
}
}
return found
}
func fail(failed *bool, template string, arg ...interface{}) {
*failed = true
fmt.Print("- ")
fmt.Printf(template, arg...)
fmt.Println()
}
func main() {
failed := false
// Load the go module to parse the version of vgn and ensure no replace.
modFile, err := os.Open("go.mod")
if err != nil {
fail(&failed, "Could not open go.mod: %s", err)
}
targetVersion := ""
vgnMatches := findMatches(modFile, vgnVersionRegex, vgnReplaceRegex)
for _, m := range vgnMatches {
if m[1] == "replace" {
fail(&failed, `Found "replace" in go.mod for go.kwusen.ca/vgn.
Comment out this line:
"%s"
And update require block to point entry for "go.kwusen.ca/vgn" to a new
version, after committing and releasing, if necessary
`, m[0])
}
if m[0][:16] == "go.kwusen.ca/vgn" {
targetVersion = strings.TrimSpace(m[1])
}
}
if targetVersion == "" {
fail(&failed, "Could not find version of vgn to target in go.mod.")
}
// Load the git modules and find the versions in each subdir.
gmFile, err := os.Open(".gitmodules")
if err != nil {
fail(&failed, "Could not open .gitmodules: %s\n", err)
}
smPaths := findMatches(gmFile, gitmodRegex)
for _, m := range smPaths {
// Get the version from the file in the submodule.
path := filepath.Join(m[1], "vgn-version.txt")
bts, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
fail(&failed, `Submodule file not found for vgn version validation:
"%s"
Create and commit the file at the submodule path and copy the version
that is pointed at in go.mod`, path)
} else {
fail(&failed, "Could not open go.mod: %s\n", err)
}
continue
}
// Make sure the version in cps is the prefix of what's referenced in go.mod for
// the vgn commit.
smVer := strings.TrimSpace(string(bts))
if targetVersion != "" && !strings.HasPrefix(targetVersion, smVer) {
fail(&failed, `Version of vgn in go.mod (%s) does not have the expected prefix (%s):
File with incorrect version: "%s"`, targetVersion, smVer, path)
continue
}
// All is good with the submodule. Make sure there are no pending changes.
// Need to reset the environment for running the git command or it will
// fail in an actual commit (but work in try-repo and running pre-commit
// explicitly).
// https://stackoverflow.com/a/55505661
cmd := exec.Command("env", "-i", "git", "status", "--porcelain")
cmd.Dir, err = filepath.Abs(m[1])
if err != nil {
fail(&failed, `Failed to get absolute path for submodule: %s`, err)
}
output, err := cmd.CombinedOutput()
if err != nil {
fail(&failed, "Failed to run git status on \"%s\": %s\n\nOutput:\n%s", m[1], err, output)
continue
}
if len(output) > 0 {
fail(&failed, "Found pending changes in \"%s\":\n\n%s", m[1], output)
}
}
if failed {
os.Exit(1)
}
}