codebuild 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 57f656279e8afad7619113d3834b6af34c1dd7d583934b2829f7a621e8a07c60
4
- data.tar.gz: e72dcd6f7db6f3b9569074e41f0c478aaf808def00360a00eabf7eea4aeee4fc
3
+ metadata.gz: 6bcfea57ca3fcb04bc2f1f79e5bbd6ccb8a69cb736b4be4c4c10cd8bebc422db
4
+ data.tar.gz: 141de3012147451070013d00cfe3ec4d67d8ed3289f143fe37d4d1f7ff57d3cc
5
5
  SHA512:
6
- metadata.gz: 64c0580f8f1dfdfefc7494cdb33a4d7805d2867158b76334f5725cc5f5fdf1103e116b160b912c1a60a8da6dcec39a2a8e6a8fd0d372e57e367e55c073028378
7
- data.tar.gz: 856cf81c1c5c6eda69a87933727c9924ae9548c398adefed1c12503fd6f92bcc67518dfaa23b0f9c04ba80d269a75db3f800297cd9bf1258133c0e67f41dafe7
6
+ metadata.gz: dec4e8ba192c051d5b23ab9ca9069e0ea6cfd134fcdb5db210f6cf2d056f5e8a65d0b58d4a92f5ec24b61ed270f0e7d3396ef43b10d18bd12e24979ce32e6921
7
+ data.tar.gz: 416cb5263cfd06c4691e5f67f016854dca5b3e88fa7342c59358eee8d06ec65d7ee9971382bec3064db6b35aa5e9d2b31d950b57984abd24a4674a7c235b840a
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/cfn-status"]
2
+ path = vendor/cfn-status
3
+ url = https://github.com/tongueroo/cfn-status
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.3
data/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
5
5
 
6
+ ## [0.3.0]
7
+ * rework cb cli interface
8
+ * project_name as cli main parameter
9
+ * type option for subprojects in .codebuild folder
10
+ * update to zeitwerk for autoloading
11
+
6
12
  ## [0.2.0]
7
13
  - First good release.
8
14
  - Project and Role DSL
data/README.md CHANGED
@@ -2,13 +2,19 @@
2
2
 
