codebuild 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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`.