@@ -2,6 +2,7 @@ package buildplan
22
33import (
44 "encoding/json"
5+ "sort"
56
67 "github.com/go-openapi/strfmt"
78
@@ -30,7 +31,7 @@ func Unmarshal(data []byte) (*BuildPlan, error) {
3031
3132 b .raw = & rawBuild
3233
33- b .cleanup ()
34+ b .sanitize ()
3435
3536 if err := b .hydrate (); err != nil {
3637 return nil , errs .Wrap (err , "error hydrating build plan" )
@@ -45,12 +46,13 @@ func Unmarshal(data []byte) (*BuildPlan, error) {
4546}
4647
4748func (b * BuildPlan ) Marshal () ([]byte , error ) {
48- return json .Marshal (b .raw )
49+ return json .MarshalIndent (b .raw , "" , " " )
4950}
5051
51- // cleanup empty targets
52- // The type aliasing in the query populates the response with emtpy targets that we should remove
53- func (b * BuildPlan ) cleanup () {
52+ // sanitize will remove empty targets and sort slices to ensure consistent interpretation of the same buildplan
53+ // Empty targets: The type aliasing in the query populates the response with emtpy targets that we should remove
54+ // Sorting: The API does not do any slice ordering, meaning the same buildplan retrieved twice can use different ordering
55+ func (b * BuildPlan ) sanitize () {
5456 b .raw .Steps = sliceutils .Filter (b .raw .Steps , func (s * raw.Step ) bool {
5557 return s .StepID != ""
5658 })
@@ -62,6 +64,27 @@ func (b *BuildPlan) cleanup() {
6264 b .raw .Artifacts = sliceutils .Filter (b .raw .Artifacts , func (a * raw.Artifact ) bool {
6365 return a .NodeID != ""
6466 })
67+
68+ sort .Slice (b .raw .Sources , func (i , j int ) bool { return b .raw .Sources [i ].NodeID < b .raw .Sources [j ].NodeID })
69+ sort .Slice (b .raw .Steps , func (i , j int ) bool { return b .raw .Steps [i ].StepID < b .raw .Steps [j ].StepID })
70+ sort .Slice (b .raw .Artifacts , func (i , j int ) bool { return b .raw .Artifacts [i ].NodeID < b .raw .Artifacts [j ].NodeID })
71+ sort .Slice (b .raw .Terminals , func (i , j int ) bool { return b .raw .Terminals [i ].Tag < b .raw .Terminals [j ].Tag })
72+ sort .Slice (b .raw .ResolvedRequirements , func (i , j int ) bool {
73+ return b .raw .ResolvedRequirements [i ].Source < b .raw .ResolvedRequirements [j ].Source
74+ })
75+ for _ , t := range b .raw .Terminals {
76+ sort .Slice (t .NodeIDs , func (i , j int ) bool { return t .NodeIDs [i ] < t .NodeIDs [j ] })
77+ }
78+ for _ , a := range b .raw .Artifacts {
79+ sort .Slice (a .RuntimeDependencies , func (i , j int ) bool { return a .RuntimeDependencies [i ] < a .RuntimeDependencies [j ] })
80+ }
81+ for _ , step := range b .raw .Steps {
82+ sort .Slice (step .Inputs , func (i , j int ) bool { return step .Inputs [i ].Tag < step .Inputs [j ].Tag })
83+ sort .Slice (step .Outputs , func (i , j int ) bool { return step .Outputs [i ] < step .Outputs [j ] })
84+ for _ , input := range step .Inputs {
85+ sort .Slice (input .NodeIDs , func (i , j int ) bool { return input .NodeIDs [i ] < input .NodeIDs [j ] })
86+ }
87+ }
6588}
6689
6790func (b * BuildPlan ) Platforms () []strfmt.UUID {
0 commit comments