1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/pkg/abap/build/bfw.go
Christian Luttenberger 7a028c4149
Refactor build framework steps (#2068)
* adding my steps

* messy step

* Update abapEnvironmentAssembly.go

* clean up

* change yaml

* corrections

* Update cloudFoundryDeploy.go

* update

* delete simulation step

* remove simulate

* Update PiperGoUtils.groovy

* Update PiperGoUtils.groovy

* Update CommonStepsTest.groovy

* add docu

* Update abapEnvironmentAssembly.md

* changes due to PR

* Update .gitignore

* b

* CV list

* Update abapEnvironmentAssembly.go

* testing with simulation

* Update abapEnvironmentAssembly.go

* remove simulation

* renaming

* Update mkdocs.yml

* moving service key to yaml and fixing code climate

* Update abapEnvironmentAssemblePackages.go

* Update abapEnvironmentAssemblePackages.go

* Update abapEnvironmentAssemblePackages.go

* Update abapEnvironmentAssemblePackages.go

* change input

* Update abapEnvironmentAssemblePackages.go

* change json tag

* fixed error handling

* documentation

* Update abapEnvironmentAssemblePackages.md

* Update abapEnvironmentAssemblePackages.md

* fixing code climate issues

* fixing code climate issues

* Update abapEnvironmentAssemblePackages.yaml

* fixing code climate issues

* Update abapEnvironmentAssemblePackages.yaml

* adding unittests

* adding unittests and improved logging

* yaml -> json

* change scope of cfServiceKeyName

* correct indentation

* Update CommonStepsTest.groovy

* maintain correct step order

* Move Connector to connector.go

* Refactor bfw with unit tests

* remove spaces

* CodeClimate Fix for unexported type

* ABAP BF - Adding Error Handling Unmarshal

* Revert Unmarshal

Co-authored-by: rosemarieB <45030247+rosemarieB@users.noreply.github.com>
Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>
Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
Co-authored-by: Koerner <tilo.koerner@sap.com>
Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com>
2020-09-30 16:40:36 +02:00

376 lines
9.0 KiB
Go

package build
import (
"encoding/json"
"errors"
"fmt"
"sort"
"github.com/SAP/jenkins-library/pkg/log"
)
// RunState : Current Status of the Build
type RunState string
type resultState string
type msgty string
const (
successful resultState = "SUCCESSFUL"
warning resultState = "WARNING"
erroneous resultState = "ERRONEOUS"
aborted resultState = "ABORTED"
// Initializing : Build Framework prepared
Initializing RunState = "INITIALIZING"
// Accepted : Build Framework triggered
Accepted RunState = "ACCEPTED"
// Running : Build Framework performs build
Running RunState = "RUNNING"
// Finished : Build Framework ended successful
Finished RunState = "FINISHED"
// Failed : Build Framework endded with error
Failed RunState = "FAILED"
loginfo msgty = "I"
logwarning msgty = "W"
logerror msgty = "E"
logaborted msgty = "A"
)
//******** structs needed for json convertion ********
type jsonBuild struct {
Build *Build `json:"d"`
}
type jsonTasks struct {
ResultTasks struct {
Tasks []task `json:"results"`
} `json:"d"`
}
type jsonLogs struct {
ResultLogs struct {
Logs []logStruct `json:"results"`
} `json:"d"`
}
type jsonResults struct {
ResultResults struct {
Results []Result `json:"results"`
} `json:"d"`
}
type jsonValues struct {
ResultValues struct {
Values []Value `json:"results"`
} `json:"d"`
}
// ******** resembling data model in backend ********
// Build : Information for all data comming from Build Framework
type Build struct {
Connector Connector
BuildID string `json:"build_id"`
RunState RunState `json:"run_state"`
ResultState resultState `json:"result_state"`
Phase string `json:"phase"`
Entitytype string `json:"entitytype"`
Startedby string `json:"startedby"`
StartedAt string `json:"started_at"`
FinishedAt string `json:"finished_at"`
Tasks []task
Values []Value
}
type task struct {
connector Connector
BuildID string `json:"build_id"`
TaskID int `json:"task_id"`
LogID string `json:"log_id"`
PluginClass string `json:"plugin_class"`
StartedAt string `json:"started_at"`
FinishedAt string `json:"finished_at"`
ResultState resultState `json:"result_state"`
Logs []logStruct
Results []Result
}
type logStruct struct {
BuildID string `json:"build_id"`
TaskID int `json:"task_id"`
LogID string `json:"log_id"`
Msgty msgty `json:"msgty"`
Detlevel string `json:"detlevel"`
Logline string `json:"log_line"`
Timestamp string `json:"TIME_STMP"`
}
// Result : Artefact from Build Framework step
type Result struct {
connector Connector
BuildID string `json:"build_id"`
TaskID int `json:"task_id"`
Name string `json:"name"`
AdditionalInfo string `json:"additional_info"`
Mimetype string `json:"mimetype"`
}
// Value : Returns Build Runtime Value
type Value struct {
connector Connector
BuildID string `json:"build_id"`
ValueID string `json:"value_id"`
Value string `json:"value"`
}
// Values : Returns Build Runtime Values
type Values struct {
Values []Value `json:"results"`
}
type inputForPost struct {
phase string
values Values
}
// *********************************************************************
// ******************************* Funcs *******************************
// *********************************************************************
// Start : Starts the Build Framework
func (b *Build) Start(phase string, inputValues Values) error {
if err := b.Connector.GetToken(""); err != nil {
return err
}
importBody := inputForPost{
phase: phase,
values: inputValues,
}.String()
body, err := b.Connector.Post("/builds", importBody)
if err != nil {
return err
}
var jBuild jsonBuild
json.Unmarshal(body, &jBuild)
b.BuildID = jBuild.Build.BuildID
b.RunState = jBuild.Build.RunState
b.ResultState = jBuild.Build.ResultState
b.Phase = jBuild.Build.Phase
b.Entitytype = jBuild.Build.Entitytype
b.Startedby = jBuild.Build.Startedby
b.StartedAt = jBuild.Build.StartedAt
b.FinishedAt = jBuild.Build.FinishedAt
fmt.Println("Hello")
return nil
}
// Get : Get all Build tasks
func (b *Build) Get() error {
appendum := "/builds('" + b.BuildID + "')"
body, err := b.Connector.Get(appendum)
if err != nil {
return err
}
var jBuild jsonBuild
json.Unmarshal(body, &jBuild)
b.RunState = jBuild.Build.RunState
b.ResultState = jBuild.Build.ResultState
b.Phase = jBuild.Build.Phase
b.Entitytype = jBuild.Build.Entitytype
b.Startedby = jBuild.Build.Startedby
b.StartedAt = jBuild.Build.StartedAt
b.FinishedAt = jBuild.Build.FinishedAt
return nil
}
func (b *Build) getTasks() error {
if len(b.Tasks) == 0 {
appendum := "/builds('" + b.BuildID + "')/tasks"
body, err := b.Connector.Get(appendum)
if err != nil {
return err
}
var jTasks jsonTasks
json.Unmarshal(body, &jTasks)
b.Tasks = jTasks.ResultTasks.Tasks
sort.Slice(b.Tasks, func(i, j int) bool {
return b.Tasks[i].TaskID < b.Tasks[j].TaskID
})
for i := range b.Tasks {
b.Tasks[i].connector = b.Connector
}
}
return nil
}
func (b *Build) getValues() error {
if len(b.Values) == 0 {
appendum := "/builds('" + b.BuildID + "')/values"
body, err := b.Connector.Get(appendum)
if err != nil {
return err
}
var jValues jsonValues
json.Unmarshal(body, &jValues)
b.Values = jValues.ResultValues.Values
for i := range b.Values {
b.Values[i].connector = b.Connector
}
}
return nil
}
func (b *Build) getLogs() error {
if err := b.getTasks(); err != nil {
return err
}
for i := range b.Tasks {
if err := b.Tasks[i].getLogs(); err != nil {
return err
}
}
return nil
}
// PrintLogs : Returns the Build logs
func (b *Build) PrintLogs() error {
if err := b.getTasks(); err != nil {
return err
}
for i := range b.Tasks {
if err := b.Tasks[i].printLogs(); err != nil {
return err
}
}
return nil
}
func (b *Build) getResults() error {
if err := b.getTasks(); err != nil {
return err
}
for i := range b.Tasks {
if err := b.Tasks[i].getResults(); err != nil {
return err
}
}
return nil
}
func (t *task) printLogs() error {
if err := t.getLogs(); err != nil {
return err
}
for _, logs := range t.Logs {
logs.print()
}
return nil
}
// GetResult : Returns the last Build artefact created from build step
func (b *Build) GetResult(name string) (Result, error) {
var Results []Result
var returnResult Result
if err := b.getResults(); err != nil {
return returnResult, err
}
for _, task := range b.Tasks {
for _, result := range task.Results {
if result.Name == name {
Results = append(Results, result)
}
}
}
switch len(Results) {
case 0:
return returnResult, errors.New("No result named " + name + " was found")
case 1:
return Results[0], nil
default:
return returnResult, errors.New("More than one result with the name " + name + " was found")
}
}
// IsFinished : Returns Build run state
func (b *Build) IsFinished() bool {
if b.RunState == Finished || b.RunState == Failed {
return true
}
return false
}
func (t *task) getLogs() error {
if len(t.Logs) == 0 {
appendum := fmt.Sprint("/tasks(build_id='", t.BuildID, "',task_id=", t.TaskID, ")/logs")
body, err := t.connector.Get(appendum)
if err != nil {
return err
}
var jLogs jsonLogs
json.Unmarshal(body, &jLogs)
t.Logs = jLogs.ResultLogs.Logs
}
return nil
}
func (t *task) getResults() error {
if len(t.Results) == 0 {
appendum := fmt.Sprint("/tasks(build_id='", t.BuildID, "',task_id=", t.TaskID, ")/results")
body, err := t.connector.Get(appendum)
if err != nil {
return err
}
var jResults jsonResults
json.Unmarshal(body, &jResults)
t.Results = jResults.ResultResults.Results
for i := range t.Results {
t.Results[i].connector = t.connector
}
}
return nil
}
// Download : Provides the atrefact of build step
func (result *Result) Download(downloadPath string) error {
appendum := fmt.Sprint("/results(build_id='", result.BuildID, "',task_id=", result.TaskID, ",name='", result.Name, "')/$value")
err := result.connector.Download(appendum, downloadPath)
return err
}
func (logging *logStruct) print() {
switch logging.Msgty {
case loginfo:
log.Entry().WithField("Timestamp", logging.Timestamp).Info(logging.Logline)
case logwarning:
log.Entry().WithField("Timestamp", logging.Timestamp).Warn(logging.Logline)
case logerror:
log.Entry().WithField("Timestamp", logging.Timestamp).Error(logging.Logline)
case logaborted:
log.Entry().WithField("Timestamp", logging.Timestamp).Error(logging.Logline)
default:
}
}
// ******** parsing ********
func (v Value) String() string {
return fmt.Sprintf(
`{ "value_id": "%s", "value": "%s" }`,
v.ValueID,
v.Value)
}
func (vs Values) String() string {
returnString := ""
for _, value := range vs.Values {
returnString = returnString + value.String() + ",\n"
}
returnString = returnString[:len(returnString)-2] //removes last ,
return returnString
}
func (in inputForPost) String() string {
return fmt.Sprintf(`{ "phase": "%s", "values": [%s]}`, in.phase, in.values.String())
}