stove 2.0.0 → 3.0.0

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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +6 -1
  4. data/CHANGELOG.md +20 -0
  5. data/README.md +34 -80
  6. data/Rakefile +9 -1
  7. data/bin/bake +2 -0
  8. data/bin/stove +4 -0
  9. data/features/plugins/community.feature +11 -26
  10. data/features/plugins/git.feature +17 -6
  11. data/features/step_definitions/community_steps.rb +3 -1
  12. data/features/step_definitions/config_steps.rb +4 -21
  13. data/features/step_definitions/git_steps.rb +38 -1
  14. data/features/support/env.rb +17 -11
  15. data/features/support/stove/git.rb +28 -8
  16. data/lib/stove/cli.rb +72 -53
  17. data/lib/stove/community.rb +16 -67
  18. data/lib/stove/config.rb +55 -46
  19. data/lib/stove/cookbook/metadata.rb +3 -5
  20. data/lib/stove/cookbook.rb +2 -41
  21. data/lib/stove/error.rb +37 -8
  22. data/lib/stove/filter.rb +2 -1
  23. data/lib/stove/mixins/instanceable.rb +3 -2
  24. data/lib/stove/mixins/validatable.rb +5 -1
  25. data/lib/stove/packager.rb +11 -3
  26. data/lib/stove/plugins/base.rb +26 -13
  27. data/lib/stove/plugins/community.rb +3 -7
  28. data/lib/stove/plugins/git.rb +27 -30
  29. data/lib/stove/rake_task.rb +3 -63
  30. data/lib/stove/runner.rb +16 -65
  31. data/lib/stove/validator.rb +7 -6
  32. data/lib/stove/version.rb +1 -1
  33. data/lib/stove.rb +3 -21
  34. data/spec/spec_helper.rb +2 -0
  35. data/spec/unit/error_spec.rb +148 -0
  36. data/stove.gemspec +10 -14
  37. data/templates/errors/abstract_method.erb +5 -0
  38. data/templates/errors/community_category_validation_failed.erb +5 -0
  39. data/templates/errors/community_key_validation_failed.erb +3 -0
  40. data/templates/errors/community_username_validation_failed.erb +3 -0
  41. data/templates/errors/git_clean_validation_failed.erb +1 -0
  42. data/templates/errors/git_failed.erb +5 -0
  43. data/templates/errors/git_repository_validation_failed.erb +3 -0
  44. data/templates/errors/git_up_to_date_validation_failed.erb +7 -0
  45. data/templates/errors/metadata_not_found.erb +1 -0
  46. data/templates/errors/server_unavailable.erb +1 -0
  47. data/templates/errors/stove_error.erb +1 -0
  48. metadata +32 -114
  49. data/features/actions/bump.feature +0 -22
  50. data/features/actions/changelog.feature +0 -52
  51. data/features/actions/dev.feature +0 -18
  52. data/features/actions/upload.feature +0 -26
  53. data/features/rake.feature +0 -15
  54. data/features/step_definitions/cli_steps.rb +0 -3
  55. data/lib/stove/actions/base.rb +0 -21
  56. data/lib/stove/actions/bump.rb +0 -25
  57. data/lib/stove/actions/changelog.rb +0 -71
  58. data/lib/stove/actions/dev.rb +0 -22
  59. data/lib/stove/actions/finish.rb +0 -8
  60. data/lib/stove/actions/start.rb +0 -7
  61. data/lib/stove/actions/upload.rb +0 -11
  62. data/lib/stove/jira.rb +0 -88
  63. data/lib/stove/middlewares/chef_authentication.rb +0 -60
  64. data/lib/stove/middlewares/exceptions.rb +0 -17
  65. data/lib/stove/mixins/filterable.rb +0 -11
  66. data/lib/stove/plugins/github.rb +0 -107
  67. data/lib/stove/plugins/jira.rb +0 -72
  68. data/locales/en.yml +0 -230