3
3
  ![Build Status](https://codebuild.us-west-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoidHFFaithL1pLZWFEUzBXbk5LY05Mc0FrZW56NDVJWTArbUlOdzBUalVPWWZ5a1ZYUEFtTkhlbFBjeURRZEd1Q292WTI1RUJwWkcvdEgxUXhSYnBqVU9VPSIsIml2UGFyYW1ldGVyU3BlYyI6IjJ0dnpqMC9XMzQ4VExCMGgiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master)
4
4
 
5
- Tool creates a CodeBuild project with some reasonable defaults. It provides a DSL that can be used to create and override setting if required.
5
+ The codebuild tool provides a DSL to create a CodeBuild project with some reasonable defaults.
6
+
7
+ The codebuild tool installs `cb` and `codebuild` executables. Both of them do the same thing, `cb` is just shorter to type.
6
8
 
7
9
  ## Quick Start
8
10
 
9
- codebuild init
10
- codebuild deploy
11
- codebuild start
11
+ cb init
12
+ cb deploy
13
+ cb start
14
+
15
+ ## Private Repo
16
+
17
+ IMPORTANT: Before deploying, if you are using a private repo, use [aws codebuild import-source-credentials](https://docs.aws.amazon.com/cli/latest/reference/codebuild/import-source-credentials.html) to add credentials so that codebuild can clone down the repo. Refer to [github_oauth.md](readme/github_oauth.md) for more info.
12
18
 
13
19
  ## Usage
14
20
 
@@ -29,37 +35,37 @@ First, run `codebuild init` to generate a starter .codebuild structure.
29
35
  File | Description
30
36
  --- | ---
31
37
  buildspec.yml | The build commands to run.
32
- project.rb | The codebuild project defined as a DSL.
33
- role.rb | The IAM role assocaited with the codebuild project defined as a DSL.
38
+ project.rb | The codebuild project written as a DSL.
39
+ role.rb | The IAM role associated with the codebuild project written as a DSL.
34
40
 
35
41
  ### Deploy
36
42
 
37
43
  Adjust the files in `.codebuild` to fit your needs. When you're ready, deploy the CodeBuild project with:
38
44
 
39
- codebuild deploy STACK_NAME
45
+ cb deploy STACK_NAME
40
46
 
41
47
  More examples:
42
48
 
43
- codebuild deploy # infers the CloudFormation name from the parent folder
44
- codebuild deploy stack-name # explicitly specify stack name
49
+ cb deploy # infers the CloudFormation name from the parent folder
50
+ cb deploy stack-name # explicitly specify stack name
45
51
 
46
52
  It is useful to just see the generated CloudFormation template with `--noop` mode:
47
53
 
48
- codebuild deploy --noop # see generated CloudFormation template
54
+ cb deploy --noop # see generated CloudFormation template
49
55
 
50
56
  For more help:
51
57
 
52
- codebuild deploy -h
58
+ cb deploy -h
53
59
 
54
60
  ### Start
55
61
 
56
62
  When you are ready to start a codebuild project run, you can use `codebuild start`. Examples:
57
63
 
58
- codebuild start # infers the name from the parent folder
59
- codebuild start stack-name # looks up project via CloudFormation stack
60
- codebuild start demo-project # looks up project via CodeBuild project name
64
+ cb start # infers the name from the parent folder
65
+ cb start stack-name # looks up project via CloudFormation stack
66
+ cb start demo-project # looks up project via CodeBuild project name
61
67
 
62
- The `codebuild start` command understands multiple identifiers. It will look up the codebuild project either via CloudFormation or the CodeBuild project name.
68
+ The `cb start` command understands multiple identifiers. It will look up the codebuild project either via CloudFormation or the CodeBuild project name.
63
69
 
64
70
  ## Project DSL
65
71
 
@@ -68,12 +74,12 @@ The tool provides a DSL to create a codebuild project. Here's an example.
68
74
  .codebuild/project.rb:
69
75
 
70
76
  ```ruby
71
- name("demo")
77
+ # name("demo") # recommended to leave unset and use the conventional name that cb tool sets
72
78
  github_url("https://github.com/tongueroo/demo-ufo")
73
79
  linux_image("aws/codebuild/ruby:2.5.3-1.7.0")
74
80
  environment_variables(
75
81
  UFO_ENV: "development",
76
- API_KEY: "ssm:/codebuild/demo/api_key"
82
+ API_KEY: "ssm:/codebuild/demo/api_key" # ssm param example
77
83
  )
78
84
  ```
79
85
 
@@ -119,9 +125,9 @@ iam_policy(
119
125
 
120
126
  The convenience DSL methods shown above are short and clean. They merely wrap a DSL that map to the properties of CloudFormation resources like [AWS::CodeBuild::Project](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codebuild-project.html) and [AWS::IAM::Role](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html). Refer the [Full DSL docs](readme/full_dsl.md) for more info.
121
127
 
122
- ## Lookup Paths
128
+ ## Type Option
123
129
 
124
- By default, the codebuild tool looks up files in the `.codebuild` folder. You can affect the behavior of the lookup logic with the `--lookup` option. More info [Lookup docs](readme/lookup.md).
130
+ By default, the codebuild tool looks up files in the `.codebuild` folder. You can affect the behavior of the Type logic with the `--Type` option. More info [Type docs](readme/type.md).
125
131
 
126
132
  ## Installation
127
133
 
data/codebuild.gemspec CHANGED
@@ -23,7 +23,9 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency "aws-sdk-codebuild"
24
24
  spec.add_dependency "aws-sdk-ssm"
25
25
  spec.add_dependency "cfn_camelizer"
26
+ spec.add_dependency "memoist"
26
27
  spec.add_dependency "rainbow"
28
+ spec.add_dependency "render_me_pretty"
27
29
  spec.add_dependency "thor"
28
30
 
29
31
  spec.add_development_dependency "bundler"
data/exe/cb ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Trap ^C
4
+ Signal.trap("INT") {
5
+ puts "\nCtrl-C detected. Exiting..."
6
+ sleep 1
7
+ exit
8
+ }
9
+
10
+ $:.unshift(File.expand_path("../../lib", __FILE__))
11
+ require "codebuild"
12
+ require "codebuild/cli"
13
+
14
+ Codebuild::CLI.start(ARGV)
Binary file
@@ -0,0 +1,21 @@
1
+ require "zeitwerk"
2
+
3
+ module Codebuild
4
+ class Autoloader
5
+ class Inflector < Zeitwerk::Inflector
6
+ def camelize(basename, _abspath)
7
+ map = { cli: "CLI", version: "VERSION" }
8
+ map[basename.to_sym] || super
9
+ end
10
+ end
11
+
12
+ class << self
13
+ def setup
14
+ loader = Zeitwerk::Loader.new
15
+ loader.inflector = Inflector.new
16
+ loader.push_dir(File.dirname(__dir__)) # lib
17
+ loader.setup
18
+ end
19
+ end
20
+ end
21
+ end
@@ -25,8 +25,25 @@ module Codebuild::AwsServices
25
25
  exist
26
26
  end
27
27
 
28
- def inferred_stack_name
29
- File.basename(Dir.pwd).gsub('_','-').gsub(/[^0-9a-zA-Z,-]/, '')
28
+ def project_name_convention(name_base)
29
+ [@project_name, @options[:type], Codebuild.env, Codebuild.env_extra].reject(&:blank?).compact.join("-")
30
+ end
31
+
32
+ def inferred_project_name
33
+ # Essentially the project's parent folder
34
+ File.basename(Dir.pwd).gsub('_','-').gsub(/\.+/,'-').gsub(/[^0-9a-zA-Z,-]/, '')
35
+ end
36
+
37
+ # Examples:
38
+ #
39
+ # myapp-ci-deploy # with Settings stack_naming append_env set to false.
40
+ # myapp-ci-deploy-development
41
+ # myapp-ci-deploy-development-2
42
+ #
43
+ def inferred_stack_name(project_name)
44
+ items = [project_name, "cb", @options[:type], Codebuild.env_extra]
45
+ items.insert(3, Codebuild.env) if Codebuild.settings.dig(:stack_naming, :append_env)
46
+ items.reject(&:blank?).compact.join("-")
30
47
  end
31
48
 
32
49
  def are_you_sure?(stack_name, action)
@@ -3,7 +3,6 @@ require "aws-sdk-cloudformation"
3
3
 
4
4
  module Codebuild
5
5
  module AwsServices
6
- autoload :Helpers, "codebuild/aws_services/helpers"
7
6
  include Helpers
8
7
 
9
8
  def codebuild
data/lib/codebuild/cli.rb CHANGED
@@ -10,49 +10,33 @@ module Codebuild
10
10
  end
11
11
  register(Init, "init", "init", "Set up initial ufo files.")
12
12
 
13
- desc "evaluate", "Evaluate the .codebuild/project.rb DSL."
14
- long_desc Help.text(:evaluate)
15
- def evaluate
16
- Dsl.new(options).evaluate
17
- end
18
-
19
- deploy_options = Proc.new do
20
- option :lookup, desc: "folder to use within .codebuild folder for extra lookups of files"
21
- end
22
-
23
- desc "create", "Create codebuild project."
24
- long_desc Help.text(:create)
25
- deploy_options.call
26
- def create(stack_name=nil)
27
- Create.new(options.merge(stack_name: stack_name)).run
28
- end
29
-
30
- desc "update", "Update codebuild project."
31
- long_desc Help.text(:update)
32
- deploy_options.call
33
- def update(stack_name=nil)
34
- Update.new(options.merge(stack_name: stack_name)).run
13
+ common_options = Proc.new do
14
+ option :type, desc: "folder to use within .codebuild folder for different build types"
15
+ option :stack_name, desc: "Override the generated stack name. If you use this you must always specify it"
35
16
  end
36
17
 
37
18
  desc "deploy", "Deploy codebuild project."
38
19
  long_desc Help.text(:deploy)
39
- deploy_options.call
40
- def deploy(stack_name=nil)
41
- Deploy.new(options.merge(stack_name: stack_name)).run
20
+ common_options.call
21
+ def deploy(project_name=nil)
22
+ Deploy.new(options.merge(project_name: project_name)).run
42
23
  end
43
24
 
44
25
  desc "delete", "Delete codebuild project."
45
26
  long_desc Help.text(:delete)
46
27
  option :sure, desc: "Bypass are you sure prompt"
47
- def delete(stack_name=nil)
48
- Delete.new(options.merge(stack_name: stack_name)).run
28
+ common_options.call
29
+ def delete(project_name=nil)
30
+ Delete.new(options.merge(project_name: project_name)).run
49
31
  end
50
32
 
51
33
  desc "start", "start codebuild project."
52
34
  long_desc Help.text(:start)
53
35
  option :source_version, default: "master", desc: "git branch"
54
- def start(identifier=nil)
55
- Start.new(options.merge(identifier: identifier)).run
36
+ option :branch, aliases: "b", default: "master", desc: "git branch"
37
+ common_options.call
38
+ def start(project_name=nil)
39
+ Start.new(options.merge(project_name: project_name)).run
56
40
  end
57
41
 
58
42
  desc "completion *PARAMS", "Prints words for auto-completion."
@@ -70,8 +70,6 @@ Auto-completion accounts for each of these type of commands.
70
70
  =end
71
71
  module Codebuild
72
72
  class Completer
73
- autoload :Script, 'codebuild/completer/script'
74
-
75
73
  def initialize(command_class, *params)
76
74
  @params = params
77
75
  @current_command = @params[0]
@@ -0,0 +1,61 @@
1
+ require 'pathname'
2
+ require 'yaml'
3
+
4
+ module Codebuild
5
+ module Core
6
+ extend Memoist
7
+
8
+ def root
9
+ path = ENV['CB_ROOT'] || '.'
10
+ Pathname.new(path)
11
+ end
12
+
13
+ def env
14
+ # 2-way binding
15
+ cb_env = env_from_profile || 'development'
16
+ cb_env = ENV['CB_ENV'] if ENV['CB_ENV'] # highest precedence
17
+ cb_env
18
+ end
19
+ memoize :env
20
+
21
+ def env_extra
22
+ env_extra = ENV['CB_ENV_EXTRA'] if ENV['CB_ENV_EXTRA'] # highest precedence
23
+ return if env_extra&.empty?
24
+ env_extra
25
+ end
26
+ memoize :env_extra
27
+
28
+ # Overrides AWS_PROFILE based on the Codebuild.env if set in configs/settings.yml
29
+ # 2-way binding.
30
+ def set_aws_profile!
31
+ return if ENV['TEST']
32
+ return unless File.exist?("#{Codebuild.root}/.codebuild/settings.yml") # for rake docs
33
+ return unless settings # Only load if within Codebuild project and there's a settings.yml
34
+ data = settings[Codebuild.env] || {}
35
+ if data["aws_profile"]
36
+ puts "Using AWS_PROFILE=#{data["aws_profile"]} from CB_ENV=#{Codebuild.env} in config/settings.yml"
37
+ ENV['AWS_PROFILE'] = data["aws_profile"]
38
+ end
39
+ end
40
+
41
+ def settings
42
+ Setting.new.data
43
+ end
44
+ memoize :settings
45
+
46
+ def check_codebuild_project!
47
+ check_path = "#{Codebuild.root}/.codebuild/settings.yml"
48
+ unless File.exist?(check_path)
49
+ puts "ERROR: No settings file at #{check_path}. Are you sure you are in a project with codebuild setup?".color(:red)
50
+ puts "Current directory: #{Dir.pwd}"
51
+ puts "If you want to set up codebuild for this prjoect, please create a settings file via: codebuild init"
52
+ exit 1 unless ENV['TEST']
53
+ end
54
+ end
55
+
56
+ private
57
+ def env_from_profile
58
+ Codebuild::Setting.new.cb_env
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ base:
2
+ stack_naming:
3
+ append_env: true
@@ -4,7 +4,8 @@ module Codebuild
4
4
 
5
5
  def initialize(options)
6
6
  @options = options
7
- @stack_name = options[:stack_name] || inferred_stack_name
7
+ @project_name = options[:project_name] || inferred_project_name
8
+ @stack_name = options[:stack_name] || inferred_stack_name(@project_name)
8
9
  end
9
10
 
10
11
  def run
@@ -1,6 +1,5 @@
1
1
  module Codebuild::Dsl
2
2
  module Project
3
- autoload :Ssm, "codebuild/dsl/project/ssm"
4
3
  include Ssm
5
4
 
6
5
  PROPERTIES = %w[
@@ -41,12 +41,7 @@ module Codebuild
41
41
  end
42
42
 
43
43
  def lookup_codebuild_file(name)
44
- folder_path = [".codebuild", @options[:lookup], name].compact.join("/")
45
- if File.exist?(folder_path)
46
- folder_path
47
- else
48
- ".codebuild/#{name}" # default
49
- end
44
+ [".codebuild", @options[:type], name].compact.join("/")
50
45
  end
51
46
  end
52
47
  end
@@ -20,7 +20,7 @@ module Codebuild
20
20
  def set_source_path
21
21
  return unless @options[:template]
22
22
 
23
- custom_template = "#{ENV['HOME']}/.codebuild/templates/#{@options[:template]}"
23
+ custom_template = "#{ENV['HOME']}/.codebuild/templates/#{full_repo_name}"
24
24
 
25
25
  if @options[:template_mode] == "replace" # replace the template entirely
26
26
  override_source_paths(custom_template)
@@ -69,7 +69,9 @@ module Codebuild
69
69
  end
70
70
  end
71
71
  versions = versions.select { |v| v =~ pattern }
72
- versions.sort.last # IE: aws/codebuild/ruby:2.5.3-1.7.0
72
+ # IE: aws/codebuild/ruby:2.5.3-1.7.0
73
+ # Falls back to hard-coded image name since the API changed and looks like it's returning no ruby images
74
+ versions.sort.last || "aws/codebuild/ruby:2.5.3-1.7.0"
73
75
  end
74
76
  end
75
77
  end
@@ -5,13 +5,20 @@ module Codebuild
5
5
  include Dsl::Project
6
6
  include Evaluate
7
7
 
8
+ attr_reader :project_name, :full_project_name, :project_path
8
9
  def initialize(options={})
9
10
  @options = options
11
+ @project_name = options[:project_name]
12
+ @full_project_name = options[:full_project_name] # includes -development at the end
10
13
  @project_path = options[:project_path] || get_project_path
11
14
  # These defaults make it the project.rb simpler
12
15
  @properties = default_properties
13
16
  end
14
17
 
18
+ def exist?
19
+ File.exist?(@project_path)
20
+ end
21
+
15
22
  def run
16
23
  evaluate(@project_path)
17
24
  resource = {
@@ -25,6 +32,8 @@ module Codebuild
25
32
 
26
33
  def default_properties
27
34
  {
35
+ name: @full_project_name,
36
+ description: @full_project_name,
28
37
  artifacts: { type: "NO_ARTIFACTS" },
29
38
  service_role: { ref: "IamRole" },
30
39
  badge_enabled: true,
@@ -38,7 +47,7 @@ module Codebuild
38
47
  source: {
39
48
  type: "GITHUB",
40
49
  # location: "", # required
41
- git_clone_depth: 1,
50
+ # git_clone_depth: 1,
42
51
  git_submodules_config: { fetch_submodules: true },
43
52
  build_spec: build_spec,
44
53
  # auth doesnt seem to work, refer to https://github.com/tongueroo/codebuild/blob/master/readme/github_oauth.md
@@ -29,7 +29,7 @@ module Codebuild
29
29
  abort "Unable to detect git installation on your system. Git needs to be installed in order to use the --template option."
30
30
  end
31
31
 
32
- template_path = "#{ENV['HOME']}/.codebuild/templates/#{options[:template]}"
32
+ template_path = "#{ENV['HOME']}/.codebuild/templates/#{full_repo_name}"
33
33
  if File.exist?(template_path)
34
34
  sh("cd #{template_path} && git pull")
35
35
  else
@@ -38,6 +38,12 @@ module Codebuild
38
38
  end
39
39
  end
40
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
+
41
47
  # normalize repo_url
42
48
  def repo_url
43
49
  template = options[:template]
@@ -0,0 +1,80 @@
1
+ require 'yaml'
2
+ require 'render_me_pretty'
3
+
4
+ module Codebuild
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 ~/.codebuild/settings.yml.
13
+ def data
14
+ if @check_codebuild_project && !File.exist?(project_settings_path)
15
+ Codebuild.check_codebuild_project!
16
+ end
17
+
18
+ # project based settings files
19
+ project = load_file(project_settings_path)
20
+
21
+ user_file = "#{ENV['HOME']}/.codebuild/settings.yml"
22
+ user = File.exist?(user_file) ? YAML.load_file(user_file) : {}
23
+
24
+ default_file = File.expand_path("default/settings.yml", __dir__)
25
+ default = load_file(default_file)
26
+
27
+ all_envs = default.deep_merge(user.deep_merge(project))
28
+ all_envs = merge_base(all_envs)
29
+ data = all_envs[cb_env] || all_envs["base"] || {}
30
+ data.deep_symbolize_keys
31
+ end
32
+ memoize :data
33
+
34
+ # Resolves infinite problem since Codebuild.env can be determined from CB_ENV or settings.yml files.
35
+ # When ufo is determined from settings it should not called Codebuild.env since that in turn calls
36
+ # Settings.new.data which can then cause an infinite loop.
37
+ def cb_env
38
+ settings = YAML.load_file("#{cb_root}/.codebuild/settings.yml")
39
+ env = settings.find do |_env, section|
40
+ section ||= {}
41
+ ENV['AWS_PROFILE'] && ENV['AWS_PROFILE'] == section['aws_profile']
42
+ end
43
+
44
+ cb_env = env.first if env
45
+ cb_env = ENV['CB_ENV'] if ENV['CB_ENV'] # highest precedence
46
+ cb_env || 'development'
47
+ end
48
+
49
+ private
50
+ def load_file(path)
51
+ return Hash.new({}) unless File.exist?(path)
52
+
53
+ content = RenderMePretty.result(path)
54
+ data = YAML.load(content)
55
+ # If key is is accidentally set to nil it screws up the merge_base later.
56
+ # So ensure that all keys with nil value are set to {}
57
+ data.each do |env, _setting|
58
+ data[env] ||= {}
59
+ end
60
+ data
61
+ end
62
+
63
+ # automatically add base settings to the rest of the environments
64
+ def merge_base(all_envs)
65
+ base = all_envs["base"] || {}
66
+ all_envs.each do |env, settings|
67
+ all_envs[env] = base.merge(settings) unless env == "base"
68
+ end
69
+ all_envs
70
+ end
71
+
72
+ def project_settings_path
73
+ "#{cb_root}/.codebuild/settings.yml"
74
+ end
75
+
76
+ def cb_root
77
+ ENV["CODEBUILD_ROOT"] || Dir.pwd
78
+ end
79
+ end
80
+ end
@@ -6,12 +6,28 @@ module Codebuild
6
6
 
7
7
  def initialize(options)
8
8
  @options = options
9
- @stack_name = options[:stack_name] || inferred_stack_name
10
- @template = {"Resources" => {} }
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
+ }
11
17
  end
12
18
 
13
19
  def run
14
- project = Project.new(@options).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: Codebuild project does not exist: #{project_builder.project_path}".color(:red)
27
+ exit 1
28
+ return
29
+ end
30
+ project = project_builder.run
15
31
  @template["Resources"].merge!(project)
16
32
 
17
33
  if project["CodeBuild"]["Properties"]["ServiceRole"] == {"Ref"=>"IamRole"}
@@ -19,16 +35,39 @@ module Codebuild
19
35
  @template["Resources"].merge!(role)
20
36
  end
21
37
 
22
- puts "Generated CloudFormation template:"
23
- puts YAML.dump(@template)
38
+ template_path = "/tmp/codebuild.yml"
39
+ FileUtils.mkdir_p(File.dirname(template_path))
40
+ IO.write(template_path, YAML.dump(@template))
41
+ puts "Generated CloudFormation template at #{template_path.color(:green)}"
24
42
  return if @options[:noop]
43
+ puts "Deploying stack #{@stack_name.color(:green)} with CodeBuild project #{@full_project_name.color(:green)}"
25
44
 
26
45
  begin
27
46
  perform
47
+ url_info
48
+ status.wait
49
+ exit 2 unless status.success?
28
50
  rescue Aws::CloudFormation::Errors::ValidationError => e
29
- puts "ERROR: #{e.message}".color(:red)
30
- exit 1
51
+ if e.message.include?("No updates") # No updates are to be performed.
52
+ puts "WARN: #{e.message}".color(:yellow)
53
+ else
54
+ puts "ERROR: #{e.message}".color(:red)
55
+ exit 1
56
+ end
31
57
  end
32
58
  end
59
+
60
+ private
61
+ def url_info
62
+ stack = cfn.describe_stacks(stack_name: @stack_name).stacks.first
63
+ region = `aws configure get region`.strip rescue "us-east-1"
64
+ url = "https://console.aws.amazon.com/cloudformation/home?region=#{region}#/stacks"
65
+ puts "Stack name #{@stack_name.color(:yellow)} status #{stack["stack_status"].color(:yellow)}"
66
+ puts "Here's the CloudFormation url to check for more details #{url}"
67
+ end
68
+
69
+ def status
70
+ @status ||= Cfn::Status.new(@stack_name)
71
+ end
33
72
  end
34
73
  end
@@ -4,26 +4,31 @@ module Codebuild
4
4
 
5
5
  def initialize(options)
6
6
  @options = options
7
- @identifier = options[:identifier] || inferred_stack_name # CloudFormation stack or CodeBuild project name
7
+ @project_name = options[:project_name] || inferred_project_name
8
+ @full_project_name = project_name_convention(@project_name)
8
9
  end
9
10
 
10
11
  def run
12
+ source_version = @options[:branch] || @options[:source_version] || 'master'
11
13
  resp = codebuild.start_build(
12
14
  project_name: project_name,
13
- source_version: @options[:source_version] || 'master'
15
+ source_version: source_version
14
16
  )
15
17
  puts "Build started for project: #{project_name}"
18
+ puts "Please check the CodeBuild console for the status."
19
+ puts "Codebuild Log Url:"
20
+ puts codebuild_log_url(resp.build.id)
16
21
  end
17
22
 
18
23
  def project_name
19
- if stack_exists?(@identifier)
20
- resp = cfn.describe_stack_resources(stack_name: @identifier)
24
+ if project_exists?(@full_project_name)
25
+ @full_project_name
26
+ elsif stack_exists?(@project_name) # allow `cb start STACK_NAME` to work too
27
+ resp = cfn.describe_stack_resources(stack_name: @project_name)
21
28
  resource = resp.stack_resources.find do |r|
22
29
  r.logical_resource_id == "CodeBuild"
23
30
  end
24
31
  resource.physical_resource_id # codebuild project name
25
- elsif project_exists?(@identifier)
26
- @identifier
27
32
  else
28
33
  puts "ERROR: Unable to find the codebuild project with identifier #@identifier".color(:red)
29
34
  exit 1
@@ -31,6 +36,12 @@ module Codebuild
31
36
  end
32
37
 
33
38
  private
39
+ def codebuild_log_url(build_id)
40
+ build_id = build_id.split(':').last
41
+ region = `aws configure get region`.strip rescue "us-east-1"
42
+ "https://#{region}.console.aws.amazon.com/codesuite/codebuild/projects/#{project_name}/build/#{project_name}%3A#{build_id}/log"
43
+ end
44
+
34
45
  def project_exists?(name)
35
46
  resp = codebuild.batch_get_projects(names: [name])
36
47
  resp.projects.size > 0
@@ -1,3 +1,3 @@
1
1
  module Codebuild
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/codebuild.rb CHANGED
@@ -2,26 +2,19 @@ $:.unshift(File.expand_path("../", __FILE__))
2
2
  require "cfn_camelizer"
3
3
  require "codebuild/version"
4
4
  require "rainbow/ext/string"
5
+ require "yaml"
6
+
7
+ require "codebuild/autoloader"
8
+ Codebuild::Autoloader.setup
9
+
10
+ gem_root = File.dirname(__dir__)
11
+ $:.unshift("#{gem_root}/vendor/cfn-status/lib")
12
+ require "cfn/status"
5
13
 
6
14
  module Codebuild
7
15
  class Error < StandardError; end
8
-
9
- autoload :AwsServices, "codebuild/aws_services"
10
- autoload :CLI, "codebuild/cli"
11
- autoload :Command, "codebuild/command"
12
- autoload :Completer, "codebuild/completer"
13
- autoload :Completion, "codebuild/completion"
14
- autoload :Create, "codebuild/create"
15
- autoload :Delete, "codebuild/delete"
16
- autoload :Deploy, "codebuild/deploy"
17
- autoload :Dsl, "codebuild/dsl"
18
- autoload :Evaluate, "codebuild/evaluate"
19
- autoload :Help, "codebuild/help"
20
- autoload :Init, "codebuild/init"
21
- autoload :Project, "codebuild/project"
22
- autoload :Role, "codebuild/role"
23
- autoload :Sequence, "codebuild/sequence"
24
- autoload :Stack, "codebuild/stack"
25
- autoload :Start, "codebuild/start"
26
- autoload :Update, "codebuild/update"
16
+ extend Core
27
17
  end
18
+
19
+
20
+ Codebuild.set_aws_profile!
@@ -4,12 +4,12 @@ version: 0.2
4
4
  # Edit to fit your needs
5
5
 
6
6
  phases:
7
- pre_build:
7
+ install:
8
8
  commands:
9
9
  - uname -a
10
10
  - pwd
11
11
  - ls
12
- - env
12
+ - env | sort
13
13
  - ls /etc/*release*
14
14
  - cat /etc/*release*
15
15
  - whoami
@@ -1,7 +1,7 @@
1
1
  # For methods, refer to the properties of the CloudFormation CodeBuild::Project https://amzn.to/2UTeNlr
2
2
  # For convenience methods, refer to the source https://github.com/tongueroo/codebuild/blob/master/lib/codebuild/dsl/project.rb
3
3
 
4
- name("<%= project_name %>")
4
+ # name("example-project-name") # recommend leaving unset and codebuild will use a conventional name
5
5
  github_url("<%= project_github_url %>")
6
6
  linux_image("<%= lookup_managed_image(/ruby:/) %>")
7
7
  environment_variables(
@@ -9,6 +9,10 @@ environment_variables(
9
9
  # API_KEY: "ssm:/codebuild/demo/api_key" # Example of ssm parameter
10
10
  )
11
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
+
12
16
  # Uncomment to enable github webhook, the GitHub oauth token needs admin:repo_hook permissions
13
17
  # Refer to https://github.com/tongueroo/codebuild/blob/master/readme/github_oauth.md
14
18
  # triggers(webhook: true)
@@ -1 +1,2 @@
1
- iam_policy("logs", "ssm")
1
+ # Example:
2
+ # iam_policy("logs", "ssm")
@@ -4,9 +4,22 @@ Thought that we need to set the oauth token as part of the CloudFormation templa
4
4
 
5
5
  Instead this guide [Using Access Tokens with Your Source Provider in CodeBuild](https://docs.aws.amazon.com/codebuild/latest/userguide/sample-access-tokens.html) with [aws codebuild import-source-credentials](https://docs.aws.amazon.com/cli/latest/reference/codebuild/import-source-credentials.html) worked.
6
6
 
7
+ ## Create the GitHub Oauth Token
8
+
9
+ One way to create an GitHub oauth token:
10
+
11
+ 1. Go to GitHub
12
+ 2. Settings
13
+ 3. Developer Settings
14
+ 4. Personal access tokens
15
+
16
+ IMPORTANT: If using webhook, the oauth token needs `admin:repo_hook` also. To check this, you can log into the github, go to the repo, and see if you have access to the "Settings" tab.
17
+
18
+ ![](https://raw.githubusercontent.com/tongueroo/codebuild/master/img/github-admin-settings-tab.png)
19
+
7
20
  ## Commands
8
21
 
9
- Here are the commands for posterity.
22
+ Here are the import-source-credentials commands for posterity.
10
23
 
11
24
  Save the GitHub oauth token to parameter store, in case we need it in the future.
12
25
 
@@ -24,14 +37,3 @@ Import the source credential into codebuild.
24
37
  EOL
25
38
  aws codebuild import-source-credentials --cli-input-json file:///tmp/codebuild-source-credentials.json
26
39
  aws codebuild list-source-credentials
27
-
28
- ## Creating the GitHub Oauth Token
29
-
30
- One way to create an GitHub oauth token:
31
-
32
- 1. Go to GitHub
33
- 2. Settings
34
- 3. Developer Settings
35
- 4. Personal access tokens
36
-
37
- If using webhook, the oauth token needs `admin:repo_hook` also.
data/readme/type.md ADDED
@@ -0,0 +1,33 @@
1
+ # Type Option
2
+
3
+ By default, the codebuild tool looks up files in the `.codebuild` folder. You can affect the behavior of the lookup logic with the `--type` option.
4
+
5
+ ## Examples
6
+
7
+ cb deploy --type deploy
8
+
9
+ This will look up buildspec.yml, project.rb, and role.rb files in the `.codebuild/deploy` folder. So:
10
+
11
+ .codebuild/deploy/buildspec.yml
12
+ .codebuild/deploy/project.rb
13
+ .codebuild/deploy/role.rb
14
+
15
+ Likewise `cb deploy --type unit` would result in:
16
+
17
+ .codebuild/unit/buildspec.yml
18
+ .codebuild/unit/project.rb
19
+ .codebuild/unit/role.rb
20
+
21
+ ## Type Stack Name
22
+
23
+ The CloudFormation stack name is appended with the name of the type option. So if you project folder is `demo` and the type option is `unit`.
24
+
25
+ cd demo # project folder
26
+ cb deploy --type deploy
27
+
28
+ It produces an inferred stack name of `demo-cb-deploy-development`. You can override the CloudFormation stack name by specifying the project name explicitly. The project name is an optional first argument. Here's an example:
29
+
30
+ cd demo # project folder
31
+ cb deploy demo-web --type deploy # stack name: demo-web-cb-deploy-development
32
+
33
+ You can also override the stack name with the `--stack-name` option.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codebuild
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-04-26 00:00:00.000000000 Z
11
+ date: 2019-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: memoist
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: rainbow
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +108,20 @@ dependencies:
94
108
  - - ">="
95
109
  - !ruby/object:Gem::Version
96
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: render_me_pretty
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
97
125
  - !ruby/object:Gem::Dependency
98
126
  name: thor
99
127
  requirement: !ruby/object:Gem::Requirement
@@ -182,6 +210,7 @@ description:
182
210
  email:
183
211
  - tongueroo@gmail.com
184
212
  executables:
213
+ - cb
185
214
  - codebuild
186
215
  extensions: []
187
216
  extra_rdoc_files: []
@@ -189,7 +218,9 @@ files:
189
218
  - ".codebuild/buildspec.yml"
190
219
  - ".codebuild/project.rb"
191
220
  - ".gitignore"
221
+ - ".gitmodules"
192
222
  - ".rspec"
223
+ - ".ruby-version"
193
224
  - CHANGELOG.md
194
225
  - Gemfile
195
226
  - Guardfile
@@ -197,8 +228,11 @@ files:
197
228
  - README.md
198
229
  - Rakefile
199
230
  - codebuild.gemspec
231
+ - exe/cb
200
232
  - exe/codebuild
233
+ - img/github-admin-settings-tab.png
201
234
  - lib/codebuild.rb
235
+ - lib/codebuild/autoloader.rb
202
236
  - lib/codebuild/aws_services.rb
203
237
  - lib/codebuild/aws_services/helpers.rb
204
238
  - lib/codebuild/cli.rb
@@ -206,10 +240,11 @@ files:
206
240
  - lib/codebuild/completer.rb
207
241
  - lib/codebuild/completer/script.rb
208
242
  - lib/codebuild/completer/script.sh
243
+ - lib/codebuild/core.rb
209
244
  - lib/codebuild/create.rb
245
+ - lib/codebuild/default/settings.yml
210
246
  - lib/codebuild/delete.rb
211
247
  - lib/codebuild/deploy.rb
212
- - lib/codebuild/dsl.rb
213
248
  - lib/codebuild/dsl/project.rb
214
249
  - lib/codebuild/dsl/project/ssm.rb
215
250
  - lib/codebuild/dsl/role.rb
@@ -224,6 +259,7 @@ files:
224
259
  - lib/codebuild/project.rb
225
260
  - lib/codebuild/role.rb
226
261
  - lib/codebuild/sequence.rb
262
+ - lib/codebuild/setting.rb
227
263
  - lib/codebuild/stack.rb
228
264
  - lib/codebuild/start.rb
229
265
  - lib/codebuild/update.rb
@@ -233,7 +269,7 @@ files:
233
269
  - lib/template/.codebuild/role.rb
234
270
  - readme/full_dsl.md
235
271
  - readme/github_oauth.md
236
- - readme/lookup.md
272
+ - readme/type.md
237
273
  - spec/fixtures/app/.codebuild/project.rb
238
274
  - spec/fixtures/app/.codebuild/role.rb
239
275
  - spec/lib/cli_spec.rb
@@ -259,7 +295,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
259
295
  - !ruby/object:Gem::Version
260
296
  version: '0'
261
297
  requirements: []
262
- rubygems_version: 3.0.2
298
+ rubygems_version: 3.0.3
263
299
  signing_key:
264
300
  specification_version: 4
265
301
  summary: CodeBuild DSL Tool to Quickly Create CodeBuild Project
data/lib/codebuild/dsl.rb DELETED
@@ -1,8 +0,0 @@
1
- require "yaml"
2
-
3
- module Codebuild
4
- module Dsl
5
- autoload :Project, "codebuild/dsl/project"
6
- autoload :Role, "codebuild/dsl/role"
7
- end
8
- end
data/readme/lookup.md DELETED
@@ -1,34 +0,0 @@
1
- # Lookup Paths
2
-
3
- By default, the codebuild tool looks up files in the `.codebuild` folder. You can affect the behavior of the lookup logic with the `--lookup` option.
4
-
5
- ## Example 1
6
-
7
- codebuild deploy --lookup unit
8
-
9
- This will look up buildspec.yml, project.rb, and role.rb files in the `.codebuild/unit` folder first. If files are found, then it will use those files in that folder. If not found, it'll fall back to the `.codebuild` parent folder.
10
-
11
- Lookup order with `--lookup unit` for `buildspec.yml`:
12
-
13
- 1. .codebuild/unit/buildspec.yml
14
- 2. .codebuild/buildspec.yml
15
-
16
- Lookup order with `--lookup unit` for `project.rb`:
17
-
18
- 1. .codebuild/unit/project.rb
19
- 2. .codebuild/project.rb
20
-
21
- The same goes other files in the `.codebuild` like `role.rb`.
22
-
23
- ## Example 2
24
-
25
- Here's another example:
26
-
27
- codebuild deploy --lookup deploy
28
-
29
- Lookup order with `--lookup deploy` for `buildspec.yml`:
30
-
31
- 1. .codebuild/deploy/buildspec.yml
32
- 2. .codebuild/buildspec.yml
33
-
34
- The same goes other files in the `.codebuild` like `project.rb` and `role.rb`.