Skip to content

Update Spec with Steps and Stages when OriginalYamlString is defined #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 37 additions & 10 deletions client/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,43 @@ func (t *Trigger) SetVariables(variables map[string]interface{}) {
}

type Spec struct {
Variables []Variable `json:"variables,omitempty"`
SpecTemplate *SpecTemplate `json:"specTemplate,omitempty"`
Triggers []Trigger `json:"triggers,omitempty"`
Priority int `json:"priority,omitempty"`
Concurrency int `json:"concurrency,omitempty"`
Contexts []interface{} `json:"contexts,omitempty"`
Steps map[string]interface{} `json:"steps,omitempty"`
Stages []interface{} `json:"stages,omitempty"`
Mode string `json:"mode,omitempty"`
RuntimeEnvironment RuntimeEnvironment `json:"runtimeEnvironment,omitempty"`
Variables []Variable `json:"variables,omitempty"`
SpecTemplate *SpecTemplate `json:"specTemplate,omitempty"`
Triggers []Trigger `json:"triggers,omitempty"`
Priority int `json:"priority,omitempty"`
Concurrency int `json:"concurrency,omitempty"`
BranchConcurrency int `json:"branchConcurrency,omitempty"`
TriggerConcurrency int `json:"triggerConcurrency,omitempty"`
Contexts []interface{} `json:"contexts,omitempty"`
Steps *Steps `json:"steps,omitempty"`
Stages *Stages `json:"stages,omitempty"`
Mode string `json:"mode,omitempty"`
RuntimeEnvironment RuntimeEnvironment `json:"runtimeEnvironment,omitempty"`
}

type Steps struct {
Steps string
}
type Stages struct {
Stages string
}

func (d Steps) MarshalJSON() ([]byte, error) {
bytes := []byte(d.Steps)
return bytes, nil
}
func (d Stages) MarshalJSON() ([]byte, error) {
bytes := []byte(d.Stages)
return bytes, nil
}

func (d Steps) UnmarshalJSON(data []byte) error {
d.Steps = string(data)
return nil
}
func (d Stages) UnmarshalJSON(data []byte) error {
d.Stages = string(data)
return nil
}

type Pipeline struct {
Expand Down
70 changes: 65 additions & 5 deletions codefresh/resource_pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package codefresh

import (
"fmt"
"log"
"strings"

cfClient "github.com/codefresh-io/terraform-provider-codefresh/client"
ghodss "github.com/ghodss/yaml"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"gopkg.in/yaml.v2"
)

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

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

originalYamlString := strings.Replace(
d.Get("original_yaml_string").(string),
"\n",
"\n",
-1)
pipeline := &cfClient.Pipeline{
Metadata: cfClient.Metadata{
Name: d.Get("name").(string),
Expand All @@ -391,11 +399,7 @@ func mapResourceToPipeline(d *schema.ResourceData) *cfClient.Pipeline {
Labels: cfClient.Labels{
Tags: convertStringArr(tags),
},
OriginalYamlString: strings.Replace(
d.Get("original_yaml_string").(string),
"\n",
"\n",
-1),
OriginalYamlString: originalYamlString,
},
Spec: cfClient.Spec{
Priority: d.Get("spec.0.priority").(int),
Expand All @@ -411,6 +415,14 @@ func mapResourceToPipeline(d *schema.ResourceData) *cfClient.Pipeline {
Revision: d.Get("spec.0.spec_template.0.revision").(string),
Context: d.Get("spec.0.spec_template.0.context").(string),
}
} else {
stages, steps := extractStagesAndSteps(originalYamlString)
pipeline.Spec.Steps = &cfClient.Steps{
Steps: steps,
}
pipeline.Spec.Stages = &cfClient.Stages{
Stages: stages,
}
}

if _, ok := d.GetOk("spec.0.runtime_environment"); ok {
Expand Down Expand Up @@ -452,3 +464,51 @@ func mapResourceToPipeline(d *schema.ResourceData) *cfClient.Pipeline {
}
return pipeline
}

// extractStagesAndSteps extracts the steps and stages from the original yaml string to enable propagation in the `Spec` attribute of the pipeline
// We cannot leverage on the standard marshal/unmarshal because the steps attribute needs to maintain the order of elements
// while by default the standard function doesn't do it because in JSON maps are unordered
func extractStagesAndSteps(originalYamlString string) (stages, steps string) {
// Use mapSlice to preserve order of items from the YAML string
m := yaml.MapSlice{}
err := yaml.Unmarshal([]byte(originalYamlString), &m)
if err != nil {
log.Fatal("Unable to unmarshall original_yaml_string")
}

stages = "[]"
// Dynamically build JSON object for steps using String builder
stepsBuilder := strings.Builder{}
stepsBuilder.WriteString("{")
// Parse elements of the YAML string to extract Steps and Stages if defined
for _, item := range m {
if item.Key == "steps" {
switch x := item.Value.(type) {
default:
log.Fatalf("unsupported value type: %T", item.Value)

case yaml.MapSlice:
numberOfSteps := len(x)
for index, item := range x {
// We only need to preserve order at the first level to guarantee order of the steps, hence the child nodes can be marshalled
// with the standard library
y, _ := yaml.Marshal(item.Value)
j2, _ := ghodss.YAMLToJSON(y)
stepsBuilder.WriteString("\"" + item.Key.(string) + "\" : " + string(j2))
if index < numberOfSteps-1 {
stepsBuilder.WriteString(",")
}
}
}
}
if item.Key == "stages" {
// For Stages we don't have ordering issue because it's a list
y, _ := yaml.Marshal(item.Value)
j2, _ := ghodss.YAMLToJSON(y)
stages = string(j2)
}
}
stepsBuilder.WriteString("}")
steps = stepsBuilder.String()
return
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ require (
github.com/bflad/tfproviderdocs v0.6.0
github.com/bflad/tfproviderlint v0.14.0
github.com/client9/misspell v0.3.4
github.com/ghodss/yaml v1.0.0
github.com/golangci/golangci-lint v1.27.0
github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.0-rc.2.0.20200717132200-7435e2abc9d1
github.com/imdario/mergo v0.3.9
github.com/stretchr/objx v0.1.1
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 // indirect
gopkg.in/yaml.v2 v2.2.8
)

go 1.13
Loading