knife-artifactory 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d57af63a2e4d97bd447477bd0ae1a3fe8dd4e10fff29f98e249a2c3945aa2b28
4
- data.tar.gz: 9deb1ef44897e7c12fe6a0ec4e440809d55df05a70d662f1008d1734a45447e2
3
+ metadata.gz: 87c86116d7a6ea38d43bdef6c785a84a332195886cb5ae80bcdac8c22df38ae5
4
+ data.tar.gz: 72f5782c99a6684a147090c9e2bedc8623beefc715077d1cbb38d9097599e4a6
5
5
  SHA512:
6
- metadata.gz: abff25d20f732130844ad178c00cf8a7149251220c3efd470405dd4111692812d8b31f6916a251978a7a772548beb3596244cf09b3fa5aba731aaed82fa01d8b
7
- data.tar.gz: 11575c085633e4bfd13fecd9a39e00a4728dee1fed23a5107224b388afc7e33f9d6d4ab2baeb8bf5025d2d97c620e8706e8360c41e6f233fde41bfdf15e566af
6
+ metadata.gz: 50d717bf5443e36954f1109464ed7ba7b538cea20ca533c57768352ed17aeb9ce495af2461f65eec8dcd0ad7421cada25a213b9579268fde9eec960c1504acf5
7
+ data.tar.gz: 697352d1bc0e7b90c87146df58e10a7dec0cf5cf88d7a3e4ecde748844f54cd956a9228f11dac81e3b1bf0699f9d8e6fc4be042834182662f44727951f639251
@@ -1,15 +1,15 @@
1
- # Overrides the default Chef::Knife::CookbookSiteShare to allow basic authentication against an Artifactory backend.
1
+ # Overrides the default Chef::Knife::SupermarketShare to allow basic authentication against an Artifactory backend.
2
2
  # Ideally we would like to use a mechanism that allows injecting pluggable authentication middleware into the Chef::Http
3
3
  # REST clients, but in the interest of allowing not-only-newest knife client versions to work with Artifactory we chose
4
4
  # this solution for now.
5
5
 
6
- require 'chef/knife'
7
- require 'chef/knife/cookbook_site_download'
8
- require 'knife-artifactory/utils'
6
+ require "chef/knife"
7
+ require "chef/knife/cookbook_site_download"
8
+ require "knife-artifactory/utils"
9
9
 
10
10
  class Chef
11
11
  class Knife
12
- class ArtifactoryDownload < Knife::CookbookSiteDownload
12
+ class ArtifactoryDownload < Knife::SupermarketDownload
13
13
 
14
14
  dependency_loaders.concat(superclass.dependency_loaders)
15
15
  options.merge!(superclass.options)
@@ -32,7 +32,7 @@ class Chef
32
32
 
33
33
  def current_cookbook_data
34
34
  unless config[:artifactory_download]
35
- Chef::Log.debug('[KNIFE-ART] ArtifactoryDownload::current_cookbook_data called without artifactory flag, delegating to super')
35
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryDownload::current_cookbook_data called without artifactory flag, delegating to super")
36
36
  return orig_current_cookbook_data
37
37
  end
38
38
  @current_cookbook_data ||= begin
@@ -42,15 +42,15 @@ class Chef
42
42
 
43
43
  def desired_cookbook_data
44
44
  unless config[:artifactory_download]
45
- Chef::Log.debug('[KNIFE-ART] ArtifactoryDownload::desired_cookbook_data called without artifactory flag, delegating to super')
45
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryDownload::desired_cookbook_data called without artifactory flag, delegating to super")
46
46
  return orig_desired_cookbook_data
47
47
  end
48
48
  @desired_cookbook_data ||= begin
49
- uri = if @name_args.length == 1
50
- current_cookbook_data["latest_version"]
51
- else
52
- specific_cookbook_version_url
53
- end
49
+ uri = if @name_args.length == 1
50
+ current_cookbook_data["latest_version"]
51
+ else
52
+ specific_cookbook_version_url
53
+ end
54
54
 
55
55
  noauth_rest.get(uri, auth_header)
56
56
  end
@@ -58,7 +58,7 @@ class Chef
58
58
 
59
59
  def download_cookbook
60
60
  unless config[:artifactory_download]
61
- Chef::Log.debug('[KNIFE-ART] ArtifactoryDownload::download_cookbook called without artifactory flag, delegating to super')
61
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryDownload::download_cookbook called without artifactory flag, delegating to super")
62
62
  return orig_download_cookbook
