sambot 0.1.193 → 0.1.194
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 +4 -4
- data/README.md +19 -10
- data/integration_tests/vault_helper_spec.rb +10 -7
- data/lib/sambot.rb +2 -0
- data/lib/sambot/application_error.rb +2 -0
- data/lib/sambot/base_command.rb +18 -18
- data/lib/sambot/chef/cookbook.rb +19 -19
- data/lib/sambot/chef/generator.rb +42 -41
- data/lib/sambot/chef/hooks.rb +13 -13
- data/lib/sambot/chef/kitchen.rb +51 -51
- data/lib/sambot/chef/metadata.rb +5 -5
- data/lib/sambot/chef/server.rb +46 -46
- data/lib/sambot/cli.rb +10 -10
- data/lib/sambot/config.rb +73 -73
- data/lib/sambot/runtime.rb +4 -6
- data/lib/sambot/template.rb +5 -5
- data/lib/sambot/templates/Berksfile +2 -0
- data/lib/sambot/templates/spec_helper.rb +2 -0
- data/lib/sambot/testing/consul_helper.rb +1 -0
- data/lib/sambot/testing/fixtures.rb +1 -0
- data/lib/sambot/testing/vault_helper.rb +11 -8
- data/lib/sambot/ui.rb +28 -28
- data/lib/sambot/version.rb +1 -1
- metadata +19 -41
- data/bin/slackbot +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e665e26a7ff750db4a39687428a170cd4769111
|
4
|
+
data.tar.gz: '0835d78e1ecd8c1e9bbb5344d00a1783ebe87f82'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f07be80b3513c861fabef6296877cd00c01d6926951856bbcabab2f663986a0e0593a78d027fa9d63e15e0441146cf25ebf98dae9ba4d3383b0dec98e4d9daab
|
7
|
+
data.tar.gz: fcd9b733f321e070bd35c060d031b3ac0a83b766a1210b3ef3c0007e3ddab40a4a725139aabff622efb29067a876e218041d10cf48087e95d575ac00a70f0cd2
|
data/README.md
CHANGED
@@ -1,20 +1,26 @@
|
|
1
1
|
# Sambot
|
2
2
|
|
3
|
-
Sambot is our internal Platform Engineering toolchain to help standardize and
|
3
|
+
Sambot is our internal Platform Engineering toolchain to help standardize and
|
4
|
+
simplify our DevOps workflow.
|
4
5
|
|
5
|
-
It provides an executable with a variety of commands, grouped in various areas
|
6
|
-
DNS changes and cookbook management.
|
6
|
+
It provides an executable with a variety of commands, grouped in various areas
|
7
|
+
of functionality such as session management, DNS changes and cookbook management.
|
7
8
|
|
8
9
|
## Usage
|
9
10
|
|
10
|
-
To install the gem, simply run `chef gem install sambot`. This will install the
|
11
|
+
To install the gem, simply run `chef gem install sambot`. This will install the
|
12
|
+
gem in your ChefDK installation. If you want to use it outside Chef,
|
13
|
+
run `gem install sambot`.
|
11
14
|
|
12
|
-
Run `chef exec sambot` to be shown the help menu. For help on specific commands,
|
13
|
-
cookbook management
|
15
|
+
Run `chef exec sambot` to be shown the help menu. For help on specific commands,
|
16
|
+
i.e. cookbook management and specific cookbook management commands, run
|
17
|
+
`chef exec sambot help cookbook` or `chef exec sambot cookbook help generate`
|
18
|
+
for example.
|
14
19
|
|
15
20
|
## Contributing
|
16
21
|
|
17
|
-
Bug reports and pull requests are welcome on GitHub at
|
22
|
+
Bug reports and pull requests are welcome on GitHub at
|
23
|
+
https://github.exacttarget.com/ads-devops/sambot.
|
18
24
|
|
19
25
|
### Installation
|
20
26
|
|
@@ -22,7 +28,8 @@ Make sure you have `ruby >= 2.4.0` installed.
|
|
22
28
|
|
23
29
|
Install `bundler >= 1.15.1` by running `gem install bundler`
|
24
30
|
|
25
|
-
Run `bundle install` from the root of the project to install the
|
31
|
+
Run `bundle install` from the root of the project to install the
|
32
|
+
required Ruby gems.
|
26
33
|
|
27
34
|
### Running Sambot
|
28
35
|
|
@@ -30,9 +37,11 @@ If you want to test your changes locally, you can run `bundle exec bin/sambot`.
|
|
30
37
|
|
31
38
|
### Running Tests
|
32
39
|
|
33
|
-
Run `bundle exec rspec spec`
|
40
|
+
Run `bundle exec rspec spec` to execute the unit tests.
|
41
|
+
|
42
|
+
Run `cd integration_tests && bundle exec rspec .` to execute the integration
|
43
|
+
tests. These require that you have Docker Compose available.
|
34
44
|
|
35
45
|
### Linting
|
36
46
|
|
37
47
|
There is nothing here yet
|
38
|
-
|
@@ -22,28 +22,31 @@ RSpec.describe Sambot::Testing::VaultHelper do
|
|
22
22
|
`docker-compose down`
|
23
23
|
end
|
24
24
|
|
25
|
-
context
|
25
|
+
context '.setup()' do
|
26
26
|
|
27
|
-
it
|
28
|
-
mounts= ::Vault.sys.mounts
|
27
|
+
it 'sets up Vault correctly' do
|
28
|
+
mounts = ::Vault.sys.mounts
|
29
29
|
expect(mounts[:"dev/common"]).to_not be_nil
|
30
30
|
end
|
31
31
|
|
32
32
|
end
|
33
33
|
|
34
|
-
context
|
34
|
+
context '.generate_wrapped_token()' do
|
35
35
|
|
36
|
-
it
|
36
|
+
it 'generates the correct token' do
|
37
37
|
wrapped_token = VaultHelper.generate_wrapped_token
|
38
38
|
access_token = ::Vault.logical.unwrap(wrapped_token)
|
39
39
|
expect(access_token.auth.renewable?).to be true
|
40
40
|
expect(access_token.auth.lease_duration).to eql(2764800)
|
41
41
|
end
|
42
42
|
|
43
|
-
it
|
43
|
+
it 'generates a renewable token' do
|
44
44
|
wrapped_token = VaultHelper.generate_wrapped_token
|
45
45
|
access_token = ::Vault.logical.unwrap(wrapped_token)
|
46
|
-
::Vault.
|
46
|
+
::Vault.configure do |config|
|
47
|
+
config.token = access_token.auth.client_token
|
48
|
+
end
|
49
|
+
::Vault.auth_token.renew_self
|
47
50
|
end
|
48
51
|
|
49
52
|
end
|
data/lib/sambot.rb
CHANGED
data/lib/sambot/base_command.rb
CHANGED
@@ -11,12 +11,12 @@ class Thor
|
|
11
11
|
paras = message.split("\n\n")
|
12
12
|
|
13
13
|
paras.map! do |unwrapped|
|
14
|
-
unwrapped.strip.tr("\n",
|
14
|
+
unwrapped.strip.tr("\n", ' ').squeeze(' ').gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }
|
15
15
|
end
|
16
16
|
|
17
17
|
paras.each do |para|
|
18
18
|
para.split("\n").each do |line|
|
19
|
-
stdout.puts line.insert(0,
|
19
|
+
stdout.puts line.insert(0, ' ' * indent)
|
20
20
|
end
|
21
21
|
stdout.puts unless para == paras.last
|
22
22
|
end
|
@@ -41,39 +41,39 @@ class Thor
|
|
41
41
|
command = all_commands[meth]
|
42
42
|
handle_no_command_error(meth) unless command
|
43
43
|
shell.say
|
44
|
-
shell.say(
|
44
|
+
shell.say(' Usage:', :green)
|
45
45
|
shell.say
|
46
46
|
shell.say " sambot #{command_name} "
|
47
47
|
shell.say
|
48
48
|
shell.say
|
49
49
|
class_options_help(shell, nil => command.options.values)
|
50
|
-
shell.say
|
50
|
+
shell.say ' Description:', :green
|
51
51
|
shell.say
|
52
|
-
shell.print_wrapped(docs(
|
52
|
+
shell.print_wrapped(docs(command_name.to_s), indent: 2)
|
53
53
|
shell.say
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
58
|
module Sambot
|
59
|
-
|
59
|
+
class BaseCommand < Thor
|
60
60
|
|
61
|
-
|
61
|
+
before :check_version
|
62
62
|
|
63
|
-
|
63
|
+
no_commands do
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
def self.docs(path)
|
73
|
-
File.read(File.join(File.dirname(__FILE__), '/docs', path + '.txt'))
|
74
|
-
end
|
65
|
+
def execute
|
66
|
+
Runtime.ensure_latest
|
67
|
+
yield
|
68
|
+
rescue ApplicationError => e
|
69
|
+
UI.error(e.message)
|
70
|
+
end
|
75
71
|
|
72
|
+
def self.docs(path)
|
73
|
+
File.read(File.join(File.dirname(__FILE__), '/docs', path + '.txt'))
|
76
74
|
end
|
77
75
|
|
76
|
+
end
|
77
|
+
|
78
78
|
end
|
79
79
|
end
|
data/lib/sambot/chef/cookbook.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#frozen_string_literal: true
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'yaml'
|
4
4
|
|
@@ -7,16 +7,16 @@ module Sambot
|
|
7
7
|
class Cookbook
|
8
8
|
|
9
9
|
GENERATED_FILES = {
|
10
|
-
'teamcity.sh.erb': {eruby: true, dest: 'teamcity.sh', platform: [
|
11
|
-
'chefignore': {eruby: false, dest: 'chefignore', platform: [
|
12
|
-
'docker-compose.yml': {eruby: false, dest: 'docker-compose.yml', platform: [
|
13
|
-
'.env': {eruby: false, dest: '.env', platform: [
|
14
|
-
'Berksfile': {eruby: false, dest: 'Berksfile', platform: [
|
15
|
-
'.rubocop.yml': {eruby: false, dest: '.rubocop.yml', platform: [
|
16
|
-
'.gitignore.sample': {eruby: false, dest: '.gitignore', platform: [
|
17
|
-
'Vagrantfile.erb': {eruby: false, dest: 'Vagrantfile.erb', platform: [
|
18
|
-
'winrm_config': {eruby: false, dest: 'winrm_config', platform: [
|
19
|
-
}
|
10
|
+
'teamcity.sh.erb': { eruby: true, dest: 'teamcity.sh', platform: %i[windows centos] },
|
11
|
+
'chefignore': { eruby: false, dest: 'chefignore', platform: %i[windows centos] },
|
12
|
+
'docker-compose.yml': { eruby: false, dest: 'docker-compose.yml', platform: %i[windows centos] },
|
13
|
+
'.env': { eruby: false, dest: '.env', platform: %i[windows centos] },
|
14
|
+
'Berksfile': { eruby: false, dest: 'Berksfile', platform: %i[windows centos] },
|
15
|
+
'.rubocop.yml': { eruby: false, dest: '.rubocop.yml', platform: %i[windows centos] },
|
16
|
+
'.gitignore.sample': { eruby: false, dest: '.gitignore', platform: %i[windows centos] },
|
17
|
+
'Vagrantfile.erb': { eruby: false, dest: 'Vagrantfile.erb', platform: %i[windows centos] },
|
18
|
+
'winrm_config': { eruby: false, dest: 'winrm_config', platform: %i[windows] }
|
19
|
+
}.freeze
|
20
20
|
|
21
21
|
class << self
|
22
22
|
|
@@ -25,18 +25,18 @@ module Sambot
|
|
25
25
|
Generator.from_templates(config, cloud, local_workflow, GENERATED_FILES)
|
26
26
|
Kitchen.setup(cloud, config, local_workflow)
|
27
27
|
Metadata.generate(config)
|
28
|
-
Hooks.copy
|
28
|
+
Hooks.copy
|
29
29
|
UI.info('The cookbook has been successfully built.')
|
30
30
|
end
|
31
31
|
|
32
|
-
def bump
|
32
|
+
def bump
|
33
33
|
new_version = Config.bump_version
|
34
34
|
UI.info("You have bumped the version of this cookbook to #{new_version}.")
|
35
35
|
end
|
36
36
|
|
37
|
-
def clean
|
37
|
+
def clean
|
38
38
|
UI.info('Removing all generated files from this cookbook.')
|
39
|
-
targets = GENERATED_FILES.map{ |
|
39
|
+
targets = GENERATED_FILES.map { |_, val| val[:dest] } - ['.gitignore']
|
40
40
|
targets.each { |file| Sambot::FS.delete(file) }
|
41
41
|
Sambot::FS.delete('bootstrap.sh')
|
42
42
|
Sambot::FS.delete('bootstrap.ps1')
|
@@ -58,16 +58,16 @@ module Sambot
|
|
58
58
|
|
59
59
|
def create_files(config)
|
60
60
|
['README.md'].each { |resource| FS.copy(resource) unless FS.exist?(resource) }
|
61
|
-
[
|
61
|
+
%w[spec test attributes local_testing].each { |resource| FS.mkdir(resource) unless FS.exist?(resource) }
|
62
62
|
Dir.chdir('attributes') { FileUtils.touch('default.rb') unless FS.exist?('default.rb') }
|
63
63
|
Dir.chdir('spec') { FS.copy('spec_helper.rb') unless FS.exist?('spec_helper.rb') }
|
64
|
-
[
|
64
|
+
%w[recipes libraries resources files templates].each { |target| FS.mkdir(target) unless FS.exist?(target) }
|
65
65
|
Dir.chdir('recipes') do
|
66
66
|
FileUtils.touch('default.rb') unless FS.exist?('default.rb')
|
67
67
|
end
|
68
68
|
unless FS.exist?('.config.yml')
|
69
|
-
Template.new('.config.yml.erb').write({config: config}, '.config.yml')
|
70
|
-
UI.debug(
|
69
|
+
Template.new('.config.yml.erb').write({ config: config }, '.config.yml')
|
70
|
+
UI.debug('./.config.yml has been added to the cookbook.')
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
@@ -1,58 +1,59 @@
|
|
1
|
-
#frozen_string_literal: true
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'awesome_print'
|
3
4
|
|
4
5
|
module Sambot
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def self.from_templates(config, cloud, local_workflow, generated_files)
|
9
|
-
generated_files.each { |template_name, opts| generate_from_template(template_name.to_s, opts, config) }
|
10
|
-
generate_bootstrap_scripts(config, cloud, local_workflow)
|
11
|
-
end
|
6
|
+
module Chef
|
7
|
+
class Generator
|
12
8
|
|
13
|
-
|
9
|
+
def self.from_templates(config, cloud, local_workflow, generated_files)
|
10
|
+
generated_files.each { |template_name, opts| generate_from_template(template_name.to_s, opts, config) }
|
11
|
+
generate_bootstrap_scripts(config, cloud, local_workflow)
|
12
|
+
end
|
14
13
|
|
15
|
-
|
16
|
-
generate_bootstrap_from_template('bootstrap.sh', path, 'sh')
|
17
|
-
end
|
14
|
+
private_class_method
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
def self.bootstrap_centos(path)
|
17
|
+
generate_bootstrap_from_template(path, 'sh')
|
18
|
+
end
|
22
19
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
20
|
+
def self.bootstrap_windows(path)
|
21
|
+
generate_bootstrap_from_template(path, 'ps1')
|
22
|
+
end
|
27
23
|
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
def self.bootstrap(config, path)
|
25
|
+
bootstrap_centos(path) if config.runs_on_centos?
|
26
|
+
bootstrap_windows(path) if config.runs_on_windows?
|
27
|
+
end
|
31
28
|
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
def self.generate_bootstrap_from_template(path, suffix)
|
30
|
+
Template.new("bootstrap_scripts/#{path}/bootstrap.#{suffix}.erb").process(eruby: true, dest: "bootstrap.#{suffix}")
|
31
|
+
end
|
35
32
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
33
|
+
def self.generate_bootstrap_scripts(config, cloud, local_workflow)
|
34
|
+
cloud != 'local' ? bootstrap(config, cloud) : bootstrap(config, "local/#{local_workflow}")
|
35
|
+
end
|
40
36
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
template.process(opts)
|
46
|
-
UI.debug("#{opts[:dest]} has been added to the cookbook.")
|
47
|
-
end
|
48
|
-
end
|
37
|
+
def self.exists!(path)
|
38
|
+
return if File.exist?(path) || Dir.exist?(path)
|
39
|
+
raise ApplicationError, "The file or directory #{path} was not found in the current directory."
|
40
|
+
end
|
49
41
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
42
|
+
def self.generate_from_template(template_file, opts, config)
|
43
|
+
UI.debug("Processing #{template_file} with opts #{opts.inspect} on platform #{config.available_platforms}")
|
44
|
+
template = Template.new(template_file)
|
45
|
+
if valid_platform?(opts, config)
|
46
|
+
template.process(opts)
|
47
|
+
UI.debug("#{opts[:dest]} has been added to the cookbook.")
|
54
48
|
end
|
49
|
+
end
|
55
50
|
|
51
|
+
def self.valid_platform?(opts, config)
|
52
|
+
targets = opts[:platform].map(&:to_s)
|
53
|
+
result = targets & config.available_platforms
|
54
|
+
result.size.positive?
|
56
55
|
end
|
56
|
+
|
57
|
+
end
|
57
58
|
end
|
58
59
|
end
|
data/lib/sambot/chef/hooks.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
|
-
#frozen_string_literal: true
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Sambot
|
4
|
-
|
5
|
-
|
4
|
+
module Chef
|
5
|
+
class Hooks
|
6
6
|
|
7
|
-
|
7
|
+
SCRIPTS = ['pre-push', 'pre-commit'].freeze
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
9
|
+
def self.copy
|
10
|
+
SCRIPTS.each do |hook|
|
11
|
+
working_path = ".git/hooks/#{hook}"
|
12
|
+
template_path = Template.new("git_hooks/#{hook}").path
|
13
|
+
File.delete(working_path) if File.exist?(working_path)
|
14
|
+
FileUtils.cp(template_path, working_path)
|
15
|
+
UI.debug("The #{hook} Git hook has been added to the cookbook.")
|
17
16
|
end
|
18
|
-
|
19
17
|
end
|
18
|
+
|
19
|
+
end
|
20
20
|
end
|
21
21
|
end
|
data/lib/sambot/chef/kitchen.rb
CHANGED
@@ -1,67 +1,67 @@
|
|
1
|
-
#frozen_string_literal: true
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Sambot
|
4
|
-
|
5
|
-
|
4
|
+
module Chef
|
5
|
+
class Kitchen
|
6
6
|
|
7
|
-
|
7
|
+
class << self
|
8
8
|
|
9
|
-
|
9
|
+
GENERATED_FILE = '.kitchen.yml'
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
def setup(cloud, config, vault_setup)
|
12
|
+
contents = generate_yml(cloud, config.name, config.available_platforms, config.suites, vault_setup)
|
13
|
+
File.write(GENERATED_FILE, contents)
|
14
|
+
UI.debug("#{GENERATED_FILE} has been added to the cookbook.")
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
def clean
|
18
|
+
FS.delete(GENERATED_FILE)
|
19
|
+
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
template.to_yaml
|
21
|
+
def generate_yml(cloud, cookbook_name, platforms, suites = nil, vault_setup = nil)
|
22
|
+
raise ApplicationError, 'Missing platforms when trying to generate Test-Kitchen YAML.' unless platforms
|
23
|
+
raise ApplicationError, 'Missing cookbook name when trying to generate Test-Kitchen YAML.' unless cookbook_name
|
24
|
+
template = read_template(cloud, cookbook_name, platforms, vault_setup)
|
25
|
+
if suites
|
26
|
+
template['suites'] = Marshal.load(Marshal.dump(suites))
|
27
|
+
add_platform_identifier(template, cloud)
|
30
28
|
end
|
29
|
+
template.to_yaml
|
30
|
+
end
|
31
31
|
|
32
|
-
|
32
|
+
private
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
34
|
+
# Adds attributes to each test suite that is only applicable to testing
|
35
|
+
# environments. These are things like controlling how Vault token
|
36
|
+
# renewal works and specifying the cloud platform.
|
37
|
+
def add_platform_identifier(value, platform)
|
38
|
+
value['suites'].each do |suite|
|
39
|
+
suite['run_list'] = handle_customized_runlists(suite, platform)
|
40
|
+
# Changes to <platform> below to keep compatibility with existing cookbooks
|
41
|
+
platform = 'LOCAL' if platform == 'local'
|
42
|
+
platform = 'GCP' if platform == 'google'
|
43
|
+
platform = 'RACKSPACE' if platform == 'rackspace'
|
44
|
+
suite['attributes'] = suite['attributes'] || {}
|
45
|
+
suite['attributes']['cloud_platform'] = platform
|
46
|
+
suite['attributes']['vault'] = suite['attributes']['vault'] || {}
|
47
|
+
suite['attributes']['vault']['exec_renew'] = false
|
49
48
|
end
|
49
|
+
end
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
51
|
+
# Provides the ability to have a different run-list for different clouds.
|
52
|
+
# This only works for the 'local' cloud and the 'dev' clouds i.e. Rackspace
|
53
|
+
# and Google.
|
54
|
+
def handle_customized_runlists(config, platform)
|
55
|
+
runlist = config['run_list']
|
56
|
+
return runlist if runlist.is_a?(Array)
|
57
|
+
platform == 'local' ? runlist['local'] : runlist['dev']
|
58
|
+
end
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
60
|
+
def read_template(cloud, cookbook_name, platforms, vault_setup)
|
61
|
+
ctx = { platforms: platforms, name: cookbook_name, vault_setup: vault_setup }
|
62
|
+
result = Template.new("test_kitchen/#{cloud}.yml.erb").evaluate(ctx, pattern: '<!--% %-->')
|
63
|
+
YAML.safe_load(result)
|
64
|
+
end
|
65
65
|
|
66
66
|
end
|
67
67
|
end
|
data/lib/sambot/chef/metadata.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#frozen_string_literal: true
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'erubis'
|
4
4
|
|
@@ -8,7 +8,7 @@ module Sambot
|
|
8
8
|
|
9
9
|
class << self
|
10
10
|
|
11
|
-
GENERATED_FILES = ['metadata.rb', 'Berksfile.lock']
|
11
|
+
GENERATED_FILES = ['metadata.rb', 'Berksfile.lock'].freeze
|
12
12
|
|
13
13
|
def clean
|
14
14
|
GENERATED_FILES.each do |filename|
|
@@ -23,15 +23,15 @@ module Sambot
|
|
23
23
|
'cookbook_version' => config.version,
|
24
24
|
'cookbook_description' => config.description,
|
25
25
|
'cookbook_dependencies' => config.dependencies,
|
26
|
-
'cookbook_gems' => config.gems
|
26
|
+
'cookbook_gems' => config.gems
|
27
27
|
}, dest)
|
28
28
|
end
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
32
|
def write(ctx, dest)
|
33
|
-
|
34
|
-
UI.debug(
|
33
|
+
Sambot::Template.new('metadata.rb.erb').write(ctx, dest)
|
34
|
+
UI.debug('A new metadata.rb file has been generated.')
|
35
35
|
end
|
36
36
|
|
37
37
|
end
|
data/lib/sambot/chef/server.rb
CHANGED
@@ -1,58 +1,58 @@
|
|
1
|
-
#frozen_string_literal: true
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'ridley'
|
4
4
|
require 'json'
|
5
5
|
|
6
6
|
module Sambot
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
7
|
+
module Chef
|
8
|
+
class Server
|
9
|
+
|
10
|
+
SHORT_NAMES = {
|
11
|
+
'wsus' => 'WSUS',
|
12
|
+
'nginx-proxy' => 'PRXY',
|
13
|
+
'jetstream' => 'JTS',
|
14
|
+
'task-scheduler' => 'TASKS',
|
15
|
+
'queue-service' => 'QUE',
|
16
|
+
'skylight' => 'SKY',
|
17
|
+
'prometheus' => 'PRT',
|
18
|
+
'octopus' => 'OCTO',
|
19
|
+
'vault' => 'VAULT',
|
20
|
+
'consul' => 'CONSUL',
|
21
|
+
'rabbitmq' => 'RMQ',
|
22
|
+
'etcd' => 'ETCD',
|
23
|
+
'teamcity-agent' => 'TCA',
|
24
|
+
'teamcity-server' => 'TCS',
|
25
|
+
'bastion' => 'BST',
|
26
|
+
'base' => 'BASE',
|
27
|
+
'grafana' => 'MON'
|
28
|
+
}.freeze
|
29
|
+
|
30
|
+
def initialize(ridley = nil)
|
31
|
+
@ridley = ridley || Ridley.new(
|
32
|
+
server_url: "https://chef.brighter.io/organizations/#{ENV['CHEF_ORGANIZATION']}",
|
33
|
+
client_name: ENV['CHEF_CLIENT_NAME'],
|
34
|
+
client_key: ENV['CHEF_CLIENT_KEY'],
|
35
|
+
proxy: ENV['FIXIE_URL']
|
36
|
+
)
|
37
|
+
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
def cookbooks
|
40
|
+
@cookbooks ||= @ridley.cookbook.all.select { |x| x =~ /as-/ }.keys.sort
|
41
|
+
end
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
def roles
|
44
|
+
cookbooks.select { |x| x =~ /role/ }
|
45
|
+
end
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
47
|
+
def find_role_name(cookbook)
|
48
|
+
naive_name = cookbook.gsub(/as-role-/, '').gsub(/as-app-role-/, '')
|
49
|
+
if SHORT_NAMES.key?(naive_name)
|
50
|
+
SHORT_NAMES[naive_name]
|
51
|
+
else
|
52
|
+
raise 'Could not generate an instance name'
|
54
53
|
end
|
55
|
-
|
56
54
|
end
|
55
|
+
|
57
56
|
end
|
58
57
|
end
|
58
|
+
end
|
data/lib/sambot/cli.rb
CHANGED
@@ -7,7 +7,7 @@ module Sambot
|
|
7
7
|
|
8
8
|
desc 'clean', 'Remove all generated build files from a Chef cookbook'
|
9
9
|
def clean
|
10
|
-
execute { Chef::Cookbook.clean
|
10
|
+
execute { Chef::Cookbook.clean }
|
11
11
|
end
|
12
12
|
|
13
13
|
desc 'populate', 'Populates Vault and Consul with seed data'
|
@@ -21,14 +21,14 @@ module Sambot
|
|
21
21
|
|
22
22
|
desc 'bump', 'Bump the patch version of a cookbook'
|
23
23
|
def bump
|
24
|
-
execute { Chef::Cookbook.bump
|
24
|
+
execute { Chef::Cookbook.bump }
|
25
25
|
end
|
26
26
|
|
27
27
|
desc 'build', 'Builds a Chef cookbook from its configuration file'
|
28
|
-
option :local, :
|
29
|
-
option :google, :
|
30
|
-
option :rackspace, :
|
31
|
-
option :docker, :
|
28
|
+
option :local, type: :boolean
|
29
|
+
option :google, type: :boolean
|
30
|
+
option :rackspace, type: :boolean
|
31
|
+
option :docker, type: :boolean
|
32
32
|
def build
|
33
33
|
execute do
|
34
34
|
cloud = nil
|
@@ -49,19 +49,19 @@ module Sambot
|
|
49
49
|
execute do
|
50
50
|
opts = {
|
51
51
|
name: ask(' What is the name of this cookbook?'),
|
52
|
-
type: ask(' What type of cookbook will this be?', :
|
53
|
-
platforms: ask(' What operating system will this cookbook run on?', :
|
52
|
+
type: ask(' What type of cookbook will this be?', limited_to: %w[wrapper role]),
|
53
|
+
platforms: ask(' What operating system will this cookbook run on?', limited_to: %w[windows centos both]),
|
54
54
|
description: ask(' What does this cookbook do?')
|
55
55
|
}
|
56
56
|
opts[:identifier] = ask(' What will be the unique machiner identifier for this role cookbook i.e. TCA (TeamCity Agent) or RMQ (RabbitMQ role)?') if opts[:type] == 'role'
|
57
|
-
opts[:platforms] = opts[:platforms] == 'both' ? [
|
57
|
+
opts[:platforms] = opts[:platforms] == 'both' ? %w[centos windows] : [opts[:platforms]]
|
58
58
|
Chef::Cookbook.create(Config.new(opts))
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
62
|
desc 'version', 'Gives the cookbook version as a TeamCity service message'
|
63
63
|
def version
|
64
|
-
execute { puts "##teamcity[buildNumber '#{Config.read.version
|
64
|
+
execute { puts "##teamcity[buildNumber '#{Config.read.version}']" }
|
65
65
|
end
|
66
66
|
|
67
67
|
end
|
data/lib/sambot/config.rb
CHANGED
@@ -4,94 +4,94 @@ require 'yaml'
|
|
4
4
|
require 'semantic'
|
5
5
|
|
6
6
|
module Sambot
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
config['platforms'] = config['platform']
|
39
|
-
end
|
40
|
-
Config.new(config)
|
7
|
+
class Config
|
8
|
+
|
9
|
+
CONFIGURATION_FILENAME = '.config.yml'
|
10
|
+
|
11
|
+
def self.bump_version(path = nil)
|
12
|
+
path ||= File.join(Dir.getwd, CONFIGURATION_FILENAME)
|
13
|
+
config = YAML.load_file(path)
|
14
|
+
version = config['version']
|
15
|
+
config['version'] = bump(version)
|
16
|
+
File.write(path, YAML.dump(config))
|
17
|
+
config['version']
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(opts)
|
21
|
+
@opts = opts
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.read(path = nil)
|
25
|
+
path ||= File.join(Dir.getwd, CONFIGURATION_FILENAME)
|
26
|
+
raise ApplicationError, "The configuration file was not found at #{path}." unless File.exist?(path)
|
27
|
+
config = YAML.load_file(path)
|
28
|
+
raise ApplicationError, 'Missing cookbook name in the .config.yml configuration file' unless config['name']
|
29
|
+
raise ApplicationError, 'Missing platforms in the .config.yml configuration file' unless config['platform'] || config['platforms']
|
30
|
+
raise ApplicationError, 'Missing version in the .config.yml configuration file' unless config['version']
|
31
|
+
raise ApplicationError, 'Missing list of suites in the .config.yml configuration file' unless config['suites']
|
32
|
+
raise ApplicationError, 'Missing description in the .config.yml configuration file' unless config['description']
|
33
|
+
# Dealing with legacy tech debt of allowing multiple platforms rather than a single platform
|
34
|
+
unless config['platforms']
|
35
|
+
unless config['platform'].is_a?(Array)
|
36
|
+
config['platform'] = [config['platform']]
|
41
37
|
end
|
38
|
+
config['platforms'] = config['platform']
|
39
|
+
end
|
40
|
+
Config.new(config)
|
41
|
+
end
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
def available_platforms
|
44
|
+
platforms = @opts[:platforms] if @opts.key?(:platforms)
|
45
|
+
platforms = @opts['platforms'] if @opts.key?('platforms')
|
46
|
+
platforms
|
47
|
+
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
def gems
|
50
|
+
@opts['gems'] || @opts[:gems] || []
|
51
|
+
end
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
def dependencies
|
54
|
+
items = @opts['dependencies'] || @opts[:dependencies]
|
55
|
+
items ? items.map { |x| transform_hashes(x) } : []
|
56
|
+
end
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
def dependencies=(value)
|
59
|
+
@opts['dependencies'] = value
|
60
|
+
end
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
def transform_hashes(obj)
|
63
|
+
obj.is_a?(Hash) ? "#{obj.keys.first}', '#{obj.values.first}" : obj
|
64
|
+
end
|
65
65
|
|
66
|
-
|
66
|
+
def description; @opts['description']; end
|
67
67
|
|
68
|
-
|
68
|
+
def identifier; @opts['identifier']; end
|
69
69
|
|
70
|
-
|
70
|
+
def suites; @opts['suites']; end
|
71
71
|
|
72
|
-
|
72
|
+
def version; @opts['version']; end
|
73
73
|
|
74
|
-
|
74
|
+
def secrets; @opts.dig('local_testing', 'secrets') || []; end
|
75
75
|
|
76
|
-
|
76
|
+
def name; @opts['name']; end
|
77
77
|
|
78
|
-
|
79
|
-
|
80
|
-
|
78
|
+
def runs_on_centos?
|
79
|
+
available_platforms.include?('centos')
|
80
|
+
end
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
82
|
+
def runs_on_windows?
|
83
|
+
available_platforms.include?('windows')
|
84
|
+
end
|
85
85
|
|
86
|
-
|
86
|
+
private_class_method
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
88
|
+
def self.bump(version)
|
89
|
+
UI.debug("Old cookbook version: #{version}")
|
90
|
+
version_info = Semantic::Version.new version
|
91
|
+
new_version = "#{version_info.major}.#{version_info.minor}.#{version_info.patch + 1}"
|
92
|
+
UI.debug("Old cookbook version: #{new_version}")
|
93
|
+
new_version
|
94
|
+
end
|
95
95
|
|
96
|
-
|
96
|
+
end
|
97
97
|
end
|
data/lib/sambot/runtime.rb
CHANGED
@@ -5,18 +5,16 @@ require 'gems'
|
|
5
5
|
module Sambot
|
6
6
|
module Runtime
|
7
7
|
|
8
|
-
def self.
|
9
|
-
latest_version = Gems.new.versions('sambot')[0][
|
8
|
+
def self.obsolete?
|
9
|
+
latest_version = Gems.new.versions('sambot')[0]['number']
|
10
10
|
Gem::Version.new(Sambot::VERSION) < Gem::Version.new(latest_version)
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.ensure_latest
|
14
|
-
latest_version = Gems.new.versions('sambot')[0][
|
14
|
+
latest_version = Gems.new.versions('sambot')[0]['number']
|
15
15
|
UI.debug("Current version is #{Sambot::VERSION}")
|
16
16
|
UI.debug("Latest version is #{latest_version}")
|
17
|
-
if
|
18
|
-
UI.info('A newer version of this gem exists - please update the gem before continuing')
|
19
|
-
end
|
17
|
+
UI.info('A newer version of this gem exists - please update the gem before continuing') if obsolete?
|
20
18
|
end
|
21
19
|
|
22
20
|
end
|
data/lib/sambot/template.rb
CHANGED
@@ -21,12 +21,12 @@ module Sambot
|
|
21
21
|
def process(opts)
|
22
22
|
File.delete(opts[:dest]) if File.exist?(opts[:dest])
|
23
23
|
if opts[:eruby]
|
24
|
-
UI.debug("Parsing #{
|
25
|
-
|
24
|
+
UI.debug("Parsing #{path} using Erubis")
|
25
|
+
write(opts, opts[:dest])
|
26
26
|
else
|
27
|
-
FileUtils.cp(
|
27
|
+
FileUtils.cp(path, opts[:dest].to_s)
|
28
28
|
end
|
29
|
-
if File.executable?(
|
29
|
+
if File.executable?(path)
|
30
30
|
UI.debug("Making #{opts[:dest]} executable")
|
31
31
|
make_executable(opts[:dest])
|
32
32
|
end
|
@@ -40,7 +40,7 @@ module Sambot
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def make_executable(working_path)
|
43
|
-
current_mask = File.stat(
|
43
|
+
current_mask = File.stat(path).mode
|
44
44
|
new_mask = current_mask | '0000000000000001'.to_i(2)
|
45
45
|
File.chmod(new_mask, working_path)
|
46
46
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'yaml'
|
2
4
|
require 'vault'
|
3
5
|
require 'fileutils'
|
@@ -20,7 +22,8 @@ module Sambot
|
|
20
22
|
end
|
21
23
|
token = ''
|
22
24
|
begin
|
23
|
-
|
25
|
+
wrap_info = Vault.auth_token.create('wrap_ttl': '72h', role: 'nightswatch-ro', policies: ['nightswatch-ro']).wrap_info
|
26
|
+
token = wrap_info.token
|
24
27
|
rescue
|
25
28
|
end
|
26
29
|
token
|
@@ -31,21 +34,21 @@ module Sambot
|
|
31
34
|
FileUtils.mkpath WORKING_DIR
|
32
35
|
UI.info("Created #{WORKING_DIR}")
|
33
36
|
Dir.chdir WORKING_DIR do
|
34
|
-
UI.info(
|
37
|
+
UI.info('Cloning the Vault policies for inclusion into the Vault Docker instance')
|
35
38
|
`git clone --depth=1 --single-branch -q #{VAULT_POLICIES_REPO}`
|
36
39
|
Dir.chdir 'vault-policies/dev/vault-config' do
|
37
40
|
FS.copy(VAULT_CONFIG_BINARY)
|
38
|
-
UI.info(
|
41
|
+
UI.info('Applying the Vault policies')
|
39
42
|
`VC_VAULT_ADDR=http://127.0.0.1:8200 VC_VAULT_TOKEN=root ./#{VAULT_CONFIG_BINARY} config`
|
40
|
-
UI.info(
|
43
|
+
UI.info('The Vault policies have been applied')
|
41
44
|
end
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
45
48
|
def load_secrets(config, src = 'local_testing')
|
46
|
-
UI.info(
|
49
|
+
UI.info('Reading secrets from the configuration file')
|
47
50
|
if config.secrets.nil? || config.secrets.empty?
|
48
|
-
UI.info(
|
51
|
+
UI.info('No secrets were found in the secrets configuration file')
|
49
52
|
return 0
|
50
53
|
else
|
51
54
|
store_secrets(config.secrets, src)
|
@@ -59,7 +62,7 @@ module Sambot
|
|
59
62
|
secrets.each do |secret|
|
60
63
|
secret['keys'].each do |item|
|
61
64
|
store_secret(src, secret['path'], item.keys[0], item.values[0])
|
62
|
-
counter
|
65
|
+
counter += 1
|
63
66
|
end
|
64
67
|
end
|
65
68
|
counter
|
@@ -76,7 +79,7 @@ module Sambot
|
|
76
79
|
end
|
77
80
|
|
78
81
|
def write_to_vault(path, key, value)
|
79
|
-
Vault.logical.write(path,
|
82
|
+
Vault.logical.write(path, key.to_sym => value)
|
80
83
|
end
|
81
84
|
|
82
85
|
end
|
data/lib/sambot/ui.rb
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Sambot
|
4
|
-
|
4
|
+
module UI
|
5
5
|
|
6
|
-
|
6
|
+
@@silent = false
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
def self.silent=(value)
|
9
|
+
@@silent = value
|
10
|
+
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def self.ask(msg)
|
13
|
+
Thor.new.ask(msg) unless @@silent
|
14
|
+
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def self.ask_password(msg)
|
17
|
+
Thor.new.ask(msg, echo: false) unless @@silent
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
def self.warn(msg)
|
21
|
+
date_format = DateTime.now.strftime('%Y-%m-%d %H:%M:%S')
|
22
|
+
Thor.new.say("#{date_format} [W] #{msg}", :yellow) unless @@silent
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
def self.debug(msg)
|
26
|
+
date_format = DateTime.now.strftime('%Y-%m-%d %H:%M:%S')
|
27
|
+
Thor.new.say("#{date_format} [D] #{msg}", :gray) unless @@silent
|
28
|
+
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
def self.info(msg)
|
31
|
+
date_format = DateTime.now.strftime('%Y-%m-%d %H:%M:%S')
|
32
|
+
Thor.new.say("#{date_format} [I] #{msg}", :green) unless @@silent
|
33
|
+
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
def self.error(msg)
|
36
|
+
date_format = DateTime.now.strftime('%Y-%m-%d %H:%M:%S')
|
37
|
+
Thor.new.say("#{date_format} [E] #{msg}", :red) unless @@silent
|
38
|
+
end
|
39
39
|
|
40
|
-
end
|
41
40
|
end
|
41
|
+
end
|
data/lib/sambot/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sambot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.194
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Olivier Kouame
|
@@ -330,45 +330,24 @@ dependencies:
|
|
330
330
|
- - "~>"
|
331
331
|
- !ruby/object:Gem::Version
|
332
332
|
version: '3.0'
|
333
|
-
description:
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
##
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
### Installation
|
353
|
-
|
354
|
-
Make sure you have `ruby >= 2.4.0` installed.
|
355
|
-
|
356
|
-
Install `bundler >= 1.15.1` by running `gem install bundler`
|
357
|
-
|
358
|
-
Run `bundle install` from the root of the project to install the required ruby gems.
|
359
|
-
|
360
|
-
### Running Sambot
|
361
|
-
|
362
|
-
If you want to test your changes locally, you can run `bundle exec bin/sambot`.
|
363
|
-
|
364
|
-
### Running Tests
|
365
|
-
|
366
|
-
Run `bundle exec rspec spec`
|
367
|
-
|
368
|
-
### Linting
|
369
|
-
|
370
|
-
There is nothing here yet
|
371
|
-
|
333
|
+
description: "# Sambot\n\nSambot is our internal Platform Engineering toolchain to
|
334
|
+
help standardize and\nsimplify our DevOps workflow.\n\nIt provides an executable
|
335
|
+
with a variety of commands, grouped in various areas\nof functionality such as session
|
336
|
+
management, DNS changes and cookbook management.\n\n## Usage\n\nTo install the gem,
|
337
|
+
simply run `chef gem install sambot`. This will install the\ngem in your ChefDK
|
338
|
+
installation. If you want to use it outside Chef,\nrun `gem install sambot`.\n\nRun
|
339
|
+
`chef exec sambot` to be shown the help menu. For help on specific commands,\ni.e.
|
340
|
+
cookbook management and specific cookbook management commands, run\n`chef exec sambot
|
341
|
+
help cookbook` or `chef exec sambot cookbook help generate`\nfor example.\n\n##
|
342
|
+
Contributing\n\nBug reports and pull requests are welcome on GitHub at\nhttps://github.exacttarget.com/ads-devops/sambot.\n\n###
|
343
|
+
Installation\n\nMake sure you have `ruby >= 2.4.0` installed.\n\nInstall `bundler
|
344
|
+
>= 1.15.1` by running `gem install bundler`\n\nRun `bundle install` from the root
|
345
|
+
of the project to install the\nrequired Ruby gems.\n\n### Running Sambot\n\nIf you
|
346
|
+
want to test your changes locally, you can run `bundle exec bin/sambot`.\n\n###
|
347
|
+
Running Tests\n\nRun `bundle exec rspec spec` to execute the unit tests.\n\nRun
|
348
|
+
`cd integration_tests && bundle exec rspec .` to execute the integration\ntests.
|
349
|
+
These require that you have Docker Compose available. \n\n### Linting\n\nThere is
|
350
|
+
nothing here yet\n"
|
372
351
|
email:
|
373
352
|
- olivier.kouame@gmail.com
|
374
353
|
executables:
|
@@ -384,7 +363,6 @@ files:
|
|
384
363
|
- README.md
|
385
364
|
- bin/sambot
|
386
365
|
- bin/setup
|
387
|
-
- bin/slackbot
|
388
366
|
- integration_tests/docker-compose.yml
|
389
367
|
- integration_tests/spec_helper.rb
|
390
368
|
- integration_tests/vault_helper_spec.rb
|
data/bin/slackbot
DELETED