stove 1.1.2 → 2.0.0.beta.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/.travis.yml +1 -2
- data/CHANGELOG.md +16 -0
- data/README.md +41 -29
- data/Rakefile +15 -0
- data/bin/bake +1 -2
- data/features/actions/bump.feature +22 -0
- data/features/actions/changelog.feature +45 -0
- data/features/actions/dev.feature +18 -0
- data/features/actions/upload.feature +48 -0
- data/features/plugins/git.feature +24 -0
- data/features/rake.feature +1 -2
- data/features/step_definitions/cli_steps.rb +1 -27
- data/features/step_definitions/{community_site_steps.rb → community_steps.rb} +9 -5
- data/features/step_definitions/config_steps.rb +24 -0
- data/features/step_definitions/cookbook_steps.rb +28 -6
- data/features/step_definitions/cucumber_steps.rb +12 -0
- data/features/step_definitions/git_steps.rb +10 -7
- data/features/support/env.rb +12 -28
- data/features/support/stove/git.rb +48 -0
- data/lib/stove.rb +102 -19
- data/lib/stove/actions/base.rb +21 -0
- data/lib/stove/actions/bump.rb +25 -0
- data/lib/stove/actions/changelog.rb +71 -0
- data/lib/stove/actions/dev.rb +22 -0
- data/lib/stove/actions/finish.rb +8 -0
- data/lib/stove/actions/start.rb +7 -0
- data/lib/stove/actions/upload.rb +27 -0
- data/lib/stove/cli.rb +107 -79
- data/lib/stove/community.rb +124 -0
- data/lib/stove/config.rb +62 -13
- data/lib/stove/cookbook.rb +76 -238
- data/lib/stove/cookbook/metadata.rb +16 -11
- data/lib/stove/error.rb +13 -107
- data/lib/stove/filter.rb +59 -0
- data/lib/stove/jira.rb +74 -30
- data/lib/stove/middlewares/chef_authentication.rb +60 -0
- data/lib/stove/middlewares/exceptions.rb +17 -0
- data/lib/stove/mixins/filterable.rb +11 -0
- data/lib/stove/mixins/insideable.rb +13 -0
- data/lib/stove/mixins/instanceable.rb +23 -0
- data/lib/stove/mixins/loggable.rb +32 -0
- data/lib/stove/mixins/optionable.rb +41 -0
- data/lib/stove/mixins/validatable.rb +7 -0
- data/lib/stove/packager.rb +23 -22
- data/lib/stove/plugins/base.rb +35 -0
- data/lib/stove/plugins/git.rb +71 -0
- data/lib/stove/plugins/github.rb +108 -0
- data/lib/stove/plugins/jira.rb +72 -0
- data/lib/stove/rake_task.rb +56 -37
- data/lib/stove/runner.rb +84 -0
- data/lib/stove/util.rb +56 -0
- data/lib/stove/validator.rb +67 -0
- data/lib/stove/version.rb +1 -1
- data/locales/en.yml +231 -0
- data/stove.gemspec +11 -11
- metadata +85 -67
- data/features/changelog.feature +0 -22
- data/features/cli.feature +0 -11
- data/features/devodd.feature +0 -19
- data/features/git.feature +0 -34
- data/features/upload.feature +0 -40
- data/lib/stove/community_site.rb +0 -85
- data/lib/stove/formatter.rb +0 -7
- data/lib/stove/formatter/base.rb +0 -32
- data/lib/stove/formatter/human.rb +0 -9
- data/lib/stove/formatter/silent.rb +0 -10
- data/lib/stove/git.rb +0 -82
- data/lib/stove/github.rb +0 -43
- data/lib/stove/logger.rb +0 -56
- data/lib/stove/uploader.rb +0 -64
- data/spec/support/community_site.rb +0 -33
- data/spec/support/git.rb +0 -52
data/lib/stove/rake_task.rb
CHANGED
@@ -1,63 +1,82 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/tasklib'
|
3
|
+
require 'stove'
|
3
4
|
|
5
|
+
#
|
6
|
+
# @todo Most of these options are duplicated from the CLI, can we unify?
|
7
|
+
#
|
4
8
|
module Stove
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# @example
|
9
|
-
# desc "Run stove tasks"
|
10
|
-
# Stove::RakeTask.new(:release) do |stove|
|
11
|
-
# stove.git = true
|
12
|
-
# stove.devodd = true
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
class RakeTask < ::Rake::TaskLib
|
9
|
+
class RakeTask < Rake::TaskLib
|
10
|
+
include Mixin::Loggable
|
11
|
+
|
16
12
|
class << self
|
17
13
|
#
|
18
14
|
# Define a CLI option.
|
19
15
|
#
|
20
16
|
# @param [Symbol] option
|
21
17
|
#
|
22
|
-
def
|
18
|
+
def option(option)
|
23
19
|
define_method("#{option}=".to_sym) do |value|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
define_method(option.to_sym) do
|
28
|
-
options[option]
|
20
|
+
log.debug("Setting #{option} = #{value.inspect}")
|
21
|
+
options[option.to_sym] = value
|
29
22
|
end
|
30
23
|
end
|
31
24
|
end
|
32
25
|
|
33
|
-
#
|
34
|
-
|
26
|
+
# Actions
|
27
|
+
Action.constants.map(&Action.method(:const_get)).select(&:id).each do |action|
|
28
|
+
option action.id
|
29
|
+
end
|
35
30
|
|
36
|
-
#
|
37
|
-
|
31
|
+
# Plugins
|
32
|
+
Plugin.constants.map(&Plugin.method(:const_get)).select(&:id).each do |plugin|
|
33
|
+
option plugin.id
|
34
|
+
end
|
38
35
|
|
39
|
-
|
40
|
-
|
41
|
-
|
36
|
+
option :category
|
37
|
+
option :path
|
38
|
+
option :remote
|
39
|
+
option :branch
|
42
40
|
|
41
|
+
def initialize(name = nil)
|
43
42
|
yield self if block_given?
|
44
43
|
|
45
44
|
desc 'Publish this cookbook' unless ::Rake.application.last_comment
|
46
|
-
task
|
47
|
-
|
48
|
-
|
45
|
+
task(name || :publish, :version) do |t, args|
|
46
|
+
log.info("Options: #{options.inspect}")
|
47
|
+
|
48
|
+
cookbook = Cookbook.new(options[:path])
|
49
|
+
options[:version] = args[:version] || minor_bump(cookbook.version)
|
50
|
+
Runner.run(cookbook, options)
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
54
|
+
def locale=(locale)
|
55
|
+
log.debug("Setting locale = #{locale.inspect}")
|
56
|
+
I18n.locale = locale
|
57
|
+
end
|
58
|
+
|
59
|
+
def log_level=(level)
|
60
|
+
log.debug("Setting log_level = #{level.inspect}")
|
61
|
+
Stove.log_level = level
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def minor_bump(version)
|
67
|
+
split = version.split('.').map(&:to_i)
|
68
|
+
split[2] += 1
|
69
|
+
split.join('.')
|
70
|
+
end
|
71
|
+
|
72
|
+
def options
|
73
|
+
@options ||= Hash.new(true).tap do |h|
|
74
|
+
h[:path] = Dir.pwd
|
75
|
+
h[:jira] = false
|
76
|
+
|
77
|
+
h[:remote] = 'origin'
|
78
|
+
h[:branch] = 'master'
|
79
|
+
end
|
80
|
+
end
|
62
81
|
end
|
63
82
|
end
|
data/lib/stove/runner.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
module Stove
|
2
|
+
class Runner
|
3
|
+
include Mixin::Instanceable
|
4
|
+
include Mixin::Loggable
|
5
|
+
include Mixin::Optionable
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def action(id)
|
9
|
+
actions << id
|
10
|
+
filters[id] = { before: [], after: [] }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :cookbook
|
15
|
+
attr_reader :options
|
16
|
+
attr_reader :validations
|
17
|
+
|
18
|
+
option :actions, []
|
19
|
+
option :filters, {}
|
20
|
+
|
21
|
+
action :start
|
22
|
+
action :bump
|
23
|
+
action :changelog
|
24
|
+
action :upload
|
25
|
+
action :dev
|
26
|
+
action :finish
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@validations = []
|
30
|
+
end
|
31
|
+
|
32
|
+
def run(cookbook, options = {})
|
33
|
+
@cookbook, @options = cookbook, options
|
34
|
+
|
35
|
+
run_validations
|
36
|
+
run_actions
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def skip?(thing)
|
42
|
+
!options[thing.to_sym]
|
43
|
+
end
|
44
|
+
|
45
|
+
def run_actions
|
46
|
+
actions.each do |action|
|
47
|
+
if skip?(action)
|
48
|
+
log.debug("Skipping action `#{action}' and filters")
|
49
|
+
else
|
50
|
+
run_filters(:before, action)
|
51
|
+
|
52
|
+
klass = Action.const_get(Util.camelize(action))
|
53
|
+
klass.new(cookbook, options).run
|
54
|
+
|
55
|
+
run_filters(:after, action)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def run_filters(placement, action)
|
61
|
+
filters[action][placement].each do |filter|
|
62
|
+
plugin = filter.klass.id
|
63
|
+
|
64
|
+
if skip?(plugin)
|
65
|
+
log.debug("Skipping filter `#{filter.message}'")
|
66
|
+
else
|
67
|
+
filter.run(cookbook, options)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def run_validations
|
73
|
+
validations.each do |validation|
|
74
|
+
parent = validation.klass.id
|
75
|
+
|
76
|
+
if skip?(parent)
|
77
|
+
log.debug("Skipping validation `#{validation.id}' for `#{parent}'")
|
78
|
+
else
|
79
|
+
validation.run(cookbook, options)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/stove/util.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Stove
|
2
|
+
module Util
|
3
|
+
extend self
|
4
|
+
|
5
|
+
# Convert a version string (x.y.z) to a community-site friendly format
|
6
|
+
# (x_y_z).
|
7
|
+
#
|
8
|
+
# @example Convert a version to a version string
|
9
|
+
# format_version('1.2.3') #=> 1_2_3
|
10
|
+
#
|
11
|
+
# @param [#to_s] version
|
12
|
+
# the version string to convert
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
def version_for_url(version)
|
16
|
+
version
|
17
|
+
.to_s
|
18
|
+
.gsub('.', '_')
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Covert the given CaMelCaSeD string to under_score. Graciously borrowed
|
23
|
+
# from http://stackoverflow.com/questions/1509915.
|
24
|
+
#
|
25
|
+
# @param [String] string
|
26
|
+
# the string to use for transformation
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
#
|
30
|
+
def underscore(string)
|
31
|
+
string
|
32
|
+
.to_s
|
33
|
+
.gsub(/::/, '/')
|
34
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
35
|
+
.gsub(/([a-z\d])([A-Z])/,'\1_\2')
|
36
|
+
.tr('-', '_')
|
37
|
+
.downcase
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Convert an underscored string to it's camelcase equivalent constant.
|
42
|
+
#
|
43
|
+
# @param [String]
|
44
|
+
# the string to convert
|
45
|
+
#
|
46
|
+
# @return [String]
|
47
|
+
#
|
48
|
+
def camelize(string)
|
49
|
+
string
|
50
|
+
.to_s
|
51
|
+
.split('_')
|
52
|
+
.map { |e| e.capitalize }
|
53
|
+
.join
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Stove
|
2
|
+
class Validator
|
3
|
+
include Mixin::Insideable
|
4
|
+
include Mixin::Loggable
|
5
|
+
|
6
|
+
#
|
7
|
+
# The class that created this validator.
|
8
|
+
#
|
9
|
+
# @return [~Class]
|
10
|
+
#
|
11
|
+
attr_reader :klass
|
12
|
+
|
13
|
+
#
|
14
|
+
# The identifier or field this validator runs against.
|
15
|
+
#
|
16
|
+
# @return [Symbol]
|
17
|
+
#
|
18
|
+
attr_reader :id
|
19
|
+
|
20
|
+
#
|
21
|
+
# The block to execute to see if the validation passes.
|
22
|
+
#
|
23
|
+
# @return [Proc]
|
24
|
+
#
|
25
|
+
attr_reader :block
|
26
|
+
|
27
|
+
#
|
28
|
+
# Create a new validator object.
|
29
|
+
#
|
30
|
+
# @param [~Class] klass
|
31
|
+
# the class that created this validator
|
32
|
+
# @param [Symbol] id
|
33
|
+
# the identifier or field this validator runs against
|
34
|
+
# @param [Proc] block
|
35
|
+
# the block to execute to see if the validation passes
|
36
|
+
#
|
37
|
+
def initialize(klass, id, &block)
|
38
|
+
@klass = klass
|
39
|
+
@id = id
|
40
|
+
@block = block
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Execute this validation in the context of the creating class, inside the
|
45
|
+
# given cookbook's path.
|
46
|
+
#
|
47
|
+
# @param [Cookbook]
|
48
|
+
# the cookbook to run this validation against
|
49
|
+
#
|
50
|
+
def run(cookbook, options = {})
|
51
|
+
log.info("Running validations for #{klass.id}.#{id}")
|
52
|
+
|
53
|
+
inside(cookbook) do
|
54
|
+
instance = klass.new(cookbook, options)
|
55
|
+
unless result = instance.instance_eval(&block)
|
56
|
+
log.debug("Validation failed, result: #{result.inspect}")
|
57
|
+
raise Error::ValidationFailed.new(klass.id, id,
|
58
|
+
path: Dir.pwd,
|
59
|
+
result: result,
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
log.debug("Validation #{id} passed!")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/stove/version.rb
CHANGED
data/locales/en.yml
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
en:
|
2
|
+
stove:
|
3
|
+
errors:
|
4
|
+
abstract_method: >
|
5
|
+
`%{method}` is an abstract method. You must override this method in
|
6
|
+
your subclass with the proper implementation and logic. For more
|
7
|
+
information, please see the inline documentation for %{method}. If you
|
8
|
+
are not a developer, this is most likely a bug. Please file a bug report
|
9
|
+
at https://github.com/sethvargo/stove/issues/new and include the
|
10
|
+
command(s) you ran to arrive at this error.
|
11
|
+
|
12
|
+
git_failed: >
|
13
|
+
An error occurred while running:
|
14
|
+
|
15
|
+
git %{command}
|
16
|
+
|
17
|
+
There is likely an informative message from git that explains what
|
18
|
+
happened right above this message.
|
19
|
+
|
20
|
+
metadata_not_found: >
|
21
|
+
The file at `%{path}' does not exist or does not contain valid metadata.
|
22
|
+
Please make sure you have specified the correct path and that the
|
23
|
+
metdata file exists.
|
24
|
+
|
25
|
+
server_unavailable: >
|
26
|
+
The server at `%{url}` is unavailable or is not currently accepting
|
27
|
+
client connections. Please ensure the server is accessible via ping (or
|
28
|
+
telnet) on your local network. If this error persists, please contact
|
29
|
+
your network administrator.
|
30
|
+
|
31
|
+
|
32
|
+
validations:
|
33
|
+
# Bump validations
|
34
|
+
# ----------------
|
35
|
+
bump:
|
36
|
+
changed: >
|
37
|
+
The version you are trying to bump already exists! You must specify a
|
38
|
+
new version.
|
39
|
+
|
40
|
+
incremented: >
|
41
|
+
The cookbook version you are attempting to bump to is less than the
|
42
|
+
existing version. You cannot (re-)release a previous version of the
|
43
|
+
same cookbook. Please specify a higher version.
|
44
|
+
|
45
|
+
|
46
|
+
# Changelog validations
|
47
|
+
# ---------------------
|
48
|
+
changelog:
|
49
|
+
editor: >
|
50
|
+
The `$EDITOR' environment variable is not set. In order to use the
|
51
|
+
Changelog plugin, you must set a default editor for Stove to open when
|
52
|
+
generating the CHANGLEOG. You can set the editor like this:
|
53
|
+
|
54
|
+
export EDITOR=vi
|
55
|
+
|
56
|
+
exists: >
|
57
|
+
There is no `CHANGELOG.md' found at `%{path}. In order to use the
|
58
|
+
Changelog plugin, you must have a changelog in markdown format at the
|
59
|
+
root of your cookbook. You can also skip the Changelog plugin by
|
60
|
+
specifying the `--no-changelog' option:
|
61
|
+
|
62
|
+
bake x.y.z --no-changelog
|
63
|
+
|
64
|
+
format: >
|
65
|
+
The changelog at `%{path}' does not appear to be a valid format. The
|
66
|
+
changelog must be in the following format:
|
67
|
+
|
68
|
+
[Cookbook Name]
|
69
|
+
===============
|
70
|
+
|
71
|
+
v[version] ([release date])
|
72
|
+
---------------------------
|
73
|
+
- [Release point]
|
74
|
+
|
75
|
+
For example:
|
76
|
+
|
77
|
+
Apache 2
|
78
|
+
========
|
79
|
+
|
80
|
+
v1.0.0 (2013-04-05)
|
81
|
+
-------------------
|
82
|
+
- Initial release
|
83
|
+
|
84
|
+
|
85
|
+
# Git validations
|
86
|
+
# ---------------
|
87
|
+
git:
|
88
|
+
clean: >
|
89
|
+
The cookbook at `%{path}' has untracked files! In order to use the git
|
90
|
+
plugin, you must have a clean working directory. Please commit or
|
91
|
+
stash your changes before running Stove again.
|
92
|
+
|
93
|
+
repository: >
|
94
|
+
The cookbook at `%{path}' does not appear to be a valid git
|
95
|
+
repository. In order to use the git plugin, your cookbook must be
|
96
|
+
initialized as a git repository. To create a git repository, run:
|
97
|
+
|
98
|
+
git init %{path}
|
99
|
+
|
100
|
+
up_to_date: >
|
101
|
+
The cookbook at `%{path}' is out of sync with the remote repository.
|
102
|
+
Please update your local cache with the remote repository before
|
103
|
+
continuing:
|
104
|
+
|
105
|
+
git pull
|
106
|
+
|
107
|
+
And then push your local changes to the remote repository:
|
108
|
+
|
109
|
+
git push
|
110
|
+
|
111
|
+
|
112
|
+
# GitHub validations
|
113
|
+
# ------------------
|
114
|
+
github:
|
115
|
+
access_token: >
|
116
|
+
The Stove configuration for GitHub does not contain an access token.
|
117
|
+
In order to use the GitHub plugin, you must set an access token in the
|
118
|
+
GitHub section of the `~/.stove' file:
|
119
|
+
|
120
|
+
{
|
121
|
+
"github": {
|
122
|
+
"access_token": "YOUR_ACCESS_TOKEN"
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
You can generate an access token for GitHub by following the
|
127
|
+
instructions at: https://help.github.com/articles/creating-an-access-token-for-command-line-use.
|
128
|
+
|
129
|
+
configuration: >
|
130
|
+
The Stove configuration for GitHub does not exist! In order to use the
|
131
|
+
GitHub plugin, you must set your GitHub information in the `~/.stove'
|
132
|
+
file:
|
133
|
+
|
134
|
+
{
|
135
|
+
"github": {
|
136
|
+
"access_token": "YOUR_ACCESS_TOKEN"
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
git: >
|
141
|
+
In order to use the GitHub plugin, you must also activate the `git'
|
142
|
+
plugin.
|
143
|
+
|
144
|
+
|
145
|
+
# JIRA validations
|
146
|
+
# ----------------
|
147
|
+
jira:
|
148
|
+
configuration: >
|
149
|
+
The Stove configuration for JIRA does not exist! In order to use the
|
150
|
+
JIRA plugin, you must set your JIRA information in the `~/.stove'
|
151
|
+
file:
|
152
|
+
|
153
|
+
{
|
154
|
+
"jira": {
|
155
|
+
"username": "YOUR_USERNAME",
|
156
|
+
"password": "YOUR_PASSWORD"
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
password: >
|
161
|
+
The Stove configuration for JIRA does not contain a password. In order
|
162
|
+
to use JIRA features, you must set a password in the jira section of
|
163
|
+
the `~/.stove' file:
|
164
|
+
|
165
|
+
{
|
166
|
+
"jira": {
|
167
|
+
"password": "YOUR_PASSWORD"
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
username: >
|
172
|
+
The Stove configuration for JIRA does not contain a username. In order
|
173
|
+
to use JIRA features, you must set a username in the jira section of
|
174
|
+
the `~/.stove' file:
|
175
|
+
|
176
|
+
{
|
177
|
+
"jira": {
|
178
|
+
"username": "YOUR_USERNAME"
|
179
|
+
}
|
180
|
+
}
|
181
|
+
|
182
|
+
|
183
|
+
# Upload validations
|
184
|
+
# ---------------------
|
185
|
+
upload:
|
186
|
+
configuration: >
|
187
|
+
The Stove configuration for the Chef community site does not exist! In
|
188
|
+
order to perform operations against the Chef community site, you must
|
189
|
+
set your username and path to your client key in the community section
|
190
|
+
of the `~/.stove' file:
|
191
|
+
|
192
|
+
{
|
193
|
+
"community": {
|
194
|
+
"username": "YOUR_USERNAME",
|
195
|
+
"key": "YOUR_KEY_PATH"
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
key: >
|
200
|
+
The Stove configuration for the Chef community site does not contain a
|
201
|
+
key. In order to use the Chef community site features, you must set
|
202
|
+
the path to your key the community section of the `~/.stove' file:
|
203
|
+
|
204
|
+
{
|
205
|
+
"community": {
|
206
|
+
"key": "YOUR_KEY_PATH"
|
207
|
+
}
|
208
|
+
}
|
209
|
+
|
210
|
+
username: >
|
211
|
+
The Stove configuration for the Chef community site does not contain a
|
212
|
+
username. In order to use the Chef community site features, you must
|
213
|
+
set a username the community section of the `~/.stove' file:
|
214
|
+
|
215
|
+
{
|
216
|
+
"community": {
|
217
|
+
"username": "YOUR_USERNAME"
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
category: >
|
222
|
+
You did not specify a category! The Chef community site requires all
|
223
|
+
cookbooks belong to a category. For existing cookboks, Stove can query
|
224
|
+
the Chef community site API and automatically complete the category
|
225
|
+
for you. However, for new cookbooks, you must specify the `--category'
|
226
|
+
flag at runtime:
|
227
|
+
|
228
|
+
bake x.y.z --category Utilities
|
229
|
+
|
230
|
+
For a complete listing of categories, please see the Chef community
|
231
|
+
site.
|