63
63
  end
64
64
  ui.info "Downloading #{@name_args[0]} from Supermarket at version #{version} to #{download_location}"
@@ -70,7 +70,7 @@ class Chef
70
70
 
71
71
  def auth_header
72
72
  @auth_header ||= begin
73
- ::Knife::KnifeArt::KnifeArtUtils.auth_header_from(cookbooks_api_url)
73
+ ::KnifeArtifactory::Utils.auth_header_from(cookbooks_api_url)
74
74
  end
75
75
  end
76
76
 
@@ -1,15 +1,14 @@
1
- # Overrides the default Chef::Knife::CookbookSiteInstall to allow basic authentication against an Artifactory backend.
1
+ # Overrides the default Chef::Knife::SupermarketInstall to allow basic authentication against an Artifactory backend.
2
2
  # Ideally we would like to use a mechanism that allows injecting pluggable authentication middleware into the Chef::Http
3
3
  # REST clients, but in the interest of allowing not-only-newest knife client versions to work with Artifactory we chose
4
4
  # this solution for now.
5
5
 
6
-
7
- require 'chef/knife'
8
- require 'chef/knife/cookbook_site_install'
6
+ require "chef/knife"
7
+ require "chef/knife/cookbook_site_install"
9
8
 
10
9
  class Chef
11
10
  class Knife
12
- class ArtifactoryInstall < Knife::CookbookSiteInstall
11
+ class ArtifactoryInstall < Knife::SupermarketInstall
13
12
 
14
13
  dependency_loaders.concat(superclass.dependency_loaders)
15
14
  options.merge!(superclass.options)
@@ -30,7 +29,7 @@ class Chef
30
29
 
31
30
  def download_cookbook_to(download_path)
32
31
  unless config[:artifactory_install]
33
- Chef::Log.debug('[KNIFE-ART] ArtifactoryInstall::download_cookbook_to called without artifactory flag, delegating to super')
32
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryInstall::download_cookbook_to called without artifactory flag, delegating to super")
34
33
  return orig_download_cookbook_to(download_path)
35
34
  end
36
35
  downloader = Chef::Knife::ArtifactoryDownload.new
@@ -1,10 +1,10 @@
1
1
 
2
- require 'chef/knife'
3
- require 'chef/knife/cookbook_site_list'
2
+ require "chef/knife"
3
+ require "chef/knife/cookbook_site_list"
4
4
 
5
5
  class Chef
6
6
  class Knife
7
- class ArtifactoryList < Knife::CookbookSiteList
7
+ class ArtifactoryList < Knife::SupermarketList
8
8
 
9
9
  dependency_loaders.concat(superclass.dependency_loaders)
10
10
  options.merge!(superclass.options)
@@ -1,10 +1,10 @@
1
1
 
2
- require 'chef/knife'
3
- require 'chef/knife/cookbook_site_search'
2
+ require "chef/knife"
3
+ require "chef/knife/cookbook_site_search"
4
4
 
5
5
  class Chef
6
6
  class Knife
7
- class ArtifactorySearch < Knife::CookbookSiteSearch
7
+ class ArtifactorySearch < Knife::SupermarketSearch
8
8
 
9
9
  dependency_loaders.concat(superclass.dependency_loaders)
10
10
  options.merge!(superclass.options)
@@ -2,19 +2,18 @@
2
2
  # 1. allow passing flags to the super class so that the do_upload method of this
3
3
  # class is called and that signing key verification is skipped by the underlying Chef::HTTP::Authenticator that's
4
4
  # used with the rest client (see comment below).
5
- # 2. Override (monkey patch) the required methods in Chef::HTTP::Authenticator and Knife::CookbookSiteShare
5
+ # 2. Override (monkey patch) the required methods in Chef::HTTP::Authenticator and Knife::SupermarketShare
6
6
  # to allow inserting our own logic that deploys a cookbook to Artifactory.
7
7
  #
8
8
  # The Supermarket API is kept (post /api/v1/cookbooks/cookbook_name) by Artifactory although it does not currently
9
9
  # return a correct response (it simply returns 200) due to performance considerations.
10
10
 
11
-
12
- require 'chef/knife'
13
- require 'chef/knife/cookbook_site_share'
11
+ require "chef/knife"
12
+ require "chef/knife/cookbook_site_share"
14
13
 
