stove 5.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 86092b84ffa5f03569b57944b56f09c82c0b24a9
4
- data.tar.gz: b42a43be5248d0ab029a93abf3a54e906521a88b
3
+ metadata.gz: 8a7b6e003eaa819a032278c65bdb28317ba36543
4
+ data.tar.gz: 71ab7d2ff0f46152784c3e4d0d60dec1cf157f01
5
5
  SHA512:
6
- metadata.gz: 7f694c9b7f8921db5683cfdc2fd326e2458545a54ba5ac9eb9ff17c5ed6e463343404a7f57ba45a55d29b8da43b429d35ca1f3037b79ff7a44ad0436d019807a
7
- data.tar.gz: a79d23a0c76f6917ef065a3a8b09afc5e78bcc2218326efb8eef091ee35bc69e300579038818d5e9a8a1e74a0d6d2d0ab7dc46580ad3b8d33145e5795846f0fd
6
+ metadata.gz: cf2361dfafbaaca8e631d0b807f6b08c9fb0c1322c0865a7ac1188fc07c1e3ada760b4bd2af1712f2e295b5595d8bd3cc0869e82a534d0f0fd71f97ea953c5c7
7
+ data.tar.gz: a8a0a61d146ac8c7df835a5ff6613528d69c664e293edbffeca7fd7b8a9c8cf34f642f7a2c2492360615ac0c75b8f42116d96d299ea485ce637156692ed83ec1
@@ -2,6 +2,10 @@
2
2
 
3
3
  This is the Changelog for the Stove gem.
4
4
 
5
+ ## v5.2.0 (2017-05-12)
6
+
7
+ - Support for uploading to Artifactory
8
+
5
9
  ## v5.1.0 (2017-03-31)
6
10
 
7
11
  - Match Chef's metadata behavior with chef_version and ohai_version to allow version constraints like '>= 12.5', '< 14'
data/README.md CHANGED
@@ -76,6 +76,21 @@ And then use rake to publish the cookbook:
76
76
  $ bin/rake publish
