forked from open-telemetry/opentelemetry-go-build-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathversions.go
173 lines (139 loc) · 5.65 KB
/
versions.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Copyright The OpenTelemetry Authors
//
// 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 common
import (
"fmt"
"github.com/spf13/viper"
)
const (
SemverRegexNumberOnly = `(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?`
SemverRegex = `v` + SemverRegexNumberOnly
)
// versionConfig is needed to parse the versions.yaml file with viper.
type versionConfig struct {
ModuleSets ModuleSetMap `mapstructure:"module-sets"`
ExcludedModules []ModulePath `mapstructure:"excluded-modules"`
ignoreExcluded bool
}
// excludedModules functions as a set containing all module paths that are excluded
// from versioning.
type excludedModulesSet map[ModulePath]struct{}
// ModuleSetMap maps the name of a module set to a ModuleSet struct.
type ModuleSetMap map[string]ModuleSet
// ModuleSet holds the version that the specified modules within the set will have.
type ModuleSet struct {
Version string `mapstructure:"version"`
Modules []ModulePath `mapstructure:"modules"`
}
// ModulePath holds the module import path, such as "go.opentelemetry.io/otel".
type ModulePath string
// ModuleRef holds a module import path and a version for that module.
type ModuleRef struct {
Path ModulePath
Version string
}
// ModuleInfoMap is a mapping from a module's import path to its ModuleInfo struct.
type ModuleInfoMap map[ModulePath]ModuleInfo
// ModuleInfo is a reverse of the ModuleSetMap, to allow for quick lookup from module
// path to its set and version.
type ModuleInfo struct {
ModuleSetName string
Version string
}
// ModuleFilePath holds the file path to the go.mod file within the repo,
// including the base file name ("go.mod").
type ModuleFilePath string
// ModulePathMap is a mapping from a module's import path to its file path.
type ModulePathMap map[ModulePath]ModuleFilePath
// ModuleTagName is the simple file path to the directory of a go.mod file used for Git tagging.
// For example, the opentelemetry-go/sdk/metric/go.mod file will have a ModuleTagName "sdk/metric".
type ModuleTagName string
// readVersioningFile reads in a versioning file (typically given as versions.yaml) and returns
// a versionConfig struct.
func readVersioningFile(versioningFilename string) (versionConfig, error) {
viper.SetConfigFile(versioningFilename)
var versionCfg versionConfig
if err := viper.ReadInConfig(); err != nil {
return versionConfig{}, fmt.Errorf("error reading versionsConfig file: %w", err)
}
if err := viper.Unmarshal(&versionCfg); err != nil {
return versionConfig{}, fmt.Errorf("unable to unmarshal versionsConfig: %w", err)
}
if viper.ConfigFileUsed() != versioningFilename {
return versionConfig{}, fmt.Errorf(
"config file used (%v) does not match input file (%v)",
viper.ConfigFileUsed(),
versioningFilename,
)
}
return versionCfg, nil
}
// buildModuleSetsMap creates a map with module set names as keys and ModuleSet structs as values.
func (versionCfg versionConfig) buildModuleSetsMap() ModuleSetMap {
return versionCfg.ModuleSets
}
// BuildModuleMap creates a map with module paths as keys and their moduleInfo as values
// by creating and "reversing" a ModuleSetsMap.
func (versionCfg versionConfig) buildModuleMap() (ModuleInfoMap, error) {
modMap := make(ModuleInfoMap)
for setName, moduleSet := range versionCfg.ModuleSets {
for _, modPath := range moduleSet.Modules {
// Check if module has already been added to the map
if _, exists := modMap[modPath]; exists {
return nil, fmt.Errorf("module %v exists more than once (exists in sets %v and %v)",
modPath, modMap[modPath].ModuleSetName, setName)
}
// Check if module is in excluded modules section
if versionCfg.shouldExcludeModule(modPath) {
return nil, fmt.Errorf("module %v is an excluded module and should not be versioned", modPath)
}
modMap[modPath] = ModuleInfo{setName, moduleSet.Version}
}
}
return modMap, nil
}
// getExcludedModules returns if a given module path is listed in the excluded modules section of a versioning file.
func (versionCfg versionConfig) shouldExcludeModule(modPath ModulePath) bool {
if versionCfg.ignoreExcluded {
return false
}
excludedModules := versionCfg.getExcludedModules()
_, exists := excludedModules[modPath]
return exists
}
// getExcludedModules returns a map structure containing all excluded module paths as keys and empty values.
func (versionCfg versionConfig) getExcludedModules() excludedModulesSet {
excludedModules := make(excludedModulesSet)
if versionCfg.ignoreExcluded {
return excludedModules
}
// add all excluded modules to the excludedModulesSet
for _, mod := range versionCfg.ExcludedModules {
excludedModules[mod] = struct{}{}
}
return excludedModules
}
// BuildModulePathMap creates a map with module paths as keys and go.mod file paths as values.
func (versionCfg versionConfig) BuildModulePathMap(root string) (ModulePathMap, error) {
modPathMap, err := newAllModulePathMap(root)
if err != nil {
return nil, err
}
for k := range modPathMap {
if versionCfg.shouldExcludeModule(k) {
delete(modPathMap, k)
}
}
return modPathMap, nil
}