data/lib/stove/jira.rb DELETED
@@ -1,88 +0,0 @@
1
- require 'faraday'
2
- require 'faraday_middleware'
3
-
4
- module Stove
5
- class JIRA
6
- include Mixin::Instanceable
7
- include Logify
8
- include Mixin::Optionable
9
-
10
- option :base_url,
11
- ENV['JIRA_URL'] || 'https://tickets.opscode.com/rest/api/2'
12
-
13
- def issue(key, options = {})
14
- connection.get("issue/#{key}", options).body
15
- end
16
-
17
- def search(query = {})
18
- jql = query.map { |k,v| %Q|#{k} = "#{v}"| }.join(' AND ')
19
- connection.get('search', jql: jql).body
20
- end
21
-
22
- def close_and_comment(key, comment)
23
- transitions = issue(key, expand: 'transitions')['transitions']
24
- close = transitions.first { |transition| transition['name'] == 'Close' }
25
-
26
- if close.nil?
27
- log.warn("Issue #{key} does not have a `Close' transition")
28
- return
29
- end
30
-
31
- connection.post("issue/#{key}/transitions", {
32
- transition: { id: close['id'] },
33
- update: {
34
- comment: [
35
- { add: { body: comment.to_s } }
36
- ]
37
- },
38
- fields: {
39
- resolution: {
40
- name: 'Fixed'
41
- },
42
- assignee: {
43
- name: nil
44
- }
45
- }
46
- })
47
- end
48
-
49
- private
50
-
51
- def connection
52
- @connection ||= Faraday.new(base_url) do |builder|
53
- # Encode request bodies as JSON
54
- builder.request :json
55
-
56
- # Add basic authentication information
57
- builder.request :basic_auth, Stove::Config[:jira][:username],
58
- Stove::Config[:jira][:password]
59
-
60
- # Handle any common errors
61
- builder.use Stove::Middleware::Exceptions
62
-
63
- # Decode responses as JSON if the Content-Type is json
64
- builder.response :json
65
- builder.response :json_fix
66
-
67
- # Allow up to 3 redirects
68
- builder.response :follow_redirects, limit: 3
69
-
70
- # Log all requests and responses (useful for development)
71
- builder.response :logger, log
72
-
73
- # Raise errors on 40x and 50x responses
74
- builder.response :raise_error
75
-
76
- # Use the default adapter (Net::HTTP)
77
- builder.adapter :net_http
78
-
79
- # Set the User-Agent header for logging purposes
80
- builder.headers[:user_agent] = Stove::USER_AGENT
81
-
82
- # Set some options, such as timeouts
83
- builder.options[:timeout] = 30
84
- builder.options[:open_timeout] = 30
85
- end
86
- end
87
- end
88
- end
@@ -1,60 +0,0 @@
1
- require 'pp'
2
-
3
- module Stove
4
- class Middleware::ChefAuthentication < Faraday::Middleware
5
- dependency do
6
- require 'mixlib/authentication/signedheaderauth'
7
- require 'openssl'
8
- require 'uri'
9
- end
10
-
11
- #
12
- # @param [Faraday::Application] app
13
- # @param [String] client
14
- # the name of the client to use for Chef
15
- # @param [OpenSSL::PKey::RSA] key
16
- # the RSA private key to sign with
17
- #
18
- def initialize(app, client, key)
19
- super(app)
20
-
21
- @client = client
22
- @key = OpenSSL::PKey::RSA.new(File.read(key))
23
- end
24
-
25
- def call(env)
26
- env[:request_headers].merge!(signing_object(env))
27
- @app.call(env)
28
- end
29
-
30
- private
31
-
32
- def signing_object(env)
33
- params = {
34
- :http_method => env[:method],
35
- :timestamp => Time.now.utc.iso8601,
36
- :user_id => @client,
37
- :path => env[:url].path,
38
- :body => env[:body] || '',
39
- }
40
-
41
- # Royal fucking hack
42
- # 1. (n.) This code sample
43
- # 2. (v.) Having to decompose a Faraday response because Mixlib
44
- # Authentication couldn't get a date to the prom
45
- if env[:body] && env[:body].is_a?(Faraday::CompositeReadIO)
46
- file = env[:body]
47
- .instance_variable_get(:@parts)
48
- .first { |part| part.is_a?(Faraday::Parts::FilePart) }
49
- .instance_variable_get(:@io)
50
- .instance_variable_get(:@ios)[1]
51
- .instance_variable_get(:@local_path)
52
-
53
- params[:file] = File.new(file)
54
- end
55
-
56
- object = Mixlib::Authentication::SignedHeaderAuth.signing_object(params)
57
- object.sign(@key)
58
- end
59
- end
60
- end
@@ -1,17 +0,0 @@
1
- module Stove
2
- class Middleware::Exceptions < Faraday::Middleware
3
- include Logify
4
-
5
- def call(env)
6
- begin
7
- @app.call(env)
8
- rescue Faraday::Error::ConnectionFailed
9
- url = env[:url].to_s.gsub(env[:url].path, '')
10
- raise Error::ServerUnavailable.new(url: url)
11
- rescue Faraday::Error::ClientError => e
12
- log.debug(env.inspect)
13
- raise
14
- end
15
- end
16
- end
17
- end
@@ -1,11 +0,0 @@
1
- module Stove
2
- module Mixin::Filterable
3
- def before(action, message, &block)
4
- Runner.filters[action][:before] << Filter.new(self, message, &block)
5
- end
6
-
7
- def after(action, message, &block)
8
- Runner.filters[action][:after] << Filter.new(self, message, &block)
9
- end
10
- end
11
- end
@@ -1,107 +0,0 @@
1
- module Stove
2
- class Plugin::GitHub < Plugin::Base
3
- id 'github'
4
- description 'Publish the release to GitHub'
5
-
6
- onload do
7
- require 'faraday'
8
- require 'faraday_middleware'
9
- require 'octokit'
10
- end
11
-
12
- validate(:git) do
13
- options[:git]
14
- end
15
-
16
- validate(:configuration) do
17
- Config.has_key?(:github)
18
- end
19
-
20
- validate(:access_token) do
21
- Config[:github].has_key?(:access_token)
22
- end
23
-
24
- after(:upload, 'Publishing the release to GitHub') do
25
- release = client.create_release(repository, cookbook.tag_version,
26
- name: cookbook.tag_version,
27
- body: cookbook.changeset,
28
- )
29
- asset = client.upload_asset("repos/#{repository}/releases/#{release.id}", cookbook.tarball,
30
- content_type: 'application/x-gzip',
31
- name: filename,
32
- )
33
- client.update_release_asset("repos/#{repository}/releases/assets/#{asset.id}",
34
- name: filename,
35
- label: 'Download Cookbook',
36
- )
37
- end
38
-
39
- def client
40
- return @client if @client
41
-
42
- config = {}.tap do |h|
43
- h[:middleware] = middleware
44
- h[:access_token] = Config[:github][:access_token]
45
- h[:api_endpoint] = Config[:github][:api_endpoint] if Config[:github][:api_endpoint]
46
- end
47
-
48
- @client = Octokit::Client.new(config)
49
- @client
50
- end
51
-
52
- def changeset
53
- @changeset ||= cookbook.changeset.split("\n")[2..-1].join("\n").strip
54
- end
55
-
56
- def repository
57
- @repository ||= Octokit::Repository.from_url(repo_url)
58
- end
59
-
60
- def filename
61
- @filename ||= "#{cookbook.name}-#{cookbook.version}.tar.gz"
62
- end
63
-
64
- def middleware
65
- Faraday::Builder.new do |builder|
66
- # Handle any common errors
67
- builder.use Stove::Middleware::Exceptions
68
- builder.use Octokit::Response::RaiseError
69
-
70
- # Log all requests and responses (useful for development)
71
- builder.response :logger, log
72
-
73
- # Raise errors on 40x and 50x responses
74
- builder.response :raise_error
75
-
76
- # Use the default adapter (Net::HTTP)
77
- builder.adapter :net_http
78
- end
79
- end
80
-
81
- #
82
- # The URL for this repository on GitHub. This method automatically
83
- # translates SSH and git:// URLs to https:// URLs.
84
- #
85
- # @return [String]
86
- #
87
- def repo_url
88
- return @repo_url if @repo_url
89
-
90
- path = File.join('.git', 'config')
91
- log.debug("Calculating repo_url from `#{path}'")
92
-
93
- config = File.read(path)
94
- log.debug("Config contents:\n#{config}")
95
-
96
- config =~ /\[remote "#{options[:remote]}"\]\n\s+url = (.+)$/
97
- log.debug("Match: #{$1.inspect}")
98
-
99
- @repo_url = $1.to_s
100
- .strip
101
- .gsub(/\.git$/, '')
102
- .gsub(/^\S+@(\S+):/, 'https://\1/')
103
- .gsub('git://', 'https://')
104
- @repo_url
105
- end
106
- end
107
- end
@@ -1,72 +0,0 @@
1
- module Stove
2
- class Plugin::JIRA < Plugin::Base
3
- id 'jira'
4
- description 'Resolve JIRA issues'
5
-
6
- validate(:configuration) do
7
- Config.has_key?(:jira)
8
- end
9
-
10
- validate(:username) do
11
- Config[:jira].has_key?(:username)
12
- end
13
-
14
- validate(:password) do
15
- Config[:jira].has_key?(:password)
16
- end
17
-
18
- before(:changelog, 'Generate JIRA changeset') do
19
- by_type = unreleased_issues.inject({}) do |hash, issue|
20
- type = issue['fields']['issuetype']['name']
21
- hash[type] ||= []
22
- hash[type] << {
23
- key: issue['key'],
24
- summary: issue['fields']['summary'],
25
- }
26
-
27
- hash
28
- end
29
-
30
- # Calculate the JIRA path based off of the JIRA base_url
31
- jira_base = URI.parse(JIRA.base_url)
32
- jira_base.path = ''
33
- jira_base = jira_base.to_s
34
- log.debug("JIRA base is `#{jira_base}'")
35
-
36
- contents = []
37
-
38
- by_type.each do |type, issues|
39
- contents << "### #{type}"
40
- issues.sort { |a, b| b[:key].to_i <=> a[:key].to_i }.each do |issue|
41
- url = "#{jira_base}/browse/#{issue[:key]}"
42
- contents << "- **[#{issue[:key]}](#{url})** - #{issue[:summary]}"
43
- end
44
- contents << ''
45
- end
46
-
47
- cookbook.changeset = contents.join("\n")
48
- end
49
-
50
- after(:upload, 'Resolving JIRA issues') do
51
- unreleased_issues.collect do |issue|
52
- Thread.new do
53
- JIRA.close_and_comment(issue['key'], "Released in #{cookbook.version}")
54
- end
55
- end.map(&:join)
56
- end
57
-
58
- #
59
- # The list of unreleased tickets on JIRA.
60
- #
61
- # @return [Array<Hash>]
62
- #
63
- def unreleased_issues
64
- @unreleased_issues ||= JIRA.search(
65
- project: 'COOK',
66
- resolution: 'Fixed',
67
- status: 'Fix Committed',
68
- component: cookbook.name,
69
- )['issues']
70
- end
71
- end
72
- end
data/locales/en.yml DELETED
@@ -1,230 +0,0 @@
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
- # Community validations
183
- # ---------------------
184
- community:
185
- configuration: >
186
- The Stove configuration for the Chef community site does not exist! In
187
- order to perform operations against the Chef community site, you must
188
- set your username and path to your client key in the community section
189
- of the `~/.stove' file:
190
-
191
- {
192
- "community": {
193
- "username": "YOUR_USERNAME",
194
- "key": "YOUR_KEY_PATH"
195
- }
196
- }
197
-
198
- key: >
199
- The Stove configuration for the Chef community site does not contain a
200
- key. In order to use the Chef community site features, you must set
201
- the path to your key the community section of the `~/.stove' file:
202
-
203
- {
204
- "community": {
205
- "key": "YOUR_KEY_PATH"
206
- }
207
- }
208
-
209
- username: >
210
- The Stove configuration for the Chef community site does not contain a
211
- username. In order to use the Chef community site features, you must
212
- set a username the community section of the `~/.stove' file:
213
-
214
- {
215
- "community": {
216
- "username": "YOUR_USERNAME"
217
- }
218
- }
219
-
220
- category: >
221
- You did not specify a category! The Chef community site requires all
222
- cookbooks belong to a category. For existing cookboks, Stove can query
223
- the Chef community site API and automatically complete the category
224
- for you. However, for new cookbooks, you must specify the `--category'
225
- flag at runtime:
226
-
227
- bake x.y.z --category Utilities
228
-
229
- For a complete listing of categories, please see the Chef community
230
- site.