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,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