comrad 0.0.3 → 0.1.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
  SHA1:
3
- metadata.gz: 66c6919f9e828f044c58110f1f249c397bf8b30f
4
- data.tar.gz: bfe6cea60a7b4284a42f4cfff6e46684da3520ff
3
+ metadata.gz: f8a7c8c56e6699348b75573ab291f298b1b40267
4
+ data.tar.gz: 4f27ebddb71d6bad85cc9ea6ec947bc1b1f524b5
5
5
  SHA512:
6
- metadata.gz: 8a3c112332856871089428d59ea4ad98f0ba0f8c5b7e155552c8854961e74b62849a3d66f0e59f88c207b1083565f6252c989854b2d5f91bbc230b9d039dd715
7
- data.tar.gz: 2b8c623f22b0d0ea2fd7ac9611a5c2625bb6f7612d1cb8632d0320006fc68d9937f4ea3c93a8bb2aafedb79cac9d908f7dbe250ac0d62f23e5b204ec43bd0d36
6
+ metadata.gz: 7807998016b768f385925a846ad053eb41be367dadb1400936ae5a7eb1746d79f1ecbc129ddf98696071f5a7fc63ccd18b05c6510065a4b25558a240ac576daf
7
+ data.tar.gz: a90d91f1dd5542dbd01c964a87305b87949ae2d277dd60500ce778df73a33a2b315d7d7a0518ecb58e5f04799d859ce449308d89e9bb3af1bbca37e390005f0e
@@ -1,7 +1,11 @@
1
1
  language: ruby
2
+ cache:
3
+ - bundler
4
+ install:
5
+ - bundle install
2
6
  rvm:
3
- - 2.1.5
4
- - 2.2.0
7
+ - 2.1.6
8
+ - 2.2.2
5
9
  script:
6
10
  - bundle exec rake test
7
11
 
