|
1 | 1 | package codefresh
|
2 | 2 |
|
3 | 3 | import (
|
4 |
| - "encoding/json" |
5 | 4 | "fmt"
|
6 | 5 | "log"
|
7 | 6 | "regexp"
|
| 7 | + "strconv" |
8 | 8 | "strings"
|
9 | 9 |
|
10 | 10 | cfClient "github.com/codefresh-io/terraform-provider-codefresh/client"
|
11 | 11 | "github.com/hashicorp/go-cty/cty"
|
12 | 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
13 | 13 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
14 | 14 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
|
15 |
| - "gopkg.in/yaml.v2" |
16 | 15 | )
|
17 | 16 |
|
18 | 17 | var terminationPolicyOnCreateBranchAttributes = []string{"branchName", "ignoreTrigger", "ignoreBranch"}
|
@@ -482,9 +481,12 @@ func resourcePipelineCreate(d *schema.ResourceData, meta interface{}) error {
|
482 | 481 |
|
483 | 482 | client := meta.(*cfClient.Client)
|
484 | 483 |
|
485 |
| - pipeline := *mapResourceToPipeline(d) |
| 484 | + pipeline, err := mapResourceToPipeline(d) |
| 485 | + if err != nil { |
| 486 | + return err |
| 487 | + } |
486 | 488 |
|
487 |
| - resp, err := client.CreatePipeline(&pipeline) |
| 489 | + resp, err := client.CreatePipeline(pipeline) |
488 | 490 | if err != nil {
|
489 | 491 | return err
|
490 | 492 | }
|
@@ -522,10 +524,14 @@ func resourcePipelineUpdate(d *schema.ResourceData, meta interface{}) error {
|
522 | 524 |
|
523 | 525 | client := meta.(*cfClient.Client)
|
524 | 526 |
|
525 |
| - pipeline := *mapResourceToPipeline(d) |
| 527 | + pipeline, err := mapResourceToPipeline(d) |
| 528 | + if err != nil { |
| 529 | + return err |
| 530 | + } |
| 531 | + |
526 | 532 | pipeline.Metadata.ID = d.Id()
|
527 | 533 |
|
528 |
| - _, err := client.UpdatePipeline(&pipeline) |
| 534 | + _, err = client.UpdatePipeline(pipeline) |
529 | 535 | if err != nil {
|
530 | 536 | return err
|
531 | 537 | }
|
@@ -735,7 +741,7 @@ func flattenTriggers(triggers []cfClient.Trigger) []map[string]interface{} {
|
735 | 741 | return res
|
736 | 742 | }
|
737 | 743 |
|
738 |
| -func mapResourceToPipeline(d *schema.ResourceData) *cfClient.Pipeline { |
| 744 | +func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { |
739 | 745 |
|
740 | 746 | tags := d.Get("tags").(*schema.Set).List()
|
741 | 747 |
|
@@ -774,7 +780,10 @@ func mapResourceToPipeline(d *schema.ResourceData) *cfClient.Pipeline {
|
774 | 780 | Context: d.Get("spec.0.spec_template.0.context").(string),
|
775 | 781 | }
|
776 | 782 | } else {
|
777 |
| - extractSpecAttributesFromOriginalYamlString(originalYamlString, pipeline) |
| 783 | + err := extractSpecAttributesFromOriginalYamlString(originalYamlString, pipeline) |
| 784 | + if err != nil { |
| 785 | + return nil, err |
| 786 | + } |
778 | 787 | }
|
779 | 788 |
|
780 | 789 | if _, ok := d.GetOk("spec.0.runtime_environment"); ok {
|
@@ -870,71 +879,61 @@ func mapResourceToPipeline(d *schema.ResourceData) *cfClient.Pipeline {
|
870 | 879 |
|
871 | 880 | pipeline.Spec.TerminationPolicy = codefreshTerminationPolicy
|
872 | 881 |
|
873 |
| - return pipeline |
| 882 | + return pipeline, nil |
874 | 883 | }
|
875 | 884 |
|
876 |
| -// extractSpecAttributesFromOriginalYamlString extracts the steps and stages from the original yaml string to enable propagation in the `Spec` attribute of the pipeline |
877 |
| -// We cannot leverage on the standard marshal/unmarshal because the steps attribute needs to maintain the order of elements |
878 |
| -// while by default the standard function doesn't do it because in JSON maps are unordered |
879 |
| -func extractSpecAttributesFromOriginalYamlString(originalYamlString string, pipeline *cfClient.Pipeline) { |
880 |
| - ms := OrderedMapSlice{} |
881 |
| - err := yaml.Unmarshal([]byte(originalYamlString), &ms) |
882 |
| - if err != nil { |
883 |
| - log.Fatalf("Unable to unmarshall original_yaml_string. Error: %v", err) |
884 |
| - } |
| 885 | +// This function is used to extract the spec attributes from the original_yaml_string attribute. |
| 886 | +// Typically, unmarshalling the YAML string is problematic because the order of the attributes is not preserved. |
| 887 | +// Namely, we care a lot about the order of the steps and stages attributes. |
| 888 | +// Luckily, the yj package introduces a MapSlice type that preserves the order Map items (see utils.go). |
| 889 | +func extractSpecAttributesFromOriginalYamlString(originalYamlString string, pipeline *cfClient.Pipeline) error { |
| 890 | + for _, attribute := range []string{"stages", "steps", "hooks"} { |
| 891 | + yamlString, err := yq(fmt.Sprintf(".%s", attribute), originalYamlString) |
| 892 | + if err != nil { |
| 893 | + return fmt.Errorf("error while extracting '%s' from original YAML string: %v", attribute, err) |
| 894 | + } else if yamlString == "" { |
| 895 | + continue |
| 896 | + } |
885 | 897 |
|
886 |
| - stages := "[]" |
887 |
| - steps := "{}" |
888 |
| - hooks := "{}" |
| 898 | + attributeJson, err := yamlToJson(yamlString) |
| 899 | + if err != nil { |
| 900 | + return fmt.Errorf("error while converting '%s' YAML to JSON: %v", attribute, err) |
| 901 | + } |
889 | 902 |
|
890 |
| - // Parse elements of the YAML string to extract Steps, Hooks and Stages if defined |
891 |
| - for _, item := range ms { |
892 |
| - key := item.Key.(string) |
893 |
| - switch key { |
| 903 | + switch attribute { |
| 904 | + case "stages": |
| 905 | + pipeline.Spec.Stages = &cfClient.Stages{ |
| 906 | + Stages: attributeJson, |
| 907 | + } |
894 | 908 | case "steps":
|
895 |
| - switch x := item.Value.(type) { |
896 |
| - default: |
897 |
| - log.Fatalf("unsupported value type: %T", item.Value) |
898 |
| - |
899 |
| - case OrderedMapSlice: |
900 |
| - s, _ := json.Marshal(x) |
901 |
| - steps = string(s) |
| 909 | + pipeline.Spec.Steps = &cfClient.Steps{ |
| 910 | + Steps: attributeJson, |
902 | 911 | }
|
903 |
| - case "stages": |
904 |
| - s, _ := json.Marshal(item.Value) |
905 |
| - stages = string(s) |
906 |
| - |
907 | 912 | case "hooks":
|
908 |
| - switch x := item.Value.(type) { |
909 |
| - default: |
910 |
| - log.Fatalf("unsupported value type: %T", item.Value) |
911 |
| - |
912 |
| - case OrderedMapSlice: |
913 |
| - h, _ := json.Marshal(x) |
914 |
| - hooks = string(h) |
| 913 | + pipeline.Spec.Hooks = &cfClient.Hooks{ |
| 914 | + Hooks: attributeJson, |
915 | 915 | }
|
916 |
| - case "mode": |
917 |
| - pipeline.Spec.Mode = item.Value.(string) |
918 |
| - case "fail_fast": |
919 |
| - ff, ok := item.Value.(bool) |
920 |
| - if ok { |
921 |
| - pipeline.Spec.FailFast = &ff |
922 |
| - } |
923 |
| - default: |
924 |
| - log.Printf("Unsupported entry %s", key) |
925 | 916 | }
|
926 | 917 | }
|
927 | 918 |
|
928 |
| - pipeline.Spec.Steps = &cfClient.Steps{ |
929 |
| - Steps: steps, |
930 |
| - } |
931 |
| - pipeline.Spec.Stages = &cfClient.Stages{ |
932 |
| - Stages: stages, |
933 |
| - } |
934 |
| - pipeline.Spec.Hooks = &cfClient.Hooks{ |
935 |
| - Hooks: hooks, |
| 919 | + mode, err := yq(".mode", originalYamlString) |
| 920 | + if err != nil { |
| 921 | + return fmt.Errorf("error while extracting 'mode' from original YAML string: %v", err) |
| 922 | + } else if mode != "" { |
| 923 | + pipeline.Spec.Mode = mode |
936 | 924 | }
|
937 | 925 |
|
| 926 | + ff, err := yq(".fail_fast", originalYamlString) |
| 927 | + if err != nil { |
| 928 | + return fmt.Errorf("error while extracting 'mode' from original YAML string: %v", err) |
| 929 | + } else if ff != "" { |
| 930 | + ff_b, err := strconv.ParseBool(strings.TrimSpace(ff)) |
| 931 | + if err != nil { |
| 932 | + return fmt.Errorf("error while parsing 'fail_fast' as boolean: %v", err) |
| 933 | + } |
| 934 | + pipeline.Spec.FailFast = &ff_b |
| 935 | + } |
| 936 | + return nil |
938 | 937 | }
|
939 | 938 |
|
940 | 939 | func getSupportedTerminationPolicyAttributes(policy string) map[string]interface{} {
|
|
0 commit comments