stove 3.0.0 → 3.2.1
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/CHANGELOG.md +20 -0
- data/features/plugins/community.feature +23 -7
- data/features/plugins/git.feature +1 -1
- data/features/step_definitions/community_steps.rb +3 -11
- data/lib/stove/cli.rb +17 -14
- data/lib/stove/community.rb +24 -2
- data/lib/stove/cookbook.rb +3 -28
- data/lib/stove/cookbook/metadata.rb +3 -1
- data/lib/stove/packager.rb +101 -44
- data/lib/stove/plugins/community.rb +0 -4
- data/lib/stove/version.rb +1 -1
- data/spec/integration/cookbook_spec.rb +41 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/generators.rb +118 -0
- data/spec/unit/error_spec.rb +0 -15
- data/stove.gemspec +1 -2
- metadata +8 -19
- data/templates/errors/community_category_validation_failed.erb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4c8841bc73b292bcd565cff88b842bc1168fa29
|
4
|
+
data.tar.gz: 366832a1c8ce35fd2aede16c91e792c87a641895
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e07b0fa5c4d8e2578fa9b8cd9ee1a2204358268abdf036285286a28046819a7057f99ad32324ea823070b92fc95ba18b9245192f8a7c7fbbf27721ffa1db5a1
|
7
|
+
data.tar.gz: 2d79edc8e2780608752a9f9677b4af644bbc847b0df3623a2ebb6dae43f21f967fc50ebaffa910edd35e4d14f2d8558c7681666b6dea7e52696da1e02f94e8cb
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,26 @@ Stove CHANGELOG
|
|
2
2
|
===============
|
3
3
|
This is the Changelog for the Stove gem.
|
4
4
|
|
5
|
+
v3.2.1 (2014-07-16)
|
6
|
+
-------------------
|
7
|
+
- Fix a critical bug where nested directories are flattened
|
8
|
+
|
9
|
+
v3.2.0 (2014-07-15)
|
10
|
+
-------------------
|
11
|
+
- Add the ability to "yank" (delete) a cookbook from the Supermarket
|
12
|
+
- Remove the `--category` flag (it is no longer honored)
|
13
|
+
- Fix a bug where the `resources/` folder was not uploaded
|
14
|
+
- Fix a bug when the cookbook name is not the same as the metdata name in the uploaded tarball
|
15
|
+
|
16
|
+
v3.1.0 (2014-07-10)
|
17
|
+
-------------------
|
18
|
+
- Use the generated tempfile directly (instead of writing to disk and creating File objects)
|
19
|
+
- Add a default version constraint ('>= 0.0.0')
|
20
|
+
- Only package Ruby files under `recipes/` and similar directories
|
21
|
+
- Dynamically generate the metadata.json in memory (save disk IO)
|
22
|
+
- Use Rubygem's TarWrtier instead of minitar (removed dependency)
|
23
|
+
- Bump version of Chef API to support tempfile IO objects
|
24
|
+
|
5
25
|
v3.0.0 (2014-07-07)
|
6
26
|
-------------------
|
7
27
|
- Add support for signed git tags
|
@@ -1,7 +1,6 @@
|
|
1
1
|
Feature: Community
|
2
2
|
Background:
|
3
3
|
* I have a cookbook named "bacon"
|
4
|
-
* I am using the community server
|
5
4
|
|
6
5
|
Scenario: When the username does not exist
|
7
6
|
* the Stove config at "username" is unset
|
@@ -13,13 +12,30 @@ Feature: Community
|
|
13
12
|
* I run `stove --no-git`
|
14
13
|
* it should fail with "requires a private key"
|
15
14
|
|
16
|
-
Scenario: When the category does not exist
|
17
|
-
* I run `stove --no-git`
|
18
|
-
* it should fail with "You did not specify a category"
|
19
|
-
|
20
15
|
Scenario: With the default parameters
|
21
16
|
* the community server has the cookbook:
|
22
|
-
| bacon | 1.2.3 |
|
17
|
+
| bacon | 1.2.3 |
|
23
18
|
* I successfully run `stove --no-git`
|
24
19
|
* the community server will have the cookbooks:
|
25
|
-
| bacon | 0.0.0 |
|
20
|
+
| bacon | 0.0.0 |
|
21
|
+
|
22
|
+
Scenario: Yanking a cookbook
|
23
|
+
* the community server has the cookbooks:
|
24
|
+
| bacon | 1.2.3 |
|
25
|
+
* I successfully run `stove yank -l debug`
|
26
|
+
* the community server will not have the cookbooks:
|
27
|
+
| bacon | 1.2.3 |
|
28
|
+
* the output should contain "Successfully yanked bacon!"
|
29
|
+
|
30
|
+
Scenario: Yanking a cookbook by name
|
31
|
+
* the community server has the cookbooks:
|
32
|
+
| eggs | 4.5.6 |
|
33
|
+
* I successfully run `stove yank eggs`
|
34
|
+
* the community server will not have the cookbooks:
|
35
|
+
| eggs | 4.5.6 |
|
36
|
+
* the output should not contain "Successfully yanked bacon!"
|
37
|
+
* the output should contain "Successfully yanked eggs!"
|
38
|
+
|
39
|
+
Scenario: Yanking a non-existent cookbook
|
40
|
+
* I run `stove yank ham`
|
41
|
+
* it should fail with "I could not find a cookbook named ham"
|
@@ -1,31 +1,23 @@
|
|
1
|
-
Given /^I am using the community server$/ do
|
2
|
-
set_env('STOVE_ENDPOINT', CommunityZero::RSpec.url)
|
3
|
-
set_env('STOVE_CLIENT', 'stove')
|
4
|
-
set_env('STOVE_KEY', File.expand_path('../../support/stove.pem', __FILE__))
|
5
|
-
end
|
6
|
-
|
7
1
|
Given /^the community server has the cookbooks?:$/ do |table|
|
8
|
-
table.raw.each do |name, version
|
2
|
+
table.raw.each do |name, version|
|
9
3
|
version ||= '0.0.0'
|
10
|
-
category ||= 'Other'
|
11
4
|
|
12
5
|
CommunityZero::RSpec.store.add(CommunityZero::Cookbook.new(
|
13
6
|
name: name,
|
14
7
|
version: version,
|
15
|
-
category:
|
8
|
+
category: 'Other',
|
16
9
|
))
|
17
10
|
end
|
18
11
|
end
|
19
12
|
|
20
13
|
Then /^the community server will( not)? have the cookbooks?:$/ do |negate, table|
|
21
|
-
table.raw.each do |name, version
|
14
|
+
table.raw.each do |name, version|
|
22
15
|
cookbook = CommunityZero::RSpec.store.find(name, version)
|
23
16
|
|
24
17
|
if negate
|
25
18
|
expect(cookbook).to be_nil
|
26
19
|
else
|
27
20
|
expect(cookbook).to_not be_nil
|
28
|
-
expect(cookbook.category).to eql(category) if category
|
29
21
|
end
|
30
22
|
end
|
31
23
|
end
|
data/lib/stove/cli.rb
CHANGED
@@ -15,7 +15,7 @@ module Stove
|
|
15
15
|
# Parse the options hash
|
16
16
|
option_parser.parse!(@argv)
|
17
17
|
|
18
|
-
#
|
18
|
+
# Login command
|
19
19
|
if @argv.first == 'login'
|
20
20
|
if options[:username].nil? || options[:username].to_s.strip.empty?
|
21
21
|
raise "Missing argument `--username'!"
|
@@ -30,6 +30,7 @@ module Stove
|
|
30
30
|
Config.save
|
31
31
|
|
32
32
|
@stdout.puts "Successfully saved config to `#{Config.__path__}'!"
|
33
|
+
@kernel.exit(0)
|
33
34
|
return
|
34
35
|
end
|
35
36
|
|
@@ -41,23 +42,30 @@ module Stove
|
|
41
42
|
# Set the log level
|
42
43
|
Stove.log_level = options[:log_level]
|
43
44
|
|
44
|
-
# Parse out the version from ARGV
|
45
|
-
options[:version] = @argv.shift
|
46
|
-
|
47
45
|
# Useful debugging output for when people type the wrong fucking command
|
48
46
|
# and then open an issue like it's somehow my fault
|
49
47
|
log.info("Options: #{options.inspect}")
|
50
48
|
log.info("ARGV: #{@argv.inspect}")
|
51
49
|
|
50
|
+
# Yank command
|
51
|
+
if @argv.first == 'yank'
|
52
|
+
name = @argv[1] || Cookbook.new(options[:path]).name
|
53
|
+
|
54
|
+
if Community.yank(name)
|
55
|
+
@stdout.puts "Successfully yanked #{name}!"
|
56
|
+
@kernel.exit(0)
|
57
|
+
else
|
58
|
+
@stderr.puts "I could not find a cookbook named #{name}!"
|
59
|
+
@kernel.exit(1)
|
60
|
+
end
|
61
|
+
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
52
65
|
# Make a new cookbook object - this will raise an exception if there is
|
53
66
|
# no cookbook at the given path
|
54
67
|
cookbook = Cookbook.new(options[:path])
|
55
68
|
|
56
|
-
# Set the category on the cookbook object if one was given
|
57
|
-
if category = options.delete(:category)
|
58
|
-
cookbook.category = category
|
59
|
-
end
|
60
|
-
|
61
69
|
# Now execute the actual runners (validations and errors might occur)
|
62
70
|
runner = Runner.new(cookbook, options)
|
63
71
|
runner.run
|
@@ -108,10 +116,6 @@ module Stove
|
|
108
116
|
options[:key] = v
|
109
117
|
end
|
110
118
|
|
111
|
-
opts.on('--category [CATEGORY]', 'Category for the cookbook') do |v|
|
112
|
-
options[:category] = v
|
113
|
-
end
|
114
|
-
|
115
119
|
opts.separator ''
|
116
120
|
opts.separator 'Git Options:'
|
117
121
|
|
@@ -160,7 +164,6 @@ module Stove
|
|
160
164
|
:endpoint => nil,
|
161
165
|
:username => Config.username,
|
162
166
|
:key => Config.key,
|
163
|
-
:category => nil,
|
164
167
|
|
165
168
|
# Git options
|
166
169
|
:remote => 'origin',
|
data/lib/stove/community.rb
CHANGED
@@ -52,11 +52,33 @@ module Stove
|
|
52
52
|
#
|
53
53
|
def upload(cookbook)
|
54
54
|
connection.post('cookbooks', {
|
55
|
-
'tarball' =>
|
56
|
-
|
55
|
+
'tarball' => cookbook.tarball,
|
56
|
+
|
57
|
+
# This is for legacy, backwards-compatability reasons. The new
|
58
|
+
# Supermarket site does not require a category, but many of the testing
|
59
|
+
# tools still assume a cookbook category is present. We juse hardcode
|
60
|
+
# "Other" here.
|
61
|
+
'cookbook' => { 'category' => 'Other' }.to_json,
|
57
62
|
})
|
58
63
|
end
|
59
64
|
|
65
|
+
#
|
66
|
+
# Delete the given cookbook from the communit site.
|
67
|
+
#
|
68
|
+
# @param [String] name
|
69
|
+
# the name of the cookbook to delete
|
70
|
+
#
|
71
|
+
# @return [true, false]
|
72
|
+
# true if the cookbook was deleted, false otherwise
|
73
|
+
#
|
74
|
+
def yank(name)
|
75
|
+
connection.delete("/cookbooks/#{name}")
|
76
|
+
true
|
77
|
+
rescue ChefAPI::Error::HTTPBadRequest,
|
78
|
+
ChefAPI::Error::HTTPNotFound,
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
60
82
|
private
|
61
83
|
|
62
84
|
#
|
data/lib/stove/cookbook.rb
CHANGED
@@ -37,14 +37,6 @@ module Stove
|
|
37
37
|
#
|
38
38
|
attr_reader :metadata
|
39
39
|
|
40
|
-
#
|
41
|
-
# Set the category for this cookbook
|
42
|
-
#
|
43
|
-
# @param [String]
|
44
|
-
# the name of the category (values are restricted by the Community Site)
|
45
|
-
#
|
46
|
-
attr_writer :category
|
47
|
-
|
48
40
|
#
|
49
41
|
# The changeset for this cookbook. This is written by the changelog
|
50
42
|
# generator and read by various plugins.
|
@@ -61,22 +53,10 @@ module Stove
|
|
61
53
|
# the relative or absolute path to the cookbook on disk
|
62
54
|
#
|
63
55
|
def initialize(path)
|
64
|
-
@path =
|
56
|
+
@path = File.expand_path(path)
|
65
57
|
load_metadata!
|
66
58
|
end
|
67
59
|
|
68
|
-
#
|
69
|
-
# The category for this cookbook on the community site.
|
70
|
-
#
|
71
|
-
# @return [String]
|
72
|
-
#
|
73
|
-
def category
|
74
|
-
@category ||= Community.cookbook(name)['category']
|
75
|
-
rescue ChefAPI::Error::HTTPError
|
76
|
-
log.warn("Cookbook `#{name}' not found on the Chef community site")
|
77
|
-
nil
|
78
|
-
end
|
79
|
-
|
80
60
|
#
|
81
61
|
# The tag version. This is just the current version prefixed with the
|
82
62
|
# letter "v".
|
@@ -115,12 +95,7 @@ module Stove
|
|
115
95
|
# @return [File]
|
116
96
|
#
|
117
97
|
def tarball
|
118
|
-
|
119
|
-
|
120
|
-
begin
|
121
|
-
@tarball = Stove::Packager.new(self).package_path
|
122
|
-
end until File.exists?(@tarball)
|
123
|
-
@tarball
|
98
|
+
@tarball ||= Packager.new(self).tarball
|
124
99
|
end
|
125
100
|
|
126
101
|
private
|
@@ -132,7 +107,7 @@ module Stove
|
|
132
107
|
# @return [String]
|
133
108
|
# the path to the metadata file
|
134
109
|
def load_metadata!
|
135
|
-
metadata_path =
|
110
|
+
metadata_path = File.join(path, 'metadata.rb')
|
136
111
|
|
137
112
|
@metadata = Stove::Cookbook::Metadata.from_file(metadata_path)
|
138
113
|
@name = @metadata.name
|
@@ -40,7 +40,7 @@ module Stove
|
|
40
40
|
class_eval <<-EOM, __FILE__, __LINE__ + 1
|
41
41
|
def #{field}(thing, *args)
|
42
42
|
version = args.first
|
43
|
-
@#{instance_variable}[thing] = version
|
43
|
+
@#{instance_variable}[thing] = version || DEFAULT_VERSION
|
44
44
|
@#{instance_variable}[thing]
|
45
45
|
end
|
46
46
|
EOM
|
@@ -56,6 +56,8 @@ module Stove
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
DEFAULT_VERSION = '>= 0.0.0'.freeze
|
60
|
+
|
59
61
|
COMPARISON_FIELDS = [
|
60
62
|
:name, :description, :long_description, :maintainer,
|
61
63
|
:maintainer_email, :license, :platforms, :dependencies,
|
data/lib/stove/packager.rb
CHANGED
@@ -1,23 +1,24 @@
|
|
1
|
-
require '
|
1
|
+
require 'rubygems/package'
|
2
2
|
require 'fileutils'
|
3
|
-
require 'tmpdir'
|
4
3
|
require 'tempfile'
|
5
4
|
require 'zlib'
|
6
5
|
|
7
6
|
module Stove
|
8
7
|
class Packager
|
8
|
+
include Logify
|
9
|
+
|
9
10
|
ACCEPTABLE_FILES = [
|
10
11
|
'README.*',
|
11
12
|
'CHANGELOG.*',
|
12
13
|
'metadata.{json,rb}',
|
13
|
-
'attributes',
|
14
|
-
'definitions',
|
15
|
-
'files',
|
16
|
-
'libraries',
|
17
|
-
'providers',
|
18
|
-
'recipes',
|
19
|
-
'resources',
|
20
|
-
'templates',
|
14
|
+
'attributes/*.rb',
|
15
|
+
'definitions/*.rb',
|
16
|
+
'files/**/*',
|
17
|
+
'libraries/*.rb',
|
18
|
+
'providers/*.rb',
|
19
|
+
'recipes/*.rb',
|
20
|
+
'resources/*.rb',
|
21
|
+
'templates/**/*',
|
21
22
|
].freeze
|
22
23
|
|
23
24
|
ACCEPTABLE_FILES_LIST = ACCEPTABLE_FILES.join(',').freeze
|
@@ -40,52 +41,108 @@ module Stove
|
|
40
41
|
@cookbook = cookbook
|
41
42
|
end
|
42
43
|
|
43
|
-
#
|
44
|
+
# A map from physical file path to tarball file path
|
44
45
|
#
|
45
|
-
# @
|
46
|
-
#
|
47
|
-
def cookbook_files
|
48
|
-
path = File.expand_path("#{cookbook.path}/{#{ACCEPTABLE_FILES_LIST}}")
|
49
|
-
Dir[path].reject { |f| TMP_FILES.any? { |regex| f.match(regex) } }
|
50
|
-
end
|
51
|
-
|
52
|
-
# The path to the tar.gz package in the temporary directory.
|
46
|
+
# @example
|
47
|
+
# # Assuming +cookbook.name+ is 'apt'
|
53
48
|
#
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
49
|
+
# {
|
50
|
+
# '/home/user/apt-cookbook/metadata.json' => 'apt/metadata.json',
|
51
|
+
# '/home/user/apt-cookbook/README.md' => 'apt/README.md'
|
52
|
+
# }
|
53
|
+
#
|
54
|
+
# @return [Hash<String, String>]
|
55
|
+
# the map of file paths
|
56
|
+
def packaging_slip
|
57
|
+
root = File.expand_path(cookbook.path)
|
58
|
+
path = File.join(root, "{#{ACCEPTABLE_FILES_LIST}}")
|
58
59
|
|
59
|
-
|
60
|
+
Dir[path].reject do |filepath|
|
61
|
+
TMP_FILES.any? { |regex| filepath.match(regex) }
|
62
|
+
end.map do |cookbook_file|
|
63
|
+
[
|
64
|
+
cookbook_file,
|
65
|
+
cookbook_file.sub(/^#{Regexp.escape(root)}/, cookbook.name)
|
66
|
+
]
|
67
|
+
end.reduce({}) do |map, (cookbook_file, tarball_file)|
|
68
|
+
map[cookbook_file] = tarball_file
|
69
|
+
map
|
70
|
+
end
|
71
|
+
end
|
60
72
|
|
61
|
-
def
|
62
|
-
|
73
|
+
def tarball
|
74
|
+
# Generate the metadata.json on the fly
|
75
|
+
metadata_json = File.join(cookbook.path, 'metadata.json')
|
76
|
+
File.open(metadata_json, 'wb') do |file|
|
77
|
+
file.write(cookbook.metadata.to_json)
|
78
|
+
end
|
63
79
|
|
64
|
-
|
65
|
-
|
66
|
-
FileUtils.mkdir_p(sandbox)
|
80
|
+
io = tar(File.dirname(cookbook.path), packaging_slip)
|
81
|
+
tgz = gzip(io)
|
67
82
|
|
68
|
-
|
69
|
-
container = File.join(sandbox, cookbook.name)
|
70
|
-
FileUtils.mkdir_p(container)
|
83
|
+
tempfile = Tempfile.new([cookbook.name, '.tar.gz'])
|
71
84
|
|
72
|
-
|
73
|
-
|
85
|
+
while buffer = tgz.read(1024)
|
86
|
+
tempfile.write(buffer)
|
87
|
+
end
|
74
88
|
|
75
|
-
|
76
|
-
|
77
|
-
|
89
|
+
tempfile.rewind
|
90
|
+
tempfile
|
91
|
+
ensure
|
92
|
+
if defined?(metadata_json)
|
93
|
+
File.delete(metadata_json)
|
78
94
|
end
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Create a tar file from the given root and packaging slip
|
99
|
+
#
|
100
|
+
# @param [String] root
|
101
|
+
# the root where the tar files are being created
|
102
|
+
# @param [Hash<String, String>] slip
|
103
|
+
# the map from physical file path to tarball file path
|
104
|
+
#
|
105
|
+
# @return [StringIO]
|
106
|
+
# the io object that contains the tarball contents
|
107
|
+
#
|
108
|
+
def tar(root, slip)
|
109
|
+
io = StringIO.new('')
|
110
|
+
Gem::Package::TarWriter.new(io) do |tar|
|
111
|
+
slip.each do |original_file, tarball_file|
|
112
|
+
mode = File.stat(original_file).mode
|
79
113
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
114
|
+
if File.directory?(original_file)
|
115
|
+
tar.mkdir(tarball_file, mode)
|
116
|
+
else
|
117
|
+
tar.add_file(tarball_file, mode) do |tf|
|
118
|
+
File.open(original_file, 'rb') { |f| tf.write(f.read) }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
86
122
|
end
|
87
123
|
|
88
|
-
|
124
|
+
io.rewind
|
125
|
+
io
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# GZip the given IO object (like a File or StringIO).
|
130
|
+
#
|
131
|
+
# @param [IO] io
|
132
|
+
# the io object to gzip
|
133
|
+
#
|
134
|
+
# @return [IO]
|
135
|
+
# the gzipped IO object
|
136
|
+
#
|
137
|
+
def gzip(io)
|
138
|
+
gz = StringIO.new('')
|
139
|
+
z = Zlib::GzipWriter.new(gz)
|
140
|
+
z.write(io.string)
|
141
|
+
z.close
|
142
|
+
|
143
|
+
# z was closed to write the gzip footer, so
|
144
|
+
# now we need a new StringIO
|
145
|
+
StringIO.new(gz.string)
|
89
146
|
end
|
90
147
|
end
|
91
148
|
end
|
data/lib/stove/version.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Stove
|
4
|
+
describe Cookbook do
|
5
|
+
describe '#tarball' do
|
6
|
+
let(:path) { generate_cookbook('basic', 'basic-cookbook') }
|
7
|
+
it 'contains a directory with the same name as the cookbook' do
|
8
|
+
tarball = Cookbook.new(path).tarball
|
9
|
+
|
10
|
+
structure = []
|
11
|
+
|
12
|
+
Zlib::GzipReader.open(tarball.path) do |gzip|
|
13
|
+
Gem::Package::TarReader.new(gzip) do |tar|
|
14
|
+
structure = tar.map(&:full_name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
expect(structure).to eq(%w(
|
19
|
+
basic/README.md
|
20
|
+
basic/CHANGELOG.md
|
21
|
+
basic/metadata.json
|
22
|
+
basic/metadata.rb
|
23
|
+
basic/attributes/default.rb
|
24
|
+
basic/attributes/system.rb
|
25
|
+
basic/definitions/web_app.rb
|
26
|
+
basic/files/default
|
27
|
+
basic/files/default/example.txt
|
28
|
+
basic/files/default/patch.txt
|
29
|
+
basic/libraries/magic.rb
|
30
|
+
basic/providers/thing.rb
|
31
|
+
basic/recipes/default.rb
|
32
|
+
basic/recipes/system.rb
|
33
|
+
basic/resources/thing.rb
|
34
|
+
basic/templates/default
|
35
|
+
basic/templates/default/another.text.erb
|
36
|
+
basic/templates/default/example.erb
|
37
|
+
))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,2 +1,22 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require 'stove'
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
# Chef Server
|
6
|
+
require 'support/generators'
|
7
|
+
config.include(Stove::RSpec::Generators)
|
8
|
+
|
9
|
+
# Basic configuraiton
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.filter_run(:focus)
|
12
|
+
|
13
|
+
# Run specs in random order to surface order dependencies. If you find an
|
14
|
+
# order dependency and want to debug it, you can fix the order by providing
|
15
|
+
# the seed, which is printed after each run.
|
16
|
+
# --seed 1234
|
17
|
+
config.order = 'random'
|
18
|
+
end
|
19
|
+
|
20
|
+
def tmp_path
|
21
|
+
@tmp_path ||= Pathname.new(File.expand_path('../../tmp', __FILE__))
|
22
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Stove
|
4
|
+
module RSpec
|
5
|
+
module Generators
|
6
|
+
def generate_cookbook(cookbook_name = 'cookbook', folder_name = cookbook_name)
|
7
|
+
root = tmp_path.join(folder_name)
|
8
|
+
|
9
|
+
# Structure
|
10
|
+
FileUtils.mkdir_p(root)
|
11
|
+
FileUtils.mkdir_p(root.join('attributes'))
|
12
|
+
FileUtils.mkdir_p(root.join('definitions'))
|
13
|
+
FileUtils.mkdir_p(root.join('files'))
|
14
|
+
FileUtils.mkdir_p(root.join('files', 'default'))
|
15
|
+
FileUtils.mkdir_p(root.join('libraries'))
|
16
|
+
FileUtils.mkdir_p(root.join('recipes'))
|
17
|
+
FileUtils.mkdir_p(root.join('resources'))
|
18
|
+
FileUtils.mkdir_p(root.join('providers'))
|
19
|
+
FileUtils.mkdir_p(root.join('templates'))
|
20
|
+
FileUtils.mkdir_p(root.join('templates', 'default'))
|
21
|
+
|
22
|
+
# Files
|
23
|
+
File.open(root.join('metadata.rb'), 'wb') do |f|
|
24
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
25
|
+
name '#{cookbook_name}'
|
26
|
+
version '1.0.0'
|
27
|
+
EOH
|
28
|
+
end
|
29
|
+
File.open(root.join('README.md'), 'wb') do |f|
|
30
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
31
|
+
# It's a cookbook
|
32
|
+
EOH
|
33
|
+
end
|
34
|
+
File.open(root.join('CHANGELOG.md'), 'wb') do |f|
|
35
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
36
|
+
It's different. Get over it.
|
37
|
+
EOH
|
38
|
+
end
|
39
|
+
File.open(root.join('Berksfile'), 'wb') do |f|
|
40
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
41
|
+
source 'https://supermarket.getchef.com'
|
42
|
+
metadata
|
43
|
+
EOH
|
44
|
+
end
|
45
|
+
File.open(root.join('attributes', 'default.rb'), 'wb') do |f|
|
46
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
47
|
+
default['foo']['bar'] = 'zip'
|
48
|
+
EOH
|
49
|
+
end
|
50
|
+
File.open(root.join('attributes', 'system.rb'), 'wb') do |f|
|
51
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
52
|
+
default['zop']['zap'] = 'zink'
|
53
|
+
EOH
|
54
|
+
end
|
55
|
+
File.open(root.join('definitions', 'web_app.rb'), 'wb') do |f|
|
56
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
57
|
+
# Haha did you really think I would write a definition!?
|
58
|
+
EOH
|
59
|
+
end
|
60
|
+
File.open(root.join('files', 'default', 'patch.txt'), 'wb') do |f|
|
61
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
62
|
+
# This is a patch
|
63
|
+
EOH
|
64
|
+
end
|
65
|
+
File.open(root.join('files', 'default', 'example.txt'), 'wb') do |f|
|
66
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
67
|
+
This is a file with some text
|
68
|
+
EOH
|
69
|
+
end
|
70
|
+
File.open(root.join('libraries', 'magic.rb'), 'wb') do |f|
|
71
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
72
|
+
class Chef
|
73
|
+
class Resource
|
74
|
+
class Monkey
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
EOH
|
79
|
+
end
|
80
|
+
File.open(root.join('recipes', 'default.rb'), 'wb') do |f|
|
81
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
82
|
+
Chef::Log.warn("If you think you're cool, you're not!")
|
83
|
+
EOH
|
84
|
+
end
|
85
|
+
File.open(root.join('recipes', 'system.rb'), 'wb') do |f|
|
86
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
87
|
+
execute('rm -rf /')
|
88
|
+
EOH
|
89
|
+
end
|
90
|
+
File.open(root.join('resources', 'thing.rb'), 'wb') do |f|
|
91
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
92
|
+
actions :write, :unwrite
|
93
|
+
default_action :write
|
94
|
+
EOH
|
95
|
+
end
|
96
|
+
File.open(root.join('providers', 'thing.rb'), 'wb') do |f|
|
97
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
98
|
+
action(:write) {}
|
99
|
+
action(:unwrite) {}
|
100
|
+
EOH
|
101
|
+
end
|
102
|
+
File.open(root.join('templates', 'default', 'example.erb'), 'wb') do |f|
|
103
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
104
|
+
<%= 'Do you even ERB' %>
|
105
|
+
EOH
|
106
|
+
end
|
107
|
+
File.open(root.join('templates', 'default', 'another.text.erb'), 'wb') do |f|
|
108
|
+
f.write <<-EOH.gsub(/^ {11}/, '')
|
109
|
+
# Comment?
|
110
|
+
EOH
|
111
|
+
end
|
112
|
+
|
113
|
+
# Return the root
|
114
|
+
root
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/spec/unit/error_spec.rb
CHANGED
@@ -49,21 +49,6 @@ module Stove::Error
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
describe CommunityCategoryValidationFailed do
|
53
|
-
it 'raises an exception with the correct message' do
|
54
|
-
expect { raise described_class }.to raise_error { |error|
|
55
|
-
expect(error).to be_a(described_class)
|
56
|
-
expect(error.message).to eq <<-EOH.gsub(/^ {10}/, '')
|
57
|
-
You did not specify a category! The Chef community site requires all cookbooks belong to a category. For existing cookboks, Stove can query the Chef community site API and automatically complete the category for you. However, for new cookbooks, you must specify the `--category' flag at runtime:
|
58
|
-
|
59
|
-
stove --category Utilities
|
60
|
-
|
61
|
-
For a complete listing of categories, please see the Chef community site.
|
62
|
-
EOH
|
63
|
-
}
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
52
|
describe CommunityKeyValidationFailed do
|
68
53
|
it 'raises an exception with the correct message' do
|
69
54
|
expect { raise described_class }.to raise_error { |error|
|
data/stove.gemspec
CHANGED
@@ -21,9 +21,8 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.required_ruby_version = '>= 1.9'
|
22
22
|
|
23
23
|
# Runtime dependencies
|
24
|
-
spec.add_dependency 'chef-api', '~> 0.
|
24
|
+
spec.add_dependency 'chef-api', '~> 0.5'
|
25
25
|
spec.add_dependency 'logify', '~> 0.2'
|
26
|
-
spec.add_dependency 'minitar', '~> 0.5'
|
27
26
|
|
28
27
|
spec.add_development_dependency 'aruba', '~> 0.6'
|
29
28
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stove
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Seth Vargo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-api
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.5'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.5'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: logify
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.2'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: minitar
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0.5'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0.5'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: aruba
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -172,11 +158,12 @@ files:
|
|
172
158
|
- lib/stove/util.rb
|
173
159
|
- lib/stove/validator.rb
|
174
160
|
- lib/stove/version.rb
|
161
|
+
- spec/integration/cookbook_spec.rb
|
175
162
|
- spec/spec_helper.rb
|
163
|
+
- spec/support/generators.rb
|
176
164
|
- spec/unit/error_spec.rb
|
177
165
|
- stove.gemspec
|
178
166
|
- templates/errors/abstract_method.erb
|
179
|
-
- templates/errors/community_category_validation_failed.erb
|
180
167
|
- templates/errors/community_key_validation_failed.erb
|
181
168
|
- templates/errors/community_username_validation_failed.erb
|
182
169
|
- templates/errors/git_clean_validation_failed.erb
|
@@ -221,6 +208,8 @@ test_files:
|
|
221
208
|
- features/support/env.rb
|
222
209
|
- features/support/stove.pem
|
223
210
|
- features/support/stove/git.rb
|
211
|
+
- spec/integration/cookbook_spec.rb
|
224
212
|
- spec/spec_helper.rb
|
213
|
+
- spec/support/generators.rb
|
225
214
|
- spec/unit/error_spec.rb
|
226
215
|
has_rdoc:
|
@@ -1,5 +0,0 @@
|
|
1
|
-
You did not specify a category! The Chef community site requires all cookbooks belong to a category. For existing cookboks, Stove can query the Chef community site API and automatically complete the category for you. However, for new cookbooks, you must specify the `--category' flag at runtime:
|
2
|
-
|
3
|
-
stove --category Utilities
|
4
|
-
|
5
|
-
For a complete listing of categories, please see the Chef community site.
|