stove 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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.