stove 1.1.2 → 2.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|