Skip to content

Commit acb5260

Browse files
authored
Merge pull request #2 from utilitywarehouse/add-comments
Add comments and remove exported methods
2 parents e1daba9 + d846f08 commit acb5260

File tree

1 file changed

+97
-48
lines changed

1 file changed

+97
-48
lines changed

patrol/repo.go

+97-48
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,23 @@ type Repo struct {
2222
Packages map[string]*Package
2323
}
2424

25+
type Package struct {
26+
Name string
27+
PartOfModule bool
28+
Dependants []*Package
29+
Changed bool
30+
}
31+
32+
// NewRepo constructs a Repo from path, which needs to contain a go.mod file.
33+
// It builds a map of all packages found in that repo and the dependencies
34+
// between them.
2535
func NewRepo(path string) (*Repo, error) {
2636
repo := &Repo{
2737
path: path,
2838
Packages: map[string]*Package{},
2939
}
3040

41+
// Parse go.mod
3142
b, err := os.ReadFile(filepath.Join(path, "go.mod"))
3243
if err != nil {
3344
return nil, err
@@ -40,9 +51,12 @@ func NewRepo(path string) (*Repo, error) {
4051

4152
repo.Module = mod
4253

54+
// Find all go packages starting from path
4355
err = filepath.Walk(path, func(p string, f os.FileInfo, err error) error {
4456
if f.IsDir() && !directoryShouldBeIgnored(p) {
4557
fset := token.NewFileSet()
58+
59+
// We're interested in each package imports at this point
4660
pkgs, err := parser.ParseDir(fset, p, nil, parser.ImportsOnly)
4761
if err != nil {
4862
return err
@@ -55,13 +69,14 @@ func NewRepo(path string) (*Repo, error) {
5569

5670
var imports []string
5771
for _, file := range pkg.Files {
72+
// Don't map test packages
5873
if !strings.HasSuffix(file.Name.Name, "_test") {
5974
for _, imp := range file.Imports {
6075
imports = append(imports, strings.ReplaceAll(imp.Path.Value, `"`, ""))
6176
}
6277
}
6378
}
64-
repo.AddPackage(strings.TrimPrefix(p, path+"/"), imports)
79+
repo.addPackage(strings.TrimPrefix(p, path+"/"), imports)
6580
}
6681
}
6782
return nil
@@ -73,18 +88,51 @@ func NewRepo(path string) (*Repo, error) {
7388
return repo, nil
7489
}
7590

76-
func (r *Repo) AddPackage(path string, imports []string) {
91+
// ChangesFrom returns a list of all packages within the repository (excluding
92+
// packages in vendor/) that changed since the given revision. A package will
93+
// be flagged as change if any file within the package itself changed or if any
94+
// packages it imports (whether local, vendored or external modules) changed
95+
// since the given revision.
96+
func (r *Repo) ChangesFrom(revision string) ([]string, error) {
97+
err := r.detectInternalChangesFrom(revision)
98+
if err != nil {
99+
return nil, err
100+
}
101+
102+
err = r.detectGoModulesChanges(revision)
103+
if err != nil {
104+
return nil, err
105+
}
106+
107+
var changedOwnedPackages []string
108+
for _, pkg := range r.Packages {
109+
if pkg.PartOfModule && pkg.Changed {
110+
changedOwnedPackages = append(changedOwnedPackages, pkg.Name)
111+
}
112+
}
113+
114+
return changedOwnedPackages, nil
115+
}
116+
117+
// addPackage adds the package found at path to the repo, and also adds it as a
118+
// dependant to all of the packages it imports.
119+
func (r *Repo) addPackage(path string, imports []string) {
77120
var pkgName string
78121

122+
// if path has vendor/ prefix, that needs to be removed to get the actual
123+
// package name
79124
if strings.HasPrefix(path, "vendor/") {
80125
pkgName = strings.TrimPrefix(path, "vendor/")
81126
} else {
127+
// if it doesn't have a vendor/ prefix it means it's part of our module and
128+
// path should be prefixed with the module name.
82129
pkgName = r.ModuleName()
83130
if path != r.path {
84131
pkgName += "/" + path
85132
}
86133
}
87134

135+
// add the new package to the repo if it didn't exist already
88136
pkg, exists := r.Packages[pkgName]
89137
if !exists {
90138
pkg = &Package{
@@ -94,17 +142,21 @@ func (r *Repo) AddPackage(path string, imports []string) {
94142
r.Packages[pkgName] = pkg
95143
}
96144

145+
// imports might not be a unique list, but we only want to add pkg as a
146+
// dependant to those packages once
97147
alreadyProcessedImports := map[string]interface{}{}
98148
for _, dependency := range imports {
99149
if _, alreadyProcessed := alreadyProcessedImports[dependency]; alreadyProcessed {
100150
continue
101151
}
102-
r.AddDependant(pkg, dependency)
152+
r.addDependant(pkg, dependency)
103153
alreadyProcessedImports[dependency] = struct{}{}
104154
}
105155
}
106156

107-
func (r *Repo) AddDependant(dependant *Package, dependencyName string) {
157+
// addDependant adds dependant as one of the dependants of the package
158+
// identified by dependencyName (if it doesn't exist yet, it will be created).
159+
func (r *Repo) addDependant(dependant *Package, dependencyName string) {
108160
dependency, exists := r.Packages[dependencyName]
109161
if !exists {
110162
dependency = &Package{
@@ -117,29 +169,10 @@ func (r *Repo) AddDependant(dependant *Package, dependencyName string) {
117169
dependency.Dependants = append(dependency.Dependants, dependant)
118170
}
119171

120-
func (r *Repo) ChangesFrom(revision string) ([]string, error) {
121-
err := r.detectInternalChangesFrom(revision)
122-
if err != nil {
123-
return nil, err
124-
}
125-
126-
err = r.detectGoModulesChanges(revision)
127-
if err != nil {
128-
return nil, err
129-
}
130-
131-
var changedOwnedPackages []string
132-
for _, pkg := range r.Packages {
133-
if pkg.PartOfModule && pkg.Changed {
134-
changedOwnedPackages = append(changedOwnedPackages, pkg.Name)
135-
}
136-
}
137-
138-
return changedOwnedPackages, nil
139-
}
140-
172+
// detectInternalChangesFrom will run a git diff (revision...HEAD) and flag as
173+
// changed any packages (part of the module in repo or vendored packages) that
174+
// have *.go files that are part of the that diff and packages that depend on them
141175
func (r *Repo) detectInternalChangesFrom(revision string) error {
142-
// git diff go files
143176
repo, err := git.PlainOpen(r.path)
144177
if err != nil {
145178
return err
@@ -150,11 +183,13 @@ func (r *Repo) detectInternalChangesFrom(revision string) error {
150183
return err
151184
}
152185

186+
// Get the HEAD commit
153187
now, err := repo.CommitObject(head.Hash())
154188
if err != nil {
155189
return err
156190
}
157191

192+
// Get the tree for HEAD
158193
nowTree, err := now.Tree()
159194
if err != nil {
160195
return err
@@ -165,31 +200,38 @@ func (r *Repo) detectInternalChangesFrom(revision string) error {
165200
return err
166201
}
167202

203+
// Find the commit for given revision
168204
then, err := repo.CommitObject(*ref)
169205
if err != nil {
170206
return err
171207
}
172208

209+
// Get the tree for given revision
173210
thenTree, err := then.Tree()
174211
if err != nil {
175212
return err
176213
}
177214

215+
// Get a diff between the two trees
178216
diff, err := nowTree.Diff(thenTree)
179217
if err != nil {
180218
return err
181219
}
182220

183221
for _, change := range diff {
222+
// we're only interested in Go files
184223
if !strings.HasSuffix(change.From.Name, ".go") {
185224
continue
186225
}
187226

188227
var pkgName string
228+
// if the changed file is in vendor/ stripping "vendor/" will give us the
229+
// package name
189230
if strings.HasPrefix(change.From.Name, "vendor/") {
190231
pkgName = strings.TrimPrefix(filepath.Dir(change.From.Name), "vendor/")
191232
}
192233

234+
// package is part of our module
193235
if pkgName == "" {
194236
pkgName = r.ModuleName() + "/" + filepath.Dir(change.From.Name)
195237
}
@@ -200,53 +242,67 @@ func (r *Repo) detectInternalChangesFrom(revision string) error {
200242
return nil
201243
}
202244

245+
// detectGoModulesChanges finds differences in dependencies required by
246+
// HEAD:go.mod and {revision}:go.mod and flags as changed any packages
247+
// depending on any of the changed dependencies.
203248
func (r *Repo) detectGoModulesChanges(revision string) error {
204-
// get old go.mod
205-
// find differences with current one
206-
repo, err := git.PlainOpen(r.path)
249+
oldGoMod, err := r.getGoModFromRevision(revision)
207250
if err != nil {
208251
return err
209252
}
210253

254+
differentModules := goModDifferences(oldGoMod, r.Module)
255+
for _, module := range differentModules {
256+
r.flagPackageAsChanged(module)
257+
}
258+
259+
return nil
260+
}
261+
262+
// getGoModFromRevision returns (if found) the go.mod file from the given
263+
// revision.
264+
func (r *Repo) getGoModFromRevision(revision string) (*modfile.File, error) {
265+
repo, err := git.PlainOpen(r.path)
266+
if err != nil {
267+
return nil, err
268+
}
269+
211270
ref, err := repo.ResolveRevision(plumbing.Revision(revision))
212271
if err != nil {
213-
return err
272+
return nil, err
214273
}
215274

216275
then, err := repo.CommitObject(*ref)
217276
if err != nil {
218-
return err
277+
return nil, err
219278
}
220279

221280
file, err := then.File("go.mod")
222281
if err != nil {
223-
return err
282+
return nil, err
224283
}
225284

226285
reader, err := file.Reader()
227286
if err != nil {
228-
return err
287+
return nil, err
229288
}
230289
defer reader.Close()
231290

232291
b, err := ioutil.ReadAll(reader)
233292
if err != nil {
234-
return err
293+
return nil, err
235294
}
236295

237296
mod, err := modfile.Parse(filepath.Join(r.path, "go.mod"), b, nil)
238297
if err != nil {
239-
return err
240-
}
241-
242-
differentModules := goModDifferences(mod, r.Module)
243-
for _, module := range differentModules {
244-
r.flagPackageAsChanged(module)
298+
return nil, err
245299
}
246300

247-
return nil
301+
return mod, nil
248302
}
249303

304+
// flagPackageAsChanged flags the package with the given name and all of its
305+
// dependant as changed, recursively.
250306
func (r *Repo) flagPackageAsChanged(name string) {
251307
pkg, exists := r.Packages[name]
252308
if !exists {
@@ -273,13 +329,6 @@ func (r *Repo) OwnsPackage(pkgName string) bool {
273329
return strings.HasPrefix(pkgName, r.ModuleName())
274330
}
275331

276-
type Package struct {
277-
Name string
278-
PartOfModule bool
279-
Dependants []*Package
280-
Changed bool
281-
}
282-
283332
func directoryShouldBeIgnored(path string) bool {
284333
return strings.Contains(path, ".git")
285334
}

0 commit comments

Comments
 (0)