15
14
  class Chef
16
15
  class Knife
17
- class ArtifactoryShare < Knife::CookbookSiteShare
16
+ class ArtifactoryShare < Knife::SupermarketShare
18
17
 
19
18
  dependency_loaders.concat(superclass.dependency_loaders)
20
19
  options.merge!(superclass.options)
@@ -22,34 +21,94 @@ class Chef
22
21
  banner "knife artifactory share COOKBOOK [CATEGORY] (options)"
23
22
  category "artifactory"
24
23
 
24
+ option :overwrite_cookbook,
25
+ long: "--[no-]overwrite-cookbook",
26
+ boolean: true,
27
+ default: true,
28
+ description: "Overwrite existing cookbook version if it already exists. Default is yes."
29
+
25
30
  alias_method :orig_run, :run
26
31
  alias_method :orig_get_category, :get_category
27
32
  alias_method :orig_do_upload, :do_upload
28
33
 
29
34
  def run
30
- begin
31
35
  # I'm forced to use threadlocal until we find a better solution... can't really find a way to pass configuration
32
36
  # down to the Chef::CookbookUploader, Chef::ServerAPI, Chef::HTTP or Chef::HTTP::Authenticator
33
37
  # (which are created one after another starting) with CookbookUploader to make it skip the signing key verification.
34
38
  # Can make the authenticator skip by passing load_signing_key(nil, nil) and opts[:sign_request] => false
35
- Thread.current[:artifactory_deploy] = 'yes'
39
+ Thread.current[:artifactory_deploy] = "yes"
36
40
  # Send artifactory deploy flag to super
37
41
  config[:artifactory_deploy] = true
38
42
  Chef::Log.debug("[KNIFE-ART] running site share with config: #{config}")
43
+
44
+ if !overwrite_cookbook? && cookbook_versions_in_artifactory.include?(cookbook_version)
45
+ ui.info("Cookbook version already exists, skipping upload.")
46
+ exit(0)
47
+ end
48
+
39
49
  orig_run
40
- ensure
50
+ ensure
41
51
  # always cleanup threadlocal
42
- Thread.current[:artifactory_deploy] = nil
52
+ Thread.current[:artifactory_deploy] = nil
53
+ end
54
+
55
+ #
56
+ # @example
57
+ # cookbook_versions_in_artifactory #=> ["1.0.0", "1.0.1", "1.1.0", "1.2.0"]
58
+ #
59
+ # @return [Array<String>] versions in artifactory
60
+ #
61
+ def cookbook_versions_in_artifactory
62
+ return [] if cookbook_name.nil?
63
+
64
+ data = noauth_rest.get("#{supermarket_uri}/cookbooks/#{cookbook_name}")
65
+ data["metrics"]["downloads"]["versions"].keys
66
+ end
67
+
68
+ #
69
+ # @example
70
+ # cookbook_version #=> 1.0.1
71
+ #
72
+ # @example
73
+ # cookbook_version #=> 0.1.0
74
+ #
75
+ # @example
76
+ # cookbook_version #=> nil
77
+ #
78
+ # @return [String, nil] version of cookbook present in cookbook path or nil if no
79
+ # coobook versions exist locally.
80
+ #
81
+ def cookbook_version
82
+ cl = Chef::CookbookLoader.new(cookbook_path)
83
+ if cl.cookbook_exists?(cookbook_name)
84
+ cookbook = cl[cookbook_name]
85
+ cookbook.version
43
86
  end
44
87
  end
45
88
 
46
89
  private
47
90
 
91
+ def cookbook_name
92
+ @name_args[0] if @name_args.length >= 1
93
+ end
94
+
95
+ def cookbook_path
96
+ config[:cookbook_path] ||= Chef::Config[:cookbook_path]
97
+ end
98
+
99
+ def supermarket_uri
100
+ "#{config[:supermarket_site]}/api/v1"
101
+ end
102
+
103
+ def overwrite_cookbook?
104
+ config[:overwrite_cookbook]
105
+ end
106
+
48
107
  # Pretty much copy paste of the original, just with authentication on the rest client...
49
108
  def get_category(cookbook_name)
50
109
  # Use Artifactory deployment logic only if flag sent by Artifactory plugin
51
110
  unless config[:artifactory_deploy]
52
- Chef::Log.debug('[KNIFE-ART] ArtifactoryShare::get_category called without artifactory flag, delegating to super')
111
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryShare::get_category called without artifactory flag, delegating to super")
53
112
  return orig_get_category(cookbook_name)
54
113
  end
55
114
  begin
@@ -57,7 +116,7 @@ class Chef
57
116
  if data.nil?
58
117
  return data["category"]
59
118
  else
60
- return 'Other'
119
+ return "Other"
61
120
  end
62
121
  rescue => e
63
122
  return "Other" if e.kind_of?(Net::HTTPServerException) && e.response.code == "404"
@@ -65,18 +124,17 @@ class Chef
65
124
  Chef::Log.debug("\n#{e.backtrace.join("\n")}")
66
125
  exit(1)
67
126
  end
68
-
69
127
  end
70
128
 
71
129
  def do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename)
72
130
  # Use Artifactory deployment logic only if flag sent by Artifactory plugin
73
131
  unless config[:artifactory_deploy]
74
- Chef::Log.debug('[KNIFE-ART] ArtifactoryShare::do_upload called without artifactory flag, delegating to super')
132
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryShare::do_upload called without artifactory flag, delegating to super")
75
133
  orig_do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename)
76
134
  return
77
135
  end
78
136
  # cookbook_filename is set as tempDir/cookbook_name in parent
79
- cookbook_name = cookbook_filename.split('/')[-1]
137
+ cookbook_name = cookbook_filename.split("/")[-1]
80
138
  uri = "#{config[:supermarket_site]}/api/v1/cookbooks/#{cookbook_name}"
81
139
  uri += "?category=#{cookbook_category}" if cookbook_category
82
140
  Chef::Log.debug("[KNIFE-ART] Deploying cookbook #{cookbook_name} to Artifactory url at #{uri}")
@@ -85,7 +143,7 @@ class Chef
85
143
  # debug log will be able to show the response Artifactory returned in case of errors.
86
144
  file_contents = File.open(cookbook_filename, "rb") { |f| f.read }
87
145
  # no need to send auth header here, 'normal' HTTP client uses url with credentials from config
88
- rest.post(uri, file_contents, {"content-type" => "application/x-binary"})
146
+ rest.post(uri, file_contents, { "content-type" => "application/x-binary" })
89
147
  end
90
148
 
91
149
  end
@@ -101,11 +159,11 @@ class Chef
101
159
 
102
160
  def load_signing_key(key_file, raw_key = nil)
103
161
  Chef::Log.debug("[KNIFE-ART] global var: #{Thread.current[:artifactory_deploy]}")
104
- if Thread.current.key?(:artifactory_deploy) and Thread.current[:artifactory_deploy].eql? 'yes'
105
- Chef::Log.debug('[KNIFE-ART] Artifactory plugin substituting for Chef::Http::Authenticator --> omitting signing key usage')
162
+ if Thread.current.key?(:artifactory_deploy) && Thread.current[:artifactory_deploy].eql?("yes")
163
+ Chef::Log.debug("[KNIFE-ART] Artifactory plugin substituting for Chef::Http::Authenticator --> omitting signing key usage")
106
164
  @sign_request = false
107
- @raw_key = ''
108
- @key = ''
165
+ @raw_key = ""
166
+ @key = ""
109
167
  else
110
168
  # Artifactory flag not present, call original implementation
111
169
  orig_load_signing_key(key_file, raw_key)
@@ -1,10 +1,10 @@
1
1
 
2
- require 'chef/knife'
3
- require 'chef/knife/cookbook_site_show'
2
+ require "chef/knife"
3
+ require "chef/knife/cookbook_site_show"
4
4
 
5
5
  class Chef
6
6
  class Knife
7
- class ArtifactoryShow < Knife::CookbookSiteShow
7
+ class ArtifactoryShow < Knife::SupermarketShow
8
8
 
9
9
  dependency_loaders.concat(superclass.dependency_loaders)
10
10
  options.merge!(superclass.options)
@@ -1,7 +1,7 @@
1
1
  # More or less copy-pasted from cookbook_site_unshare because the http call happens inside the run method, not much
2
2
  # sense in extending it
3
3
 
4
- require 'chef/knife'
4
+ require "chef/knife"
5
5
 
6
6
  class Chef
7
7
  class Knife
@@ -15,11 +15,11 @@ class Chef
15
15
  category "artifactory"
16
16
 
17
17
  option :supermarket_site,
