cody 0.9.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitmodules +0 -9
- data/CHANGELOG.md +8 -0
- data/Gemfile +0 -2
- data/cody.gemspec +3 -3
- data/lib/cody.rb +4 -8
- data/lib/cody/aws_services.rb +1 -1
- data/lib/cody/aws_services/helpers.rb +20 -3
- data/lib/cody/cli.rb +2 -13
- data/lib/cody/{badge.rb → cli/badge.rb} +1 -1
- data/lib/cody/{base.rb → cli/base.rb} +9 -3
- data/lib/cody/{delete.rb → cli/delete.rb} +3 -3
- data/lib/cody/cli/deploy.rb +7 -0
- data/lib/cody/cli/help.rb +11 -0
- data/lib/cody/{help → cli/help}/deploy.md +0 -0
- data/lib/cody/{help → cli/help}/init.md +0 -0
- data/lib/cody/{help → cli/help}/logs.md +0 -0
- data/lib/cody/{help → cli/help}/start.md +0 -0
- data/lib/cody/{help → cli/help}/stop.md +0 -0
- data/lib/cody/{init.rb → cli/init.rb} +1 -2
- data/lib/cody/{list.rb → cli/list.rb} +7 -3
- data/lib/cody/cli/logs.rb +10 -0
- data/lib/cody/{sequence.rb → cli/sequence.rb} +3 -3
- data/lib/cody/{start.rb → cli/start.rb} +3 -3
- data/lib/cody/{status.rb → cli/status.rb} +2 -1
- data/lib/cody/{stop.rb → cli/stop.rb} +2 -1
- data/lib/cody/command.rb +11 -0
- data/lib/cody/core.rb +5 -5
- data/lib/cody/dsl/base.rb +9 -0
- data/lib/cody/dsl/project.rb +54 -49
- data/lib/cody/dsl/role.rb +11 -11
- data/lib/cody/dsl/schedule.rb +8 -8
- data/lib/cody/list/no_builds_project.rb +1 -1
- data/lib/cody/list/project.rb +1 -1
- data/lib/cody/project.rb +23 -23
- data/lib/cody/role.rb +20 -20
- data/lib/cody/schedule.rb +37 -37
- data/lib/cody/stack.rb +16 -71
- data/lib/cody/stack/base.rb +104 -0
- data/lib/cody/{create.rb → stack/create.rb} +2 -2
- data/lib/cody/{update.rb → stack/update.rb} +2 -2
- data/lib/cody/tailer.rb +1 -1
- data/lib/cody/version.rb +1 -1
- data/lib/template/project/buildspec.yml +1 -1
- data/lib/template/project/project.rb.tt +5 -19
- metadata +64 -70
- data/lib/cody/completer.rb +0 -159
- data/lib/cody/completer/script.rb +0 -6
- data/lib/cody/completer/script.sh +0 -10
- data/lib/cody/deploy.rb +0 -40
- data/lib/cody/help.rb +0 -9
- data/lib/cody/help/completion.md +0 -22
- data/lib/cody/help/completion_script.md +0 -3
- data/lib/cody/logs.rb +0 -14
- data/vendor/aws_data/CHANGELOG.md +0 -7
- data/vendor/aws_data/Gemfile +0 -4
- data/vendor/aws_data/LICENSE.txt +0 -21
- data/vendor/aws_data/README.md +0 -42
- data/vendor/aws_data/Rakefile +0 -6
- data/vendor/aws_data/aws_data.gemspec +0 -30
- data/vendor/aws_data/bin/console +0 -14
- data/vendor/aws_data/bin/setup +0 -8
- data/vendor/aws_data/lib/aws_data.rb +0 -91
- data/vendor/aws_data/lib/aws_data/version.rb +0 -3
- data/vendor/aws_data/spec/aws_data_spec.rb +0 -5
- data/vendor/aws_data/spec/spec_helper.rb +0 -14
- data/vendor/cfn-status/Gemfile +0 -4
- data/vendor/cfn-status/LICENSE.txt +0 -21
- data/vendor/cfn-status/README.md +0 -56
- data/vendor/cfn-status/Rakefile +0 -6
- data/vendor/cfn-status/bin/console +0 -14
- data/vendor/cfn-status/bin/setup +0 -8
- data/vendor/cfn-status/cfn-status.gemspec +0 -30
- data/vendor/cfn-status/lib/cfn/aws_service.rb +0 -56
- data/vendor/cfn-status/lib/cfn/status.rb +0 -220
- data/vendor/cfn-status/lib/cfn/status/version.rb +0 -5
- data/vendor/cfn-status/spec/cfn/status_spec.rb +0 -81
- data/vendor/cfn-status/spec/fixtures/cfn/stack-events-complete.json +0 -1080
- data/vendor/cfn-status/spec/fixtures/cfn/stack-events-in-progress.json +0 -1080
- data/vendor/cfn-status/spec/fixtures/cfn/stack-events-update-rollback-complete.json +0 -1086
- data/vendor/cfn-status/spec/spec_helper.rb +0 -14
- data/vendor/cfn_camelizer/CHANGELOG.md +0 -10
- data/vendor/cfn_camelizer/Gemfile +0 -4
- data/vendor/cfn_camelizer/LICENSE.txt +0 -21
- data/vendor/cfn_camelizer/README.md +0 -40
- data/vendor/cfn_camelizer/Rakefile +0 -6
- data/vendor/cfn_camelizer/bin/console +0 -14
- data/vendor/cfn_camelizer/bin/setup +0 -8
- data/vendor/cfn_camelizer/cfn_camelizer.gemspec +0 -32
- data/vendor/cfn_camelizer/lib/camelizer.yml +0 -33
- data/vendor/cfn_camelizer/lib/cfn_camelizer.rb +0 -92
- data/vendor/cfn_camelizer/lib/cfn_camelizer/version.rb +0 -3
- data/vendor/cfn_camelizer/spec/cfn_camelizer_spec.rb +0 -79
- data/vendor/cfn_camelizer/spec/spec_helper.rb +0 -14
data/lib/cody/dsl/role.rb
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
module Cody::Dsl
|
|
2
2
|
module Role
|
|
3
3
|
PROPERTIES = %w[
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
AssumeRolePolicyDocument
|
|
5
|
+
ManagedPolicyArns
|
|
6
|
+
MaxSessionDuration
|
|
7
|
+
Path
|
|
8
|
+
PermissionsBoundary
|
|
9
|
+
Policies
|
|
10
|
+
RoleName
|
|
11
11
|
]
|
|
12
12
|
PROPERTIES.each do |prop|
|
|
13
|
-
define_method(prop) do |v|
|
|
13
|
+
define_method(prop.underscore) do |v|
|
|
14
14
|
@properties[prop.to_sym] = v
|
|
15
15
|
end
|
|
16
16
|
end
|
|
@@ -27,9 +27,9 @@ module Cody::Dsl
|
|
|
27
27
|
# Expands simple string from: logs => logs:*
|
|
28
28
|
definition = "#{definition}:*" unless definition.include?(':')
|
|
29
29
|
{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
Action: [definition],
|
|
31
|
+
Effect: "Allow",
|
|
32
|
+
Resource: "*",
|
|
33
33
|
}
|
|
34
34
|
when Hash
|
|
35
35
|
definition
|
data/lib/cody/dsl/schedule.rb
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
module Cody::Dsl
|
|
2
2
|
module Schedule
|
|
3
3
|
PROPERTIES = %w[
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
Description
|
|
5
|
+
EventPattern
|
|
6
|
+
Name
|
|
7
|
+
RoleArn
|
|
8
|
+
ScheduleExpression
|
|
9
|
+
State
|
|
10
|
+
Targets
|
|
11
11
|
]
|
|
12
12
|
PROPERTIES.each do |prop|
|
|
13
|
-
define_method(prop) do |v|
|
|
13
|
+
define_method(prop.underscore) do |v|
|
|
14
14
|
@properties[prop.to_sym] = v
|
|
15
15
|
end
|
|
16
16
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Represents a project with no builds yet. In this case we just return an info message for the columns.
|
|
2
2
|
# This allows `cody list` to work without breaking for Fresh projects with zero builds.
|
|
3
|
-
|
|
3
|
+
module Cody::List
|
|
4
4
|
class NoBuildsProject
|
|
5
5
|
def method_missing(meth, *args, &block)
|
|
6
6
|
"no builds"
|
data/lib/cody/list/project.rb
CHANGED
data/lib/cody/project.rb
CHANGED
|
@@ -20,40 +20,40 @@ module Cody
|
|
|
20
20
|
load_variables
|
|
21
21
|
evaluate(@project_path)
|
|
22
22
|
resource = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
CodeBuild: {
|
|
24
|
+
Type: "AWS::CodeBuild::Project",
|
|
25
|
+
Properties: @properties
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
auto_camelize(resource)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def default_properties
|
|
32
32
|
{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
Name: @full_project_name,
|
|
34
|
+
Description: @full_project_name,
|
|
35
|
+
Artifacts: { Type: "NO_ARTIFACTS" },
|
|
36
|
+
ServiceRole: { Ref: "IamRole" },
|
|
37
|
+
BadgeEnabled: true,
|
|
38
|
+
TimeoutInMinutes: 20,
|
|
39
|
+
LogsConfig: {
|
|
40
|
+
CloudWatchLogs: {
|
|
41
|
+
Status: "ENABLED",
|
|
42
42
|
# the default log group name is thankfully the project name
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
Source: {
|
|
46
|
+
Type: "GITHUB",
|
|
47
47
|
# location: "", # required
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
# auth doesnt seem to work, refer to https://github.com/tongueroo/cody/blob/master/readme/
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# #
|
|
48
|
+
# GitCloneDepth: 1,
|
|
49
|
+
GitSubmodulesConfig: { FetchSubmodules: true },
|
|
50
|
+
BuildSpec: build_spec,
|
|
51
|
+
# auth doesnt seem to work, refer to https://github.com/tongueroo/cody/blob/master/readme/GithubOauth.md
|
|
52
|
+
# Auth: {
|
|
53
|
+
# Type: "OAUTH",
|
|
54
|
+
# # Resource: "", # required
|
|
55
55
|
# },
|
|
56
|
-
|
|
56
|
+
ReportBuildStatus: true,
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
end
|
data/lib/cody/role.rb
CHANGED
|
@@ -15,23 +15,23 @@ module Cody
|
|
|
15
15
|
def run
|
|
16
16
|
load_variables
|
|
17
17
|
evaluate(@role_path) if File.exist?(@role_path)
|
|
18
|
-
@properties[:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
@properties[:Policies] = [{
|
|
19
|
+
PolicyName: "CodeBuildAccess",
|
|
20
|
+
PolicyDocument: {
|
|
21
|
+
Version: "2012-10-17",
|
|
22
|
+
Statement: derived_iam_statements
|
|
23
23
|
}
|
|
24
24
|
}]
|
|
25
25
|
|
|
26
|
-
@properties[:
|
|
26
|
+
@properties[:ManagedPolicyArns] ||= @managed_policy_arns || default_managed_policy_arns
|
|
27
27
|
|
|
28
28
|
resource = {
|
|
29
29
|
IamRole: {
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
Type: "AWS::IAM::Role",
|
|
31
|
+
Properties: @properties
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
auto_camelize(resource)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
private
|
|
@@ -41,17 +41,17 @@ module Cody
|
|
|
41
41
|
|
|
42
42
|
def default_properties
|
|
43
43
|
{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
AssumeRolePolicyDocument: {
|
|
45
|
+
Statement: [{
|
|
46
|
+
Action: ["sts:AssumeRole"],
|
|
47
|
+
Effect: "Allow",
|
|
48
|
+
Principal: {
|
|
49
|
+
Service: ["codebuild.amazonaws.com"]
|
|
50
50
|
}
|
|
51
51
|
}],
|
|
52
|
-
|
|
52
|
+
Version: "2012-10-17"
|
|
53
53
|
},
|
|
54
|
-
|
|
54
|
+
Path: "/"
|
|
55
55
|
}
|
|
56
56
|
end
|
|
57
57
|
|
|
@@ -61,7 +61,7 @@ module Cody
|
|
|
61
61
|
|
|
62
62
|
def default_iam_statements
|
|
63
63
|
[{
|
|
64
|
-
|
|
64
|
+
Action: [
|
|
65
65
|
"logs:CreateLogGroup",
|
|
66
66
|
"logs:CreateLogStream",
|
|
67
67
|
"logs:PutLogEvents",
|
|
@@ -69,8 +69,8 @@ module Cody
|
|
|
69
69
|
"ssm:DescribeParameters",
|
|
70
70
|
"ssm:GetParameter*",
|
|
71
71
|
],
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
Effect: "Allow",
|
|
73
|
+
Resource: "*"
|
|
74
74
|
}]
|
|
75
75
|
end
|
|
76
76
|
|
data/lib/cody/schedule.rb
CHANGED
|
@@ -17,27 +17,27 @@ module Cody
|
|
|
17
17
|
load_variables
|
|
18
18
|
evaluate(@schedule_path)
|
|
19
19
|
|
|
20
|
-
@properties[:
|
|
20
|
+
@properties[:ScheduleExpression] = @schedule_expression if @schedule_expression
|
|
21
21
|
set_rule_event! if @rule_event_props
|
|
22
22
|
return if old_properties == @properties # empty schedule.rb file
|
|
23
23
|
|
|
24
24
|
resource = {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
EventsRule: {
|
|
26
|
+
Type: "AWS::Events::Rule",
|
|
27
|
+
Properties: @properties
|
|
28
28
|
},
|
|
29
|
-
|
|
29
|
+
EventsRuleRole: events_rule_role,
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
auto_camelize(resource)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def set_rule_event!
|
|
35
35
|
props = @rule_event_props
|
|
36
|
-
if props.key?(:
|
|
37
|
-
description = props.key?(:
|
|
38
|
-
rule_props = {
|
|
39
|
-
else # if props.key?(:
|
|
40
|
-
props[:
|
|
36
|
+
if props.key?(:Detail)
|
|
37
|
+
description = props.key?(:Description) ? props.delete(:Description) : rule_description
|
|
38
|
+
rule_props = { EventPattern: props, description: description }
|
|
39
|
+
else # if props.key?(:EventPattern)
|
|
40
|
+
props[:Description] ||= rule_description
|
|
41
41
|
rule_props = props
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -48,15 +48,15 @@ module Cody
|
|
|
48
48
|
description = "Cody #{@options[:full_project_name]}"
|
|
49
49
|
name = description.gsub(" ", "-").downcase
|
|
50
50
|
{
|
|
51
|
-
|
|
52
|
-
#
|
|
53
|
-
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
Description: "#{description} CodeBuild project",
|
|
52
|
+
# EventPattern: ,
|
|
53
|
+
Name: name,
|
|
54
|
+
# ScheduleExpression: ,
|
|
55
|
+
State: "ENABLED",
|
|
56
|
+
Targets: [{
|
|
57
|
+
Arn: { "Fn::GetAtt": "CodeBuild.Arn" },
|
|
58
|
+
RoleArn: { "Fn::GetAtt": "EventsRuleRole.Arn" }, # required for specific CodeBuild target.
|
|
59
|
+
Id: "CodeBuildTarget",
|
|
60
60
|
}]
|
|
61
61
|
}
|
|
62
62
|
end
|
|
@@ -68,25 +68,25 @@ module Cody
|
|
|
68
68
|
|
|
69
69
|
def events_rule_role
|
|
70
70
|
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
Type: "AWS::IAM::Role",
|
|
72
|
+
Properties: {
|
|
73
|
+
AssumeRolePolicyDocument: {
|
|
74
|
+
Statement: [{
|
|
75
|
+
Action: [ "sts:AssumeRole" ],
|
|
76
|
+
Effect: "Allow",
|
|
77
|
+
Principal: { service: [ "events.amazonaws.com" ] }
|
|
78
78
|
}],
|
|
79
|
-
|
|
79
|
+
Version: "2012-10-17"
|
|
80
80
|
},
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
81
|
+
Path: "/",
|
|
82
|
+
Policies: [{
|
|
83
|
+
PolicyName: "CodeBuildAccess",
|
|
84
|
+
PolicyDocument: {
|
|
85
|
+
Version: "2012-10-17",
|
|
86
|
+
Statement: [{
|
|
87
|
+
Action: "codebuild:StartBuild",
|
|
88
|
+
Effect: "Allow",
|
|
89
|
+
Resource: "arn:aws:codebuild:#{aws_data.region}:#{aws_data.account}:project/#{@options[:full_project_name]}"
|
|
90
90
|
}]
|
|
91
91
|
}
|
|
92
92
|
}]
|
data/lib/cody/stack.rb
CHANGED
|
@@ -2,92 +2,37 @@ require "aws-sdk-cloudformation"
|
|
|
2
2
|
|
|
3
3
|
module Cody
|
|
4
4
|
class Stack
|
|
5
|
-
include AwsServices
|
|
5
|
+
include Cody::AwsServices
|
|
6
6
|
|
|
7
7
|
def initialize(options)
|
|
8
8
|
@options = options
|
|
9
9
|
@project_name = @options[:project_name] || inferred_project_name
|
|
10
|
-
@stack_name = options[:stack_name] || inferred_stack_name(@project_name)
|
|
11
|
-
|
|
12
|
-
@full_project_name = project_name_convention(@project_name)
|
|
13
|
-
@template = {
|
|
14
|
-
"Description" => "CodeBuild Project: #{@full_project_name}",
|
|
15
|
-
"Resources" => {}
|
|
16
|
-
}
|
|
10
|
+
@stack_name = normalize_stack_name(options[:stack_name] || inferred_stack_name(@project_name))
|
|
17
11
|
end
|
|
18
12
|
|
|
19
13
|
def run
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
unless project_builder.exist?
|
|
26
|
-
puts "ERROR: Cody project does not exist: #{project_builder.project_path}".color(:red)
|
|
27
|
-
exit 1
|
|
28
|
-
return
|
|
29
|
-
end
|
|
30
|
-
project = project_builder.run
|
|
31
|
-
@template["Resources"].merge!(project)
|
|
32
|
-
|
|
33
|
-
if project["CodeBuild"]["Properties"]["ServiceRole"] == {"Ref"=>"IamRole"}
|
|
34
|
-
role = Role.new(options).run
|
|
35
|
-
@template["Resources"].merge!(role)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
schedule = Schedule.new(options).run
|
|
39
|
-
@template["Resources"].merge!(schedule) if schedule
|
|
40
|
-
|
|
41
|
-
template_path = "/tmp/codebuild.yml"
|
|
42
|
-
FileUtils.mkdir_p(File.dirname(template_path))
|
|
43
|
-
IO.write(template_path, YAML.dump(@template))
|
|
44
|
-
puts "Generated CloudFormation template at #{template_path.color(:green)}"
|
|
45
|
-
return if @options[:noop]
|
|
46
|
-
puts "Deploying stack #{@stack_name.color(:green)} with CodeBuild project #{@full_project_name.color(:green)}"
|
|
47
|
-
|
|
48
|
-
begin
|
|
49
|
-
perform
|
|
50
|
-
url_info
|
|
51
|
-
return unless @options[:wait]
|
|
52
|
-
status.wait
|
|
53
|
-
exit 2 unless status.success?
|
|
54
|
-
rescue Aws::CloudFormation::Errors::ValidationError => e
|
|
55
|
-
if e.message.include?("No updates") # No updates are to be performed.
|
|
56
|
-
puts "WARN: #{e.message}".color(:yellow)
|
|
57
|
-
else
|
|
58
|
-
puts "ERROR ValidationError: #{e.message}".color(:red)
|
|
59
|
-
exit 1
|
|
60
|
-
end
|
|
14
|
+
handle_rollback_completed!
|
|
15
|
+
if stack_exists?(@stack_name)
|
|
16
|
+
Update.new(@options).run
|
|
17
|
+
else
|
|
18
|
+
Create.new(@options).run
|
|
61
19
|
end
|
|
62
20
|
end
|
|
63
21
|
|
|
64
22
|
private
|
|
65
|
-
def
|
|
66
|
-
stack =
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
@status ||= Cfn::Status.new(@stack_name)
|
|
23
|
+
def handle_rollback_completed!
|
|
24
|
+
@stack = find_stack(@stack_name)
|
|
25
|
+
if @stack && rollback_complete?(@stack)
|
|
26
|
+
puts "Existing stack in ROLLBACK_COMPLETE state. Deleting stack before continuing."
|
|
27
|
+
cfn.delete_stack(stack_name: @stack_name)
|
|
28
|
+
status.wait
|
|
29
|
+
status.reset
|
|
30
|
+
@stack = nil # at this point stack has been deleted
|
|
31
|
+
end
|
|
75
32
|
end
|
|
76
33
|
|
|
77
34
|
def rollback_complete?(stack)
|
|
78
35
|
stack.stack_status == 'ROLLBACK_COMPLETE'
|
|
79
36
|
end
|
|
80
|
-
|
|
81
|
-
def find_stack(stack_name)
|
|
82
|
-
resp = cfn.describe_stacks(stack_name: stack_name)
|
|
83
|
-
resp.stacks.first
|
|
84
|
-
rescue Aws::CloudFormation::Errors::ValidationError => e
|
|
85
|
-
# example: Stack with id demo-web does not exist
|
|
86
|
-
if e.message =~ /Stack with/ && e.message =~ /does not exist/
|
|
87
|
-
nil
|
|
88
|
-
else
|
|
89
|
-
raise
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
37
|
end
|
|
93
38
|
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
class Cody::Stack
|
|
2
|
+
class Base
|
|
3
|
+
include Cody::AwsServices
|
|
4
|
+
|
|
5
|
+
def initialize(options)
|
|
6
|
+
@options = options
|
|
7
|
+
@project_name = @options[:project_name] || inferred_project_name
|
|
8
|
+
@stack_name = normalize_stack_name(options[:stack_name] || inferred_stack_name(@project_name))
|
|
9
|
+
|
|
10
|
+
@full_project_name = project_name_convention(@project_name)
|
|
11
|
+
@template = {
|
|
12
|
+
"Description" => "CodeBuild Project: #{@full_project_name}",
|
|
13
|
+
"Resources" => {}
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
options = @options.merge(
|
|
19
|
+
project_name: @project_name,
|
|
20
|
+
full_project_name: @full_project_name,
|
|
21
|
+
)
|
|
22
|
+
project_builder = Cody::Project.new(options)
|
|
23
|
+
unless project_builder.exist?
|
|
24
|
+
puts "ERROR: Cody project does not exist: #{project_builder.project_path}".color(:red)
|
|
25
|
+
exit 1
|
|
26
|
+
return
|
|
27
|
+
end
|
|
28
|
+
project = project_builder.run
|
|
29
|
+
@template["Resources"].merge!(project)
|
|
30
|
+
|
|
31
|
+
if project["CodeBuild"]["Properties"]["ServiceRole"] == {"Ref"=>"IamRole"}
|
|
32
|
+
role = Cody::Role.new(options).run
|
|
33
|
+
@template["Resources"].merge!(role)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
schedule = Cody::Schedule.new(options).run
|
|
37
|
+
@template["Resources"].merge!(schedule) if schedule
|
|
38
|
+
|
|
39
|
+
template_path = "/tmp/codebuild.yml"
|
|
40
|
+
FileUtils.mkdir_p(File.dirname(template_path))
|
|
41
|
+
IO.write(template_path, YAML.dump(@template))
|
|
42
|
+
puts "Generated CloudFormation template at #{template_path.color(:green)}"
|
|
43
|
+
return if @options[:noop]
|
|
44
|
+
puts "Deploying stack #{@stack_name.color(:green)} with CodeBuild project #{@full_project_name.color(:green)}"
|
|
45
|
+
|
|
46
|
+
begin
|
|
47
|
+
perform
|
|
48
|
+
url_info
|
|
49
|
+
return unless @options[:wait]
|
|
50
|
+
status.wait
|
|
51
|
+
exit 2 unless status.success?
|
|
52
|
+
rescue Aws::CloudFormation::Errors::ValidationError => e
|
|
53
|
+
if e.message.include?("No updates") # No updates are to be performed.
|
|
54
|
+
puts "WARN: #{e.message}".color(:yellow)
|
|
55
|
+
else
|
|
56
|
+
puts "ERROR ValidationError: #{e.message}".color(:red)
|
|
57
|
+
exit 1
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
def url_info
|
|
64
|
+
stack = cfn.describe_stacks(stack_name: @stack_name).stacks.first
|
|
65
|
+
region = `aws configure get region`.strip rescue "us-east-1"
|
|
66
|
+
url = "https://console.aws.amazon.com/cloudformation/home?region=#{region}#/stacks"
|
|
67
|
+
puts "Stack name #{@stack_name.color(:yellow)} status #{stack["stack_status"].color(:yellow)}"
|
|
68
|
+
puts "Here's the CloudFormation url to check for more details #{url}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def status
|
|
72
|
+
@status ||= CfnStatus.new(@stack_name)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def rollback_complete?(stack)
|
|
76
|
+
stack.stack_status == 'ROLLBACK_COMPLETE'
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def handle_rollback_completed!
|
|
81
|
+
@stack = find_stack(@stack_name)
|
|
82
|
+
if @stack && rollback_complete?(@stack)
|
|
83
|
+
puts "Existing stack in ROLLBACK_COMPLETE state. Deleting stack before continuing."
|
|
84
|
+
cfn.delete_stack(stack_name: @stack_name)
|
|
85
|
+
status.wait
|
|
86
|
+
status.reset
|
|
87
|
+
@stack = nil # at this point stack has been deleted
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def find_stack(stack_name)
|
|
92
|
+
return if ENV['TEST']
|
|
93
|
+
resp = cfn.describe_stacks(stack_name: stack_name)
|
|
94
|
+
resp.stacks.first
|
|
95
|
+
rescue Aws::CloudFormation::Errors::ValidationError => e
|
|
96
|
+
# example: Stack with id demo-web does not exist
|
|
97
|
+
if e.message =~ /Stack with/ && e.message =~ /does not exist/
|
|
98
|
+
nil
|
|
99
|
+
else
|
|
100
|
+
raise
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|