Skip to content

Commit

Permalink
Merge pull request #81 from jgramoll/cloudformation
Browse files Browse the repository at this point in the history
Cloudformation
  • Loading branch information
jgramoll committed Nov 13, 2020
2 parents 70ca7a0 + 004f65b commit 3a60535
Show file tree
Hide file tree
Showing 49 changed files with 781 additions and 179 deletions.
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,47 @@ resource "spinnaker_pipeline_patch_manifest_stage" "test" {
merge_strategy = "strategic"
}
}
resource "spinnaker_pipeline_deploy_cloudformation_stage" "test" {
pipeline = spinnaker_pipeline.test.id
name = "Deploy Cloudformation"
credentials = "my-aws-account"
stack_name = "my cf stack"
regions = [
"us-east-1"
]
templateBody = <<EOT
AWSTemplateFormatVersion: 2010-09-09
Description: "Sample"
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: error.html
DeletionPolicy: Retain
Outputs:
WebsiteURL:
Value:
GetAtt:
- S3Bucket
- WebsiteURL
Description: URL for website hosted on S3
S3BucketSecureURL:
Value:
Join:
- ''
- - 'https://'
-
GetAtt:
- S3Bucket
- DomainName
Description: Name of S3 bucket to hold website content
EOT
}
```

## Local Dev ##
Expand Down
1 change: 1 addition & 0 deletions client/check_preconditions_stage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ var checkPreconditionsJson = `{
"restrictedExecutionWindow": null,
"notifications": null,
"expectedArtifacts": [],
"requiredArtifactIds": [],
"preconditions": [
{
"failPipeline": true,
Expand Down
48 changes: 48 additions & 0 deletions client/deploy_cloudformation_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package client

import (
"fmt"
)

// DeployCloudformationSource source type
type DeployCloudformationSource int

const (
// DeployCloudformationSourceUnknown default unknown
DeployCloudformationSourceUnknown DeployCloudformationSource = iota
// DeployCloudformationSourceText text
DeployCloudformationSourceText
// DeployCloudformationSourceArtifact artifact
DeployCloudformationSourceArtifact
)

func (s DeployCloudformationSource) String() string {
return [...]string{"unknown", "text", "artifact"}[s]
}

// ParseDeployCloudformationSource parse source
func ParseDeployCloudformationSource(s string) (DeployCloudformationSource, error) {
switch s {
default:
return DeployCloudformationSourceUnknown, fmt.Errorf("Unknown source %s", s)
case "text":
return DeployCloudformationSourceText, nil
case "artifact":
return DeployCloudformationSourceArtifact, nil
}
}

// MarshalText source to text
func (s DeployCloudformationSource) MarshalText() ([]byte, error) {
return []byte(s.String()), nil
}

// UnmarshalText source from text
func (s *DeployCloudformationSource) UnmarshalText(text []byte) error {
parsedSource, err := ParseDeployCloudformationSource(string(text))
if err != nil {
return err
}
*s = parsedSource
return nil
}
65 changes: 65 additions & 0 deletions client/deploy_cloudformation_stage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package client

import (
"fmt"

"github.com/mitchellh/mapstructure"
)

// DeployCloudformationStageType deploy manifest stage
var DeployCloudformationStageType StageType = "deployCloudFormation"

func init() {
stageFactories[DeployCloudformationStageType] = parseDeployCloudformationStage
}

// DeployCloudformationStage deploy cloudforamtion stage
type DeployCloudformationStage struct {
BaseStage `mapstructure:",squash"`

ActionOnReplacement string `json:"actionOnReplacement"`
Capabilities []string `json:"capabilities"`
ChangeSetName string `json:"changeSetName"`
Credentials string `json:"credentials"`
ExecuteChangeSet bool `json:"executeChangeSet"`
IsChangeSet bool `json:"isChangeSet"`
Parameters map[string]string `json:"parameters"`
Regions []string `json:"regions"`
RoleARN string `json:"roleARN"`
Source DeployCloudformationSource `json:"source"`
StackArtifact *StackArtifact `json:"stackArtifact"`
StackName string `json:"stackName"`
Tags map[string]string `json:"tags"`
TemplateBody []string `json:"templateBody"`
}

// NewDeployCloudformationStage deploy cloudformation stage
func NewDeployCloudformationStage() *DeployCloudformationStage {
return &DeployCloudformationStage{
BaseStage: *newBaseStage(DeployCloudformationStageType),
Source: DeployCloudformationSourceText,
}
}

func parseDeployCloudformationStage(stageMap map[string]interface{}) (Stage, error) {
stage := NewDeployCloudformationStage()
if err := stage.parseBaseStage(stageMap); err != nil {
return nil, err
}

sourceString, ok := stageMap["source"].(string)
if !ok {
return nil, fmt.Errorf("Could not parse cloudformation source %v", stageMap["source"])
}
source, err := ParseDeployCloudformationSource(sourceString)
if err != nil {
return nil, err
}
stage.Source = source
delete(stageMap, "source")

if err := mapstructure.Decode(stageMap, stage); err != nil {
return nil, err
}
return stage, nil
}
93 changes: 93 additions & 0 deletions client/deploy_cloudformation_stage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package client

import (
"encoding/json"
"testing"

"github.com/sergi/go-diff/diffmatchpatch"
)

var deployCloudformationStage DeployCloudformationStage

func init() {
deployCloudformationStage = *NewDeployCloudformationStage()
deployCloudformationStage.Name = "New Deploy Cloudformation"
}

func TestDeployCloudformationStageGetName(t *testing.T) {
name := "New Deploy Cloudformation"
if deployCloudformationStage.GetName() != name {
t.Fatalf("Deploy Cloudformation stage GetName() should be %s, not \"%s\"", name, deployCloudformationStage.GetName())
}
}

func TestDeployCloudformationStageGetType(t *testing.T) {
if deployCloudformationStage.GetType() != DeployCloudformationStageType {
t.Fatalf("Deploy Cloudformation stage GetType() should be %s, not \"%s\"", DeployCloudformationStageType, deployCloudformationStage.GetType())
}
if deployCloudformationStage.Type != DeployCloudformationStageType {
t.Fatalf("Deploy Cloudformation stage Type should be %s, not \"%s\"", DeployCloudformationStageType, deployCloudformationStage.Type)
}
}

func TestDeployCloudformationStageSerialize(t *testing.T) {
b, err := json.MarshalIndent(deployCloudformationStage, "", "\t")
if err != nil {
t.Fatal(err)
}
result := string(b)
if result != deployCloudformationJSON {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(deployCloudformationJSON, result, true)
t.Fatalf("Deploy Cloudformation not as expected: %s", dmp.DiffPrettyText(diffs))
}
}

func TestDeployCloudformationStageDeserialize(t *testing.T) {
var stageMap map[string]interface{}
err := json.Unmarshal([]byte(deployCloudformationJSON), &stageMap)
if err != nil {
t.Fatal(err)
}
stageInterface, err := parseDeployCloudformationStage(stageMap)
if err != nil {
t.Fatal(err)
}
stage := stageInterface.(*DeployCloudformationStage)
if stage.Source != DeployCloudformationSourceText {
t.Fatalf("Should have source type text")
}
}

var deployCloudformationJSON = `{
"name": "New Deploy Cloudformation",
"refId": "",
"type": "deployCloudFormation",
"requisiteStageRefIds": [],
"sendNotifications": false,
"stageEnabled": null,
"completeOtherBranchesThenFail": false,
"continuePipeline": false,
"failOnFailedExpressions": false,
"failPipeline": true,
"overrideTimeout": false,
"restrictExecutionDuringTimeWindow": false,
"restrictedExecutionWindow": null,
"notifications": null,
"expectedArtifacts": [],
"requiredArtifactIds": [],
"actionOnReplacement": "",
"capabilities": null,
"changeSetName": "",
"credentials": "",
"executeChangeSet": false,
"isChangeSet": false,
"parameters": null,
"regions": null,
"roleARN": "",
"source": "text",
"stackArtifact": null,
"stackName": "",
"tags": null,
"templateBody": null
}`
1 change: 1 addition & 0 deletions client/deploy_manifest_stage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ var deployManifestJson = `{
"restrictedExecutionWindow": null,
"notifications": null,
"expectedArtifacts": [],
"requiredArtifactIds": [],
"account": "",
"cloudProvider": "",
"manifests": [
Expand Down
1 change: 1 addition & 0 deletions client/manifest_expected_artifacts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ var expectedArtifactsJSON = `{
"usePriorArtifact": false
}
],
"requiredArtifactIds": [],
"account": "",
"alias": "runJob",
"application": "",
Expand Down
1 change: 1 addition & 0 deletions client/run_job_manifest_stage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ var runJobManifestJson = `{
"restrictedExecutionWindow": null,
"notifications": null,
"expectedArtifacts": [],
"requiredArtifactIds": [],
"account": "learn-nonprod",
"alias": "runJob",
"application": "bridgelearn",
Expand Down
11 changes: 11 additions & 0 deletions client/stack_artifact.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package client

// StackArtifact stack artifact
type StackArtifact struct {
ArtifactAccount string `json:"artifactAccount"`
ID string `json:"id"`
Name string `json:"name"`
Reference string `json:"reference"`
Type string `json:"type"`
Version string `json:"version"`
}
11 changes: 4 additions & 7 deletions provider/manual_judgement_notification_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,7 @@ func TestAccPipelineManualJudgementNotificationBasic(t *testing.T) {
}

func testAccPipelineManualJudgmentNotificationConfigBasic(pipelineName string) string {
return fmt.Sprintf(`
resource "spinnaker_pipeline" "test" {
application = "app"
name = "%s"
}
var stages = `
resource "spinnaker_pipeline_manual_judgment_stage" "s1" {
pipeline = "${spinnaker_pipeline.test.id}"
name = "Stage 1"
Expand Down Expand Up @@ -79,5 +74,7 @@ resource "spinnaker_pipeline_manual_judgment_stage" "s1" {
manual_judgment = false
}
}
}`, pipelineName)
}`

return testAccPipelineConfigBasic("app", pipelineName) + stages
}
3 changes: 3 additions & 0 deletions provider/notification_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ func toClientMessage(level client.NotificationLevel, m *[]*message) (client.Mess
return nil, err
}
message := (*m)[0]
if message == nil {
return nil, nil
}

if message.Complete != "" {
newMessage.SetCompleteText(message.Complete)
Expand Down
6 changes: 1 addition & 5 deletions provider/notification_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,5 @@ resource "spinnaker_pipeline_jenkins_stage" "s%v" {
}`, i, i, completeText)
}

