cody 0.1.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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,22 @@
1
+ Example:
2
+
3
+ cody completion
4
+
5
+ Prints words for TAB auto-completion.
6
+
7
+ Examples:
8
+
9
+ cody completion
10
+ cody completion hello
11
+ cody completion hello name
12
+
13
+ To enable, TAB auto-completion add the following to your profile:
14
+
15
+ eval $(cody completion_script)
16
+
17
+ Auto-completion example usage:
18
+
19
+ cody [TAB]
20
+ cody hello [TAB]
21
+ cody hello name [TAB]
22
+ cody hello name --[TAB]
@@ -0,0 +1,3 @@
1
+ To use, add the following to your `~/.bashrc` or `~/.profile`
2
+
3
+ eval $(cody completion_script)
@@ -0,0 +1,32 @@
1
+ ## Examples
2
+
3
+ cody deploy PROJECT_NAME # explicitly specify project-name
4
+ cody deploy # infers the CodeBuild name from the parent folder
5
+
6
+ It is useful to just see the generated CloudFormation template with `--noop` mode:
7
+
8
+ cody deploy PROJECT_NAME --noop # see generated CloudFormation template
9
+
10
+ ## Types
11
+
12
+ By default, cody looks up files in the `.cody` folder. Example:
13
+
14
+ .cody/buildspec.yml
15
+ .cody/project.rb
16
+ .cody/role.rb
17
+
18
+ ### Examples
19
+
20
+ cody deploy PROJECT_NAME --type deploy
21
+
22
+ This will look up buildspec.yml, project.rb, and role.rb files in the `.cody/deploy` folder. So:
23
+
24
+ .cody/deploy/buildspec.yml
25
+ .cody/deploy/project.rb
26
+ .cody/deploy/role.rb
27
+
28
+ Likewise `cody deploy PROJECT_NAME --type unit` would result in:
29
+
30
+ .cody/unit/buildspec.yml
31
+ .cody/unit/project.rb
32
+ .cody/unit/role.rb
@@ -0,0 +1,71 @@
1
+ ## Examples
2
+
3
+ cody init # infers the name from the parent folder
4
+ cody init my-project # set the name
5
+
6
+ ## Type Option
7
+
8
+ The type option is useful to generate subfolder under .cody that contain another codebuild project. Example:
9
+
10
+ cody init --type unit
11
+
12
+ Thi generates the cb files under the `.cody/unit` folder.
13
+
14
+ .cody
15
+ └── unit
16
+ ├── buildspec.yml
17
+ └── project.rb
18
+
19
+ To tell cody to use these files, you specify the `--type` option as a part of the other commands. Examples:
20
+
21
+ cody deploy --type unit
22
+ cody start --type unit
23
+
24
+ ## Structure
25
+
26
+ So if you need multiple CodeBuild projects that perform different tasks but are both related to the same code repo, you might have a structure like this:
27
+
28
+ .cody
29
+ ├── deploy
30
+ │ ├── buildspec.yml
31
+ │ └── project.rb
32
+ └── unit
33
+ ├── buildspec.yml
34
+ └── project.rb
35
+
36
+ ## Mode Option
37
+
38
+ By default, `cody init` generates a very lightweight structure. You can have it also generate a "full" structure with the `--mode` option. Example.
39
+
40
+ $ cody init --mode full
41
+ $ tree .cody
42
+ .cody
43
+ ├── buildspec.yml
44
+ ├── project.rb
45
+ ├── role.rb
46
+ ├── schedule.rb
47
+ ├── settings.yml
48
+ └── variables
49
+ ├── base.rb
50
+ ├── development.rb
51
+ └── production.rb
52
+
53
+ ## Custom Templates
54
+
55
+ If you would like the `cody init` command to use your own custom templates, you can achieve this with the `--template` and `--template-mode` options. Example:
56
+
57
+ cody init --template=tongueroo/cody-custom-template
58
+
59
+ This will clone the repo on GitHub into the `~/.cody/templates/tongueroo/cody-custom-template` and use that as an additional template source. The default `--template-mode=additive` mode means that if there's a file in `tongueroo/cody-custom-template` that exists it will use that in place of the default template files.
60
+
61
+ If you do not want to use any of the original default template files within the cody gem at all, you can use the `--template-mode=replace` mode. Replace mode will only use templates from the provided `--template` option. Example:
62
+
63
+ cody init --template=tongueroo/cody-custom-template --template-mode=replace
64
+
65
+ You can also specific the full GitHub url. Example:
66
+
67
+ cody init --template=https://github.com/tongueroo/cody-custom-template
68
+
69
+ If you would like to use a local template that is not on GitHub, then created a top-level folder in `~/.cody/templates` without a subfolder. Example:
70
+
71
+ cody init --template=my-custom # uses ~/.cody/templates/my-custom
@@ -0,0 +1,12 @@
1
+ # Examples
2
+
3
+ cody start # infers the name from the parent folder
4
+ cody start stack-name # looks up project via CloudFormation stack
5
+ cody start demo-project # looks up project via codebuild project name
6
+
7
+ ## Overriding Env Variables at Runtime
8
+
9
+ You can override env variables at runtime with `--env-vars`. Examples:
10
+
11
+ cody start --type vpc --env-vars K1=v1 K2=v2
12
+ cody start --type vpc --env-vars K1=v1 K2=ssm:v2 # support for PARAMETER_STORE
@@ -0,0 +1,102 @@
1
+ module Cody
2
+ class Init < Sequence
3
+ # Ugly, this is how I can get the options from to match with this Thor::Group
4
+ def self.cli_options
5
+ [
6
+ [:force, type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
7
+ [:name, desc: "CodeBuild project name"],
8
+ [:mode, default: "light", desc: "Modes: light or full"],
9
+ [:template, desc: "Custom template to use"],
10
+ [:template_mode, desc: "Template mode: replace or additive"],
11
+ [:type, desc: "Type option creates a subfolder under .cody"],
12
+ ]
13
+ end
14
+ cli_options.each { |o| class_option(*o) }
15
+
16
+ def setup_template_repo
17
+ return unless @options[:template]&.include?('/')
18
+
19
+ sync_template_repo
20
+ end
21
+
22
+ def set_source_path
23
+ return unless @options[:template]
24
+
25
+ custom_template = "#{ENV['HOME']}/.cody/templates/#{full_repo_name}"
26
+
27
+ if @options[:template_mode] == "replace" # replace the template entirely
28
+ override_source_paths(custom_template)
29
+ else # additive: modify on top of default template
30
+ default_template = File.expand_path("../../template", __FILE__)
31
+ puts "default_template: #{default_template}"
32
+ override_source_paths([custom_template, default_template])
33
+ end
34
+ end
35
+
36
+ def copy_top_level
37
+ puts "Initialize codebuild top-level folder"
38
+ dest = ".cody"
39
+ excludes = %w[.git]
40
+ if @options[:mode] == "light"
41
+ excludes += %w[
42
+ settings.yml
43
+ variables
44
+ ]
45
+ end
46
+ pattern = Regexp.new(excludes.join('|'))
47
+ directory "top", dest, exclude_pattern: pattern
48
+ end
49
+
50
+ def copy_project
51
+ puts "Initialize codebuild project in .cody"
52
+ dest = ".cody"
53
+ dest = "#{dest}/#{@options[:type]}" if @options[:type]
54
+
55
+ excludes = %w[.git]
56
+ if @options[:mode] == "light"
57
+ excludes += %w[
58
+ role.rb
59
+ schedule.rb
60
+ ]
61
+ end
62
+
63
+ pattern = Regexp.new(excludes.join('|'))
64
+ directory "project", dest, exclude_pattern: pattern
65
+ end
66
+
67
+ private
68
+ def project_name
69
+ inferred_name = File.basename(Dir.pwd).gsub('_','-').gsub(/[^0-9a-zA-Z,-]/, '')
70
+ @options[:name] || inferred_name
71
+ end
72
+
73
+ def project_github_url
74
+ default = "https://github.com/user/repo"
75
+ return default unless File.exist?(".git/config") && git_installed?
76
+
77
+ url = `git config --get remote.origin.url`.strip
78
+ url = url.sub('git@github.com:','https://github.com/')
79
+ url == '' ? default : url
80
+ end
81
+
82
+ def lookup_managed_image(pattern=/ruby:/)
83
+ resp = codebuild.list_curated_environment_images
84
+
85
+ # Helpful for debugging:
86
+ # aws codebuild list-curated-environment-images | jq -r '.platforms[].languages[].images[].versions[]' | sort
87
+
88
+ versions = []
89
+ resp.platforms.each do |platform|
90
+ platform.languages.each do |lang|
91
+ lang.images.each do |image|
92
+ versions += image.versions.compact
93
+ end
94
+ end
95
+ end
96
+ versions = versions.select { |v| v =~ pattern }
97
+ # IE: aws/codebuild/ruby:2.5.3-1.7.0
98
+ # Falls back to hard-coded image name since the API changed and looks like it's returning no ruby images
99
+ versions.sort.last || "aws/codebuild/ruby:2.5.3-1.7.0"
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,72 @@
1
+ require "yaml"
2
+
3
+ module Cody
4
+ class Project
5
+ include Dsl::Project
6
+ include Evaluate
7
+ include Variables
8
+
9
+ attr_reader :project_name, :full_project_name, :project_path
10
+ def initialize(options={})
11
+ @options = options
12
+ @project_name = options[:project_name]
13
+ @full_project_name = options[:full_project_name] # includes -development at the end
14
+ @project_path = options[:project_path] || get_project_path
15
+ @properties = default_properties # defaults make project.rb simpler
16
+ end
17
+
18
+ def exist?
19
+ File.exist?(@project_path)
20
+ end
21
+
22
+ def run
23
+ load_variables
24
+ evaluate(@project_path)
25
+ resource = {
26
+ code_build: {
27
+ type: "AWS::CodeBuild::Project",
28
+ properties: @properties
29
+ }
30
+ }
31
+ CfnCamelizer.transform(resource)
32
+ end
33
+
34
+ def default_properties
35
+ {
36
+ name: @full_project_name,
37
+ description: @full_project_name,
38
+ artifacts: { type: "NO_ARTIFACTS" },
39
+ service_role: { ref: "IamRole" },
40
+ badge_enabled: true,
41
+ timeout_in_minutes: 20,
42
+ logs_config: {
43
+ cloud_watch_logs: {
44
+ status: "ENABLED",
45
+ # the default log group name is thankfully the project name
46
+ }
47
+ },
48
+ source: {
49
+ type: "GITHUB",
50
+ # location: "", # required
51
+ # git_clone_depth: 1,
52
+ git_submodules_config: { fetch_submodules: true },
53
+ build_spec: build_spec,
54
+ # auth doesnt seem to work, refer to https://github.com/tongueroo/cody/blob/master/readme/github_oauth.md
55
+ # auth: {
56
+ # type: "OAUTH",
57
+ # # resource: "", # required
58
+ # },
59
+ report_build_status: true,
60
+ }
61
+ }
62
+ end
63
+
64
+ def get_project_path
65
+ lookup_codebuild_file("project.rb")
66
+ end
67
+
68
+ def build_spec
69
+ lookup_codebuild_file("buildspec.yml")
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,87 @@
1
+ require "yaml"
2
+
3
+ module Cody
4
+ class Role
5
+ include Cody::Dsl::Role
6
+ include Evaluate
7
+ include Variables
8
+
9
+ def initialize(options={})
10
+ @options = options
11
+ @role_path = options[:role_path] || get_role_path
12
+ @properties = default_properties
13
+ @iam_policy = {}
14
+ end
15
+
16
+ def run
17
+ load_variables
18
+ evaluate(@role_path) if File.exist?(@role_path)
19
+ @properties[:policies] = [{
20
+ policy_name: "CodeBuildAccess",
21
+ policy_document: {
22
+ version: "2012-10-17",
23
+ statement: derived_iam_statements
24
+ }
25
+ }]
26
+
27
+ if @managed_policy_arns && !@managed_policy_arns.empty?
28
+ @properties[:managed_policy_arns] = @managed_policy_arns
29
+ else
30
+ @properties[:managed_policy_arns] = default_managed_policy_arns
31
+ end
32
+
33
+ resource = {
34
+ IamRole: {
35
+ type: "AWS::IAM::Role",
36
+ properties: @properties
37
+ }
38
+ }
39
+ CfnCamelizer.transform(resource)
40
+ end
41
+
42
+ private
43
+ def get_role_path
44
+ lookup_codebuild_file("role.rb")
45
+ end
46
+
47
+ def default_properties
48
+ {
49
+ assume_role_policy_document: {
50
+ statement: [{
51
+ action: ["sts:AssumeRole"],
52
+ effect: "Allow",
53
+ principal: {
54
+ service: ["codebuild.amazonaws.com"]
55
+ }
56
+ }],
57
+ version: "2012-10-17"
58
+ },
59
+ path: "/"
60
+ }
61
+ end
62
+
63
+ def derived_iam_statements
64
+ @iam_statements || default_iam_statements
65
+ end
66
+
67
+ def default_iam_statements
68
+ [{
69
+ action: [
70
+ "logs:CreateLogGroup",
71
+ "logs:CreateLogStream",
72
+ "logs:PutLogEvents",
73
+ "ssm:DescribeDocumentParameters",
74
+ "ssm:DescribeParameters",
75
+ "ssm:GetParameter*",
76
+ ],
77
+ effect: "Allow",
78
+ resource: "*"
79
+ }]
80
+ end
81
+
82
+ def default_managed_policy_arns
83
+ # Useful when using with CodePipeline
84
+ ["arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"]
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,102 @@
1
+ module Cody
2
+ class Schedule
3
+ include Cody::Dsl::Schedule
4
+ include Evaluate
5
+ include Variables
6
+
7
+ def initialize(options={})
8
+ @options = options
9
+ @schedule_path = options[:schedule_path] || get_schedule_path
10
+ @properties = default_properties
11
+ @iam_policy = {}
12
+ end
13
+
14
+ def run
15
+ return unless File.exist?(@schedule_path)
16
+
17
+ old_properties = @properties.clone
18
+ load_variables
19
+ evaluate(@schedule_path)
20
+
21
+ @properties[:schedule_expression] = @schedule_expression if @schedule_expression
22
+ set_rule_event! if @rule_event_props
23
+ return if old_properties == @properties # empty schedule.rb file
24
+
25
+ resource = {
26
+ events_rule: {
27
+ type: "AWS::Events::Rule",
28
+ properties: @properties
29
+ },
30
+ events_rule_role: events_rule_role,
31
+ }
32
+ CfnCamelizer.transform(resource)
33
+ end
34
+
35
+ def set_rule_event!
36
+ props = @rule_event_props
37
+ if props.key?(:detail)
38
+ description = props.key?(:description) ? props.delete(:description) : rule_description
39
+ rule_props = { event_pattern: props, description: description }
40
+ else # if props.key?(:event_pattern)
41
+ props[:description] ||= rule_description
42
+ rule_props = props
43
+ end
44
+
45
+ @properties.merge!(rule_props)
46
+ end
47
+
48
+ def default_properties
49
+ description = "Cody #{@options[:full_project_name]}"
50
+ name = description.gsub(" ", "-").downcase
51
+ {
52
+ description: "#{description} CodeBuild project",
53
+ # event_pattern: ,
54
+ name: name,
55
+ # schedule_expression: ,
56
+ state: "ENABLED",
57
+ targets: [{
58
+ arn: { "Fn::GetAtt": "CodeBuild.Arn" },
59
+ role_arn: { "Fn::GetAtt": "EventsRuleRole.Arn" }, # required for specific CodeBuild target.
60
+ id: "CodeBuildTarget",
61
+ }]
62
+ }
63
+ end
64
+
65
+ private
66
+ def get_schedule_path
67
+ lookup_codebuild_file("schedule.rb")
68
+ end
69
+
70
+ def events_rule_role
71
+ {
72
+ type: "AWS::IAM::Role",
73
+ properties: {
74
+ assume_role_policy_document: {
75
+ statement: [{
76
+ action: [ "sts:AssumeRole" ],
77
+ effect: "Allow",
78
+ principal: { service: [ "events.amazonaws.com" ] }
79
+ }],
80
+ version: "2012-10-17"
81
+ },
82
+ path: "/",
83
+ policies: [{
84
+ policy_name: "CodeBuildAccess",
85
+ policy_document: {
86
+ version: "2012-10-17",
87
+ statement: [{
88
+ action: "codebuild:StartBuild",
89
+ effect: "Allow",
90
+ resource: "arn:aws:codebuild:#{aws_data.region}:#{aws_data.account}:project/#{@options[:full_project_name]}"
91
+ }]
92
+ }
93
+ }]
94
+ }
95
+ }
96
+ end
97
+
98
+ def aws_data
99
+ @aws_data ||= AwsData.new
100
+ end
101
+ end
102
+ end