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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.cody/buildspec.yml +8 -0
  3. data/.cody/project.rb +4 -0
  4. data/.cody/settings.yml +13 -0
  5. data/.gitignore +17 -10
  6. data/.gitmodules +9 -0
  7. data/.rspec +1 -1
  8. data/.ruby-version +1 -0
  9. data/CHANGELOG.md +59 -0
  10. data/Gemfile +3 -1
  11. data/Guardfile +19 -0
  12. data/LICENSE.txt +18 -17
  13. data/README.md +145 -18
  14. data/Rakefile +9 -2
  15. data/cody.gemspec +26 -12
  16. data/exe/cody +14 -0
  17. data/img/github-admin-settings-tab.png +0 -0
  18. data/lib/cody.rb +17 -1
  19. data/lib/cody/autoloader.rb +21 -0
  20. data/lib/cody/aws_services.rb +16 -0
  21. data/lib/cody/aws_services/helpers.rb +72 -0
  22. data/lib/cody/cli.rb +61 -0
  23. data/lib/cody/command.rb +82 -0
  24. data/lib/cody/completer.rb +159 -0
  25. data/lib/cody/completer/script.rb +6 -0
  26. data/lib/cody/completer/script.sh +10 -0
  27. data/lib/cody/core.rb +63 -0
  28. data/lib/cody/create.rb +12 -0
  29. data/lib/cody/default/settings.yml +3 -0
  30. data/lib/cody/delete.rb +27 -0
  31. data/lib/cody/deploy.rb +40 -0
  32. data/lib/cody/dsl/project.rb +119 -0
  33. data/lib/cody/dsl/project/ssm.rb +22 -0
  34. data/lib/cody/dsl/role.rb +50 -0
  35. data/lib/cody/dsl/schedule.rb +30 -0
  36. data/lib/cody/evaluate.rb +47 -0
  37. data/lib/cody/help.rb +9 -0
  38. data/lib/cody/help/completion.md +22 -0
  39. data/lib/cody/help/completion_script.md +3 -0
  40. data/lib/cody/help/deploy.md +32 -0
  41. data/lib/cody/help/init.md +71 -0
  42. data/lib/cody/help/start.md +12 -0
  43. data/lib/cody/init.rb +102 -0
  44. data/lib/cody/project.rb +72 -0
  45. data/lib/cody/role.rb +87 -0
  46. data/lib/cody/schedule.rb +102 -0
  47. data/lib/cody/sequence.rb +66 -0
  48. data/lib/cody/setting.rb +82 -0
  49. data/lib/cody/stack.rb +93 -0
  50. data/lib/cody/start.rb +69 -0
  51. data/lib/cody/update.rb +12 -0
  52. data/lib/cody/variables.rb +17 -0
  53. data/lib/cody/version.rb +2 -2
  54. data/lib/template/project/buildspec.yml +28 -0
  55. data/lib/template/project/project.rb.tt +29 -0
  56. data/lib/template/project/role.rb +2 -0
  57. data/lib/template/project/schedule.rb +3 -0
  58. data/lib/template/top/README.md +32 -0
  59. data/lib/template/top/settings.yml +9 -0
  60. data/lib/template/top/variables/base.rb +1 -0
  61. data/lib/template/top/variables/development.rb +1 -0
  62. data/lib/template/top/variables/production.rb +1 -0
  63. data/vendor/aws_data/CHANGELOG.md +7 -0
  64. data/vendor/aws_data/Gemfile +4 -0
  65. data/vendor/aws_data/LICENSE.txt +21 -0
  66. data/vendor/aws_data/README.md +42 -0
  67. data/vendor/aws_data/Rakefile +6 -0
  68. data/vendor/aws_data/aws_data.gemspec +30 -0
  69. data/{bin → vendor/aws_data/bin}/console +1 -1
  70. data/{bin → vendor/aws_data/bin}/setup +0 -0
  71. data/vendor/aws_data/lib/aws_data.rb +91 -0
  72. data/vendor/aws_data/lib/aws_data/version.rb +3 -0
  73. data/vendor/aws_data/spec/aws_data_spec.rb +5 -0
  74. data/vendor/aws_data/spec/spec_helper.rb +14 -0
  75. data/vendor/cfn-status/Gemfile +4 -0
  76. data/vendor/cfn-status/LICENSE.txt +21 -0
  77. data/vendor/cfn-status/README.md +56 -0
  78. data/vendor/cfn-status/Rakefile +6 -0
  79. data/vendor/cfn-status/bin/console +14 -0
  80. data/vendor/cfn-status/bin/setup +8 -0
  81. data/vendor/cfn-status/cfn-status.gemspec +30 -0
  82. data/vendor/cfn-status/lib/cfn/aws_service.rb +56 -0
  83. data/vendor/cfn-status/lib/cfn/status.rb +220 -0
  84. data/vendor/cfn-status/lib/cfn/status/version.rb +5 -0
  85. data/vendor/cfn-status/spec/cfn/status_spec.rb +81 -0
  86. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-complete.json +1080 -0
  87. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-in-progress.json +1080 -0
  88. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-update-rollback-complete.json +1086 -0
  89. data/vendor/cfn-status/spec/spec_helper.rb +14 -0
  90. data/vendor/cfn_camelizer/CHANGELOG.md +10 -0
  91. data/vendor/cfn_camelizer/Gemfile +4 -0
  92. data/vendor/cfn_camelizer/LICENSE.txt +21 -0
  93. data/vendor/cfn_camelizer/README.md +40 -0
  94. data/vendor/cfn_camelizer/Rakefile +6 -0
  95. data/vendor/cfn_camelizer/bin/console +14 -0
  96. data/vendor/cfn_camelizer/bin/setup +8 -0
  97. data/vendor/cfn_camelizer/cfn_camelizer.gemspec +32 -0
  98. data/vendor/cfn_camelizer/lib/camelizer.yml +33 -0
  99. data/vendor/cfn_camelizer/lib/cfn_camelizer.rb +92 -0
  100. data/vendor/cfn_camelizer/lib/cfn_camelizer/version.rb +3 -0
  101. data/vendor/cfn_camelizer/spec/cfn_camelizer_spec.rb +79 -0
  102. data/vendor/cfn_camelizer/spec/spec_helper.rb +14 -0
  103. metadata +268 -21
  104. data/.travis.yml +0 -7
