Skip to content

Commit

Permalink
Add postSync configuration as part of DeploymentConfiguration (#2792)
Browse files Browse the repository at this point in the history
**What this PR does / why we need it**:

**Which issue(s) this PR fixes**:

Fixes #

**Does this PR introduce a user-facing change?**:
<!--
If no, just write "NONE" in the release-note block below.
-->
```release-note
NONE
```

This PR was merged by Kapetanios.
  • Loading branch information
khanhtc1202 authored Nov 18, 2021
1 parent 4142590 commit bac362b
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 0 deletions.
83 changes: 83 additions & 0 deletions pkg/config/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type GenericDeploymentSpec struct {
TriggerPaths []string `json:"triggerPaths,omitempty"`
// The trigger configuration use to determine trigger logic.
Trigger Trigger `json:"trigger"`
// Configuration to be used once the deployment is triggered successfully.
PostSync *PostSync `json:"postSync"`
// The maximum length of time to execute deployment before giving up.
// Default is 6h.
Timeout Duration `json:"timeout,omitempty" default:"6h"`
Expand Down Expand Up @@ -106,6 +108,12 @@ func (s *GenericDeploymentSpec) Validate() error {
}
}

if ps := s.PostSync; ps != nil {
if err := ps.Validate(); err != nil {
return err
}
}

if e := s.Encryption; e != nil {
if err := e.Validate(); err != nil {
return err
Expand Down Expand Up @@ -524,3 +532,78 @@ func (n *NotificationMention) Validate() error {
}
return fmt.Errorf("event %q is incorrect as NotificationEventType", n.Event)
}

// PostSync provides all configurations to be used once the current deployment
// is triggered successfully.
type PostSync struct {
DeploymentChain *DeploymentChain `json:"chain"`
}

func (p *PostSync) Validate() error {
if dc := p.DeploymentChain; dc != nil {
return dc.Validate()
}
return nil
}

// DeploymentChain provides all configurations used to trigger a chain of deployments.
type DeploymentChain struct {
// Nodes provides list of DeploymentChainNodes which contain filters to be used
// to find applications to deploy as chain node. It's required to not empty.
Nodes []*DeploymentChainNode `json:"applications"`
// Conditions provides configuration used to determine should the piped in charge in
// the first applications in the chain trigger a whole new deployment chain or not.
// If this field is not set, always trigger a whole new deployment chain when the current
// application is triggered.
// TODO: Add conditions to deployment chain configuration.
// Conditions *DeploymentChainTriggerCondition `json:"conditions,omitempty"`
}

func (dc *DeploymentChain) Validate() error {
if len(dc.Nodes) == 0 {
return fmt.Errorf("missing specified applications that will be triggered on this chain of deployment")
}

for _, n := range dc.Nodes {
if err := n.Validate(); err != nil {
return err
}
}

// if cc := dc.Conditions; cc != nil {
// if err := cc.Validate(); err != nil {
// return err
// }
// }

return nil
}

// DeploymentChainNode provides filters used to find the right applications to trigger
// as a part of the deployment chain.
type DeploymentChainNode struct {
AppName string `json:"name"`
AppKind string `json:"kind"`
AppLabels map[string]string `json:"labels"`
}

func (n *DeploymentChainNode) Validate() error {
hasFilterCond := n.AppName != "" || n.AppKind != "" || len(n.AppLabels) != 0

if !hasFilterCond {
return fmt.Errorf("at least one of \"name\", \"kind\" or \"labels\" must be set to find applications to deploy")
}
return nil
}

type DeploymentChainTriggerCondition struct {
CommitPrefix string `json:"commitPrefix"`
}

func (c *DeploymentChainTriggerCondition) Validate() error {
hasCond := c.CommitPrefix != ""
if !hasCond {
return fmt.Errorf("missing commitPrefix configration as deployment chain trigger condition")
}
return nil
}
60 changes: 60 additions & 0 deletions pkg/config/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,3 +383,63 @@ func TestTrueByDefaultBoolConfiguration(t *testing.T) {
})
}
}

func TestGenericPostSyncConfiguration(t *testing.T) {
testcases := []struct {
fileName string
expectedKind Kind
expectedAPIVersion string
expectedSpec interface{}
expectedError error
}{
{
fileName: "testdata/application/generic-postsync.yaml",
expectedKind: KindKubernetesApp,
expectedAPIVersion: "pipecd.dev/v1beta1",
expectedSpec: &KubernetesDeploymentSpec{
GenericDeploymentSpec: GenericDeploymentSpec{
Timeout: Duration(6 * time.Hour),
Trigger: Trigger{
OnOutOfSync: OnOutOfSync{
Disabled: newBoolPointer(true),
MinWindow: Duration(5 * time.Minute),
},
},
PostSync: &PostSync{
DeploymentChain: &DeploymentChain{
Nodes: []*DeploymentChainNode{
{
AppName: "app-1",
},
{
AppLabels: map[string]string{
"env": "staging",
"foo": "bar",
},
},
{
AppKind: "ECSApp",
},
},
},
},
},
Input: KubernetesDeploymentInput{
AutoRollback: newBoolPointer(true),
},
},
expectedError: nil,
},
}
for _, tc := range testcases {
t.Run(tc.fileName, func(t *testing.T) {
cfg, err := LoadFromYAML(tc.fileName)
require.Equal(t, tc.expectedError, err)
if err == nil {
assert.Equal(t, tc.expectedKind, cfg.Kind)
assert.Equal(t, tc.expectedAPIVersion, cfg.APIVersion)
assert.Equal(t, tc.expectedSpec, cfg.spec)
}
})
}
}
11 changes: 11 additions & 0 deletions pkg/config/testdata/application/generic-postsync.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: pipecd.dev/v1beta1
kind: KubernetesApp
spec:
postSync:
chain:
applications:
- name: app-1
- labels:
env: staging
foo: bar
- kind: ECSApp

0 comments on commit bac362b

Please sign in to comment.