data/Gemfile CHANGED
@@ -1,10 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'chef', '>= 11.0'
4
- gem 'ridley', '~> 4.1'
5
- gem 'rest-client', '~> 1.7.0'
6
-
7
- group :test do
8
- gem 'rubocop', '~> 0.30.0'
9
- gem 'rake', '~> 10.4'
10
- end
3
+ gemspec
data/README.md CHANGED
@@ -1,2 +1,6 @@
1
- # Comrad
1
+ Comrad
2
+ ======
3
+ [![Build Status](https://travis-ci.org/tas50/Comrad.svg)](https://travis-ci.org/tas50/Comrad)
4
+
2
5
  Application to sync changes from git to Chef Server via Jenkins
6
+
data/bin/comrad CHANGED
@@ -20,6 +20,6 @@
20
20
  # load the libs
21
21
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
22
22
 
23
- require 'application'
23
+ require 'comrad'
24
24
 
25
- Comrad::Application.new.run
25
+ Comrad.run
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'comrad'
3
- s.version = '0.0.3'
3
+ s.version = '0.1.0'
4
4
  s.date = Date.today.to_s
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.extra_rdoc_files = ['README.md', 'LICENSE']
@@ -14,13 +14,13 @@ Gem::Specification.new do |s|
14
14
  s.required_ruby_version = '>= 1.9.3'
15
15
  s.add_dependency 'rest-client', '~> 1.7.0'
16
16
  s.add_dependency 'chef', '>= 11.0'
17
- s.add_dependency 'ridley', '~> 4.0'
17
+ s.add_dependency 'slack-post', '~> 0.3'
18
18
  s.add_development_dependency 'rake', '~> 10.0'
19
19
  s.add_development_dependency 'rubocop', '~> 0.30.0'
20
20
 
21
21
  s.files = `git ls-files -z`.split("\x0")
22
- s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ s.executables = s.name
23
23
  s.require_paths = ['lib']
24
24
  s.extra_rdoc_files = ['README.md']
25
- s.rdoc_options = ['--line-numbers', '--inline-source', '--title', 'reagan', '--main', 'README.md']
25
+ s.rdoc_options = ['--line-numbers', '--inline-source', '--title', 'comrad', '--main', 'README.md']
26
26
  end
@@ -1,5 +1,6 @@
1
1
  slack:
2
2
  webhook_url: 1234abcde1234abcde
3
+ channel: '#general'
3
4
  jenkins:
4
5
  workspace_dir: '/home/jenkins/workspace/chef-repo/'
5
6
  chef:
@@ -0,0 +1,54 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author:: Tim Smith (<tim@cozy.co>)
4
+ # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ require 'pp'
19
+
20
+ require 'core_ext/string'
21
+
22
+ require 'comrad/config'
23
+ require 'comrad/changeset'
24
+ require 'comrad/chef'
25
+ require 'comrad/notifier'
26
+
27
+ # Your rad comrade - Sync changes from git to Chef Server via Jenkins
28
+ module Comrad
29
+ module_function
30
+
31
+ # Evaluate the current build for chef object changes,
32
+ # use knife to upload changed objects to the Chef server,
33
+ # send a notification to slack.
34
+ def self::run
35
+ if Config.config['flags']['print_config']
36
+ 'Current config file / CLI flag values'.marquee
37
+ Config.print
38
+ exit
39
+ end
40
+
41
+ if Changeset.empty?
42
+ 'No objects to test. Exiting'.to_green
43
+ exit
44
+ end
45
+
46
+ 'The following chef objects will be changed'.marquee
47
+ pp Changeset.changes
48
+
49
+ 'Making Chef Changes'.marquee
50
+ Chef.process_changes
51
+
52
+ Notifier.notify_changes
53
+ end
54
+ end
@@ -16,82 +16,72 @@
16
16
  # See the License for the specific language governing permissions and
17
17
  # limitations under the License.
18
18
 
19
- begin
20
- require 'json'
21
- require 'rest_client'
22
- require 'uri'
23
- rescue LoadError => e
24
- raise "Missing gem or lib #{e}"
25
- end
19
+ require 'json'
20
+ require 'rest_client'
26
21
 
27
22
  module Comrad
28
23
  # interacts with jenkins API to determine changes files
29
24
  # parses changed files to determine relevant files that will
30
25
  # need to be uploaded to chef server
31
- class Change < Application
32
- attr_accessor :changes
33
- def initialize(config)
34
- @config = config
35
- @protocol = URI(@config['jenkins']['url']).scheme
36
- @jenkins_host = URI(@config['jenkins']['url']).host
37
- @username = @config['jenkins']['username']
38
- @password = @config['jenkins']['password']
39
- @job_name = @config['jenkins']['job_name']
40
- @jenkins_workspace_path = @config['jenkins']['workspace_dir']
41
- @build_num = ENV['BUILD_NUMBER']
26
+ class Changeset
27
+ # Return a hash of all changed objects
28
+ def self::changes
29
+ @changes ||= create_change_hash(changed_files_array)
30
+ end
42
31
 
43
- @build_data = query_build_data
44
- @changes = create_change_hash(changed_files_array)
32
+ # True if there are no changed objects
33
+ def self::empty?
34
+ changes == empty_chef_object_hash
35
+ end
36
+
37
+ # Return a hash of all Jenkins details for this build
38
+ def self::build_data
39
+ @build_data ||= fetch_build_data
45
40
  end
46
41
 
47
42
  # fetch build data using Jenkins API
48
- def query_build_data
49
- conn = RestClient::Resource.new("#{@protocol}://#{@jenkins_host}/job/#{@job_name}/#{@build_num}/api/json?", @username, @password)
43
+ def self::fetch_build_data
44
+ j = Config.config['jenkins']
45
+ url = j['url'] + '/job/' + j['job_name'] + '/' + ENV['BUILD_NUMBER'] + '/api/json?'
46
+ conn = RestClient::Resource.new(url, j['username'], j['password'])
50
47
  JSON.parse(conn.get)
51
48
  end
52
49
 
53
50
  # parse jenkins build data to determine unique list of all files that have changed accross multiple commits
54
- def changed_files_array
51
+ def self::changed_files_array
55
52
  changed_files = []
56
-
57
- @build_data['changeSet']['items'].each do |change|
53
+ build_data['changeSet']['items'].each do |change|
58
54
  changed_files.concat(change['affectedPaths'])
59
55
  end
60
-
61
56
  changed_files.uniq
62
57
  end
63
58
 
64
- # create the empty hash that stores the changed objects
65
- def empty_chef_object_hash
66
- objects = {}
67
- objects['environments'] = {}
68
- objects['roles'] = {}
69
- objects['data_bags'] = {}
70
- objects['cookbooks'] = {}
71
-
72
- objects
59
+ def self::empty_chef_object_hash
60
+ {
61
+ 'environments' => {},
62
+ 'roles' => {},
63
+ 'data_bags' => {},
64
+ 'cookbooks' => {}
65
+ }
73
66
  end
74
67
 
75
68
  # return an action based on the status of the object in the workspace
76
- def action(file)
77
- ::File.exist?(::File.join(@jenkins_workspace_path, file)) ? 'update' : 'delete'
78
- end
79
-
80
- def print
69
+ def self::action(file)
70
+ ::File.exist?(::File.join(Config.config['jenkins']['workspace_dir'], file)) ? 'update' : 'delete'
81
71
  end
82
72
 
83
73
  # takes an array of files that have changes and returns hash of chef objects and an action to take on the object
84
- def create_change_hash(files_array)
74
+ def self::create_change_hash(files_array)
85
75
  objects = empty_chef_object_hash
86
76
  files_array.each do |file|
77
+ split_file = file.split('/')
87
78
  case
88
79
  when file.match(/^[cookbook|roles|environments]/)
89
- split_file = file.split('/')
80
+ # "cookbooks"=>{"some-cookbook"=>"update"}
90
81
  objects[split_file[0]][split_file[1]] = action(split_file[0..1].join('/'))
91
82
  when file.match(/^data_bags/)
92
- split_file = file.split('/')
93
- objects[split_file[0]][split_file[1]] = {} unless objects[split_file[0]].key?(split_file[1])
94
- objects[split_file[0]][split_file[1]][split_file[2]] = action(split_file[0..2].join('/'))
83
+ # "data_bags"=>{"some_dbag/some_item.json"=>"update"}
84
+ objects[split_file[0]][split_file[1..2].join('/')] = action(split_file[0..2].join('/'))
95
85
  end
96
86
  end
97
87
  objects
@@ -0,0 +1,64 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author:: Tim Smith (<tim@cozy.co>)
4
+ # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ module Comrad
20
+ # uploads / removes objects that changed from the chef server
21
+ class Chef
22
+ # Given an +item+ of +item_class+, return a knife command that performs +action+
23
+ def self::knife_command(item_class, item, action)
24
+ item_path = {
25
+ cookbooks: item,
26
+ data_bags: "data_bags/#{item}",
27
+ environments: "environments/#{item}",
28
+ roles: "roles/#{item}"
29
+ }
30
+ # Special case: if we're deleting a data_bag, we want
31
+ # "bag_name item_name" without the '.json' rather than the path to the item.
32
+ item_path[:data_bags] = item.split('/').join(' ').chomp('.json') if action == 'delete'
33
+
34
+ knife_action = { delete: 'delete', update: 'from file' }
35
+ # Special case: we call 'upload' instead of 'from file' for updated cookbooks
36
+ knife_action[:update] = 'upload' if item_class == 'cookbooks'
37
+
38
+ 'knife %s %s %s' % [ # rubocop:disable FormatString
39
+ item_class.chomp('s'), # cookbook, data_bag, environment, role
40
+ knife_action[action.to_sym], # 'upload', 'delete' or 'from file'
41
+ item_path[item_class.to_sym] # cookbookname, environments/foo.json, 'dbag bagitem', etc.
42
+ ]
43
+ end
44
+
45
+ # run the provided knife command
46
+ def self::excute_knife_cmd(cmd)
47
+ if Config.config['flags']['dryrun']
48
+ puts "I would be running '#{cmd}'"
49
+ else
50
+ puts "Live mode is not implemented. Not performing '#{cmd}'"
51
+ end
52
+ end
53
+
54
+ # perform the appropriate knife action for each item in the +changeset+
55
+ def self::process_changes
56
+ Changeset.changes.each_pair do |item_class, action_pairs|
57
+ next if action_pairs.empty?
58
+ action_pairs.each_pair do |item, action|
59
+ excute_knife_cmd(knife_command(item_class, item, action))
60
+ end
61
+ end
62
+ end
63
+ end # Chef class
64
+ end # Comrad Module
@@ -16,25 +16,34 @@
16
16
  # See the License for the specific language governing permissions and
17
17
  # limitations under the License.
18
18
 
19
- begin
20
- require 'yaml'
21
- require 'optparse'
22
- rescue LoadError => e
23
- raise "Missing gem or lib #{e}"
24
- end
19
+ require 'yaml'
20
+ require 'optparse'
25
21
 
26
22
  module Comrad
27
23
  # builds a single config from passed flags, yaml config, and knife.rb
28
24
  class Config
29
- attr_accessor :settings
30
- def initialize
31
- @flags = parse_flags
32
- @config_file = load_file
33
- @settings = merge_configs
25
+ # return the fully-evaluated configuration hash
26
+ def self::config
27
+ @flags ||= parse_flags
28
+ @config ||= merge_configs(load_file(@flags[:config]), @flags)
29
+ end
30
+
31
+ # pretty print the config hash
32
+ def self::print(hash = config, spaces = 0)
33
+ hash.each do |k, v|
34
+ spaces.times { print ' ' }
35
+ print k.to_s + ': '
36
+ if v.class == Hash
37
+ print "\n"
38
+ print_config(v, spaces + 2)
39
+ else
40
+ puts v
41
+ end
42
+ end
34
43
  end
35
44
 
36
45
  # make sure the BUILD_NUMBER Jenkins variable exists. If not force help
37
- def check_jenkins_env_variable
46
+ def self::check_jenkins_env_variable
38
47
  if ENV['BUILD_NUMBER'].nil?
39
48
  puts "Jenkins set BUILD_NUMBER environmental variable not set. Cannot continue.\n\n"
40
49
  ARGV[0] = '-h'
@@ -42,14 +51,14 @@ module Comrad
42
51
  end
43
52
 
44
53
  # grabs the flags passed in via command line
45
- def parse_flags
54
+ def self::parse_flags
46
55
  check_jenkins_env_variable
47
56
 
48
57
  flags = { config: '/etc/comrad.yml', print_config: false, quiet: false }
49
58
  OptionParser.new do |opts|
50
59
  opts.banner = 'Usage: comrad [options]'
51
60
 
52
- opts.on('-p', '--print', 'Print the config options that will be used') do |config|
61
+ opts.on('-p', '--print', 'Print the config options that would be used, and then exit') do |config|
53
62
  flags[:print_config] = config
54
63
  end
55
64
 
@@ -79,42 +88,27 @@ module Comrad
79
88
  end
80
89
 
81
90
  # loads the comrad.yml config file from /etc/comrad.yml or the passed location
82
- def load_file
83
- config = YAML.load_file(@flags[:config])
91
+ def self::load_file(file_path)
92
+ config = YAML.load_file(file_path)
84
93
  if config == false
85
94
  puts "ERROR: Comrad config at #{@flags[:config]} does not contain any configuration data"
86
95
  exit 1
87
96
  end
88
97
  config
89
98
  rescue Errno::ENOENT
90
- puts "ERROR: Cannot load Comrad config file at #{@flags[:config]}"
99
+ puts "ERROR: Cannot load Comrad config file at #{file_path}"
91
100
  exit 1
92
101
  rescue Psych::SyntaxError
93
- puts "ERROR: Syntax error in Comrad config file at #{@flags[:config]}"
102
+ puts "ERROR: Syntax error in Comrad config file at #{file_path}"
94
103
  exit 1
95
104
  end
96
105
 
97
106
  # join the config file with the passed flags into a single object
98
- def merge_configs
99
- config = @config_file
107
+ def self::merge_configs(file_config, flags_config)
108
+ config = file_config.dup
100
109
  config['flags'] = {}
101
- @flags.each { |k, v| config['flags'][k.to_s] = v }
110
+ flags_config.each { |k, v| config['flags'][k.to_s] = v }
102
111
  config
103
112
  end
104
-
105
- # pretty print the config hash
106
- def print(hash = nil, spaces = 0)
107
- hash = @settings if hash.nil?
108
- hash.each do |k, v|
109
- spaces.times { print ' ' }
110
- print k.to_s + ': '
111
- if v.class == Hash
112
- print "\n"
113
- print_config(v, spaces + 2)
114
- else
115
- puts v
116
- end
117
- end
118
- end
119
113
  end
120
114
  end
@@ -0,0 +1,62 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author:: Tim Smith (<tim@cozy.co>)
4
+ # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'slack/post'
20
+
21
+ module Comrad
22
+ # send notifications to slack
23
+ class Notifier
24
+ def self::configure
25
+ Slack::Post.configure(
26
+ webhook_url: Config.config['slack']['webhook_url'],
27
+ username: 'comrad',
28
+ channel: Config.config['slack']['channel']
29
+ )
30
+ @configured = true
31
+ end
32
+
33
+ # Post a Slack notification containing details of the changes
34
+ def self::notify_changes
35
+ unless Config.config['flags']['quiet']
36
+ configure unless @configured
37
+ Slack::Post.post_with_attachments(
38
+ 'Comrad action for chef repo <%s|Build #%s>' % [ # rubocop:disable FormatString
39
+ Changeset.build_data['url'],
40
+ Changeset.build_data['number']],
41
+ changeset_attachment)
42
+ end
43
+ end
44
+
45
+ # Generate a Slack message attachment that contains changeset details
46
+ def self::changeset_attachment
47
+ attach = { fallback: '', color: '#36a64f', fields: [] }
48
+
49
+ Changeset.changes.each_pair do |item_class, action_pairs|
50
+ next if action_pairs.empty?
51
+ text = ''
52
+ action_pairs.each_pair do |item, action|
53
+ text << "#{action} #{item}\n"
54
+ end
55
+ attach[:fallback] << "#{item_class}:\n#{text}"
56
+ attach[:fields] << { title: item_class, value: text, short: false }
57
+ end
58
+
59
+ [attach]
60
+ end
61
+ end
62
+ end
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: comrad
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-22 00:00:00.000000000 Z
11
+ date: 2015-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -39,19 +39,19 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '11.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: ridley
42
+ name: slack-post
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
- version: '4.0'
47
+ version: '0.3'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: '4.0'
54
+ version: '0.3'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -98,12 +98,12 @@ files:
98
98
  - bin/comrad
99
99
  - comrad.gemspec
100
100
  - comrad.yml.EXAMPLE
101
- - lib/application.rb
102
- - lib/change.rb
103
- - lib/chef.rb
104
- - lib/config.rb
105
- - lib/slack.rb
106
- - lib/string.rb
101
+ - lib/comrad.rb
102
+ - lib/comrad/changeset.rb
103
+ - lib/comrad/chef.rb
104
+ - lib/comrad/config.rb
105
+ - lib/comrad/notifier.rb
106
+ - lib/core_ext/string.rb
107
107
  homepage: http://www.github.com/tas50/Comrad
108
108
  licenses:
109
109
  - Apache-2.0
@@ -113,7 +113,7 @@ rdoc_options:
113
113
  - --line-numbers
114
114
  - --inline-source
115
115
  - --title
116
- - reagan
116
+ - comrad
117
117
  - --main
118
118
  - README.md
119
119
  require_paths:
@@ -1,66 +0,0 @@
1
- # encoding: UTF-8
2
- #
3
- # Author:: Tim Smith (<tim@cozy.co>)
4
- # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
- # License:: Apache License, Version 2.0
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
-
19
- module Comrad
20
- # the main class for the comrad app. gets called by the comrad bin
21
- class Application
22
- require 'config'
23
- require 'change'
24
- require 'chef'
25
- require 'string'
26
- require 'slack'
27
-
28
- def initialize
29
- @config_obj = Comrad::Config.new
30
- @config = @config_obj.settings
31
- @changes = Comrad::Change.new(@config).changes
32
- end
33
-
34
- # exit with a friendly message if nothing we test has been changed
35
- def check_empty_update
36
- objects_updated = false
37
- %w(cookbooks roles environments data_bags).each do |object|
38
- objects_updated = true unless @changes[object].empty?
39
- end
40
-
41
- ('No objects to test. Exiting'.to_green && exit) unless objects_updated
42
- end
43
-
44
- # check and see if the -p flag was passed and if so print the config hash
45
- def check_print_config
46
- if @config['flags']['print_config']
47
- 'Current config file / CLI flag values'.marquee
48
- @config_obj.print
49
- exit
50
- end
51
- end
52
-
53
- # run tests on each changed cookbook
54
- def run
55
- check_print_config
56
- ('No objects updated by this commit. Exiting'.to_green && exit) if check_empty_update
57
-
58
- # print objects that will be uploaded
59
- 'The following chef objects will be changed'.marquee
60
- puts @changes
61
-
62
- 'Making Chef Changes'.marquee
63
- Comrad::Chef.new(@config, @changes).run
64
- end
65
- end
66
- end
@@ -1,94 +0,0 @@
1
- # encoding: UTF-8
2
- #
3
- # Author:: Tim Smith (<tim@cozy.co>)
4
- # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
- # License:: Apache License, Version 2.0
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
-
19
- begin
20
- require 'ridley'
21
- rescue LoadError => e
22
- raise "Missing gem or lib #{e}"
23
- end
24
-
25
- module Comrad
26
- # uploads / removes objects that changed from the chef server
27
- class Chef < Application
28
- def initialize(config, changes)
29
- @config = config
30
- @changes = changes
31
- @slack = Comrad::Slack.new(config)
32
- end
33
-
34
- # builds a string of what the action is / would be depending on dry run or not
35
- def action_string(action, trailing_text)
36
- string = @config['flags']['dryrun'] ? " - I would #{action} " : " - #{action.capitalize.chomp('e')}ing "
37
- string + trailing_text
38
- end
39
-
40
- # a really horrible method to build knife commands based on item / action / item type (cookbook/role/environment/data_bag)
41
- def build_knife_cmd(type, action, item1, item2 = nil)
42
- if type == 'data_bags'
43
- action == 'delete' ? "knife data bag delete #{item1} #{item2}" : "knife data bag from file #{item1} data_bags/#{item1}/#{item2}"
44
- elsif action == 'delete'
45
- "knife #{type.chomp('s')} delete #{item1} #{item2}"
46
- elsif type == 'cookbooks'
47
- "knife cookbook #{action == 'update' ? 'upload' : 'delete'} #{item1}"
48
- else
49
- "knife #{type.chomp('s')} from file #{type}/#{item1}"
50
- end
51
- end
52
-
53
- # run the provided knife command
54
- def excute_knife_cmd(cmd)
55
- if @config['flags']['dryrun']
56
- @slack.slack_put(" - I would be running #{cmd}")
57
- else
58
- @slack.slack_put(' - Non-dry mode is not implemented. Doing nothing')
59
- end
60
- end
61
-
62
- # main method of the class. Iterates over the changes passed in and kicks off actions / slack messaging
63
- def take_actions
64
- @changes.each_pair do |type, name|
65
- next if name.empty?
66
- case
67
- when type.match(/^['environments|roles']/)
68
- name.each_pair do |item, action|
69
- @slack.slack_put(action_string(action, "#{item}"))
70
- excute_knife_cmd(build_knife_cmd(type, action, item))
71
- end
72
- when type == 'cookbooks'
73
- name.each_pair do |item, action|
74
- @slack.slack_put(action_string(action, "#{item}"))
75
- excute_knife_cmd(build_knife_cmd(type, action, item))
76
- end
77
- when type == 'data_bags'
78
- name.each_pair do |bag, item|
79
- item.each_pair do |bag_item_name, action|
80
- @slack.slack_put(action_string(action, "#{bag}::#{bag_item_name} data bag item"))
81
- excute_knife_cmd(build_knife_cmd(type, action, bag, bag_item_name))
82
- end
83
- end
84
- end
85
- end
86
- end
87
-
88
- # called by application to perform actions
89
- def run
90
- @slack.slack_put("Comrad action for chef repo build # #{ENV['BUILD_NUMBER']}:")
91
- take_actions
92
- end
93
- end # Chef class
94
- end # Comrad Module
@@ -1,46 +0,0 @@
1
- # encoding: UTF-8
2
- #
3
- # Author:: Tim Smith (<tim@cozy.co>)
4
- # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
- # License:: Apache License, Version 2.0
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
-
19
- require 'rest-client'
20
- require 'json'
21
-
22
- # base module
23
- module Comrad
24
- # send notifications to slack
25
- class Slack
26
- def initialize(config)
27
- @config = config
28
- @url = config['slack']['webhook_url']
29
- end
30
-
31
- def slack_put(text)
32
- puts text
33
- post(text) unless @config['flags']['quiet']
34
- end
35
-
36
- def post(text)
37
- RestClient.post @url, create_message(text).to_json
38
- end
39
-
40
- def create_message(text)
41
- message = {}
42
- message['text'] = text
43
- message
44
- end
45
- end
46
- end