@@ -0,0 +1,66 @@
1
+ require 'fileutils'
2
+ require 'thor'
3
+
4
+ module Cody
5
+ class Sequence < Thor::Group
6
+ include AwsServices
7
+ include Thor::Actions
8
+
9
+ add_runtime_options! # force, pretend, quiet, skip options
10
+ # https://github.com/erikhuda/thor/blob/master/lib/thor/actions.rb#L49
11
+
12
+ def self.source_paths
13
+ [File.expand_path("../../template", __FILE__)]
14
+ end
15
+
16
+ private
17
+ def override_source_paths(*paths)
18
+ # Using string with instance_eval because block doesnt have access to
19
+ # path at runtime.
20
+ self.class.instance_eval %{
21
+ def self.source_paths
22
+ #{paths.flatten.inspect}
23
+ end
24
+ }
25
+ end
26
+
27
+ def sync_template_repo
28
+ unless git_installed?
29
+ abort "Unable to detect git installation on your system. Git needs to be installed in order to use the --template option."
30
+ end
31
+
32
+ template_path = "#{ENV['HOME']}/.cody/templates/#{full_repo_name}"
33
+ if File.exist?(template_path)
34
+ sh("cd #{template_path} && git pull")
35
+ else
36
+ FileUtils.mkdir_p(File.dirname(template_path))
37
+ sh("git clone #{repo_url} #{template_path}")
38
+ end
39
+ end
40
+
41
+ def full_repo_name
42
+ full_repo = options[:template].split("/")[-2..-1].join("/")
43
+ full_repo = full_repo.split(":").last
44
+ full_repo.sub(".git", "")
45
+ end
46
+
47
+ # normalize repo_url
48
+ def repo_url
49
+ template = options[:template]
50
+ if template.include?('github.com')
51
+ template # leave as is, user has provided full github url
52
+ else
53
+ "https://github.com/#{template}"
54
+ end
55
+ end
56
+
57
+ def git_installed?
58
+ system("type git > /dev/null")
59
+ end
60
+
61
+ def sh(command)
62
+ puts "=> #{command}"
63
+ system(command)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,82 @@
1
+ require 'yaml'
2
+ require 'render_me_pretty'
3
+
4
+ module Cody
5
+ class Setting
6
+ extend Memoist
7
+ def initialize(check_codebuild_project=true)
8
+ @check_codebuild_project = check_codebuild_project
9
+ end
10
+
11
+ # data contains the settings.yml config. The order or precedence for settings
12
+ # is the project ufo/settings.yml and then the ~/.cody/settings.yml.
13
+ def data
14
+ Cody.check_codebuild_project! if @check_codebuild_project
15
+ return {} unless File.exist?(project_settings_path)
16
+
17
+ # project based settings files
18
+ project = load_file(project_settings_path)
19
+
20
+ user_file = "#{ENV['HOME']}/.cody/settings.yml"
21
+ user = File.exist?(user_file) ? YAML.load_file(user_file) : {}
22
+
23
+ default_file = File.expand_path("default/settings.yml", __dir__)
24
+ default = load_file(default_file)
25
+
26
+ all_envs = default.deep_merge(user.deep_merge(project))
27
+ all_envs = merge_base(all_envs)
28
+ data = all_envs[cb_env] || all_envs["base"] || {}
29
+ data.deep_symbolize_keys
30
+ end
31
+ memoize :data
32
+
33
+ # Resolves infinite problem since Cody.env can be determined from CODY_ENV or settings.yml files.
34
+ # When ufo is determined from settings it should not called Cody.env since that in turn calls
35
+ # Settings.new.data which can then cause an infinite loop.
36
+ def cb_env
37
+ path = "#{cb_root}/.cody/settings.yml"
38
+ if File.exist?(path)
39
+ settings = YAML.load_file(path)
40
+ env = settings.find do |_env, section|
41
+ section ||= {}
42
+ ENV['AWS_PROFILE'] && ENV['AWS_PROFILE'] == section['aws_profile']
43
+ end
44
+ end
45
+
46
+ cb_env = env.first if env
47
+ cb_env = ENV['CODY_ENV'] if ENV['CODY_ENV'] # highest precedence
48
+ cb_env || 'development'
49
+ end
50
+
51
+ private
52
+ def load_file(path)
53
+ return Hash.new({}) unless File.exist?(path)
54
+
55
+ content = RenderMePretty.result(path)
56
+ data = YAML.load(content)
57
+ # If key is is accidentally set to nil it screws up the merge_base later.
58
+ # So ensure that all keys with nil value are set to {}
59
+ data.each do |env, _setting|
60
+ data[env] ||= {}
61
+ end
62
+ data
63
+ end
64
+
65
+ # automatically add base settings to the rest of the environments
66
+ def merge_base(all_envs)
67
+ base = all_envs["base"] || {}
68
+ all_envs.each do |env, settings|
69
+ all_envs[env] = base.merge(settings) unless env == "base"
70
+ end
71
+ all_envs
72
+ end
73
+
74
+ def project_settings_path
75
+ "#{cb_root}/.cody/settings.yml"
76
+ end
77
+
78
+ def cb_root
79
+ ENV["CODEBUILD_ROOT"] || Dir.pwd
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,93 @@
1
+ require "aws-sdk-cloudformation"
2
+
3
+ module Cody
4
+ class Stack
5
+ include AwsServices
6
+
7
+ def initialize(options)
8
+ @options = options
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
+ }
17
+ end
18
+
19
+ def run
20
+ options = @options.merge(
21
+ project_name: @project_name,
22
+ full_project_name: @full_project_name,
23
+ )
24
+ project_builder = Project.new(options)
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
61
+ end
62
+ end
63
+
64
+ private
65
+ def url_info
66
+ stack = cfn.describe_stacks(stack_name: @stack_name).stacks.first
67
+ region = `aws configure get region`.strip rescue "us-east-1"
68
+ url = "https://console.aws.amazon.com/cloudformation/home?region=#{region}#/stacks"
69
+ puts "Stack name #{@stack_name.color(:yellow)} status #{stack["stack_status"].color(:yellow)}"
70
+ puts "Here's the CloudFormation url to check for more details #{url}"
71
+ end
72
+
73
+ def status
74
+ @status ||= Cfn::Status.new(@stack_name)
75
+ end
76
+
77
+ def rollback_complete?(stack)
78
+ stack.stack_status == 'ROLLBACK_COMPLETE'
79
+ 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
+ end
93
+ end
@@ -0,0 +1,69 @@
1
+ module Cody
2
+ class Start
3
+ include AwsServices
4
+
5
+ def initialize(options)
6
+ @options = options
7
+ @project_name = options[:project_name] || inferred_project_name
8
+ @full_project_name = project_name_convention(@project_name)
9
+ end
10
+
11
+ def run
12
+ source_version = @options[:branch] || @options[:source_version] || 'master'
13
+ params = {
14
+ project_name: project_name,
15
+ source_version: source_version
16
+ }
17
+ params[:environment_variables_override] = environment_variables_override if @options[:env_vars]
18
+ resp = codebuild.start_build(params)
19
+ puts "Build started for project: #{project_name}"
20
+ puts "Please check the CodeBuild console for the status."
21
+ puts "Cody Log Url:"
22
+ puts codebuild_log_url(resp.build.id)
23
+ end
24
+
25
+ def environment_variables_override
26
+ @options[:env_vars].map do |s|
27
+ k, v = s.split('=')
28
+ ssm = false
29
+ if /^ssm:(.*)/.match(v)
30
+ v = $1
31
+ ssm = true
32
+ end
33
+
34
+ {
35
+ name: k,
36
+ value: v,
37
+ type: ssm ? "PARAMETER_STORE" : "PLAINTEXT"
38
+ }
39
+ end
40
+ end
41
+
42
+ def project_name
43
+ if project_exists?(@full_project_name)
44
+ @full_project_name
45
+ elsif stack_exists?(@project_name) # allow `cody start STACK_NAME` to work too
46
+ resp = cfn.describe_stack_resources(stack_name: @project_name)
47
+ resource = resp.stack_resources.find do |r|
48
+ r.logical_resource_id == "CodeBuild"
49
+ end
50
+ resource.physical_resource_id # codebuild project name
51
+ else
52
+ puts "ERROR: Unable to find the codebuild project with either full_project_name: #{@full_project_name} or project_name: #{@project_name}".color(:red)
53
+ exit 1
54
+ end
55
+ end
56
+
57
+ private
58
+ def codebuild_log_url(build_id)
59
+ build_id = build_id.split(':').last
60
+ region = `aws configure get region`.strip rescue "us-east-1"
61
+ "https://#{region}.console.aws.amazon.com/codesuite/codebuild/projects/#{project_name}/build/#{project_name}%3A#{build_id}/log"
62
+ end
63
+
64
+ def project_exists?(name)
65
+ resp = codebuild.batch_get_projects(names: [name])
66
+ resp.projects.size > 0
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,12 @@
1
+ module Cody
2
+ class Update < Stack
3
+ def perform
4
+ cfn.update_stack(
5
+ stack_name: @stack_name,
6
+ template_body: YAML.dump(@template),
7
+ capabilities: ["CAPABILITY_IAM"]
8
+ )
9
+ puts "Updating stack #{@stack_name}. Check CloudFormation console for status."
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ module Cody
2
+ module Variables
3
+ def load_variables
4
+ load_variables_file("base")
5
+ load_variables_file(Cody.env)
6
+ # Then load type scope variables, so they take higher precedence
7
+ load_variables_file("base", @options[:type])
8
+ load_variables_file(Cody.env, @options[:type])
9
+ end
10
+
11
+ def load_variables_file(filename, type=nil)
12
+ items = ["#{Cody.root}/.cody", type, "variables/#{filename}.rb"].compact
13
+ path = items.join('/')
14
+ instance_eval(IO.read(path), path) if File.exist?(path)
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module Cody
2
- VERSION = "0.1.0"
3
- end
2
+ VERSION = "0.7.0"
3
+ end
@@ -0,0 +1,28 @@
1
+ version: 0.2
2
+
3
+ # Example starter file
4
+ # Edit to fit your needs
5
+
6
+ phases:
7
+ install:
8
+ commands:
9
+ # - uname -a
10
+ # - pwd
11
+ # - ls
12
+ # - env | sort
13
+ # - ls /etc/*release*
14
+ # - cat /etc/*release*
15
+ # - whoami
16
+ # - bundle
17
+ build:
18
+ commands:
19
+ - echo Build started on `date`
20
+ - uptime
21
+ # - bundle exec rspec
22
+ # cache:
23
+ # paths:
24
+ # - /usr/local/bundle
25
+ # - /usr/local/lib/ruby/gems/2.5.0
26
+ # artifacts:
27
+ # files:
28
+ # - result.txt
@@ -0,0 +1,29 @@
1
+ # For methods, refer to the properties of the CloudFormation CodeBuild::Project https://amzn.to/2UTeNlr
2
+ # For convenience methods, refer to the source https://github.com/tongueroo/cody/blob/master/lib/codebuild/dsl/project.rb
3
+
4
+ # name("example-project-name") # recommend leaving unset and codebuild will use a conventional name
5
+ github_url("<%= project_github_url %>")
6
+ linux_image("<%= lookup_managed_image(/ruby:/) %>")
7
+ environment_variables(
8
+ JETS_ENV: "test",
9
+ # API_KEY: "ssm:/codebuild/demo/api_key" # Example of ssm parameter
10
+ )
11
+
12
+ # Some useful helpers:
13
+ # puts "project_name #{project_name}" # IE: demo-web
14
+ # puts "full_project_name #{full_project_name}" # demo-web-development
15
+
16
+ # Uncomment to enable github webhook, the GitHub oauth token needs admin:repo_hook permissions
17
+ # Refer to https://cody.run/docs/github_oauth/
18
+ # triggers(webhook: true)
19
+ # Another example:
20
+ # Docs: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-projecttriggers.html
21
+ # {type: "EVENT", pattern: "PUSH"} is required
22
+ # Also, note the extra brackets: [[]] is actually the proper format. I know weird.
23
+ # triggers(
24
+ # webhook: true,
25
+ # filter_groups: [[{type: "HEAD_REF", pattern: "my-branch"}, {type: "EVENT", pattern: "PUSH"}]]
26
+ # )
27
+
28
+ # Shorthand to enable all local cache modes
29
+ # local_cache(true)
@@ -0,0 +1,2 @@
1
+ # Example:
2
+ # iam_policy("logs", "ssm")
@@ -0,0 +1,3 @@
1
+ # rate "1 day"
2
+ # or
3
+ # cron("0 10 * * ? *") # Run at 10:00 am (UTC) every day
@@ -0,0 +1,32 @@
1
+ # Cody Files
2
+
3
+ The files in folder are used by cody to build AWS CodeBuild projects. For more info, check out the [cody docs](https://cody.run). Here's a quick start.
4
+
5
+ ## Install Tool
6
+
7
+ gem install cody
8
+
9
+ This installs the `cody` command to manage the AWS CodeBuild project.
10
+
11
+ ## Update Project
12
+
13
+ To update the CodeBuild project:
14
+
15
+ Main services:
16
+
17
+ cody deploy demo
18
+
19
+ If you have multiple codebuild projects associated with the same repo, you can use the `--type` option. Example:
20
+
21
+ cody deploy demo --type deploy
22
+
23
+ ## Start a Deploy
24
+
25
+ To start a CodeBuild build:
26
+
27
+ cody start demo
28
+ cody start demo --type deploy
29
+
30
+ To specify a branch:
31
+
32
+ cody start demo --type deploy -b feature