chef-nexus 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 299e66e72b5581163aa8163f83be911991095b08
4
+ data.tar.gz: 678d20d78de9794c2673a96c88da97be19104027
5
+ SHA512:
6
+ metadata.gz: 14decdddf3b530b3564400d2cff09ed8aef4200745df4ad470ffa40df4b1d460ba882f311bad1b3338dd6dcd7b8386fcdd25fd58367dcbe948e0deae83af4ff5
7
+ data.tar.gz: 908bc1459dc537bedb6832990f4b465469af4731f4e2c795eed0212b737d033385da1050af5ebbe2ebc2eddb74dc82bdb7dcf33c546fe564f8bb6d279b65f1b5
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## 0.1.2 (04/28/2016)
4
+ - Added copyright notices
5
+ - Created .rubocop.yml and ran RuboCop
6
+
7
+ ## 0.1.1 (04/04/2016)
8
+ - Fixed bug regarding improper parsing of local_file with names like test.0.0.4.qcow2
9
+ - Now guarding against empty strings for coordinates
10
+
11
+ ## 0.1.0 (03/23/2016)
12
+ - Implemented actions :upload, :download, :delete, :delete_url
13
+ - Created rspec tests
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in chef-nexus.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,224 @@
1
+ # Chef::Nexus
2
+
3
+ chef-nexus is a Ruby gem that provides the `nexus` Chef resource for managing artifacts on Nexus by Sonatype.
4
+
5
+ ## Usage
6
+
7
+ Simply install the gem and `require 'chef/nexus'` in your recipes, then you can use the `nexus` resource.
8
+
9
+ There is an optional Nexus config file that you can create and it will be read in the following order:
10
+ 1. `File.read(ENV['NEXUS_CONFIG'])`
11
+ 2. `File.read("#{ENV['HOME']}/.nexus/config")`
12
+ 3. `File.read('/etc/.nexus/config')`
13
+
14
+ **NOTE:** only the first one found will be loaded
15
+
16
+ Example config file:
17
+ ```json
18
+ {
19
+ "default": {
20
+ "url": "http://mynexus.net/nexus/content/",
21
+ "repo": "name_of_repo",
22
+ "auth": "gary:secr3t"
23
+ },
24
+ "gary": {
25
+ "url": "http://mynexus.net/nexus/content/",
26
+ "repo": "disk_images",
27
+ "auth": "gary:p@ssw0rd"
28
+ }
29
+ }
30
+ ```
31
+
32
+ **NOTE:**
33
+
34
+ * You can pick different profiles with attribute `nexus_profile`
35
+ * You can set you default profile with environment variable `export NEXUS_PROFILE=gary`
36
+ * If you don't set the env variable or use the attributes below - `"default"` profile must be present, or you will need to specify the `nexus_profile` attribute every time.
37
+ * Attribute `nexus_profile` has precedence over environment variable
38
+
39
+ You can also specify these as attributes:
40
+ ```ruby
41
+ nexus_url 'http://mynexus.net/nexus/content/'
42
+ nexus_repo 'name_of_repo'
43
+ nexus_auth 'gary:secr3t'
44
+ ```
45
+
46
+ And as environment variables:
47
+ ```shell
48
+ export NEXUS_URL=http://mynexus.net/nexus/content/
49
+ export NEXUS_REPO=name_of_repo
50
+ export NEXUS_AUTH=gary:secr3t
51
+ ```
52
+
53
+ Order of precedence:
54
+ 1. `attribute`
55
+ 2. `environment`
56
+ 3. `config`
57
+
58
+ ### Attributes
59
+
60
+ ```ruby
61
+ :nexus_profile => String of the profile you want to use
62
+ :nexus_url => String url of Nexus
63
+ :nexus_repo => String name of your repository
64
+ :nexus_auth => String of your Nexus credentials
65
+ :use_auth => Boolean specifing whether to authenticate against the Nexus server, fix for 403 Forbidden
66
+
67
+ :upload_pom => Boolean indicating whether to generate and upload a pom file, default true
68
+ :update_if_exists => Boolean specifying whether to overwrite existing artifacts during upload action (deletes artifact folder first)
69
+
70
+ :local_file => String absolute path to the file to upload from, or download to
71
+ :remote_url => String of the URL to be upload to / download from, if used, all attributes below are ignored. SEE NOTES
72
+
73
+ :coordinates => String Maven coordinates, see: https://maven.apache.org/pom.html#Maven_Coordinates
74
+ :groupId => String name of group
75
+ :artifactId => String name of artifact
76
+ :packaging => String of packaging type
77
+ :classifier => String name of the files classifier
78
+ :version => [String, Fixnum, Float] of the version
79
+ ```
80
+ **NOTE:**
81
+
82
+ * `:remote_url` will be parsed for pom information if it is syntactically correct according to Maven & Nexus standards, as in:
83
+ `<NEXUS_URL>/repositories/<NEXUS_REPO>/<groupId>/<artifactId>/<version>/<artifactId>-<version>-<classifier>.<packaging>`
84
+ * `:remote_url` takes precedence over coordinates as the upload / download endpoint.
85
+ * Usage of `:remote_url` is **NOT RECOMMENDED**
86
+ * Order of precedence during generation of pom file:
87
+ (groupId & artifactId & packaging & classifier & version) > coordinates > remote_url
88
+
89
+ ### Actions
90
+
91
+ ```ruby
92
+ actions :upload, :download, :delete, :delete_url
93
+ default_action :upload
94
+ ```
95
+
96
+ ### Examples
97
+
98
+ #### 1. Upload a file to Nexus without authentication and without the pom file
99
+
100
+ ```ruby
101
+ nexus 'some description' do
102
+ use_auth false
103
+ upload_pom false
104
+
105
+ coordinates 'com.gary.image:cloud-img:jar:1.2.0'
106
+ local_file '/home/gary/cloud-img-1.2.0.jar'
107
+
108
+ action :upload
109
+ end
110
+ ```
111
+
112
+ #### 2. Upload a file to Nexus without using coordinates and overriding Nexus endpoint config
113
+
114
+ ```ruby
115
+ nexus 'some description' do
116
+ local_file '/home/gary/cloud-img-1.2.0.jar'
117
+
118
+ nexus_url 'http://mynexus.net/nexus/content/repositories/'
119
+ nexus_auth 'gary:secr3t'
120
+ nexus_repo 'name_of_repo'
121
+
122
+ groupId 'com.gary.image'
123
+ artifactId 'cloud-img'
124
+ packaging 'jar'
125
+ classifier 'some_classifier'
126
+ version '1.2.0'
127
+
128
+ action :upload
129
+ end
130
+ ```
131
+
132
+ #### 3. Upload a file to an exact location on Nexus using remote_url (not recommended)
133
+
134
+ ```ruby
135
+ nexus 'some description' do
136
+ remote_url 'http://mynexus.net/nexus/content/repositories/com/gary/image/cloud-img/some_folder/bad_practice.jar'
137
+ local_file '/home/gary/cloud-img-1.2.0.jar'
138
+
139
+ action :upload
140
+ end
141
+ ```
142
+
143
+ #### 4. Download a file from Nexus using coordinates, with another profile
144
+
145
+ ```ruby
146
+ nexus 'some description' do
147
+ nexus_profile 'gary'
148
+ coordinates 'com.gary.image:cloud-img:jar:1.2.0'
149
+ local_file '/home/gary/cloud-img-1.2.0.jar'
150
+
151
+ action :download
152
+ end
153
+ ```
154
+
155
+ #### 5. Download a file from Nexus using remote_url
156
+
157
+ ```ruby
158
+ nexus 'some description' do
159
+ remote_url 'http://mynexus.net/nexus/content/repositories/com/gary/image/cloud-img/1.2.0/cloud-img-1.2.0.jar'
160
+ local_file '/home/gary/cloud-img-1.2.0.jar'
161
+
162
+ action :download
163
+ end
164
+ ```
165
+
166
+ #### 6. Delete an artifact from Nexus
167
+
168
+ ```ruby
169
+ nexus 'some description' do
170
+ coordinates 'com.gary.image:cloud-img:jar:1.2.0'
171
+
172
+ action :delete
173
+ end
174
+ ```
175
+ **NOTE:** This action does not accept attribute `:remote_url` as it is dangerous to do so. **Ex.** you might delete *ALL* artifacts by accident
176
+
177
+ **WARNING:** This action will delete the version folder (folder that holds the file), so everything inside it will be deleted as well
178
+
179
+ #### 7. Delete a file or folder from Nexus (delete folder 1.2.0 in this case)
180
+
181
+ ```ruby
182
+ nexus 'some description' do
183
+ remote_url 'http://mynexus.net/nexus/content/repositories/com/gary/image/cloud-img/1.2.0/'
184
+
185
+ action :delete_url
186
+ end
187
+ ```
188
+ **NOTE:** This action requires attribute `:remote_url`
189
+
190
+ ## Development
191
+
192
+ * Source hosted at [GitHub](https://github.com/blackberry/chef-nexus)
193
+ * Report issues/questions/feature requests on [GitHub Issues](https://github.com/blackberry/chef-nexus/issues)
194
+
195
+ Pull requests are very welcome! Make sure your patches are well tested. Ideally create a topic branch for every separate change you make. For example:
196
+
197
+ 1. Fork the repo
198
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
199
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
200
+ 4. Push to the branch (`git push origin my-new-feature`)
201
+ 5. Create new Pull Request
202
+
203
+ To build and install the gem, go to your `chef-nexus` folder and then run:
204
+
205
+ 1. `rake build`
206
+ 2. `gem install pkg/chef-nexus-x.y.z.gem`, where `x.y.z` is the version you just built
207
+
208
+ ### Testing
209
+
210
+ Please test your changes! Here's how:
211
+
212
+ 1. Create and configure `spec/config.rb` from `spec/config_sample.rb`
213
+ 2. Run `rspec spec/chef/nexus_spec.rb` from your `chef-nexus` folder
214
+
215
+ If you add new functionality, please create new tests accordingly.
216
+
217
+ ## Authors
218
+
219
+ Created by [Dongyu 'Gary' Zheng](https://github.com/dongyuzheng) (<garydzheng@gmail.com>)
220
+
221
+ ## Maintainers
222
+
223
+ * [Bogdan Buczynski](https://github.com/bbuczynski) (<pikus1@gmail.com>)
224
+ * [Phil Oliva](https://github.com/poliva83) (<philoliva8@gmail.com>)
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,46 @@
1
+ # Copyright 2016, BlackBerry Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # coding: utf-8
16
+ lib = File.expand_path('../lib', __FILE__)
17
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
18
+ require 'chef/nexus/version'
19
+
20
+ Gem::Specification.new do |spec|
21
+ spec.name = 'chef-nexus'
22
+ spec.version = Chef::Nexus::VERSION
23
+ spec.license = 'Apache 2.0'
24
+ spec.platform = Gem::Platform::RUBY
25
+ spec.extra_rdoc_files = ['README.md', 'LICENSE']
26
+
27
+ spec.authors = ['Dongyu \'Gary\' Zheng']
28
+ spec.email = ['garydzheng@gmail.com']
29
+
30
+ spec.summary = 'chef-nexus is a Ruby gem that provides the `nexus` Chef resource for managing artifacts on Nexus by Sonatype.'
31
+ spec.description = spec.summary
32
+ spec.homepage = 'https://github.com/blackberry/chef-nexus'
33
+
34
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
35
+ spec.bindir = 'exe'
36
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
+ spec.require_paths = ['lib']
38
+
39
+ spec.add_dependency 'chef'
40
+ spec.add_dependency 'compat_resource', '~> 12.8.0'
41
+ spec.add_dependency 'activesupport'
42
+
43
+ spec.add_development_dependency 'bundler', '~> 1.11'
44
+ spec.add_development_dependency 'rake', '~> 10.0'
45
+ spec.add_development_dependency 'rspec', '~> 3.0'
46
+ end
@@ -0,0 +1,375 @@
1
+ # Copyright 2016, BlackBerry Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ gem 'compat_resource', '~> 12.8.0'
16
+ require 'chef_compat/resource'
17
+ require 'active_support/all'
18
+ require 'json'
19
+ require 'erb'
20
+ require 'digest'
21
+
22
+ class Chef
23
+ class Resource
24
+ #
25
+ # Chef resource for managing artifacts on Nexus by Sonatype
26
+ #
27
+ class Nexus < ChefCompat::Resource
28
+ resource_name :nexus
29
+
30
+ property :nexus_profile, String, desired_state: false
31
+ property :nexus_url, String, desired_state: false
32
+ property :nexus_repo, String, desired_state: false
33
+ property :nexus_auth, String, desired_state: false
34
+ property :use_auth, [TrueClass, FalseClass], default: true, desired_state: false
35
+
36
+ property :upload_pom, [TrueClass, FalseClass], default: true, desired_state: false
37
+ property :update_if_exists, [TrueClass, FalseClass], default: false
38
+
39
+ property :local_file, String, desired_state: false
40
+ property :remote_url, String, desired_state: false
41
+
42
+ property :coordinates, String, desired_state: false
43
+ property :groupId, String, desired_state: false
44
+ property :artifactId, String, desired_state: false
45
+ property :packaging, String, desired_state: false
46
+ property :classifier, String, desired_state: false
47
+ property :version, [String, Fixnum, Float], desired_state: false
48
+
49
+ property :file_sha1, [String, NilClass]
50
+ property :file_md5, [String, NilClass]
51
+ property :pom_sha1, [String, NilClass]
52
+ property :pom_md5, [String, NilClass]
53
+
54
+ load_current_value do
55
+ file_sha1 download_and_read(curl_url + '.sha1')
56
+ file_md5 download_and_read(curl_url + '.md5')
57
+ if upload_pom && can_generate_pom
58
+ pom_sha1 download_and_read(curl_base_url + '.pom.sha1')
59
+ pom_md5 download_and_read(curl_base_url + '.pom.md5')
60
+ end
61
+ end
62
+
63
+ action :upload do
64
+ raise ':local_file is missing' unless local_file
65
+ raise "#{local_file} does not exist" unless ::File.exist?(local_file)
66
+
67
+ if upload_pom && !can_generate_pom
68
+ msg = "chef-nexus was unable retrieve enough information to generate a pom\n"
69
+ msg << "is :remote_url correct in terms of Maven & Nexus syntax? See README: Attributes - Notes\n"
70
+ msg << 'Set attribute :upload_pom false to bypass this error.'
71
+ raise msg
72
+ end
73
+
74
+ file_sha1 local_file_sha1
75
+ file_md5 local_file_md5
76
+
77
+ unless file_equal(current_resource)
78
+ if file_exists
79
+ raise 'Different file currently exists on Nexus (or checksums are missing), if you want to overwrite it, set attribute :update_if_exists to true' unless update_if_exists
80
+ delete(curl_url)
81
+ end
82
+ converge_by "uploaded file '#{local_file}' to Nexus at '#{curl_url}'" do
83
+ upload(local_file, curl_url)
84
+ end
85
+ end
86
+
87
+ converge_if_changed :file_sha1 do
88
+ delete(curl_url + '.sha1') if url_exists(curl_url + '.sha1')
89
+ write_file(curl_url + '.sha1', file_sha1)
90
+ end
91
+
92
+ converge_if_changed :file_md5 do
93
+ delete(curl_url + '.md5') if url_exists(curl_url + '.md5')
94
+ write_file(curl_url + '.md5', file_md5)
95
+ end
96
+
97
+ if upload_pom
98
+ pom_content = ERB.new(::File.read("#{::File.dirname(__FILE__)}/pom.erb"), nil, '-').result(binding)
99
+
100
+ pom_sha1 Digest::SHA1.hexdigest(pom_content)
101
+ pom_md5 Digest::MD5.hexdigest(pom_content)
102
+
103
+ unless pom_equal(current_resource)
104
+ if pom_exists
105
+ raise 'Different pom currently exists on Nexus (or checksums are missing), if you want to overwrite it, set attribute :update_if_exists to true' unless update_if_exists
106
+ delete(curl_base_url + '.pom')
107
+ end
108
+ converge_by "uploaded pom to Nexus at '#{curl_base_url + '.pom'}'" do
109
+ write_file(curl_base_url + '.pom', pom_content)
110
+ end
111
+ end
112
+
113
+ converge_if_changed :pom_sha1 do
114
+ delete(curl_base_url + '.pom.sha1') if url_exists(curl_base_url + '.pom.sha1')
115
+ write_file(curl_base_url + '.pom.sha1', pom_sha1)
116
+ end
117
+
118
+ converge_if_changed :pom_md5 do
119
+ delete(curl_base_url + '.pom.md5') if url_exists(curl_base_url + '.pom.md5')
120
+ write_file(curl_base_url + '.pom.md5', pom_md5)
121
+ end
122
+ end
123
+ end
124
+
125
+ action :download do
126
+ raise ':local_file is missing' unless local_file
127
+ raise "No file exists at '#{curl_url}' or you do not permissions" unless file_exists
128
+ unless file_equal(current_resource)
129
+ raise 'Different version currently exists locally, if you want to overwrite it, set attribute :update_if_exists to true' if ::File.exist?(local_file) && !update_if_exists
130
+ converge_by "downloaded file '#{local_file}' from Nexus at '#{curl_url}'" do
131
+ execute_or_fail("mkdir -p #{::File.dirname(local_file)}")
132
+ download(curl_url, local_file)
133
+ updated_by_last_action(true)
134
+ end
135
+ end
136
+ end
137
+
138
+ action :delete do
139
+ raise 'action :delete does not accept attribute :remote_url ... use Maven coordinates instead, or use action :delete_url' if remote_url
140
+ converge_by "deleted artifact '#{curl_url}' from Nexus" do
141
+ delete(curl_url.split('/')[0...-1].join('/'))
142
+ updated_by_last_action(true)
143
+ end if url_exists(curl_url.split('/')[0...-1].join('/'))
144
+ end
145
+
146
+ action :delete_url do
147
+ raise 'action :delete_url requires attribute :remote_url' unless remote_url
148
+ converge_by "deleted '#{curl_url}' from Nexus" do
149
+ delete(curl_url)
150
+ updated_by_last_action(true)
151
+ end if url_exists(curl_url)
152
+ end
153
+
154
+ protected
155
+
156
+ def upload(local, remote)
157
+ execute_or_fail("curl -v #{use_auth ? "-u #{n_auth} " : nil}-T #{local} #{remote}")
158
+ raise "Server responded with successful creation, but '#{remote}' does not exist." unless url_exists(remote)
159
+ end
160
+
161
+ def download(remote, local)
162
+ execute_or_fail("curl -v #{use_auth ? "-u #{n_auth} " : nil}#{remote} > #{local}")
163
+ raise "File appears to have been downloaded, but '#{local}' does not exist." unless ::File.exist?(local)
164
+ end
165
+
166
+ def delete(remote)
167
+ execute_or_fail("curl -v #{use_auth ? "-u #{n_auth} " : nil}-X DELETE #{remote}")
168
+ raise "Server responded with successful deletion, but '#{remote}' still exists." if url_exists(remote)
169
+ end
170
+
171
+ def execute_or_fail(cmd, check_http = true)
172
+ output = `#{cmd}`
173
+ fail_me = false
174
+ output.scan(%r{^ +<title>(\d{3}) - .*?</title>$}).each { |code| fail_me = true unless code[0] == '1' || code[0] == '2' } if check_http
175
+ if $?.exitstatus != 0 || fail_me
176
+ raise "Command failed: #{cmd}\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n#{output.strip}\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
177
+ end
178
+ output
179
+ end
180
+
181
+ def write_file(remote, content)
182
+ tmp = '/tmp/' + Digest::SHA1.hexdigest(rand(100000000000000).to_s)
183
+ ::File.open(tmp, 'w') { |file| file.write(content) }
184
+ upload(tmp, remote)
185
+ ::File.delete(tmp)
186
+ end
187
+
188
+ def cords
189
+ @cords ||= begin
190
+ hsh = {}
191
+ if remote_url
192
+ scn = remote_url.scan(%r{^.*?/repositories/.*?/(.*?)/((?:\d+\.)*\d+)/(.*?)-((?:\d+\.)*\d+)(?:-(.*?))?\.(.*)$})
193
+ if scn.length == 1 && scn[0][1] == scn[0][3]
194
+ group_id, _, artifact_id = scn[0][0].rpartition('/')
195
+ if !group_id.empty? && artifact_id == scn[0][2]
196
+ hsh[:groupId] = group_id.tr('/', '.')
197
+ hsh[:artifactId] = artifact_id
198
+ hsh[:version] = scn[0][1]
199
+ hsh[:packaging] = scn[0][5]
200
+ hsh[:classifier] = scn[0][4]
201
+ end
202
+ end
203
+ hsh.delete_if { |_, v| v.nil? }
204
+ end
205
+ if coordinates
206
+ splt = coordinates.split(':')
207
+ unless splt.length >= 3 && splt.length <= 5
208
+ raise ':coordinates must follow the one of the following formats
209
+ groupId:artifactId:version
210
+ groupId:artifactId:packaging:version
211
+ groupId:artifactId:packaging:classifier:version'
212
+ end
213
+ hsh[:groupId] = splt.first
214
+ hsh[:artifactId] = splt[1]
215
+ hsh[:version] = splt.last
216
+ hsh[:packaging] = splt[2] if splt.length >= 4
217
+ hsh[:classifier] = splt[3] if splt.length == 5
218
+ end
219
+ %w(groupId artifactId version packaging classifier).each do |x|
220
+ p = eval(x)
221
+ hsh[x.to_sym] = p if p
222
+ end
223
+
224
+ [:groupId, :artifactId, :version].each do |x|
225
+ raise 'Your must specify :coordinates OR at least all of [:groupId, :artifactId, :version]' unless hsh[x].present?
226
+ end unless remote_url
227
+
228
+ if local_file && !hsh[:packaging].present?
229
+ extn = ::File.extname(local_file)
230
+ if !remote_url && extn.empty?
231
+ raise 'Files require an extension, or specify it with :packaging'
232
+ else
233
+ hsh[:packaging] = extn[1..-1]
234
+ end
235
+ end
236
+ hsh
237
+ end
238
+ end
239
+
240
+ def curl_url
241
+ @curl_url ||= begin
242
+ remote_url || begin
243
+ url = curl_base_url.dup
244
+ url += "-#{cords[:classifier]}" if cords[:classifier]
245
+ url += ".#{cords[:packaging]}"
246
+ url
247
+ end
248
+ end
249
+ end
250
+
251
+ def curl_base_url
252
+ @curl_base_url ||= begin
253
+ url = [n_url, 'repositories', n_repo]
254
+ url.push(cords[:groupId].split('.')).flatten!
255
+ url.push(cords[:artifactId])
256
+ url.push(cords[:version])
257
+ url.push("#{cords[:artifactId]}-#{cords[:version]}")
258
+ url.join('/')
259
+ end
260
+ end
261
+
262
+ def n_url
263
+ @n_url ||= begin
264
+ nurl = nexus_url || ENV['NEXUS_URL'] || n_config['url']
265
+ raise "Please provide Nexus url as either an attribute :nexus_url or in ~/.nexus/config profile '#{n_profile}'" unless nurl
266
+ nurl.chomp('/')
267
+ end
268
+ end
269
+
270
+ def n_auth
271
+ @n_auth ||= begin
272
+ nauth = nexus_auth || ENV['NEXUS_AUTH'] || n_config['auth']
273
+ raise "Please provide Nexus auth as either an attribute :nexus_auth or in ~/.nexus/config profile '#{n_profile}'" if use_auth && !nauth
274
+ nauth
275
+ end
276
+ end
277
+
278
+ def n_repo
279
+ @n_repo ||= begin
280
+ nrepo = nexus_repo || ENV['NEXUS_REPO'] || n_config['repo']
281
+ raise "Please provide Nexus repository as either an attribute :repository or in ~/.nexus/config profile '#{n_profile}'" unless nrepo
282
+ nrepo
283
+ end
284
+ end
285
+
286
+ def n_config
287
+ @n_config ||= begin
288
+ if ENV['NEXUS_CONFIG'] && ::File.exist?(ENV['NEXUS_CONFIG'])
289
+ JSON.parse(::File.read(ENV['NEXUS_CONFIG']))[n_profile] || {}
290
+ elsif ::File.exist?("#{ENV['HOME']}/.nexus/config")
291
+ JSON.parse(::File.read("#{ENV['HOME']}/.nexus/config"))[n_profile] || {}
292
+ elsif ::File.exist?('/etc/.nexus/config')
293
+ JSON.parse(::File.read('/etc/.nexus/config'))[n_profile] || {}
294
+ else
295
+ {}
296
+ end
297
+ end
298
+ end
299
+
300
+ def n_profile
301
+ @n_profile ||= nexus_profile || ENV['NEXUS_PROFILE'] || 'default'
302
+ end
303
+
304
+ def local_file_md5
305
+ @local_file_md5 ||= begin
306
+ ::File.open(local_file, 'rb') do |f|
307
+ digest = Digest::MD5.new
308
+ buffer = ''
309
+ digest.update(buffer) while f.read(4096, buffer)
310
+ digest.hexdigest
311
+ end if ::File.exist?(local_file)
312
+ end
313
+ end
314
+
315
+ def local_file_sha1
316
+ @local_file_sha1 ||= begin
317
+ ::File.open(local_file, 'rb') do |f|
318
+ digest = Digest::SHA1.new
319
+ buffer = ''
320
+ digest.update(buffer) while f.read(4096, buffer)
321
+ digest.hexdigest
322
+ end if ::File.exist?(local_file)
323
+ end
324
+ end
325
+
326
+ def file_exists
327
+ @file_exists ||= url_exists(curl_url)
328
+ end
329
+
330
+ # If neither SHA1 or MD5 checksums are on Nexus, we will assume not equal.
331
+ def file_equal(current_resource)
332
+ @file_equal ||= begin
333
+ if file_exists
334
+ return true if current_resource.file_sha1 && local_file_sha1 == current_resource.file_sha1
335
+ return true if current_resource.file_md5 && local_file_md5 == current_resource.file_md5
336
+ end
337
+ false
338
+ end
339
+ end
340
+
341
+ def pom_exists
342
+ @pom_exists ||= url_exists(curl_base_url + '.pom')
343
+ end
344
+
345
+ def pom_equal(current_resource)
346
+ @pom_equal ||= begin
347
+ if pom_exists
348
+ return true if current_resource.pom_sha1 && pom_sha1 == current_resource.pom_sha1
349
+ return true if current_resource.pom_md5 && pom_md5 == current_resource.pom_md5
350
+ end
351
+ false
352
+ end
353
+ end
354
+
355
+ def can_generate_pom
356
+ @can_generate_pom ||= [:groupId, :artifactId, :version, :packaging].all? { |x| cords.key?(x) }
357
+ end
358
+
359
+ def url_exists(url)
360
+ `curl --output /dev/null --silent --head --fail #{use_auth ? "-u #{n_auth} " : nil}#{url}`
361
+ $?.exitstatus == 0
362
+ end
363
+
364
+ def download_and_read(url)
365
+ return nil unless url_exists(url)
366
+ tmp = '/tmp/' + Digest::SHA1.hexdigest(rand(100000000000000).to_s)
367
+ cmd = "curl -v #{use_auth ? "-u #{n_auth} " : nil}#{url} > #{tmp}"
368
+ execute_or_fail(cmd)
369
+ content = ::File.read(tmp)
370
+ ::File.delete(tmp)
371
+ content
372
+ end
373
+ end
374
+ end
375
+ end
@@ -0,0 +1,23 @@
1
+ # Copyright 2016, BlackBerry Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Chef
16
+ #
17
+ # The version of chef-nexus, follows Semantic Versioning 2.0.0
18
+ # See: http://semver.org/spec/v2.0.0.html
19
+ #
20
+ module Nexus
21
+ VERSION = '0.1.2'
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4
+ <modelVersion>4.0.0</modelVersion>
5
+ <groupId><%= cords[:groupId] %></groupId>
6
+ <artifactId><%= cords[:artifactId] %></artifactId>
7
+ <version><%= cords[:version] %></version>
8
+ <packaging><%= cords[:packaging] %></packaging>
9
+ </project>
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chef-nexus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Dongyu 'Gary' Zheng
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chef
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: compat_resource
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 12.8.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 12.8.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ description: chef-nexus is a Ruby gem that provides the `nexus` Chef resource for
98
+ managing artifacts on Nexus by Sonatype.
99
+ email:
100
+ - garydzheng@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files:
104
+ - README.md
105
+ - LICENSE
106
+ files:
107
+ - CHANGELOG.md
108
+ - Gemfile
109
+ - LICENSE
110
+ - README.md
111
+ - Rakefile
112
+ - chef-nexus.gemspec
113
+ - lib/chef/nexus.rb
114
+ - lib/chef/nexus/version.rb
115
+ - lib/chef/pom.erb
116
+ homepage: https://github.com/blackberry/chef-nexus
117
+ licenses:
118
+ - Apache 2.0
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.5.2
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: chef-nexus is a Ruby gem that provides the `nexus` Chef resource for managing
140
+ artifacts on Nexus by Sonatype.
141
+ test_files: []
142
+ has_rdoc: