-
Notifications
You must be signed in to change notification settings - Fork 1
/
scan.go
112 lines (101 loc) · 3.89 KB
/
scan.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
/******************************************************************************
*
* Copyright 2022 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package golang
import (
"os"
"strings"
"github.com/sapcc/go-bits/logg"
"github.com/sapcc/go-bits/must"
"golang.org/x/mod/modfile"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
)
// ScanResult contains data obtained through a scan of the configuration files
// in the repository. At the moment, only `go.mod` is scanned.
type ScanResult struct {
ModulePath string // from "module" directive in go.mod, e.g. "github.com/foo/bar"
GoVersion string // from "go" directive in go.mod, e.g. "1.22.0"
GoVersionMajorMinor string // GoVersion but the patch version is stripped
GoDirectDependencies []module.Version // from "require" directive(s) in go.mod without the "// indirect" comment
HasBinInfo bool // whether we can produce linker instructions for "github.com/sapcc/go-api-declarations/bininfo"
UseGinkgo bool // wether to use ginkgo test runner instead of go test
UsesPostgres bool // whether postgres is used
KubernetesController bool // whether the repository contains a Kubernetes controller
KubernetesVersion string // version of kubernetes to use, derived from k8s.io/api
}
const ModFilename = "go.mod"
func Scan() ScanResult {
modFileBytes := must.Return(os.ReadFile(ModFilename))
modFile := must.Return(modfile.Parse(ModFilename, modFileBytes, nil))
var (
goDeps []module.Version
hasBinInfo bool
kubernetesController bool
kubernetesVersion string
useGinkgo bool
usesPostgres bool
)
for _, v := range modFile.Require {
if !v.Indirect {
goDeps = append(goDeps, v.Mod)
}
if v.Mod.Path == "github.com/sapcc/go-api-declarations" {
if semver.Compare(v.Mod.Version, "v1.2.0") >= 0 {
hasBinInfo = true
}
}
if v.Mod.Path == "github.com/lib/pq" {
usesPostgres = true
}
if strings.HasPrefix(v.Mod.Path, "github.com/onsi/ginkgo") {
useGinkgo = true
}
if v.Mod.Path == "k8s.io/api" {
kubernetesVersion = strings.ReplaceAll(v.Mod.Version, "v0", "1")
splitted := strings.Split(kubernetesVersion, ".")
kubernetesVersion = strings.Join(splitted[:len(splitted)-1], ".")
}
if v.Mod.Path == "sigs.k8s.io/controller-runtime" {
kubernetesController = true
}
}
goVersion := modFile.Go.Version
// do not cut of go directives which do not contain a patch version
goVersionSlice := strings.Split(modFile.Go.Version, ".")
if len(goVersionSlice) == 3 {
goVersion = strings.Join(goVersionSlice[:len(goVersionSlice)-1], ".")
}
return ScanResult{
GoVersion: modFile.Go.Version,
GoVersionMajorMinor: goVersion,
ModulePath: modFile.Module.Mod.Path,
GoDirectDependencies: goDeps,
HasBinInfo: hasBinInfo,
UseGinkgo: useGinkgo,
UsesPostgres: usesPostgres,
KubernetesController: kubernetesController,
KubernetesVersion: kubernetesVersion,
}
}
// MustModulePath reads the ModulePath field, but fails if it is empty.
func (sr ScanResult) MustModulePath() string {
if sr.ModulePath == "" {
logg.Fatal("could not find module path from go.mod file, make sure it is defined")
}
return sr.ModulePath
}