2021-06-23 15:05:00 +02:00
|
|
|
package toolrecord
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2022-08-09 10:57:02 +02:00
|
|
|
"io/fs"
|
2021-07-23 08:48:48 +02:00
|
|
|
"os"
|
2021-06-23 15:05:00 +02:00
|
|
|
"path/filepath"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type keydataset struct {
|
|
|
|
Name string // technical name from the tool
|
|
|
|
Value string // technical value
|
|
|
|
DisplayName string // user friendly name - optional
|
|
|
|
URL string // direct URL to navigate to this key in the tool backend - optional
|
|
|
|
}
|
|
|
|
|
|
|
|
// Toolrecord holds all data to locate a tool result
|
|
|
|
// in the tool's backend
|
|
|
|
type Toolrecord struct {
|
|
|
|
RecordVersion int
|
|
|
|
|
|
|
|
ToolName string
|
|
|
|
ToolInstance string
|
|
|
|
|
|
|
|
// tool agnostic convenience aggregations
|
|
|
|
// picks the most specific URL + concatenate the dimension names
|
|
|
|
// for easy dashboard / xls creation
|
|
|
|
DisplayName string
|
|
|
|
DisplayURL string
|
|
|
|
|
2022-08-09 10:57:02 +02:00
|
|
|
fileUtils fileWriteUtils
|
|
|
|
|
2021-06-23 15:05:00 +02:00
|
|
|
// detailed keydata - needs tool-specific parsing
|
|
|
|
Keys []keydataset
|
|
|
|
|
|
|
|
// place for additional context information
|
|
|
|
Context map[string]interface{}
|
|
|
|
|
|
|
|
// internal - not exported to the json
|
|
|
|
workspace string
|
|
|
|
reportFileName string
|
|
|
|
}
|
|
|
|
|
2022-08-09 10:57:02 +02:00
|
|
|
type fileWriteUtils interface {
|
|
|
|
MkdirAll(path string, perm fs.FileMode) error
|
|
|
|
WriteFile(name string, data []byte, perm fs.FileMode) error
|
|
|
|
}
|
|
|
|
|
2021-06-23 15:05:00 +02:00
|
|
|
// New - initialize a new toolrecord
|
2022-08-09 10:57:02 +02:00
|
|
|
func New(fileUtils fileWriteUtils, workspace, toolName, toolInstance string) *Toolrecord {
|
2021-06-23 15:05:00 +02:00
|
|
|
tr := Toolrecord{}
|
2022-08-09 10:57:02 +02:00
|
|
|
tr.fileUtils = fileUtils
|
2021-06-23 15:05:00 +02:00
|
|
|
|
|
|
|
tr.RecordVersion = 1
|
|
|
|
tr.ToolName = toolName
|
|
|
|
tr.ToolInstance = toolInstance
|
|
|
|
tr.Keys = []keydataset{}
|
|
|
|
tr.Context = make(map[string]interface{})
|
|
|
|
|
|
|
|
tr.workspace = workspace
|
|
|
|
|
|
|
|
now := time.Now().UTC()
|
|
|
|
reportFileName := filepath.Join(workspace,
|
2021-07-23 08:48:48 +02:00
|
|
|
"toolruns",
|
2021-06-23 15:05:00 +02:00
|
|
|
"toolrun_"+toolName+"_"+
|
2021-07-23 08:48:48 +02:00
|
|
|
now.Format("20060102150405")+
|
2021-06-23 15:05:00 +02:00
|
|
|
".json")
|
|
|
|
tr.reportFileName = reportFileName
|
|
|
|
|
|
|
|
return &tr
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddKeyData - add one key to the current toolrecord
|
|
|
|
// calls must follow the tool's hierachy ( e.g. org -> project)
|
|
|
|
// as DisplayName & DisplayURL are based on the call sequence
|
|
|
|
func (tr *Toolrecord) AddKeyData(keyname, keyvalue, displayname, url string) error {
|
|
|
|
if keyname == "" {
|
|
|
|
return errors.New("TR_ADD_KEY: empty keyname")
|
|
|
|
}
|
|
|
|
if keyvalue == "" {
|
|
|
|
return fmt.Errorf("TR_ADD_KEY: empty keyvalue for %v", keyname)
|
|
|
|
}
|
|
|
|
keydata := keydataset{Name: keyname, Value: keyvalue, DisplayName: displayname, URL: url}
|
|
|
|
tr.Keys = append(tr.Keys, keydata)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddContext - add additional context information
|
|
|
|
// second call with the same label will overwrite the first call's data
|
|
|
|
func (tr *Toolrecord) AddContext(label string, data interface{}) error {
|
|
|
|
if label == "" {
|
|
|
|
return errors.New("TR_ADD_CONTEXT: no label supplied")
|
|
|
|
}
|
|
|
|
tr.Context[label] = data
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetFileName - local filename for the current record
|
|
|
|
func (tr *Toolrecord) GetFileName() string {
|
|
|
|
return tr.reportFileName
|
|
|
|
}
|
|
|
|
|
|
|
|
// Persist - write the current record to file system
|
|
|
|
func (tr *Toolrecord) Persist() error {
|
|
|
|
if tr.workspace == "" {
|
|
|
|
return errors.New("TR_PERSIST: empty workspace ")
|
|
|
|
}
|
|
|
|
if tr.ToolName == "" {
|
|
|
|
return errors.New("TR_PERSIST: empty toolName")
|
|
|
|
}
|
|
|
|
if tr.ToolInstance == "" {
|
|
|
|
return errors.New("TR_PERSIST: empty instanceName")
|
|
|
|
}
|
2021-07-23 08:48:48 +02:00
|
|
|
// create workspace/toolrecord
|
|
|
|
dirPath := filepath.Join(tr.workspace, "toolruns")
|
2022-08-09 10:57:02 +02:00
|
|
|
err := tr.fileUtils.MkdirAll(dirPath, os.ModePerm)
|
2021-07-23 08:48:48 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("TR_PERSIST: %v", err)
|
|
|
|
}
|
2021-09-10 13:20:54 +02:00
|
|
|
|
|
|
|
// set default display data if required
|
|
|
|
if tr.DisplayName == "" {
|
|
|
|
tr.GenerateDefaultDisplayData()
|
|
|
|
}
|
|
|
|
|
|
|
|
file, err := json.Marshal(tr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("TR_PERSIST: %v", err)
|
|
|
|
}
|
|
|
|
// no json generated ?
|
|
|
|
if len(file) == 0 {
|
|
|
|
return fmt.Errorf("TR_PERSIST: empty json content")
|
|
|
|
}
|
2022-08-09 10:57:02 +02:00
|
|
|
err = tr.fileUtils.WriteFile(tr.GetFileName(), file, 0o644)
|
2021-09-10 13:20:54 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("TR_PERSIST: %v", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-09 10:57:02 +02:00
|
|
|
// GenerateDefaultDisplayData - default aggregation for overall displayName and URL
|
2021-09-10 13:20:54 +02:00
|
|
|
// can be overriden by calling SetOverallDisplayData
|
|
|
|
func (tr *Toolrecord) GenerateDefaultDisplayData() {
|
2021-06-23 15:05:00 +02:00
|
|
|
displayName := ""
|
|
|
|
displayURL := ""
|
|
|
|
for _, keyset := range tr.Keys {
|
|
|
|
// create "name1 - name2 - name3"
|
|
|
|
subDisplayName := keyset.DisplayName
|
|
|
|
if subDisplayName != "" {
|
|
|
|
if displayName != "" {
|
|
|
|
displayName = displayName + " - "
|
|
|
|
}
|
|
|
|
displayName = displayName + subDisplayName
|
|
|
|
}
|
|
|
|
subURL := keyset.URL
|
|
|
|
if subURL != "" {
|
|
|
|
displayURL = subURL
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tr.DisplayName = displayName
|
|
|
|
tr.DisplayURL = displayURL
|
|
|
|
}
|
2021-09-09 10:50:33 +02:00
|
|
|
|
2022-08-09 10:57:02 +02:00
|
|
|
// SetOverallDisplayData - override the default generation for DisplayName & DisplayURL
|
2021-09-09 10:50:33 +02:00
|
|
|
func (tr *Toolrecord) SetOverallDisplayData(newName, newURL string) {
|
|
|
|
tr.DisplayName = newName
|
|
|
|
tr.DisplayURL = newURL
|
|
|
|
}
|