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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/CHANGELOG.md +16 -0
  4. data/README.md +41 -29
  5. data/Rakefile +15 -0
  6. data/bin/bake +1 -2
  7. data/features/actions/bump.feature +22 -0
  8. data/features/actions/changelog.feature +45 -0
  9. data/features/actions/dev.feature +18 -0
  10. data/features/actions/upload.feature +48 -0
  11. data/features/plugins/git.feature +24 -0
  12. data/features/rake.feature +1 -2
  13. data/features/step_definitions/cli_steps.rb +1 -27
  14. data/features/step_definitions/{community_site_steps.rb → community_steps.rb} +9 -5
  15. data/features/step_definitions/config_steps.rb +24 -0
  16. data/features/step_definitions/cookbook_steps.rb +28 -6
  17. data/features/step_definitions/cucumber_steps.rb +12 -0
  18. data/features/step_definitions/git_steps.rb +10 -7
  19. data/features/support/env.rb +12 -28
  20. data/features/support/stove/git.rb +48 -0
  21. data/lib/stove.rb +102 -19
  22. data/lib/stove/actions/base.rb +21 -0
  23. data/lib/stove/actions/bump.rb +25 -0
  24. data/lib/stove/actions/changelog.rb +71 -0
  25. data/lib/stove/actions/dev.rb +22 -0
  26. data/lib/stove/actions/finish.rb +8 -0
  27. data/lib/stove/actions/start.rb +7 -0
  28. data/lib/stove/actions/upload.rb +27 -0
  29. data/lib/stove/cli.rb +107 -79
  30. data/lib/stove/community.rb +124 -0
  31. data/lib/stove/config.rb +62 -13
  32. data/lib/stove/cookbook.rb +76 -238
  33. data/lib/stove/cookbook/metadata.rb +16 -11
  34. data/lib/stove/error.rb +13 -107
  35. data/lib/stove/filter.rb +59 -0
  36. data/lib/stove/jira.rb +74 -30
  37. data/lib/stove/middlewares/chef_authentication.rb +60 -0
  38. data/lib/stove/middlewares/exceptions.rb +17 -0
  39. data/lib/stove/mixins/filterable.rb +11 -0
  40. data/lib/stove/mixins/insideable.rb +13 -0
  41. data/lib/stove/mixins/instanceable.rb +23 -0
  42. data/lib/stove/mixins/loggable.rb +32 -0
  43. data/lib/stove/mixins/optionable.rb +41 -0
  44. data/lib/stove/mixins/validatable.rb +7 -0
  45. data/lib/stove/packager.rb +23 -22
  46. data/lib/stove/plugins/base.rb +35 -0
  47. data/lib/stove/plugins/git.rb +71 -0
  48. data/lib/stove/plugins/github.rb +108 -0
  49. data/lib/stove/plugins/jira.rb +72 -0
  50. data/lib/stove/rake_task.rb +56 -37
  51. data/lib/stove/runner.rb +84 -0
  52. data/lib/stove/util.rb +56 -0
  53. data/lib/stove/validator.rb +67 -0
  54. data/lib/stove/version.rb +1 -1
  55. data/locales/en.yml +231 -0
  56. data/stove.gemspec +11 -11
  57. metadata +85 -67
  58. data/features/changelog.feature +0 -22
  59. data/features/cli.feature +0 -11
  60. data/features/devodd.feature +0 -19
  61. data/features/git.feature +0 -34
  62. data/features/upload.feature +0 -40
  63. data/lib/stove/community_site.rb +0 -85
  64. data/lib/stove/formatter.rb +0 -7
  65. data/lib/stove/formatter/base.rb +0 -32
  66. data/lib/stove/formatter/human.rb +0 -9
  67. data/lib/stove/formatter/silent.rb +0 -10
  68. data/lib/stove/git.rb +0 -82
  69. data/lib/stove/github.rb +0 -43
  70. data/lib/stove/logger.rb +0 -56
  71. data/lib/stove/uploader.rb +0 -64
  72. data/spec/support/community_site.rb +0 -33
  73. data/spec/support/git.rb +0 -52
@@ -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
- # Run Stove tasks from your +Rakefile+.
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 cli_option(option)
18
+ def option(option)
23
19
  define_method("#{option}=".to_sym) do |value|
24
- options[option] = value
25
- end
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
- # @return [Symbol]
34
- attr_accessor :name
26
+ # Actions
27
+ Action.constants.map(&Action.method(:const_get)).select(&:id).each do |action|
28
+ option action.id
29
+ end
35
30
 
36
- # @return [Hash]
37
- attr_reader :options
31
+ # Plugins
32
+ Plugin.constants.map(&Plugin.method(:const_get)).select(&:id).each do |plugin|
33
+ option plugin.id
34
+ end
38
35
 
39
- def initialize(task_name = nil)
40
- @options = {}
41
- @name = (task_name || :publish).to_sym
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 name do |t, args|
47
- require 'stove'
48
- Stove::Cookbook.new(options).release!
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
- cli_option :branch
53
- cli_option :category
54
- cli_option :changelog
55
- cli_option :devodd
56
- cli_option :git
57
- cli_option :jira
58
- cli_option :log_level
59
- cli_option :path
60
- cli_option :remote
61
- cli_option :upload
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Stove
2
- VERSION = '1.1.2'
2
+ VERSION = '2.0.0.beta.1'
3
3
  end
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.