return fmt.Sprintf(`
resource "spinnaker_pipeline" "test" {
application = "app"
name = "%s"
}`, pipeName) + stages
return testAccPipelineConfigBasic("app", pipeName) + stages
}
6 changes: 1 addition & 5 deletions provider/pipeline_bake_manifest_stage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,7 @@ resource "spinnaker_pipeline_bake_manifest_stage" "s%v" {
}`, i, i, accountName)
}

return fmt.Sprintf(`
resource "spinnaker_pipeline" "test" {
application = "app"
name = "%s"
}`, pipeName) + stages
return testAccPipelineConfigBasic("app", pipeName) + stages
}

func testAccPipelineBakeManifestStageConfigKustomize(pipeName string) string {
Expand Down
6 changes: 1 addition & 5 deletions provider/pipeline_bake_stage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,5 @@ resource "spinnaker_pipeline_bake_stage" "s%v" {
}`, i, i, vmType)
}

return fmt.Sprintf(`
resource "spinnaker_pipeline" "test" {
application = "app"
name = "%s"
}`, pipeName) + stages
return testAccPipelineConfigBasic("app", pipeName) + stages
}
6 changes: 1 addition & 5 deletions provider/pipeline_canary_analysis_stage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,5 @@ resource "spinnaker_pipeline_canary_analysis_stage" "s%v" {
}`, i, i)
}

return fmt.Sprintf(`
resource "spinnaker_pipeline" "test" {
application = "app"
name = "%s"
}`, pipeName) + stages
return testAccPipelineConfigBasic("app", pipeName) + stages
}
6 changes: 1 addition & 5 deletions provider/pipeline_check_preconditions_stage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,5 @@ resource "spinnaker_pipeline_check_preconditions_stage" "s%v" {
}`, i, i, stageName)
}

return fmt.Sprintf(`
resource "spinnaker_pipeline" "test" {
application = "app"
name = "%s"
}`, pipeName) + stages
return testAccPipelineConfigBasic("app", pipeName) + stages
}

0 comments on commit 3a60535

Please sign in to comment.