-
Notifications
You must be signed in to change notification settings - Fork 584
/
abapAddonAssemblyKitReserveNextPackages.go
212 lines (184 loc) · 11.7 KB
/
abapAddonAssemblyKitReserveNextPackages.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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
package cmd
import (
"fmt"
"time"
"github.com/SAP/jenkins-library/pkg/abap/aakaas"
abapbuild "github.com/SAP/jenkins-library/pkg/abap/build"
"github.com/SAP/jenkins-library/pkg/abaputils"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/pkg/errors"
)
func abapAddonAssemblyKitReserveNextPackages(config abapAddonAssemblyKitReserveNextPackagesOptions, telemetryData *telemetry.CustomData, cpe *abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment) {
utils := aakaas.NewAakBundleWithTime(time.Duration(config.MaxRuntimeInMinutes), time.Duration(config.PollingIntervalInSeconds))
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
if err := runAbapAddonAssemblyKitReserveNextPackages(&config, telemetryData, &utils, cpe); err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runAbapAddonAssemblyKitReserveNextPackages(config *abapAddonAssemblyKitReserveNextPackagesOptions, telemetryData *telemetry.CustomData, utils *aakaas.AakUtils,
cpe *abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment) error {
log.Entry().Info("╔═════════════════════════════════════════╗")
log.Entry().Info("║ abapAddonAssemblyKitReserveNextPackages ║")
log.Entry().Info("╚═════════════════════════════════════════╝")
log.Entry().Infof("... initializing connection to AAKaaS @ %v", config.AbapAddonAssemblyKitEndpoint)
conn := new(abapbuild.Connector)
if err := conn.InitAAKaaS(config.AbapAddonAssemblyKitEndpoint, config.Username, config.Password, *utils, config.AbapAddonAssemblyKitOriginHash, config.AbapAddonAssemblyKitCertificateFile, config.AbapAddonAssemblyKitCertificatePass); err != nil {
return err
}
log.Entry().Info("... reading AddonDescriptor (Software Component, Version) from CommonPipelineEnvironment")
addonDescriptor := new(abaputils.AddonDescriptor)
if err := addonDescriptor.InitFromJSONstring(config.AddonDescriptor); err != nil {
return errors.Wrap(err, "Reading AddonDescriptor failed [Make sure abapAddonAssemblyKit...CheckCVs|CheckPV steps have been run before]")
}
log.Entry().Info("╭────────────────────────────────┬──────────────────────╮")
log.Entry().Info("│ Software Component │ Version │")
log.Entry().Info("├────────────────────────────────┼──────────────────────┤")
for i := range addonDescriptor.Repositories {
log.Entry().Infof("│ %-30v │ %-20v │", addonDescriptor.Repositories[i].Name, addonDescriptor.Repositories[i].VersionYAML)
}
log.Entry().Info("╰────────────────────────────────┴──────────────────────╯")
packagesWithRepos, err := reservePackages(addonDescriptor.Repositories, *conn)
if err != nil {
return err
}
log.Entry().Info("... checking for ongoing Reservations")
if err = pollReserveNextPackages(packagesWithRepos, utils); err != nil {
return err
}
log.Entry().Info("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓")
log.Entry().Infof("┃ %-30v ┃ %-20v ┃ %-5v ┃ %-6v ┃ %-10v ┃ %-40v ┃ %-40v ┃", "Software Component", "Package Name", "Type", "Status", "Namespace", "CommitID (from addon.yml)", "PredecessorCommitID (from AAKaaS)")
log.Entry().Info("┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫")
for i := range packagesWithRepos {
log.Entry().Infof("┃ %-30v ┃ %-20v ┃ %-5v ┃ %-6v ┃ %-10v ┃ %-40v ┃ %-40v ┃", packagesWithRepos[i].Repo.Name, packagesWithRepos[i].Package.PackageName, packagesWithRepos[i].Package.Type, packagesWithRepos[i].Package.Status, packagesWithRepos[i].Package.Namespace, packagesWithRepos[i].Repo.CommitID, packagesWithRepos[i].Package.PredecessorCommitID)
}
log.Entry().Info("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━┻━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛")
log.Entry().Info("... checking and processing provided and received data")
if addonDescriptor.Repositories, err = checkAndCopyFieldsToRepositories(packagesWithRepos); err != nil {
return err
}
log.Entry().Info("... writing AddonDescriptor (package name, type, status, namespace and predecessorCommitID) back to CommonPipelineEnvironment")
cpe.abap.addonDescriptor = addonDescriptor.AsJSONstring()
return nil
}
func checkAndCopyFieldsToRepositories(pckgWR []aakaas.PackageWithRepository) ([]abaputils.Repository, error) {
var repos []abaputils.Repository
var checkFailure error = nil
for i := range pckgWR {
checkFailure = checkCommitID(pckgWR, i, checkFailure)
pckgWR[i].Package.CopyFieldsToRepo(&pckgWR[i].Repo)
repos = append(repos, pckgWR[i].Repo)
}
return repos, checkFailure
}
func checkCommitID(pckgWR []aakaas.PackageWithRepository, i int, checkFailure error) error {
if !pckgWR[i].Repo.UseClassicCTS {
if pckgWR[i].Package.Status == aakaas.PackageStatusReleased {
checkFailure = checkCommitIDSameAsGiven(pckgWR, i, checkFailure)
} else if pckgWR[i].Package.PredecessorCommitID != "" {
checkFailure = checkCommitIDNotSameAsPrevious(pckgWR, i, checkFailure)
}
}
return checkFailure
}
func checkCommitIDSameAsGiven(pckgWR []aakaas.PackageWithRepository, i int, checkFailure error) error {
//Ensure for Packages with Status R that CommitID of package = the one from addon.yml, beware of short commitID in addon.yml (and AAKaaS had due to a bug some time also short commid IDs)
AAKaaSCommitId := pckgWR[i].Package.CommitID
AddonYAMLCommitId := pckgWR[i].Repo.CommitID
var commitIdLength int
//determine shortes commitID length
if len(AAKaaSCommitId) >= len(AddonYAMLCommitId) {
commitIdLength = len(AddonYAMLCommitId)
} else {
commitIdLength = len(AAKaaSCommitId)
}
//shorten both to common length
AAKaaSCommitId = AAKaaSCommitId[0:commitIdLength]
AddonYAMLCommitId = AddonYAMLCommitId[0:commitIdLength]
if AddonYAMLCommitId != AAKaaSCommitId {
log.Entry().Error("package " + pckgWR[i].Package.PackageName + " was already build but with commit " + pckgWR[i].Package.CommitID + ", not with " + pckgWR[i].Repo.CommitID)
log.Entry().Error("If you want to build a new package make sure to increase the dotted-version-string in addon.yml - current value: " + pckgWR[i].Package.VersionYAML)
log.Entry().Error("If you do NOT want to build a new package enter the commitID " + pckgWR[i].Package.CommitID + " for software component " + pckgWR[i].Repo.Name + " in addon.yml")
checkFailure = errors.New("commit of already released package does not match with addon.yml")
log.Entry().WithError(checkFailure).Error(" => Check failure: to be corrected in addon.yml prior next execution")
}
return checkFailure
}
func checkCommitIDNotSameAsPrevious(pckgWR []aakaas.PackageWithRepository, i int, checkFailure error) error {
//Check for newly reserved packages which are to be build that CommitID from addon.yml != PreviousCommitID [this will result in an error as no delta can be calculated]
AAKaaSPreviousCommitId := pckgWR[i].Package.PredecessorCommitID
AddonYAMLCommitId := pckgWR[i].Repo.CommitID
var commitIdLength int
//determine shortes commitID length
if len(AAKaaSPreviousCommitId) >= len(AddonYAMLCommitId) {
commitIdLength = len(AddonYAMLCommitId)
} else {
commitIdLength = len(AAKaaSPreviousCommitId)
}
AAKaaSPreviousCommitId = AAKaaSPreviousCommitId[0:commitIdLength]
AddonYAMLCommitId = AddonYAMLCommitId[0:commitIdLength]
if AddonYAMLCommitId == AAKaaSPreviousCommitId {
checkFailure = errors.New("CommitID of package " + pckgWR[i].Package.PackageName + " is the same as the one of the predecessor package. Make sure to change both the dotted-version-string AND the commitID in addon.yml")
log.Entry().WithError(checkFailure).Error(" => Check failure: to be corrected in addon.yml prior next execution")
}
return checkFailure
}
func pollReserveNextPackages(pckgWR []aakaas.PackageWithRepository, utils *aakaas.AakUtils) error {
pollingInterval := (*utils).GetPollingInterval()
timeout := time.After((*utils).GetMaxRuntime())
ticker := time.Tick(pollingInterval)
for {
select {
case <-timeout:
return errors.New("Timed out")
case <-ticker:
var allFinished bool = true
for i := range pckgWR {
if pckgWR[i].Package.Status == aakaas.PackageStatusReleased {
continue
}
err := pckgWR[i].Package.GetPackageAndNamespace()
// if there is an error, reservation is not yet finished
if err != nil {
log.Entry().Infof("Reservation of %s is not yet finished, check again in %s", pckgWR[i].Package.PackageName, pollingInterval)
allFinished = false
} else {
switch pckgWR[i].Package.Status {
case aakaas.PackageStatusLocked:
return fmt.Errorf("Package %s has invalid status 'locked'", pckgWR[i].Package.PackageName)
case aakaas.PackageStatusCreationTriggered:
log.Entry().Infof("Reservation of %s is still running with status 'creation triggered', check again in %s", pckgWR[i].Package.PackageName, pollingInterval)
allFinished = false
case aakaas.PackageStatusPlanned:
log.Entry().Infof("Reservation of %s was successful with status 'planned'", pckgWR[i].Package.PackageName)
case aakaas.PackageStatusReleased:
log.Entry().Infof("Reservation of %s not needed, package is already in status 'released'", pckgWR[i].Package.PackageName)
default:
return fmt.Errorf("Package %s has unknown status '%s'", pckgWR[i].Package.PackageName, pckgWR[i].Package.Status)
}
}
}
if allFinished {
log.Entry().Infof(" => Reservations of package(s) finished successfully")
return nil
}
}
}
}
func reservePackages(repositories []abaputils.Repository, conn abapbuild.Connector) ([]aakaas.PackageWithRepository, error) {
var packagesWithRepos []aakaas.PackageWithRepository
for i := range repositories {
var p aakaas.Package
p.InitPackage(repositories[i], conn)
err := p.ReserveNext()
if err != nil {
return packagesWithRepos, err
}
pWR := aakaas.PackageWithRepository{
Package: p,
Repo: repositories[i],
}
packagesWithRepos = append(packagesWithRepos, pWR)
}
return packagesWithRepos, nil
}