Skip to content

Commit

Permalink
fix(3125): merge parent build meta order by end time (#481)
Browse files Browse the repository at this point in the history
* feat: merge parent build meta by end time order

* feat: add multi parent build meta test

* fix: endTime

* fix: indent

* fix: review

* fix: review

---------

Co-authored-by: Keisuke Kumada <[email protected]>
  • Loading branch information
y-oksaku and kumada626 authored Nov 23, 2024
1 parent 0e8b012 commit dafc34c
Show file tree
Hide file tree
Showing 4 changed files with 388 additions and 52 deletions.
127 changes: 76 additions & 51 deletions launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"path/filepath"
"regexp"
"runtime/debug"
"sort"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -293,53 +294,84 @@ func writeMetafile(metaSpace, metaFile, metaLog string, mergedMeta map[string]in
return nil
}

// SetExternalMeta checks if parent build is external and sets meta in external file accordingly
func SetExternalMeta(api screwdriver.API, pipelineID, parentBuildID int, mergedMeta map[string]interface{}, metaSpace, metaLog string, join bool) (map[string]interface{}, error) {
// setParentBuildsMeta checks if parent build is external and sets meta in external file accordingly
func setParentBuildsMeta(api screwdriver.API, pipelineID int, parentBuildIDs []int, mergedMeta map[string]interface{}, metaSpace, metaLog string) (map[string]interface{}, error) {
var resultMeta = mergedMeta
log.Printf("Fetching Parent Build %d", parentBuildID)
parentBuild, err := api.BuildFromID(parentBuildID)
if err != nil {
return resultMeta, fmt.Errorf("Fetching Parent Build ID %d: %v", parentBuildID, err)
}
var isJoin = len(parentBuildIDs) > 1

log.Printf("Fetching Parent Job %d", parentBuild.JobID)
parentJob, err := api.JobFromID(parentBuild.JobID)
if err != nil {
return resultMeta, fmt.Errorf("Fetching Job ID %d: %v", parentBuild.JobID, err)
parentBuilds := []screwdriver.Build{}

for _, parentBuildId := range parentBuildIDs {
log.Printf("Fetching Parent Build %d", parentBuildId)

parentBuild, err := api.BuildFromID(parentBuildId)

if err != nil {
return resultMeta, fmt.Errorf("Fetching Parent Build ID %d: %v", parentBuildId, err)
}

parentBuilds = append(parentBuilds, parentBuild)
}

if parentBuild.Meta != nil {
// Sort by Endtime ASC
// Last finished parent build is priority
sort.SliceStable(parentBuilds, func(i, j int) bool {
return parentBuilds[i].Endtime.Before(parentBuilds[j].Endtime)
})

for _, parentBuild := range parentBuilds {
if parentBuild.Meta == nil {
continue
}

log.Printf("Fetching Parent Job %d", parentBuild.JobID)
parentJob, err := api.JobFromID(parentBuild.JobID)
if err != nil {
return resultMeta, fmt.Errorf("Fetching Job ID %d: %v", parentBuild.JobID, err)
}

// Check if build is from external pipeline
if pipelineID != parentJob.PipelineID {
// Write to "sd@123:component.json", where sd@123:component is the triggering job
externalMetaFile := "sd@" + strconv.Itoa(parentJob.PipelineID) + ":" + parentJob.Name + ".json"
writeMetafile(metaSpace, externalMetaFile, metaLog, parentBuild.Meta)
if join {
marshallValue, err := json.Marshal(parentBuild.Meta)
if err != nil {
return resultMeta, fmt.Errorf("Cloning meta of Parent Build ID %d: %v", parentBuildID, err)
}
var externalParentBuildMeta map[string]interface{}
json.Unmarshal(marshallValue, &externalParentBuildMeta)

// Always exclude parameters from external meta
delete(externalParentBuildMeta, "parameters")

resultMeta = deepMergeJSON(resultMeta, externalParentBuildMeta)
if pipelineID == parentJob.PipelineID {
resultMeta = deepMergeJSON(resultMeta, parentBuild.Meta)
} else {
resultMeta, err = handleExternalPipelineMeta(parentBuild, parentJob, resultMeta, metaSpace, metaLog, isJoin)

if err != nil {
return resultMeta, fmt.Errorf("Merging meta of External Parent Build ID %d: %v", parentBuild.ID, err)
}
}
}

return resultMeta, nil
}

func handleExternalPipelineMeta(parentBuild screwdriver.Build, parentJob screwdriver.Job, resultMeta map[string]interface{}, metaSpace, metaLog string, isJoin bool) (map[string]interface{}, error) {
// Write to "sd@123:component.json", where sd@123:component is the triggering job
externalMetaFile := "sd@" + strconv.Itoa(parentJob.PipelineID) + ":" + parentJob.Name + ".json"
writeMetafile(metaSpace, externalMetaFile, metaLog, parentBuild.Meta)

if isJoin {
marshallValue, err := json.Marshal(parentBuild.Meta)
if err != nil {
return resultMeta, fmt.Errorf("Cloning meta of Parent Build ID %d: %v", parentBuild.ID, err)
}
var externalParentBuildMeta map[string]interface{}
json.Unmarshal(marshallValue, &externalParentBuildMeta)

// Always exclude parameters from external meta
delete(externalParentBuildMeta, "parameters")

// delete local version of external meta
pIDString := strconv.Itoa(parentJob.PipelineID)
pjn := parentJob.Name
if sdMeta, ok := resultMeta["sd"]; ok {
if externalPipelineMeta, ok := sdMeta.(map[string]interface{})[pIDString]; ok {
if _, ok := externalPipelineMeta.(map[string]interface{})[pjn]; ok {
delete(externalPipelineMeta.(map[string]interface{}), pjn)
}
}
resultMeta = deepMergeJSON(resultMeta, externalParentBuildMeta)
}

// delete local version of external meta
pIDString := strconv.Itoa(parentJob.PipelineID)
pjn := parentJob.Name
if sdMeta, ok := resultMeta["sd"]; ok {
if externalPipelineMeta, ok := sdMeta.(map[string]interface{})[pIDString]; ok {
if _, ok := externalPipelineMeta.(map[string]interface{})[pjn]; ok {
delete(externalPipelineMeta.(map[string]interface{}), pjn)
}
} else {
resultMeta = deepMergeJSON(resultMeta, parentBuild.Meta)
}
}

Expand Down Expand Up @@ -499,23 +531,16 @@ func launch(api screwdriver.API, buildID int, rootDir, emitterPath, metaSpace, s
}
}

if len(parentBuildIDs) > 1 { // If has multiple parent build IDs, merge their metadata (join case)
// If has parent build IDs, merge their metadata
if len(parentBuildIDs) > 0 {
// Get meta from all parent builds
for _, pbID := range parentBuildIDs {
mergedMeta, err = SetExternalMeta(api, pipeline.ID, pbID, mergedMeta, metaSpace, metaLog, true)
if err != nil {
return fmt.Errorf("Setting meta for Parent Build ID %d: %v", pbID, err), "", ""
}
}
mergedMeta, err = setParentBuildsMeta(api, pipeline.ID, parentBuildIDs, mergedMeta, metaSpace, metaLog)

metaLog = fmt.Sprintf(`Builds(%v)`, parentBuildIDs)
} else if len(parentBuildIDs) == 1 { // If has parent build, fetch from parent build
mergedMeta, err = SetExternalMeta(api, pipeline.ID, parentBuildIDs[0], mergedMeta, metaSpace, metaLog, false)
if err != nil {
return fmt.Errorf("Setting meta for Parent Build ID %d: %v", parentBuildIDs[0], err), "", ""
return fmt.Errorf("Setting meta for Parent Build ID %d: %v", parentBuildIDs, err), "", ""
}

metaLog = fmt.Sprintf(`Build(%v)`, parentBuildIDs[0])
metaLog = fmt.Sprintf(`Builds(%v)`, parentBuildIDs)
}

// Initialize pr comments (Issue #1858)
Expand Down
Loading

0 comments on commit dafc34c

Please sign in to comment.