18
- :short => "-m SUPERMARKET_SITE",
19
- :long => "--supermarket-site SUPERMARKET_SITE",
20
- :description => "Supermarket Site",
21
- :default => "https://supermarket.chef.io",
22
- :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
18
+ short: "-m SUPERMARKET_SITE",
19
+ long: "--supermarket-site SUPERMARKET_SITE",
20
+ description: "Supermarket Site",
21
+ default: "https://supermarket.chef.io",
22
+ proc: Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
23
23
 
24
24
  def run
25
25
  @cookbook_name = @name_args[0]
@@ -41,7 +41,7 @@ class Chef
41
41
  url = "#{cookbooks_api_url}/#{@cookbook_name}/#{@cookbook_version}"
42
42
  noauth_rest.delete(url, auth_header)
43
43
  rescue Net::HTTPServerException => e
44
- raise e unless (e.message =~ /Forbidden/ || e.message =~ /Unauthorized/)
44
+ raise e unless e.message =~ /Forbidden/ || e.message =~ /Unauthorized/
45
45
  ui.error "Forbidden: You must have delete permissions on the target repo to delete #{@cookbook_name}."
46
46
  exit 1
47
47
  end
@@ -57,7 +57,7 @@ class Chef
57
57
 
58
58
  def auth_header
59
59
  @auth_header ||= begin
60
- ::Knife::KnifeArt::KnifeArtUtils.auth_header_from(cookbooks_api_url)
60
+ ::KnifeArtifactory::Utils.auth_header_from(cookbooks_api_url)
61
61
  end
62
62
  end
63
63
 
@@ -1,4 +1,4 @@
1
- require 'base64'
1
+ require "base64"
2
2
 
3
3
  module KnifeArtifactory
4
4
  class Utils
@@ -6,14 +6,14 @@ module KnifeArtifactory
6
6
  def self.auth_header_from(uri)
7
7
  Chef::Log.debug("[KNIFE-ART] in util, got url: #{uri}")
8
8
  begin
9
- url = URI.parse(uri.gsub(%r{/+$}, ""))
10
- Chef::Log.debug("[KNIFE-ART] in util, parsed url: #{uri}")
11
- if url.user and url.password
12
- user = URI.unescape(url.user)
13
- password = URI.unescape(url.password)
14
- return {"Authorization" => "Basic " + Base64.strict_encode64("#{user}:#{password}")}
15
- end
16
- {}
9
+ url = URI.parse(uri.gsub(%r{/+$}, ""))
10
+ Chef::Log.debug("[KNIFE-ART] in util, parsed url: #{uri}")
11
+ if url.user && url.password
12
+ user = URI.unescape(url.user)
13
+ password = URI.unescape(url.password)
14
+ return { "Authorization" => "Basic " + Base64.strict_encode64("#{user}:#{password}") }
15
+ end
16
+ {}
17
17
  end
18
18
  rescue Exception => e
19
19
  Chef::Log.warn("[KNIFE-ART] Unable to parse url: #{uri} --> #{e.message}")
@@ -1,3 +1,3 @@
1
1
  module KnifeArtifactory
2
- VERSION = '0.1.0'
2
+ VERSION = "0.2.0".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-artifactory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Feldman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-23 00:00:00.000000000 Z
11
+ date: 2019-05-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Enables basic authentication support for share and upload operations
14
14
  to Artifactory when it serves as a Supermarket.
@@ -18,13 +18,13 @@ executables: []
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - lib/chef/knife/artifactory_download.rb
22
+ - lib/chef/knife/artifactory_install.rb
23
+ - lib/chef/knife/artifactory_list.rb
24
+ - lib/chef/knife/artifactory_search.rb
25
+ - lib/chef/knife/artifactory_share.rb
21
26
  - lib/chef/knife/artifactory_show.rb
22
- - lib/chef/knife/knife_art_download.rb
23
- - lib/chef/knife/knife_art_install.rb
24
- - lib/chef/knife/knife_art_list.rb
25
- - lib/chef/knife/knife_art_search.rb
26
- - lib/chef/knife/knife_art_share.rb
27
- - lib/chef/knife/knife_art_unshare.rb
27
+ - lib/chef/knife/artifactory_unshare.rb
28
28
  - lib/knife-artifactory/utils.rb
29
29
  - lib/knife-artifactory/version.rb
30
30
  homepage: https://github.com/jasonwbarnett/knife-artifactory