77
77
  ```
78
78
 
79
+ ## Artifactory Support
80
+
81
+ In addition to uploading to a standard [Supermarket](https://github.com/chef/supermarket) server, Stove can upload to an Artifactory repository [configured to be in Chef mode](https://www.jfrog.com/confluence/display/RTF/Chef+Cookbook+Repositories).
82
+
83
+ You specify the URL to upload to via `--artifactory`, which you can find the URL Artifactory repository configuration. Your API key can be specified either in the `$ARTIFACTORY_API_KEY` environment variable or via `--artifactory-key`:
84
+
85
+ ```bash
86
+ # API key in $ARTIFACTORY_API_KEY
87
+ $ stove --artifactory https://artifactory.example.com/api/chef/nameofrepo
88
+ # API key in a file
89
+ $ stove --artifactory https://artifactory.example.com/api/chef/nameofrepo --artifactory-key=@path/to/key/file
90
+ # API key on the command line
91
+ $ stove --artifactory https://artifactory.example.com/api/chef/nameofrepo --artifactory-key=XZg6tefUZYfiglmSbQ1s1e6habk
92
+ ```
93
+
79
94
  ## Contributing
80
95
 
81
96
  1. Fork it
@@ -2,18 +2,19 @@ require 'logify'
2
2
  require 'pathname'
3
3
 
4
4
  module Stove
5
- autoload :Community, 'stove/community'
6
- autoload :Config, 'stove/config'
7
- autoload :Cookbook, 'stove/cookbook'
8
- autoload :Cli, 'stove/cli'
9
- autoload :Error, 'stove/error'
10
- autoload :Filter, 'stove/filter'
11
- autoload :Mash, 'stove/mash'
12
- autoload :Packager, 'stove/packager'
13
- autoload :Runner, 'stove/runner'
14
- autoload :Util, 'stove/util'
15
- autoload :Validator, 'stove/validator'
16
- autoload :VERSION, 'stove/version'
5
+ autoload :Artifactory, 'stove/artifactory'
6
+ autoload :Community, 'stove/community'
7
+ autoload :Config, 'stove/config'
8
+ autoload :Cookbook, 'stove/cookbook'
9
+ autoload :Cli, 'stove/cli'
10
+ autoload :Error, 'stove/error'
11
+ autoload :Filter, 'stove/filter'
12
+ autoload :Mash, 'stove/mash'
13
+ autoload :Packager, 'stove/packager'
14
+ autoload :Runner, 'stove/runner'
15
+ autoload :Util, 'stove/util'
16
+ autoload :Validator, 'stove/validator'
17
+ autoload :VERSION, 'stove/version'
17
18
 
18
19
  module Middleware
19
20
  autoload :ChefAuthentication, 'stove/middlewares/chef_authentication'
@@ -28,9 +29,10 @@ module Stove
28
29
  end
29
30
 
30
31
  module Plugin
31
- autoload :Base, 'stove/plugins/base'
32
- autoload :Community, 'stove/plugins/community'
33
- autoload :Git, 'stove/plugins/git'
32
+ autoload :Artifactory, 'stove/plugins/artifactory'
33
+ autoload :Base, 'stove/plugins/base'
34
+ autoload :Community, 'stove/plugins/community'
35
+ autoload :Git, 'stove/plugins/git'
34
36
  end
35
37
 
36
38
  #
@@ -0,0 +1,83 @@
1
+ require 'net/http'
2
+
3
+ module Stove
4
+ class Artifactory
5
+ include Mixin::Instanceable
6
+
7
+ #
8
+ # Upload a cookbook to an Artifactory server.
9
+ #
10
+ # @param [Cookbook] cookbook
11
+ # the cookbook to upload
12
+ #
13
+ def upload(cookbook, extended_metadata = false)
14
+ # Artifactory doesn't prevent uploading over an existing release in
15
+ # some cases so let's check for that. Seriously never do this, go delete
16
+ # and then re-upload if you have to.
17
+ response = request(:get, "api/v1/cookbooks/#{cookbook.name}/versions/#{cookbook.version}")
18
+ # Artifactory's version of the cookbook_version endpoint returns an
19
+ # empty 200 on an unknown version.
20
+ unless response.code == '404' || (response.code == '200' && response.body.to_s == '')
21
+ raise Error::CookbookAlreadyExists.new(cookbook: cookbook)
22
+ end
23
+
24
+ # Run the upload.
25
+ response = request(:post, "api/v1/cookbooks/#{cookbook.name}.tgz") do |req|
26
+ req.body_stream = cookbook.tarball(extended_metadata)
27
+ req.content_length = req.body_stream.size
28
+ req['Content-Type'] = 'application/x-binary'
29
+ end
30
+ response.error! unless response.code == '201'
31
+ end
32
+
33
+ private
34
+
35
+ #
36
+ # Create an HTTP connect to the Artifactory server.
37
+ #
38
+ # @return [Net::HTTP]
39
+ #
40
+ def connection
41
+ @connection ||= begin
42
+ uri = URI(Config.artifactory.strip)
43
+ # Open the HTTP connection to artifactory.
44
+ http = Net::HTTP.new(uri.host, uri.port)
45
+ if uri.scheme == 'https'
46
+ http.use_ssl = true
47
+ # Mimic the behavior of the Cookbook uploader for SSL verification.
48
+ if ENV['STOVE_NO_SSL_VERIFY'] || !Config.ssl_verify
49
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
50
+ end
51
+ end
52
+ http.start
53
+ end
54
+ end
55
+
56
+ #
57
+ # Send an HTTP request to the Artifactory server.
58
+ #
59
+ # @param [Symbol] method
60
+ # HTTP method to use
61
+ #
62
+ # @param [String] path
63
+ # URI path to request
64
+ #
65
+ # @param [Proc] block
66
+ # Optional block to set request values
67
+ #
68
+ # @return [Net::HTTPResponse]
69
+ #
70
+ def request(method, path, &block)
71
+ uri_string = Config.artifactory.strip
72
+ # Make sure we end up with the right number of separators.
73
+ uri_string << '/' unless uri_string.end_with?('/')
74
+ uri_string << path
75
+ uri = URI(uri_string)
76
+ request = Net::HTTP.const_get(method.to_s.capitalize).new(uri)
77
+ request['X-Jfrog-Art-Api'] = Config.artifactory_key.strip
78
+ block.call(request) if block
79
+ connection.request(request)
80
+ end
81
+
82
+ end
83
+ end
@@ -36,10 +36,12 @@ module Stove
36
36
  end
37
37
 
38
38
  # Override configs
39
- Config.endpoint = options[:endpoint] if options[:endpoint]
40
- Config.username = options[:username] if options[:username]
41
- Config.key = options[:key] if options[:key]
42
- Config.ssl_verify = options[:ssl_verify]
39
+ Config.endpoint = options[:endpoint] if options[:endpoint]
40
+ Config.username = options[:username] if options[:username]
41
+ Config.key = options[:key] if options[:key]
42
+ Config.artifactory = options[:artifactory] if options[:artifactory]
43
+ Config.artifactory_key = options[:artifactory_key] if options[:artifactory_key]
44
+ Config.ssl_verify = options[:ssl_verify]
43
45
 
44
46
  # Set the log level
45
47
  Stove.log_level = options[:log_level]
@@ -141,6 +143,23 @@ module Stove
141
143
  options[:sign] = true
142
144
  end
143
145
 
146
+ opts.separator ''
147
+ opts.separator 'Artifactory Options:'
148
+
149
+ opts.on('--artifactory [URL]', 'URL for the Artifactory repository') do |v|
150
+ options[:artifactory] = v
151
+ end
152
+
153
+ opts.on('--artifactory-key [KEY]', 'Artifactory API key to use') do |v|
154
+ options[:artifactory_key] = if v[0] == '@'
155
+ # If passed a key looking like @foo, read it as a file. This allows
156
+ # passing in the key securely.
157
+ IO.read(File.expand_path(v[1..-1]))
158
+ else
159
+ v
160
+ end
161
+ end
162
+
144
163
  opts.separator ''
145
164
  opts.separator 'Global Options:'
146
165
 
@@ -182,6 +201,10 @@ module Stove
182
201
  :branch => 'master',
183
202
  :sign => false,
184
203
 
204
+ # Artifactory options
205
+ :artifactory => false,
206
+ :artifactory_key => ENV['ARTIFACTORY_API_KEY'],
207
+
185
208
  # Global options
186
209
  :log_level => :warn,
187
210
  :path => Dir.pwd,
@@ -63,7 +63,7 @@ module Stove
63
63
  end
64
64
 
65
65
  #
66
- # Delete the given cookbook from the communit site.
66
+ # Delete the given cookbook from the community site.
67
67
  #
68
68
  # @param [String] name
69
69
  # the name of the cookbook to delete
@@ -40,6 +40,7 @@ module Stove
40
40
  class GitFailed < StoveError; end
41
41
  class MetadataNotFound < StoveError; end
42
42
  class ServerUnavailable < StoveError; end
43
+ class CookbookAlreadyExists < StoveError; end
43
44
 
44
45
  # Validations
45
46
  class ValidationFailed < StoveError; end
@@ -49,5 +50,6 @@ module Stove
49
50
  class GitCleanValidationFailed < ValidationFailed; end
50
51
  class GitRepositoryValidationFailed < ValidationFailed; end
51
52
  class GitUpToDateValidationFailed < ValidationFailed; end
53
+ class ArtifactoryKeyValidationFailed < ValidationFailed; end
52
54
  end
53
55
  end
@@ -0,0 +1,14 @@
1
+ module Stove
2
+ class Plugin::Artifactory < Plugin::Base
3
+ id 'artifactory'
4
+ description 'Publish the release to an Artifactory server'
5
+
6
+ validate(:key) do
7
+ Config.artifactory_key && !Config.artifactory_key.strip.empty?
8
+ end
9
+
10
+ run('Publishing the release to the Artifactory server') do
11
+ Artifactory.upload(cookbook, options[:extended_metadata])
12
+ end
13
+ end
14
+ end
@@ -12,7 +12,11 @@ module Stove
12
12
 
13
13
  def run
14
14
  run_plugin :git
15
- run_plugin :community
15
+ if Config.artifactory
16
+ run_plugin :artifactory
17
+ else
18
+ run_plugin :community
19
+ end
16
20
  end
17
21
 
18
22
  private
@@ -1,3 +1,3 @@
1
1
  module Stove
2
- VERSION = '5.1.0'
2
+ VERSION = '5.2.0'
3
3
  end
@@ -0,0 +1 @@
1
+ default['key'] = 'value'
@@ -0,0 +1,2 @@
1
+ name 'stove_integration_test'
2
+ version '1.0.0'
@@ -0,0 +1 @@
1
+ log 'this is a test recipe'
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ # This integration test uses some environment variables to configure which
4
+ # Artifactory server to talk to, as there is no ArtifactoryZero to test against.
5
+ # If those aren't present, we skip the tests.
6
+ #
7
+ # $TEST_STOVE_ARTIFACTORY - URL to the Chef virtual repository.
8
+ # $TEST_STOVE_ARTIFACTORY_REAL - URL to the non-virtual repository.
9
+ # $TEST_STOVE_ARTIFACTORY_API_KEY - API key to use.
10
+
11
+ describe 'artifactory integration test', artifactory_integration: true do
12
+ include RSpecCommand
13
+ let(:upload_url) { ENV['TEST_STOVE_ARTIFACTORY'] }
14
+ let(:delete_url) { ENV['TEST_STOVE_ARTIFACTORY_REAL'] }
15
+ let(:api_key) { ENV['TEST_STOVE_ARTIFACTORY_API_KEY'] }
16
+ around do |ex|
17
+ WebMock.disable!
18
+ request(:delete, "#{delete_url}/stove_integration_test")
19
+ begin
20
+ ex.run
21
+ ensure
22
+ request(:delete, "#{delete_url}/stove_integration_test")
23
+ WebMock.enable!
24
+ end
25
+ end
26
+
27
+ def request(method, url)
28
+ uri = URI(url)
29
+ req = Net::HTTP.const_get(method.to_s.capitalize).new(uri)
30
+ req['X-Jfrog-Art-Api'] = api_key
31
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
32
+ http.request(req)
33
+ end
34
+ end
35
+
36
+ let(:upload) { JSON.parse(request(:get, "#{upload_url}/api/v1/cookbooks/stove_integration_test/versions/1.0.0").body) }
37
+
38
+ describe 'help output' do
39
+ command 'stove --help'
40
+ its(:stdout) { is_expected.to include('--artifactory ').and(include('--artifactory-key ')) }
41
+ end
42
+
43
+ describe 'uploading a cookbook' do
44
+ context 'with no key' do
45
+ fixture_file 'integration_cookbook'
46
+ command(nil, allow_error: true) { "stove --no-git --artifactory #{upload_url}" }
47
+
48
+ it 'fails to upload' do
49
+ expect(subject.exitstatus).to_not eq 0
50
+ expect(subject.stdout).to match /You did not specify and Artifactory API key/
51
+ end
52
+ end
53
+
54
+ context 'with $ARTIFACTORY_API_KEY' do
55
+ before { _environment['ARTIFACTORY_API_KEY'] = api_key }
56
+ fixture_file 'integration_cookbook'
57
+ command { "stove --no-git --artifactory #{upload_url}" }
58
+
59
+ it 'uploads the cookbook' do
60
+ expect(subject.stdout).to eq ''
61
+ expect(upload['version']).to eq '1.0.0'
62
+ end
63
+ end
64
+
65
+ context 'with --artifactory-key=@key' do
66
+ fixture_file 'integration_cookbook'
67
+ file('key') { api_key }
68
+ command { "stove --no-git --artifactory #{upload_url} --artifactory-key=@key" }
69
+
70
+ it 'uploads the cookbook' do
71
+ expect(subject.stdout).to eq ''
72
+ expect(upload['version']).to eq '1.0.0'
73
+ end
74
+ end
75
+
76
+ context 'with --artifactory-key=key' do
77
+ fixture_file 'integration_cookbook'
78
+ file('key') { api_key }
79
+ # Using allow_error here so the command isn't shown if things fail.
80
+ command(nil, allow_error: true) { "stove --no-git --artifactory #{upload_url} --artifactory-key=#{api_key}" }
81
+
82
+ it 'uploads the cookbook' do
83
+ expect(subject.stdout).to eq ''
84
+ expect(subject.exitstatus).to eq 0
85
+ expect(upload['version']).to eq '1.0.0'
86
+ end
87
+ end
88
+
89
+ end
90
+ end
@@ -1,4 +1,6 @@
1
1
  require 'rspec'
2
+ require 'webmock/rspec'
3
+ require 'rspec_command'
2
4
  require 'stove'
3
5
 
4
6
  RSpec.configure do |config|
@@ -8,13 +10,17 @@ RSpec.configure do |config|
8
10
 
9
11
  # Basic configuraiton
10
12
  config.run_all_when_everything_filtered = true
11
- config.filter_run(:focus)
13
+ config.filter_run(:focus) unless ENV['CI']
12
14
 
13
15
  # Run specs in random order to surface order dependencies. If you find an
14
16
  # order dependency and want to debug it, you can fix the order by providing
15
17
  # the seed, which is printed after each run.
16
18
  # --seed 1234
17
19
  config.order = 'random'
20
+
21
+ # Don't try running the Artifactory integration tests without the config for it.
22
+ # See integration/artifactory_spec for more info.
23
+ config.filter_run_excluding(:artifactory_integration) unless ENV['TEST_STOVE_ARTIFACTORY']
18
24
  end
19
25
 
20
26
  def tmp_path
@@ -0,0 +1,131 @@
1
+ require 'spec_helper'
2
+
3
+ # Can't use a double() for this because of the late-binding way StoveError
4
+ # renders the Erb content, which is after the example ends.
5
+ FakeCookbook = Struct.new(:name, :version)
6
+
7
+ describe Stove::Artifactory do
8
+ before { Stove::Config.ssl_verify = true }
9
+
10
+ describe '.upload' do
11
+ let(:cookbook) { FakeCookbook.new('testcook', '1.2.3') }
12
+ subject { described_class.upload(cookbook) }
13
+ before do
14
+ # Default configuration for the test.
15
+ Stove::Config.artifactory = 'https://artifactory.example/api/chef/chef'
16
+ Stove::Config.artifactory_key = 'secret'
17
+ # cookbook.tarball() stub.
18
+ allow(cookbook).to receive(:tarball) {|ext| StringIO.new(ext ? 'extended' : 'simple') }
19
+ end
20
+
21
+ context 'with defaults' do
22
+ it 'uploads the file' do
23
+ stub_request(:get, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook/versions/1.2.3').with(headers: {'X-Jfrog-Art-Api' => 'secret'}).to_return(body: '')
24
+ stub_request(:post, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook.tgz').with(headers: {'X-Jfrog-Art-Api' => 'secret'}, body: 'simple').to_return(status: 201)
25
+ expect { subject }.to_not raise_error
26
+ end
27
+ end
28
+
29
+ context 'with a 404 for an unknown cookbook' do
30
+ # This is how real Supermarket returns a non-existent cookbook so make sure it works with that too.
31
+ it 'uploads the file' do
32
+ stub_request(:get, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook/versions/1.2.3').with(headers: {'X-Jfrog-Art-Api' => 'secret'}).to_return(status: 404, body: '{some json error}')
33
+ stub_request(:post, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook.tgz').with(headers: {'X-Jfrog-Art-Api' => 'secret'}, body: 'simple').to_return(status: 201)
34
+ expect { subject }.to_not raise_error
35
+ end
36
+ end
37
+
38
+ context 'with extended_metadata = true' do
39
+ subject { described_class.upload(cookbook, true) }
40
+ it 'uploads with extended metadata' do
41
+ stub_request(:get, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook/versions/1.2.3').with(headers: {'X-Jfrog-Art-Api' => 'secret'}).to_return(body: '')
42
+ stub_request(:post, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook.tgz').with(headers: {'X-Jfrog-Art-Api' => 'secret'}, body: 'extended').to_return(status: 201)
43
+ expect { subject }.to_not raise_error
44
+ end
45
+ end
46
+
47
+ context 'with a colliding upload' do
48
+ it 'should raise an exception' do
49
+ stub_request(:get, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook/versions/1.2.3').with(headers: {'X-Jfrog-Art-Api' => 'secret'}).to_return(body: '{some json}')
50
+ expect { subject }.to raise_error Stove::Error::CookbookAlreadyExists
51
+ end
52
+ end
53
+
54
+ context 'with a failed upload' do
55
+ it 'uploads the file' do
56
+ stub_request(:get, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook/versions/1.2.3').with(headers: {'X-Jfrog-Art-Api' => 'secret'}).to_return(body: '')
57
+ stub_request(:post, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook.tgz').with(headers: {'X-Jfrog-Art-Api' => 'secret'}, body: 'simple').to_return(status: 500)
58
+ expect { subject }.to raise_error Net::HTTPFatalError
59
+ end
60
+ end
61
+
62
+ context 'with a newline in the API key' do
63
+ before { Stove::Config.artifactory_key = "secret\n" }
64
+ it 'uploads the file' do
65
+ stub_request(:get, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook/versions/1.2.3').with(headers: {'X-Jfrog-Art-Api' => 'secret'}).to_return(body: '')
66
+ stub_request(:post, 'https://artifactory.example/api/chef/chef/api/v1/cookbooks/testcook.tgz').with(headers: {'X-Jfrog-Art-Api' => 'secret'}, body: 'simple').to_return(status: 201)
67
+ expect { subject }.to_not raise_error
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ # Break encapsulation a bit to test the ssl_verify configuration.
74
+ describe '#connection' do
75
+ let(:url) { 'https://artifactory.example/api/chef/chef' }
76
+ let(:http) { double('Net::HTTP') }
77
+ # Make sure we don't use the singleton instance so this stub HTTP object
78
+ # doesn't get cached on it.
79
+ subject { described_class.send(:new).send(:connection) }
80
+ before do
81
+ allow(http).to receive(:start).and_return(http)
82
+ Stove::Config.artifactory = url
83
+ end
84
+
85
+ context 'with an HTTPS URI' do
86
+ it 'enables TLS' do
87
+ expect(Net::HTTP).to receive(:new).with('artifactory.example', 443).and_return(http)
88
+ expect(http).to receive(:use_ssl=).with(true)
89
+ expect(subject).to eq http
90
+ end
91
+ end
92
+
93
+ context 'with an HTTP URI' do
94
+ let(:url) { 'http://artifactory.example/api/chef/chef' }
95
+ it 'does not enable TLS' do
96
+ expect(Net::HTTP).to receive(:new).with('artifactory.example', 80).and_return(http)
97
+ expect(http).to_not receive(:use_ssl=)
98
+ expect(subject).to eq http
99
+ end
100
+ end
101
+
102
+ context 'with Config.ssl_verify = false' do
103
+ before { Stove::Config.ssl_verify = false }
104
+ it 'sets verify mode VERIFY_NONE' do
105
+ expect(Net::HTTP).to receive(:new).with('artifactory.example', 443).and_return(http)
106
+ expect(http).to receive(:use_ssl=).with(true)
107
+ expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
108
+ expect(subject).to eq http
109
+ end
110
+ end
111
+
112
+ context 'with $STOVE_NO_SSL_VERIFY' do
113
+ around do |ex|
114
+ old_value = ENV['STOVE_NO_SSL_VERIFY']
115
+ ENV['STOVE_NO_SSL_VERIFY'] = 'true'
116
+ begin
117
+ ex.run
118
+ ensure
119
+ ENV['STOVE_NO_SSL_VERIFY'] = old_value
120
+ end
121
+ end
122
+ it 'sets verify mode VERIFY_NONE' do
123
+ expect(Net::HTTP).to receive(:new).with('artifactory.example', 443).and_return(http)
124
+ expect(http).to receive(:use_ssl=).with(true)
125
+ expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
126
+ expect(subject).to eq http
127
+ end
128
+ end
129
+
130
+ end
131
+ end
@@ -29,4 +29,6 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency 'community-zero', '~> 2.0'
30
30
  spec.add_development_dependency 'rake'
31
31
  spec.add_development_dependency 'rspec', '~> 3.0'
32
+ spec.add_development_dependency 'rspec-command', '~> 1.0'
33
+ spec.add_development_dependency 'webmock', '~> 3.0'
32
34
  end
@@ -0,0 +1,11 @@
1
+ You did not specify an Artifactory API key! You can pass the key either via a command line argument:
2
+
3
+ stove --artifactory-key sUeEpLXJvfhw3UZHbVPrGCgdou8VI6fXpD5sUHd0pKAxCmuGWNHLgerpFPkCJ2EjBBPYcM4My
4
+
5
+ Or via a file path:
6
+
7
+ stove --artifactory-key @~/.artifactory/api.key
8
+
9
+ Or via an environment variable:
10
+
11
+ export ARTIFACTORY_API_KEY=sUeEpLXJvfhw3UZHbVPrGCgdou8VI6fXpD5sUHd0pKAxCmuGWNHLgerpFPkCJ2EjBBPYcM4My
@@ -0,0 +1,5 @@
1
+ Cookbook <%= @cookbook.name %> already has a version <%= @cookbook.version %> uploaded.
2
+
3
+ Please change the version number before uploading again.
4
+
5
+ If you need to change an existing version, please remove it first.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stove
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seth Vargo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-31 00:00:00.000000000 Z
11
+ date: 2017-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef-api
@@ -108,6 +108,34 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '3.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec-command
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: webmock
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
111
139
  description: A utility for releasing Chef community cookbooks
112
140
  email:
113
141
  - sethvargo@gmail.com
@@ -137,6 +165,7 @@ files:
137
165
  - features/support/stove.pem
138
166
  - features/support/stove/git.rb
139
167
  - lib/stove.rb
168
+ - lib/stove/artifactory.rb
140
169
  - lib/stove/cli.rb
141
170
  - lib/stove/community.rb
142
171
  - lib/stove/config.rb
@@ -150,6 +179,7 @@ files:
150
179
  - lib/stove/mixins/optionable.rb
151
180
  - lib/stove/mixins/validatable.rb
152
181
  - lib/stove/packager.rb
182
+ - lib/stove/plugins/artifactory.rb
153
183
  - lib/stove/plugins/base.rb
154
184
  - lib/stove/plugins/community.rb
155
185
  - lib/stove/plugins/git.rb
@@ -158,15 +188,22 @@ files:
158
188
  - lib/stove/util.rb
159
189
  - lib/stove/validator.rb
160
190
  - lib/stove/version.rb
191
+ - spec/fixtures/integration_cookbook/attributes/default.rb
192
+ - spec/fixtures/integration_cookbook/metadata.rb
193
+ - spec/fixtures/integration_cookbook/recipes/default.rb
194
+ - spec/integration/artifactory_spec.rb
161
195
  - spec/integration/cookbook_spec.rb
162
196
  - spec/spec_helper.rb
163
197
  - spec/support/generators.rb
198
+ - spec/unit/artifactory_spec.rb
164
199
  - spec/unit/cookbook/metadata_spec.rb
165
200
  - spec/unit/error_spec.rb
166
201
  - stove.gemspec
167
202
  - templates/errors/abstract_method.erb
203
+ - templates/errors/artifactory_key_validation_failed.erb
168
204
  - templates/errors/community_key_validation_failed.erb
169
205
  - templates/errors/community_username_validation_failed.erb
206
+ - templates/errors/cookbook_already_exists.erb
170
207
  - templates/errors/git_clean_validation_failed.erb
171
208
  - templates/errors/git_failed.erb
172
209
  - templates/errors/git_repository_validation_failed.erb
@@ -209,8 +246,13 @@ test_files:
209
246
  - features/support/env.rb
210
247
  - features/support/stove.pem
211
248
  - features/support/stove/git.rb
249
+ - spec/fixtures/integration_cookbook/attributes/default.rb
250
+ - spec/fixtures/integration_cookbook/metadata.rb
251
+ - spec/fixtures/integration_cookbook/recipes/default.rb
252
+ - spec/integration/artifactory_spec.rb
212
253
  - spec/integration/cookbook_spec.rb
213
254
  - spec/spec_helper.rb
214
255
  - spec/support/generators.rb
256
+ - spec/unit/artifactory_spec.rb
215
257
  - spec/unit/cookbook/metadata_spec.rb
216
258
  - spec/unit/error_spec.rb