capsulecd 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.dockerignore +5 -0
- data/.gitignore +95 -0
- data/.rspec +3 -0
- data/.simplecov +9 -0
- data/Dockerfile +16 -0
- data/Dockerfile.chef +26 -0
- data/Dockerfile.javascript +7 -0
- data/Dockerfile.node +7 -0
- data/Dockerfile.python +7 -0
- data/Dockerfile.ruby +4 -0
- data/FEATURES.md +12 -0
- data/Gemfile +26 -0
- data/LICENSE.md +22 -0
- data/README.md +227 -0
- data/Rakefile +43 -0
- data/bin/capsulecd +4 -0
- data/capsulecd.gemspec +27 -0
- data/circle.yml +24 -0
- data/lib/capsulecd/base/common/git_utils.rb +90 -0
- data/lib/capsulecd/base/common/validation_utils.rb +22 -0
- data/lib/capsulecd/base/configuration.rb +151 -0
- data/lib/capsulecd/base/engine.rb +163 -0
- data/lib/capsulecd/base/runner/circleci.rb +37 -0
- data/lib/capsulecd/base/runner/default.rb +38 -0
- data/lib/capsulecd/base/source/github.rb +183 -0
- data/lib/capsulecd/base/transform_engine.rb +62 -0
- data/lib/capsulecd/chef/chef_engine.rb +172 -0
- data/lib/capsulecd/chef/chef_helper.rb +29 -0
- data/lib/capsulecd/cli.rb +64 -0
- data/lib/capsulecd/error.rb +51 -0
- data/lib/capsulecd/javascript/javascript_engine.rb +213 -0
- data/lib/capsulecd/node/node_engine.rb +141 -0
- data/lib/capsulecd/python/python_engine.rb +157 -0
- data/lib/capsulecd/ruby/ruby_engine.rb +191 -0
- data/lib/capsulecd/ruby/ruby_helper.rb +60 -0
- data/lib/capsulecd/version.rb +3 -0
- data/lib/capsulecd.rb +16 -0
- data/logo.svg +1 -0
- data/spec/fixtures/chef/cookbook_analogj_test/CHANGELOG.md +3 -0
- data/spec/fixtures/chef/cookbook_analogj_test/Gemfile +18 -0
- data/spec/fixtures/chef/cookbook_analogj_test/LICENSE +21 -0
- data/spec/fixtures/chef/cookbook_analogj_test/README.md +13 -0
- data/spec/fixtures/chef/cookbook_analogj_test/Rakefile +1 -0
- data/spec/fixtures/chef/cookbook_analogj_test/Thorfile +12 -0
- data/spec/fixtures/chef/cookbook_analogj_test/chefignore +94 -0
- data/spec/fixtures/chef/cookbook_analogj_test/metadata.rb +5 -0
- data/spec/fixtures/chef/cookbook_analogj_test/recipes/default.rb +6 -0
- data/spec/fixtures/incorrect_configuration.yml +4 -0
- data/spec/fixtures/javascript/javascript_analogj_test/LICENSE +21 -0
- data/spec/fixtures/javascript/javascript_analogj_test/README.md +2 -0
- data/spec/fixtures/javascript/javascript_analogj_test/package.json +19 -0
- data/spec/fixtures/node/npm_analogj_test/LICENSE +21 -0
- data/spec/fixtures/node/npm_analogj_test/README.md +2 -0
- data/spec/fixtures/node/npm_analogj_test/package.json +19 -0
- data/spec/fixtures/python/pip_analogj_test/LICENSE +21 -0
- data/spec/fixtures/python/pip_analogj_test/MANIFEST.in +1 -0
- data/spec/fixtures/python/pip_analogj_test/README.md +1 -0
- data/spec/fixtures/python/pip_analogj_test/VERSION +1 -0
- data/spec/fixtures/python/pip_analogj_test/setup.cfg +5 -0
- data/spec/fixtures/python/pip_analogj_test/setup.py +80 -0
- data/spec/fixtures/python/pip_analogj_test/tox.ini +14 -0
- data/spec/fixtures/ruby/gem_analogj_test/Gemfile +4 -0
- data/spec/fixtures/ruby/gem_analogj_test/LICENSE.txt +21 -0
- data/spec/fixtures/ruby/gem_analogj_test/README.md +41 -0
- data/spec/fixtures/ruby/gem_analogj_test/Rakefile +6 -0
- data/spec/fixtures/ruby/gem_analogj_test/bin/console +14 -0
- data/spec/fixtures/ruby/gem_analogj_test/bin/setup +8 -0
- data/spec/fixtures/ruby/gem_analogj_test/gem_analogj_test.gemspec +25 -0
- data/spec/fixtures/ruby/gem_analogj_test/lib/gem_analogj_test/version.rb +3 -0
- data/spec/fixtures/ruby/gem_analogj_test/lib/gem_analogj_test.rb +5 -0
- data/spec/fixtures/ruby/gem_analogj_test/spec/gem_analogj_test_spec.rb +7 -0
- data/spec/fixtures/ruby/gem_analogj_test/spec/spec_helper.rb +2 -0
- data/spec/fixtures/ruby/gem_analogj_test-0.1.4.gem +0 -0
- data/spec/fixtures/sample_chef_configuration.yml +8 -0
- data/spec/fixtures/sample_configuration.yml +7 -0
- data/spec/fixtures/sample_global_configuration.yml +23 -0
- data/spec/fixtures/sample_node_configuration.yml +7 -0
- data/spec/fixtures/sample_python_configuration.yml +8 -0
- data/spec/fixtures/sample_repo_configuration.yml +22 -0
- data/spec/fixtures/sample_ruby_configuration.yml +5 -0
- data/spec/fixtures/vcr_cassettes/chef_build_step.yml +636 -0
- data/spec/fixtures/vcr_cassettes/gem_build_step.yml +653 -0
- data/spec/fixtures/vcr_cassettes/gem_build_step_without_version_rb.yml +653 -0
- data/spec/fixtures/vcr_cassettes/integration_chef.yml +1399 -0
- data/spec/fixtures/vcr_cassettes/integration_node.yml +1388 -0
- data/spec/fixtures/vcr_cassettes/integration_python.yml +1388 -0
- data/spec/fixtures/vcr_cassettes/integration_ruby.yml +1377 -0
- data/spec/fixtures/vcr_cassettes/node_build_step.yml +647 -0
- data/spec/fixtures/vcr_cassettes/pip_build_step.yml +653 -0
- data/spec/lib/capsulecd/base/configuration_spec.rb +75 -0
- data/spec/lib/capsulecd/base/engine_spec.rb +51 -0
- data/spec/lib/capsulecd/base/source/github_spec.rb +253 -0
- data/spec/lib/capsulecd/base/transform_engine_spec.rb +55 -0
- data/spec/lib/capsulecd/chef/chef_engine_spec.rb +114 -0
- data/spec/lib/capsulecd/cli_spec.rb +57 -0
- data/spec/lib/capsulecd/node/node_engine_spec.rb +113 -0
- data/spec/lib/capsulecd/python/python_engine_spec.rb +118 -0
- data/spec/lib/capsulecd/ruby/ruby_engine_spec.rb +128 -0
- data/spec/spec_helper.rb +105 -0
- data/spec/support/file_system.rb +21 -0
- data/spec/support/package_types.rb +11 -0
- metadata +281 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
require 'semverly'
|
|
2
|
+
require 'open3'
|
|
3
|
+
require 'bundler'
|
|
4
|
+
require 'json'
|
|
5
|
+
require_relative '../base/engine'
|
|
6
|
+
|
|
7
|
+
module CapsuleCD
|
|
8
|
+
module Javascript
|
|
9
|
+
class JavascriptEngine < Engine
|
|
10
|
+
def build_step
|
|
11
|
+
super
|
|
12
|
+
|
|
13
|
+
@_is_bower = File.exist?(@source_git_local_path + '/bower.json')
|
|
14
|
+
@_is_npm = File.exist?(@source_git_local_path + '/package.json')
|
|
15
|
+
|
|
16
|
+
# validate that the metadata files exist
|
|
17
|
+
if !@_is_bower && !@_is_npm
|
|
18
|
+
fail CapsuleCD::Error::BuildPackageInvalid, 'package.json or bower.json file must be present for Javascript packages'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# we can't bump the npm version here because the npm version patch command will set it.
|
|
22
|
+
# howerver we need to make sure the bower.json and package.json versions are insync.
|
|
23
|
+
# we'll take the latest version of either the package.json or bower.json and set that as the version of both.
|
|
24
|
+
sync_versions
|
|
25
|
+
|
|
26
|
+
# now that the bower and package versions are in sync, lets bump the version of bower.json
|
|
27
|
+
# (because package.json will be bumped automatically.)
|
|
28
|
+
if @_is_bower
|
|
29
|
+
bower_file = File.read(@source_git_local_path + '/bower.json')
|
|
30
|
+
bower_data = JSON.parse(bower_file)
|
|
31
|
+
next_version = bump_version(SemVer.parse(bower_data['version']))
|
|
32
|
+
bower_data['version'] = next_version.to_s
|
|
33
|
+
File.write(@source_git_local_path + '/bower.json', JSON.pretty_generate(bower_data))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# TODO: check if this module name and version already exist.
|
|
38
|
+
|
|
39
|
+
# check for/create any required missing folders/files
|
|
40
|
+
unless File.exist?(@source_git_local_path + '/test')
|
|
41
|
+
FileUtils.mkdir(@source_git_local_path + '/test')
|
|
42
|
+
end
|
|
43
|
+
unless File.exist?(@source_git_local_path + '/.gitignore')
|
|
44
|
+
CapsuleCD::GitUtils.create_gitignore(@source_git_local_path, ['Node','Yeoman'])
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_step
|
|
49
|
+
super
|
|
50
|
+
|
|
51
|
+
if @_is_npm
|
|
52
|
+
# the module has already been downloaded. lets make sure all its dependencies are available.
|
|
53
|
+
Open3.popen3('npm install', chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
54
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
55
|
+
Thread.new do
|
|
56
|
+
until (line = stream_buffer.gets).nil?
|
|
57
|
+
puts "#{name} -> #{line}"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
# wait for process
|
|
62
|
+
external.join
|
|
63
|
+
unless external.value.success?
|
|
64
|
+
fail CapsuleCD::Error::TestDependenciesError, 'npm install failed. Check module dependencies'
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
# create a shrinkwrap file.
|
|
68
|
+
Open3.popen3('npm shrinkwrap', chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
69
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
70
|
+
Thread.new do
|
|
71
|
+
until (line = stream_buffer.gets).nil?
|
|
72
|
+
puts "#{name} -> #{line}"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
# wait for process
|
|
77
|
+
external.join
|
|
78
|
+
unless external.value.success?
|
|
79
|
+
fail CapsuleCD::Error::TestDependenciesError, 'npm shrinkwrap failed. Check log for exact error'
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# run test command
|
|
84
|
+
test_cmd = @config.engine_cmd_test || 'npm test'
|
|
85
|
+
Open3.popen3(ENV, test_cmd, chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
86
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
87
|
+
Thread.new do
|
|
88
|
+
until (line = stream_buffer.gets).nil?
|
|
89
|
+
puts "#{name} -> #{line}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
# wait for process
|
|
94
|
+
external.join
|
|
95
|
+
unless external.value.success?
|
|
96
|
+
fail CapsuleCD::Error::TestRunnerError, test_cmd + ' failed. Check log for exact error'
|
|
97
|
+
end
|
|
98
|
+
end unless @config.engine_disable_test
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
if @_is_bower
|
|
102
|
+
# lets make sure all the bower dependencies are available.
|
|
103
|
+
Open3.popen3('bower install --allow-root', chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
104
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
105
|
+
Thread.new do
|
|
106
|
+
until (line = stream_buffer.gets).nil?
|
|
107
|
+
puts "#{name} -> #{line}"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
# wait for process
|
|
112
|
+
external.join
|
|
113
|
+
unless external.value.success?
|
|
114
|
+
fail CapsuleCD::Error::TestDependenciesError, 'npm install failed. Check module dependencies'
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# run npm publish
|
|
121
|
+
def package_step
|
|
122
|
+
super
|
|
123
|
+
|
|
124
|
+
# commit changes to the cookbook. (test run occurs before this, and it should clean up any instrumentation files, created,
|
|
125
|
+
# as they will be included in the commmit and any release artifacts)
|
|
126
|
+
CapsuleCD::GitUtils.commit(@source_git_local_path, 'Committing automated changes before packaging.') rescue puts 'No changes to commit..'
|
|
127
|
+
if @_is_bower && !@_is_npm
|
|
128
|
+
bower_file = File.read(@source_git_local_path + '/bower.json')
|
|
129
|
+
bower_data = JSON.parse(bower_file)
|
|
130
|
+
next_version = SemVer.parse(bower_data['version'])
|
|
131
|
+
@source_release_commit = CapsuleCD::GitUtils.tag(@source_git_local_path, "v#{next_version}")
|
|
132
|
+
|
|
133
|
+
else
|
|
134
|
+
|
|
135
|
+
# run npm publish
|
|
136
|
+
Open3.popen3("npm version #{@config.engine_version_bump_type} -m '(v%s) Automated packaging of release by CapsuleCD'", chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
137
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
138
|
+
Thread.new do
|
|
139
|
+
until (line = stream_buffer.gets).nil?
|
|
140
|
+
puts "#{name} -> #{line}"
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
# wait for process
|
|
145
|
+
external.join
|
|
146
|
+
fail 'npm version bump failed' unless external.value.success?
|
|
147
|
+
end
|
|
148
|
+
@source_release_commit = CapsuleCD::GitUtils.get_latest_tag_commit(@source_git_local_path)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# this step should push the release to the package repository (ie. npm, chef supermarket, rubygems)
|
|
155
|
+
def release_step
|
|
156
|
+
super
|
|
157
|
+
|
|
158
|
+
if @_is_npm
|
|
159
|
+
npmrc_path = File.expand_path('~/.npmrc')
|
|
160
|
+
|
|
161
|
+
unless @config.npm_auth_token
|
|
162
|
+
fail CapsuleCD::Error::ReleaseCredentialsMissing, 'cannot deploy page to npm, credentials missing'
|
|
163
|
+
return
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# write the knife.rb config file.
|
|
167
|
+
File.open(npmrc_path, 'w+') do |file|
|
|
168
|
+
file.write("//registry.npmjs.org/:_authToken=#{@config.npm_auth_token}")
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# run npm publish
|
|
172
|
+
Open3.popen3('npm publish .', chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
173
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
174
|
+
Thread.new do
|
|
175
|
+
until (line = stream_buffer.gets).nil?
|
|
176
|
+
puts "#{name} -> #{line}"
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
# wait for process
|
|
181
|
+
external.join
|
|
182
|
+
unless external.value.success?
|
|
183
|
+
fail CapsuleCD::Error::ReleasePackageError, 'npm publish failed. Check log for exact error'
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
private
|
|
190
|
+
def sync_versions
|
|
191
|
+
#this method only needs to run if bower and package json files exist.
|
|
192
|
+
if !@_is_bower || !@_is_npm
|
|
193
|
+
return
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
bower_file = File.read(@source_git_local_path + '/bower.json')
|
|
197
|
+
bower_data = JSON.parse(bower_file)
|
|
198
|
+
bower_version = SemVer.parse(bower_data['version'])
|
|
199
|
+
package_file = File.read(@source_git_local_path + '/package.json')
|
|
200
|
+
package_data = JSON.parse(package_file)
|
|
201
|
+
package_version = SemVer.parse(package_data['version'])
|
|
202
|
+
|
|
203
|
+
if(bower_version>package_version)
|
|
204
|
+
package_data['version'] = bower_version.to_s
|
|
205
|
+
File.write(@source_git_local_path + '/package.json', JSON.pretty_generate(package_data))
|
|
206
|
+
else
|
|
207
|
+
bower_data['version'] = package_version.to_s
|
|
208
|
+
File.write(@source_git_local_path + '/bower.json', JSON.pretty_generate(bower_data))
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
require 'semverly'
|
|
2
|
+
require 'open3'
|
|
3
|
+
require 'bundler'
|
|
4
|
+
require_relative '../base/engine'
|
|
5
|
+
|
|
6
|
+
module CapsuleCD
|
|
7
|
+
module Node
|
|
8
|
+
class NodeEngine < Engine
|
|
9
|
+
def build_step
|
|
10
|
+
super
|
|
11
|
+
# validate that the chef metadata.rb file exists
|
|
12
|
+
unless File.exist?(@source_git_local_path + '/package.json')
|
|
13
|
+
fail CapsuleCD::Error::BuildPackageInvalid, 'package.json file is required to process Npm package'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# no need to bump up the version here. It will automatically be bumped up via the npm version patch command.
|
|
17
|
+
# however we need to read the version from the package.json file and check if a npm module already exists.
|
|
18
|
+
|
|
19
|
+
# TODO: check if this module name and version already exist.
|
|
20
|
+
|
|
21
|
+
# check for/create any required missing folders/files
|
|
22
|
+
unless File.exist?(@source_git_local_path + '/test')
|
|
23
|
+
FileUtils.mkdir(@source_git_local_path + '/test')
|
|
24
|
+
end
|
|
25
|
+
unless File.exist?(@source_git_local_path + '/.gitignore')
|
|
26
|
+
CapsuleCD::GitUtils.create_gitignore(@source_git_local_path, ['Node'])
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_step
|
|
31
|
+
super
|
|
32
|
+
|
|
33
|
+
# the module has already been downloaded. lets make sure all its dependencies are available.
|
|
34
|
+
Open3.popen3('npm install', chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
35
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
36
|
+
Thread.new do
|
|
37
|
+
until (line = stream_buffer.gets).nil?
|
|
38
|
+
puts "#{name} -> #{line}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
# wait for process
|
|
43
|
+
external.join
|
|
44
|
+
unless external.value.success?
|
|
45
|
+
fail CapsuleCD::Error::TestDependenciesError, 'npm install failed. Check module dependencies'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# create a shrinkwrap file.
|
|
50
|
+
Open3.popen3('npm shrinkwrap', chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
51
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
52
|
+
Thread.new do
|
|
53
|
+
until (line = stream_buffer.gets).nil?
|
|
54
|
+
puts "#{name} -> #{line}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
# wait for process
|
|
59
|
+
external.join
|
|
60
|
+
unless external.value.success?
|
|
61
|
+
fail CapsuleCD::Error::TestDependenciesError, 'npm shrinkwrap failed. Check log for exact error'
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# run test command
|
|
66
|
+
test_cmd = @config.engine_cmd_test || 'npm test'
|
|
67
|
+
Open3.popen3(ENV, test_cmd, chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
68
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
69
|
+
Thread.new do
|
|
70
|
+
until (line = stream_buffer.gets).nil?
|
|
71
|
+
puts "#{name} -> #{line}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
# wait for process
|
|
76
|
+
external.join
|
|
77
|
+
unless external.value.success?
|
|
78
|
+
fail CapsuleCD::Error::TestRunnerError, test_cmd + ' failed. Check log for exact error'
|
|
79
|
+
end
|
|
80
|
+
end unless @config.engine_disable_test
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# run npm publish
|
|
84
|
+
def package_step
|
|
85
|
+
super
|
|
86
|
+
|
|
87
|
+
# commit changes to the cookbook. (test run occurs before this, and it should clean up any instrumentation files, created,
|
|
88
|
+
# as they will be included in the commmit and any release artifacts)
|
|
89
|
+
CapsuleCD::GitUtils.commit(@source_git_local_path, 'Committing automated changes before packaging.') rescue puts 'No changes to commit..'
|
|
90
|
+
|
|
91
|
+
# run npm publish
|
|
92
|
+
Open3.popen3("npm version #{@config.engine_version_bump_type} -m '(v%s) Automated packaging of release by CapsuleCD'", chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
93
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
94
|
+
Thread.new do
|
|
95
|
+
until (line = stream_buffer.gets).nil?
|
|
96
|
+
puts "#{name} -> #{line}"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
# wait for process
|
|
101
|
+
external.join
|
|
102
|
+
fail 'npm version bump failed' unless external.value.success?
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
@source_release_commit = CapsuleCD::GitUtils.get_latest_tag_commit(@source_git_local_path)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# this step should push the release to the package repository (ie. npm, chef supermarket, rubygems)
|
|
109
|
+
def release_step
|
|
110
|
+
super
|
|
111
|
+
npmrc_path = File.expand_path('~/.npmrc')
|
|
112
|
+
|
|
113
|
+
unless @config.npm_auth_token
|
|
114
|
+
fail CapsuleCD::Error::ReleaseCredentialsMissing, 'cannot deploy page to npm, credentials missing'
|
|
115
|
+
return
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# write the knife.rb config file.
|
|
119
|
+
File.open(npmrc_path, 'w+') do |file|
|
|
120
|
+
file.write("//registry.npmjs.org/:_authToken=#{@config.npm_auth_token}")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# run npm publish
|
|
124
|
+
Open3.popen3('npm publish .', chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
125
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
126
|
+
Thread.new do
|
|
127
|
+
until (line = stream_buffer.gets).nil?
|
|
128
|
+
puts "#{name} -> #{line}"
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
# wait for process
|
|
133
|
+
external.join
|
|
134
|
+
unless external.value.success?
|
|
135
|
+
fail CapsuleCD::Error::ReleasePackageError, 'npm publish failed. Check log for exact error'
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
require 'semverly'
|
|
2
|
+
require 'open3'
|
|
3
|
+
require 'bundler'
|
|
4
|
+
require_relative '../base/engine'
|
|
5
|
+
|
|
6
|
+
module CapsuleCD
|
|
7
|
+
module Python
|
|
8
|
+
class PythonEngine < Engine
|
|
9
|
+
def build_step
|
|
10
|
+
super
|
|
11
|
+
unless File.exist?(@source_git_local_path + '/setup.py')
|
|
12
|
+
fail CapsuleCD::Error::BuildPackageInvalid, 'setup.py file is required to process Python package'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# check for/create required VERSION file
|
|
16
|
+
unless File.exist?(@source_git_local_path + '/VERSION')
|
|
17
|
+
File.open(@source_git_local_path + '/VERSION', 'w') { |file| file.write('0.0.0') }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# bump up the version here.
|
|
21
|
+
# since there's no standardized way to bump up the version in the setup.py file, we're going to assume that the version
|
|
22
|
+
# is specified in a VERSION file in the root of the source repository
|
|
23
|
+
# this is option #4 in the python packaging guide:
|
|
24
|
+
# https://packaging.python.org/en/latest/single_source_version/#single-sourcing-the-version
|
|
25
|
+
#
|
|
26
|
+
# additional packaging structures, like those listed below, may also be supported in the future.
|
|
27
|
+
# http://stackoverflow.com/a/7071358/1157633
|
|
28
|
+
|
|
29
|
+
version = File.read(@source_git_local_path + '/VERSION').strip
|
|
30
|
+
next_version = bump_version(SemVer.parse(version))
|
|
31
|
+
File.open(@source_git_local_path + '/VERSION', 'w') do |file|
|
|
32
|
+
file.write(next_version)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# make sure the package testing manager is available.
|
|
36
|
+
# there is a standardized way to test packages (python setup.py tests), however for automation tox is preferred
|
|
37
|
+
# because of virtualenv and its support for multiple interpreters.
|
|
38
|
+
unless File.exist?(@source_git_local_path + '/tox.ini')
|
|
39
|
+
# if a tox.ini file is not present, we'll create a default one and specify 'python setup.py test' as the test
|
|
40
|
+
# runner command, and requirements.txt as the dependencies for this package.
|
|
41
|
+
File.open(@source_git_local_path + '/tox.ini', 'w') { |file|
|
|
42
|
+
file.write(<<-TOX.gsub(/^\s+/, '')
|
|
43
|
+
# Tox (http://tox.testrun.org/) is a tool for running tests
|
|
44
|
+
# in multiple virtualenvs. This configuration file will run the
|
|
45
|
+
# test suite on all supported python versions. To use it, "pip install tox"
|
|
46
|
+
# and then run "tox" from this directory.
|
|
47
|
+
|
|
48
|
+
[tox]
|
|
49
|
+
envlist = py27
|
|
50
|
+
usedevelop = True
|
|
51
|
+
|
|
52
|
+
[testenv]
|
|
53
|
+
commands = python setup.py test
|
|
54
|
+
deps =
|
|
55
|
+
-rrequirements.txt
|
|
56
|
+
TOX
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# check for/create any required missing folders/files
|
|
62
|
+
unless File.exist?(@source_git_local_path + '/requirements.txt')
|
|
63
|
+
File.open(@source_git_local_path + '/requirements.txt', 'w') { |file| file.write('') }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
unless File.exist?(@source_git_local_path + '/tests')
|
|
67
|
+
FileUtils.mkdir(@source_git_local_path + '/tests')
|
|
68
|
+
end
|
|
69
|
+
unless File.exist?(@source_git_local_path + '/tests/__init__.py')
|
|
70
|
+
File.open(@source_git_local_path + '/tests/__init__.py', 'w') { |file| file.write('') }
|
|
71
|
+
end
|
|
72
|
+
unless File.exist?(@source_git_local_path + '/.gitignore')
|
|
73
|
+
CapsuleCD::GitUtils.create_gitignore(@source_git_local_path, ['Python'])
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_step
|
|
78
|
+
super
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# download the package dependencies and register it in the virtualenv using tox (which will do pip install -e .)
|
|
82
|
+
# https://packaging.python.org/en/latest/distributing/
|
|
83
|
+
# once that's done, tox will run tests
|
|
84
|
+
# run test command
|
|
85
|
+
test_cmd = @config.engine_cmd_test || 'tox'
|
|
86
|
+
Open3.popen3(test_cmd, chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
87
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
88
|
+
Thread.new do
|
|
89
|
+
until (line = stream_buffer.gets).nil?
|
|
90
|
+
puts "#{name} -> #{line}"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
# wait for process
|
|
95
|
+
external.join
|
|
96
|
+
unless external.value.success?
|
|
97
|
+
fail CapsuleCD::Error::TestDependenciesError, test_cmd + ' failed to test package.'
|
|
98
|
+
end
|
|
99
|
+
end unless @config.engine_disable_test
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# run npm publish
|
|
103
|
+
def package_step
|
|
104
|
+
super
|
|
105
|
+
|
|
106
|
+
# commit changes to the cookbook. (test run occurs before this, and it should clean up any instrumentation files, created,
|
|
107
|
+
# as they will be included in the commmit and any release artifacts)
|
|
108
|
+
version = File.read(@source_git_local_path + '/VERSION').strip
|
|
109
|
+
next_version = SemVer.parse(version)
|
|
110
|
+
CapsuleCD::GitUtils.commit(@source_git_local_path, "(v#{next_version}) Automated packaging of release by CapsuleCD")
|
|
111
|
+
@source_release_commit = CapsuleCD::GitUtils.tag(@source_git_local_path, "v#{next_version}")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# this step should push the release to the package repository (ie. npm, chef supermarket, rubygems)
|
|
115
|
+
def release_step
|
|
116
|
+
super
|
|
117
|
+
pypirc_path = File.expand_path('~/.pypirc')
|
|
118
|
+
|
|
119
|
+
unless @config.pypi_username || @config.pypi_password
|
|
120
|
+
fail CapsuleCD::Error::ReleaseCredentialsMissing, 'cannot deploy package to pip, credentials missing'
|
|
121
|
+
return
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# write the knife.rb config file.
|
|
125
|
+
File.open(pypirc_path, 'w+') do |file|
|
|
126
|
+
file.write(<<-EOT.gsub(/^\s+/, '')
|
|
127
|
+
[distutils]
|
|
128
|
+
index-servers=pypi
|
|
129
|
+
|
|
130
|
+
[pypi]
|
|
131
|
+
repository = https://pypi.python.org/pypi
|
|
132
|
+
username = #{@config.pypi_username}
|
|
133
|
+
password = #{@config.pypi_password}
|
|
134
|
+
EOT
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# run python setup.py sdist upload
|
|
139
|
+
# TODO: use twine instead (it supports HTTPS.)https://python-packaging-user-guide.readthedocs.org/en/latest/distributing/#uploading-your-project-to-pypi
|
|
140
|
+
Open3.popen3('python setup.py sdist upload', chdir: @source_git_local_path) do |_stdin, stdout, stderr, external|
|
|
141
|
+
{ stdout: stdout, stderr: stderr }. each do |name, stream_buffer|
|
|
142
|
+
Thread.new do
|
|
143
|
+
until (line = stream_buffer.gets).nil?
|
|
144
|
+
puts "#{name} -> #{line}"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
# wait for process
|
|
149
|
+
external.join
|
|
150
|
+
unless external.value.success?
|
|
151
|
+
fail CapsuleCD::Error::ReleasePackageError, 'python setup.py upload failed. Check log for exact error'
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|