Skip to content

Commit b174d11

Browse files
sandrogattusoGattuso, Sandro
and
Gattuso, Sandro
authored
Update Spec with Steps and Stages when OriginalYamlString is defined (#25)
* Update Spec with Steps and Stages when OriginalYamlString is defined * Fix Order for Pipeline steps in Spec attribute Co-authored-by: Gattuso, Sandro <[email protected]>
1 parent 190c930 commit b174d11

File tree

4 files changed

+105
-167
lines changed

4 files changed

+105
-167
lines changed

client/pipeline.go

+37-10
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,43 @@ func (t *Trigger) SetVariables(variables map[string]interface{}) {
6363
}
6464

6565
type Spec struct {
66-
Variables []Variable `json:"variables,omitempty"`
67-
SpecTemplate *SpecTemplate `json:"specTemplate,omitempty"`
68-
Triggers []Trigger `json:"triggers,omitempty"`
69-
Priority int `json:"priority,omitempty"`
70-
Concurrency int `json:"concurrency,omitempty"`
71-
Contexts []interface{} `json:"contexts,omitempty"`
72-
Steps map[string]interface{} `json:"steps,omitempty"`
73-
Stages []interface{} `json:"stages,omitempty"`
74-
Mode string `json:"mode,omitempty"`
75-
RuntimeEnvironment RuntimeEnvironment `json:"runtimeEnvironment,omitempty"`
66+
Variables []Variable `json:"variables,omitempty"`
67+
SpecTemplate *SpecTemplate `json:"specTemplate,omitempty"`
68+
Triggers []Trigger `json:"triggers,omitempty"`
69+
Priority int `json:"priority,omitempty"`
70+
Concurrency int `json:"concurrency,omitempty"`
71+
BranchConcurrency int `json:"branchConcurrency,omitempty"`
72+
TriggerConcurrency int `json:"triggerConcurrency,omitempty"`
73+
Contexts []interface{} `json:"contexts,omitempty"`
74+
Steps *Steps `json:"steps,omitempty"`
75+
Stages *Stages `json:"stages,omitempty"`
76+
Mode string `json:"mode,omitempty"`
77+
RuntimeEnvironment RuntimeEnvironment `json:"runtimeEnvironment,omitempty"`
78+
}
79+
80+
type Steps struct {
81+
Steps string
82+
}
83+
type Stages struct {
84+
Stages string
85+
}
86+
87+
func (d Steps) MarshalJSON() ([]byte, error) {
88+
bytes := []byte(d.Steps)
89+
return bytes, nil
90+
}
91+
func (d Stages) MarshalJSON() ([]byte, error) {
92+
bytes := []byte(d.Stages)
93+
return bytes, nil
94+
}
95+
96+
func (d Steps) UnmarshalJSON(data []byte) error {
97+
d.Steps = string(data)
98+
return nil
99+
}
100+
func (d Stages) UnmarshalJSON(data []byte) error {
101+
d.Stages = string(data)
102+
return nil
76103
}
77104

78105
type Pipeline struct {

codefresh/resource_pipeline.go

+65-5
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ package codefresh
22

33
import (
44
"fmt"
5+
"log"
56
"strings"
67

78
cfClient "github.com/codefresh-io/terraform-provider-codefresh/client"
9+
ghodss "github.com/ghodss/yaml"
810
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
"gopkg.in/yaml.v2"
912
)
1013

1114
func resourcePipeline() *schema.Resource {
@@ -383,6 +386,11 @@ func mapResourceToPipeline(d *schema.ResourceData) *cfClient.Pipeline {
383386

384387
tags := d.Get("tags").(*schema.Set).List()
385388

389+
originalYamlString := strings.Replace(
390+
d.Get("original_yaml_string").(string),
391+
"\n",
392+
"\n",
393+
-1)
386394
pipeline := &cfClient.Pipeline{
387395
Metadata: cfClient.Metadata{
388396
Name: d.Get("name").(string),
@@ -391,11 +399,7 @@ func mapResourceToPipeline(d *schema.ResourceData) *cfClient.Pipeline {
391399
Labels: cfClient.Labels{
392400
Tags: convertStringArr(tags),
393401
},
394-
OriginalYamlString: strings.Replace(
395-
d.Get("original_yaml_string").(string),
396-
"\n",
397-
"\n",
398-
-1),
402+
OriginalYamlString: originalYamlString,
399403
},
400404
Spec: cfClient.Spec{
401405
Priority: d.Get("spec.0.priority").(int),
@@ -411,6 +415,14 @@ func mapResourceToPipeline(d *schema.ResourceData) *cfClient.Pipeline {
411415
Revision: d.Get("spec.0.spec_template.0.revision").(string),
412416
Context: d.Get("spec.0.spec_template.0.context").(string),
413417
}
418+
} else {
419+
stages, steps := extractStagesAndSteps(originalYamlString)
420+
pipeline.Spec.Steps = &cfClient.Steps{
421+
Steps: steps,
422+
}
423+
pipeline.Spec.Stages = &cfClient.Stages{
424+
Stages: stages,
425+
}
414426
}
415427

416428
if _, ok := d.GetOk("spec.0.runtime_environment"); ok {
@@ -452,3 +464,51 @@ func mapResourceToPipeline(d *schema.ResourceData) *cfClient.Pipeline {
452464
}
453465
return pipeline
454466
}
467+
468+
// extractStagesAndSteps extracts the steps and stages from the original yaml string to enable propagation in the `Spec` attribute of the pipeline
469+
// We cannot leverage on the standard marshal/unmarshal because the steps attribute needs to maintain the order of elements
470+
// while by default the standard function doesn't do it because in JSON maps are unordered
471+
func extractStagesAndSteps(originalYamlString string) (stages, steps string) {
472+
// Use mapSlice to preserve order of items from the YAML string
473+
m := yaml.MapSlice{}
474+
err := yaml.Unmarshal([]byte(originalYamlString), &m)
475+
if err != nil {
476+
log.Fatal("Unable to unmarshall original_yaml_string")
477+
}
478+
479+
stages = "[]"
480+
// Dynamically build JSON object for steps using String builder
481+
stepsBuilder := strings.Builder{}
482+
stepsBuilder.WriteString("{")
483+
// Parse elements of the YAML string to extract Steps and Stages if defined
484+
for _, item := range m {
485+
if item.Key == "steps" {
486+
switch x := item.Value.(type) {
487+
default:
488+
log.Fatalf("unsupported value type: %T", item.Value)
489+
490+
case yaml.MapSlice:
491+
numberOfSteps := len(x)
492+
for index, item := range x {
493+
// We only need to preserve order at the first level to guarantee order of the steps, hence the child nodes can be marshalled
494+
// with the standard library
495+
y, _ := yaml.Marshal(item.Value)
496+
j2, _ := ghodss.YAMLToJSON(y)
497+
stepsBuilder.WriteString("\"" + item.Key.(string) + "\" : " + string(j2))
498+
if index < numberOfSteps-1 {
499+
stepsBuilder.WriteString(",")
500+
}
501+
}
502+
}
503+
}
504+
if item.Key == "stages" {
505+
// For Stages we don't have ordering issue because it's a list
506+
y, _ := yaml.Marshal(item.Value)
507+
j2, _ := ghodss.YAMLToJSON(y)
508+
stages = string(j2)
509+
}
510+
}
511+
stepsBuilder.WriteString("}")
512+
steps = stepsBuilder.String()
513+
return
514+
}

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ require (
55
github.com/bflad/tfproviderdocs v0.6.0
66
github.com/bflad/tfproviderlint v0.14.0
77
github.com/client9/misspell v0.3.4
8+
github.com/ghodss/yaml v1.0.0
89
github.com/golangci/golangci-lint v1.27.0
910
github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7 // indirect
1011
github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.0-rc.2.0.20200717132200-7435e2abc9d1
1112
github.com/imdario/mergo v0.3.9
1213
github.com/stretchr/objx v0.1.1
1314
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 // indirect
15+
gopkg.in/yaml.v2 v2.2.8
1416
)
1517

1618
go 1.13

0 commit comments

Comments
 (0)