@@ -2,10 +2,13 @@ package codefresh
22
33import (
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
1114func 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+ }
0 commit comments