cody 0.1.0 → 0.7.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/.cody/buildspec.yml +8 -0
- data/.cody/project.rb +4 -0
- data/.cody/settings.yml +13 -0
- data/.gitignore +17 -10
- data/.gitmodules +9 -0
- data/.rspec +1 -1
- data/.ruby-version +1 -0
- data/CHANGELOG.md +59 -0
- data/Gemfile +3 -1
- data/Guardfile +19 -0
- data/LICENSE.txt +18 -17
- data/README.md +145 -18
- data/Rakefile +9 -2
- data/cody.gemspec +26 -12
- data/exe/cody +14 -0
- data/img/github-admin-settings-tab.png +0 -0
- data/lib/cody.rb +17 -1
- data/lib/cody/autoloader.rb +21 -0
- data/lib/cody/aws_services.rb +16 -0
- data/lib/cody/aws_services/helpers.rb +72 -0
- data/lib/cody/cli.rb +61 -0
- data/lib/cody/command.rb +82 -0
- data/lib/cody/completer.rb +159 -0
- data/lib/cody/completer/script.rb +6 -0
- data/lib/cody/completer/script.sh +10 -0
- data/lib/cody/core.rb +63 -0
- data/lib/cody/create.rb +12 -0
- data/lib/cody/default/settings.yml +3 -0
- data/lib/cody/delete.rb +27 -0
- data/lib/cody/deploy.rb +40 -0
- data/lib/cody/dsl/project.rb +119 -0
- data/lib/cody/dsl/project/ssm.rb +22 -0
- data/lib/cody/dsl/role.rb +50 -0
- data/lib/cody/dsl/schedule.rb +30 -0
- data/lib/cody/evaluate.rb +47 -0
- data/lib/cody/help.rb +9 -0
- data/lib/cody/help/completion.md +22 -0
- data/lib/cody/help/completion_script.md +3 -0
- data/lib/cody/help/deploy.md +32 -0
- data/lib/cody/help/init.md +71 -0
- data/lib/cody/help/start.md +12 -0
- data/lib/cody/init.rb +102 -0
- data/lib/cody/project.rb +72 -0
- data/lib/cody/role.rb +87 -0
- data/lib/cody/schedule.rb +102 -0
- data/lib/cody/sequence.rb +66 -0
- data/lib/cody/setting.rb +82 -0
- data/lib/cody/stack.rb +93 -0
- data/lib/cody/start.rb +69 -0
- data/lib/cody/update.rb +12 -0
- data/lib/cody/variables.rb +17 -0
- data/lib/cody/version.rb +2 -2
- data/lib/template/project/buildspec.yml +28 -0
- data/lib/template/project/project.rb.tt +29 -0
- data/lib/template/project/role.rb +2 -0
- data/lib/template/project/schedule.rb +3 -0
- data/lib/template/top/README.md +32 -0
- data/lib/template/top/settings.yml +9 -0
- data/lib/template/top/variables/base.rb +1 -0
- data/lib/template/top/variables/development.rb +1 -0
- data/lib/template/top/variables/production.rb +1 -0
- data/vendor/aws_data/CHANGELOG.md +7 -0
- data/vendor/aws_data/Gemfile +4 -0
- data/vendor/aws_data/LICENSE.txt +21 -0
- data/vendor/aws_data/README.md +42 -0
- data/vendor/aws_data/Rakefile +6 -0
- data/vendor/aws_data/aws_data.gemspec +30 -0
- data/{bin → vendor/aws_data/bin}/console +1 -1
- data/{bin → vendor/aws_data/bin}/setup +0 -0
- data/vendor/aws_data/lib/aws_data.rb +91 -0
- data/vendor/aws_data/lib/aws_data/version.rb +3 -0
- data/vendor/aws_data/spec/aws_data_spec.rb +5 -0
- data/vendor/aws_data/spec/spec_helper.rb +14 -0
- data/vendor/cfn-status/Gemfile +4 -0
- data/vendor/cfn-status/LICENSE.txt +21 -0
- data/vendor/cfn-status/README.md +56 -0
- data/vendor/cfn-status/Rakefile +6 -0
- data/vendor/cfn-status/bin/console +14 -0
- data/vendor/cfn-status/bin/setup +8 -0
- data/vendor/cfn-status/cfn-status.gemspec +30 -0
- data/vendor/cfn-status/lib/cfn/aws_service.rb +56 -0
- data/vendor/cfn-status/lib/cfn/status.rb +220 -0
- data/vendor/cfn-status/lib/cfn/status/version.rb +5 -0
- data/vendor/cfn-status/spec/cfn/status_spec.rb +81 -0
- data/vendor/cfn-status/spec/fixtures/cfn/stack-events-complete.json +1080 -0
- data/vendor/cfn-status/spec/fixtures/cfn/stack-events-in-progress.json +1080 -0
- data/vendor/cfn-status/spec/fixtures/cfn/stack-events-update-rollback-complete.json +1086 -0
- data/vendor/cfn-status/spec/spec_helper.rb +14 -0
- data/vendor/cfn_camelizer/CHANGELOG.md +10 -0
- data/vendor/cfn_camelizer/Gemfile +4 -0
- data/vendor/cfn_camelizer/LICENSE.txt +21 -0
- data/vendor/cfn_camelizer/README.md +40 -0
- data/vendor/cfn_camelizer/Rakefile +6 -0
- data/vendor/cfn_camelizer/bin/console +14 -0
- data/vendor/cfn_camelizer/bin/setup +8 -0
- data/vendor/cfn_camelizer/cfn_camelizer.gemspec +32 -0
- data/vendor/cfn_camelizer/lib/camelizer.yml +33 -0
- data/vendor/cfn_camelizer/lib/cfn_camelizer.rb +92 -0
- data/vendor/cfn_camelizer/lib/cfn_camelizer/version.rb +3 -0
- data/vendor/cfn_camelizer/spec/cfn_camelizer_spec.rb +79 -0
- data/vendor/cfn_camelizer/spec/spec_helper.rb +14 -0
- metadata +268 -21
- data/.travis.yml +0 -7
data/lib/cody/core.rb
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
require 'active_support/core_ext/string'
|
|
4
|
+
|
|
5
|
+
module Cody
|
|
6
|
+
module Core
|
|
7
|
+
extend Memoist
|
|
8
|
+
|
|
9
|
+
def root
|
|
10
|
+
path = ENV['CODY_ROOT'] || '.'
|
|
11
|
+
Pathname.new(path)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def env
|
|
15
|
+
# 2-way binding
|
|
16
|
+
cb_env = env_from_profile || 'development'
|
|
17
|
+
cb_env = ENV['CODY_ENV'] if ENV['CODY_ENV'] # highest precedence
|
|
18
|
+
ActiveSupport::StringInquirer.new(cb_env)
|
|
19
|
+
end
|
|
20
|
+
memoize :env
|
|
21
|
+
|
|
22
|
+
def env_extra
|
|
23
|
+
env_extra = ENV['CODY_ENV_EXTRA'] if ENV['CODY_ENV_EXTRA'] # highest precedence
|
|
24
|
+
return if env_extra&.empty?
|
|
25
|
+
env_extra
|
|
26
|
+
end
|
|
27
|
+
memoize :env_extra
|
|
28
|
+
|
|
29
|
+
# Overrides AWS_PROFILE based on the Cody.env if set in configs/settings.yml
|
|
30
|
+
# 2-way binding.
|
|
31
|
+
def set_aws_profile!
|
|
32
|
+
return if ENV['TEST']
|
|
33
|
+
return unless File.exist?("#{Cody.root}/.cody/settings.yml") # for rake docs
|
|
34
|
+
return unless settings # Only load if within Cody project and there's a settings.yml
|
|
35
|
+
|
|
36
|
+
data = settings || {}
|
|
37
|
+
if data[:aws_profile]
|
|
38
|
+
puts "Using AWS_PROFILE=#{data[:aws_profile]} from CODY_ENV=#{Cody.env} in config/settings.yml"
|
|
39
|
+
ENV['AWS_PROFILE'] = data[:aws_profile]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def settings
|
|
44
|
+
Setting.new.data
|
|
45
|
+
end
|
|
46
|
+
memoize :settings
|
|
47
|
+
|
|
48
|
+
def check_codebuild_project!
|
|
49
|
+
check_path = "#{Cody.root}/.cody"
|
|
50
|
+
unless File.exist?(check_path)
|
|
51
|
+
puts "ERROR: No .cody folder found. Are you sure you are in a project with codebuild setup?".color(:red)
|
|
52
|
+
puts "Current directory: #{Dir.pwd}"
|
|
53
|
+
puts "If you want to set up codebuild for this project, please create a settings file via: cody init"
|
|
54
|
+
exit 1 unless ENV['TEST']
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
def env_from_profile
|
|
60
|
+
Cody::Setting.new.cb_env
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
data/lib/cody/create.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Cody
|
|
2
|
+
class Create < Stack
|
|
3
|
+
def perform
|
|
4
|
+
cfn.create_stack(
|
|
5
|
+
stack_name: @stack_name,
|
|
6
|
+
template_body: YAML.dump(@template),
|
|
7
|
+
capabilities: ["CAPABILITY_IAM"]
|
|
8
|
+
)
|
|
9
|
+
puts "Creating stack #{@stack_name}. Check CloudFormation console for status."
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/cody/delete.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Cody
|
|
2
|
+
class Delete
|
|
3
|
+
include AwsServices
|
|
4
|
+
|
|
5
|
+
def initialize(options)
|
|
6
|
+
@options = options
|
|
7
|
+
@project_name = options[:project_name] || inferred_project_name
|
|
8
|
+
@stack_name = options[:stack_name] || inferred_stack_name(@project_name)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def run
|
|
12
|
+
message = "Deleted #{@stack_name} stack."
|
|
13
|
+
if @options[:noop]
|
|
14
|
+
puts "NOOP #{message}"
|
|
15
|
+
else
|
|
16
|
+
are_you_sure?(@stack_name, :delete)
|
|
17
|
+
|
|
18
|
+
if stack_exists?(@stack_name)
|
|
19
|
+
cfn.delete_stack(stack_name: @stack_name)
|
|
20
|
+
puts message
|
|
21
|
+
else
|
|
22
|
+
puts "#{@stack_name.inspect} stack does not exist".color(:red)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/cody/deploy.rb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Cody
|
|
2
|
+
class Deploy < Stack
|
|
3
|
+
def run
|
|
4
|
+
handle_rollback_completed!
|
|
5
|
+
if stack_exists?(@stack_name)
|
|
6
|
+
Update.new(@options).run
|
|
7
|
+
else
|
|
8
|
+
Create.new(@options).run
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def handle_rollback_completed!
|
|
13
|
+
@stack = find_stack(@stack_name)
|
|
14
|
+
if @stack && rollback_complete?(@stack)
|
|
15
|
+
puts "Existing stack in ROLLBACK_COMPLETE state. Deleting stack before continuing."
|
|
16
|
+
cfn.delete_stack(stack_name: @stack_name)
|
|
17
|
+
status.wait
|
|
18
|
+
status.reset
|
|
19
|
+
@stack = nil # at this point stack has been deleted
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def rollback_complete?(stack)
|
|
24
|
+
stack.stack_status == 'ROLLBACK_COMPLETE'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def find_stack(stack_name)
|
|
28
|
+
return if ENV['TEST']
|
|
29
|
+
resp = cfn.describe_stacks(stack_name: stack_name)
|
|
30
|
+
resp.stacks.first
|
|
31
|
+
rescue Aws::CloudFormation::Errors::ValidationError => e
|
|
32
|
+
# example: Stack with id demo-web does not exist
|
|
33
|
+
if e.message =~ /Stack with/ && e.message =~ /does not exist/
|
|
34
|
+
nil
|
|
35
|
+
else
|
|
36
|
+
raise
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
module Cody::Dsl
|
|
2
|
+
module Project
|
|
3
|
+
include Ssm
|
|
4
|
+
|
|
5
|
+
PROPERTIES = %w[
|
|
6
|
+
artifacts
|
|
7
|
+
badge_enabled
|
|
8
|
+
cache
|
|
9
|
+
description
|
|
10
|
+
encryption_key
|
|
11
|
+
environment
|
|
12
|
+
logs_config
|
|
13
|
+
name
|
|
14
|
+
queued_timeout_in_minutes
|
|
15
|
+
secondary_artifacts
|
|
16
|
+
secondary_sources
|
|
17
|
+
service_role
|
|
18
|
+
source
|
|
19
|
+
tags
|
|
20
|
+
timeout_in_minutes
|
|
21
|
+
triggers
|
|
22
|
+
vpc_config
|
|
23
|
+
]
|
|
24
|
+
PROPERTIES.each do |prop|
|
|
25
|
+
define_method(prop) do |v|
|
|
26
|
+
@properties[prop.to_sym] = v
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Convenience wrapper methods
|
|
31
|
+
def github_url(url)
|
|
32
|
+
@properties[:source][:location] = url
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# So it looks like the auth resource property doesnt really get used.
|
|
36
|
+
# Instead an account level credential is worked. Refer to:
|
|
37
|
+
# https://github.com/tongueroo/cody/blob/master/readme/github_oauth.md
|
|
38
|
+
#
|
|
39
|
+
# Keeping this method around in case the CloudFormation method works one day,
|
|
40
|
+
# or end up figuring out to use it properly.
|
|
41
|
+
def github_token(token)
|
|
42
|
+
@properties[:source][:auth][:resource] = token
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def github_source(options={})
|
|
46
|
+
source = {
|
|
47
|
+
type: "GITHUB",
|
|
48
|
+
location: options[:location],
|
|
49
|
+
git_clone_depth: 1,
|
|
50
|
+
git_submodules_config: { fetch_submodules: true },
|
|
51
|
+
build_spec: options[:buildspec] || ".cody/buildspec.yml", # options[:buildspec] accounts for type already
|
|
52
|
+
report_build_status: true,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if options[:oauth_token]
|
|
56
|
+
source[:auth] = {
|
|
57
|
+
type: "OAUTH",
|
|
58
|
+
resource: options[:oauth_token],
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
@properties[:source] = source
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def linux_image(name)
|
|
66
|
+
linux_environment(image: name)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def linux_environment(options={})
|
|
70
|
+
image = options[:image] || "aws/codebuild/ruby:2.5.3-1.7.0"
|
|
71
|
+
env = {
|
|
72
|
+
compute_type: options[:compute_type] || "BUILD_GENERAL1_SMALL",
|
|
73
|
+
image_pull_credentials_type: "CODEBUILD", # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-environment.html#cfn-codebuild-project-environment-imagepullcredentialstype
|
|
74
|
+
privileged_mode: true,
|
|
75
|
+
image: image,
|
|
76
|
+
type: "LINUX_CONTAINER"
|
|
77
|
+
}
|
|
78
|
+
# @mapped_env_vars is in memory
|
|
79
|
+
env[:environment_variables] = @mapped_env_vars if @mapped_env_vars
|
|
80
|
+
# options has highest precedence
|
|
81
|
+
env[:environment_variables] = options[:environment_variables] if options[:environment_variables]
|
|
82
|
+
@properties[:environment] = env
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def environment_variables(vars)
|
|
86
|
+
# Storing @mapped_env_vars as instance variable for later usage in linux_environment
|
|
87
|
+
@mapped_env_vars = vars.map { |k,v|
|
|
88
|
+
k, v = k.to_s, v.to_s
|
|
89
|
+
if v =~ /^ssm:/
|
|
90
|
+
{ type: "PARAMETER_STORE", name: k, value: v.sub('ssm:','') }
|
|
91
|
+
else
|
|
92
|
+
{ type: "PLAINTEXT", name: k, value: v }
|
|
93
|
+
end
|
|
94
|
+
}
|
|
95
|
+
@properties[:environment] ||= {}
|
|
96
|
+
@properties[:environment][:environment_variables] = @mapped_env_vars
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def local_cache(enable=true)
|
|
100
|
+
cache = if enable
|
|
101
|
+
{
|
|
102
|
+
type: "LOCAL",
|
|
103
|
+
modes: [
|
|
104
|
+
"LOCAL_DOCKER_LAYER_CACHE",
|
|
105
|
+
"LOCAL_SOURCE_CACHE",
|
|
106
|
+
"LOCAL_CUSTOM_CACHE"
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
else
|
|
110
|
+
{type: "NO_CACHE"}
|
|
111
|
+
end
|
|
112
|
+
@properties[:cache] = cache
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def type
|
|
116
|
+
@options[:type]
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require "aws-sdk-ssm"
|
|
2
|
+
|
|
3
|
+
module Cody::Dsl::Project
|
|
4
|
+
module Ssm
|
|
5
|
+
# This method grabs the ssm parameter store value at "compile" time vs
|
|
6
|
+
# CloudFormation run time. In case we need it as part of the DSL compile phase.
|
|
7
|
+
def ssm(name)
|
|
8
|
+
resp = ssm_client.get_parameter(name: name)
|
|
9
|
+
if resp.parameter.type == "SecureString"
|
|
10
|
+
resp = ssm_client.get_parameter(name: name, with_decryption: true)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
resp.parameter.value
|
|
14
|
+
rescue Aws::SSM::Errors::ParameterNotFound
|
|
15
|
+
puts "WARN: #{name} found on AWS SSM.".color(:yellow)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def ssm_client
|
|
19
|
+
@ssm_client ||= Aws::SSM::Client.new
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Cody::Dsl
|
|
2
|
+
module Role
|
|
3
|
+
PROPERTIES = %w[
|
|
4
|
+
assume_role_policy_document
|
|
5
|
+
managed_policy_arns
|
|
6
|
+
max_session_duration
|
|
7
|
+
path
|
|
8
|
+
permissions_boundary
|
|
9
|
+
policies
|
|
10
|
+
role_name
|
|
11
|
+
]
|
|
12
|
+
PROPERTIES.each do |prop|
|
|
13
|
+
define_method(prop) do |v|
|
|
14
|
+
@properties[prop.to_sym] = v
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# convenience wrapper methods
|
|
19
|
+
def iam_policy(*definitions)
|
|
20
|
+
@iam_statements = definitions.map { |definition| standardize_iam_policy(definition) }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns standarized IAM statement
|
|
24
|
+
def standardize_iam_policy(definition)
|
|
25
|
+
case definition
|
|
26
|
+
when String
|
|
27
|
+
# Expands simple string from: logs => logs:*
|
|
28
|
+
definition = "#{definition}:*" unless definition.include?(':')
|
|
29
|
+
{
|
|
30
|
+
action: [definition],
|
|
31
|
+
effect: "Allow",
|
|
32
|
+
resource: "*",
|
|
33
|
+
}
|
|
34
|
+
when Hash
|
|
35
|
+
definition
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def managed_iam_policy(*definitions)
|
|
40
|
+
@managed_policy_arns = definitions.map { |definition| standardize_managed_iam_policy(definition) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# AmazonEC2ReadOnlyAccess => arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess
|
|
44
|
+
def standardize_managed_iam_policy(definition)
|
|
45
|
+
return definition if definition.include?('iam::aws:policy')
|
|
46
|
+
|
|
47
|
+
"arn:aws:iam::aws:policy/#{definition}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Cody::Dsl
|
|
2
|
+
module Schedule
|
|
3
|
+
PROPERTIES = %w[
|
|
4
|
+
description
|
|
5
|
+
event_pattern
|
|
6
|
+
name
|
|
7
|
+
role_arn
|
|
8
|
+
schedule_expression
|
|
9
|
+
state
|
|
10
|
+
targets
|
|
11
|
+
]
|
|
12
|
+
PROPERTIES.each do |prop|
|
|
13
|
+
define_method(prop) do |v|
|
|
14
|
+
@properties[prop.to_sym] = v
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def rate(period)
|
|
19
|
+
@schedule_expression = "rate(#{period})"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def cron(expression)
|
|
23
|
+
@schedule_expression = "cron(#{expression})"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def rule_event(props={})
|
|
27
|
+
@rule_event_props = props
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Cody
|
|
2
|
+
module Evaluate
|
|
3
|
+
def evaluate(path)
|
|
4
|
+
source_code = IO.read(path)
|
|
5
|
+
begin
|
|
6
|
+
instance_eval(source_code, path)
|
|
7
|
+
rescue Exception => e
|
|
8
|
+
if e.class == SystemExit # allow exit to happen normally
|
|
9
|
+
raise
|
|
10
|
+
else
|
|
11
|
+
task_definition_error(e)
|
|
12
|
+
puts "\nFull error:"
|
|
13
|
+
raise
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
# Prints out a user friendly task_definition error message
|
|
20
|
+
def task_definition_error(e)
|
|
21
|
+
error_info = e.backtrace.first
|
|
22
|
+
path, line_no, _ = error_info.split(':')
|
|
23
|
+
line_no = line_no.to_i
|
|
24
|
+
puts "Error evaluating #{path}:".color(:red)
|
|
25
|
+
puts e.message
|
|
26
|
+
puts "Here's the line in #{path} with the error:\n\n"
|
|
27
|
+
|
|
28
|
+
contents = IO.read(path)
|
|
29
|
+
content_lines = contents.split("\n")
|
|
30
|
+
context = 5 # lines of context
|
|
31
|
+
top, bottom = [line_no-context-1, 0].max, line_no+context-1
|
|
32
|
+
spacing = content_lines.size.to_s.size
|
|
33
|
+
content_lines[top..bottom].each_with_index do |line_content, index|
|
|
34
|
+
line_number = top+index+1
|
|
35
|
+
if line_number == line_no
|
|
36
|
+
printf("%#{spacing}d %s\n".color(:red), line_number, line_content)
|
|
37
|
+
else
|
|
38
|
+
printf("%#{spacing}d %s\n", line_number, line_content)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def lookup_codebuild_file(name)
|
|
44
|
+
[".cody", @options[:type], name].compact.join("/")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|