nucleus 0.2.0 → 0.3.1
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 +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +9 -0
- data/README.md +43 -72
- data/lib/nucleus/adapter_resolver.rb +3 -3
- data/lib/nucleus/adapters/base_adapter.rb +109 -109
- data/lib/nucleus/adapters/v1/cloud_foundry_v2/application.rb +111 -111
- data/lib/nucleus/adapters/v1/cloud_foundry_v2/cloud_foundry_v2.rb +141 -141
- data/lib/nucleus/adapters/v1/cloud_foundry_v2/data.rb +97 -97
- data/lib/nucleus/adapters/v1/cloud_foundry_v2/domains.rb +5 -5
- data/lib/nucleus/adapters/v1/cloud_foundry_v2/lifecycle.rb +41 -41
- data/lib/nucleus/adapters/v1/cloud_foundry_v2/logs.rb +6 -6
- data/lib/nucleus/adapters/v1/cloud_foundry_v2/regions.rb +33 -33
- data/lib/nucleus/adapters/v1/cloud_foundry_v2/services.rb +6 -6
- data/lib/nucleus/adapters/v1/cloud_foundry_v2/vars.rb +80 -80
- data/lib/nucleus/adapters/v1/heroku/app_states.rb +57 -57
- data/lib/nucleus/adapters/v1/heroku/data.rb +78 -78
- data/lib/nucleus/adapters/v1/heroku/heroku.rb +146 -146
- data/lib/nucleus/adapters/v1/heroku/lifecycle.rb +51 -51
- data/lib/nucleus/adapters/v1/heroku/logs.rb +2 -2
- data/lib/nucleus/adapters/v1/heroku/regions.rb +42 -42
- data/lib/nucleus/adapters/v1/heroku/services.rb +168 -168
- data/lib/nucleus/adapters/v1/heroku/vars.rb +65 -65
- data/lib/nucleus/adapters/v1/openshift_v2/app_states.rb +68 -68
- data/lib/nucleus/adapters/v1/openshift_v2/application.rb +1 -1
- data/lib/nucleus/adapters/v1/openshift_v2/data.rb +96 -96
- data/lib/nucleus/adapters/v1/openshift_v2/lifecycle.rb +60 -60
- data/lib/nucleus/adapters/v1/openshift_v2/logs.rb +106 -106
- data/lib/nucleus/adapters/v1/openshift_v2/openshift_v2.rb +125 -125
- data/lib/nucleus/adapters/v1/openshift_v2/regions.rb +58 -58
- data/lib/nucleus/adapters/v1/openshift_v2/services.rb +173 -173
- data/lib/nucleus/adapters/v1/openshift_v2/vars.rb +49 -49
- data/lib/nucleus/adapters/v1/stub_adapter.rb +464 -464
- data/lib/nucleus/core/adapter_extensions/auth/auth_client.rb +44 -44
- data/lib/nucleus/core/adapter_extensions/auth/expiring_token_auth_client.rb +53 -53
- data/lib/nucleus/core/adapter_extensions/auth/http_basic_auth_client.rb +3 -3
- data/lib/nucleus/core/adapter_extensions/auth/o_auth2_auth_client.rb +95 -95
- data/lib/nucleus/core/adapter_extensions/auth/token_auth_client.rb +36 -36
- data/lib/nucleus/core/adapter_extensions/http_client.rb +5 -5
- data/lib/nucleus/core/common/files/archive_extractor.rb +1 -1
- data/lib/nucleus/core/common/files/archiver.rb +2 -2
- data/lib/nucleus/core/file_handling/file_manager.rb +64 -64
- data/lib/nucleus/core/file_handling/git_deployer.rb +133 -133
- data/lib/nucleus/core/import/adapter_configuration.rb +53 -53
- data/lib/nucleus/scripts/initialize_config_defaults.rb +26 -26
- data/lib/nucleus/version.rb +1 -1
- data/nucleus.gemspec +2 -2
- data/spec/integration/api/auth_spec.rb +3 -3
- data/spec/spec_helper.rb +98 -98
- data/spec/test_suites.rake +1 -1
- data/spec/unit/adapters/git_deployer_spec.rb +262 -262
- data/spec/unit/common/helpers/auth_helper_spec.rb +1 -1
- data/tasks/evaluation.rake +1 -1
- data/wiki/adapter_tests.md +0 -7
- data/wiki/implement_new_adapter.md +1 -1
- metadata +4 -20
- data/config/adapters/cloud_control.yml +0 -32
- data/lib/nucleus/adapters/v1/cloud_control/application.rb +0 -108
- data/lib/nucleus/adapters/v1/cloud_control/authentication.rb +0 -27
- data/lib/nucleus/adapters/v1/cloud_control/buildpacks.rb +0 -23
- data/lib/nucleus/adapters/v1/cloud_control/cloud_control.rb +0 -153
- data/lib/nucleus/adapters/v1/cloud_control/data.rb +0 -76
- data/lib/nucleus/adapters/v1/cloud_control/domains.rb +0 -68
- data/lib/nucleus/adapters/v1/cloud_control/lifecycle.rb +0 -27
- data/lib/nucleus/adapters/v1/cloud_control/log_poller.rb +0 -71
- data/lib/nucleus/adapters/v1/cloud_control/logs.rb +0 -103
- data/lib/nucleus/adapters/v1/cloud_control/regions.rb +0 -32
- data/lib/nucleus/adapters/v1/cloud_control/scaling.rb +0 -17
- data/lib/nucleus/adapters/v1/cloud_control/semantic_errors.rb +0 -31
- data/lib/nucleus/adapters/v1/cloud_control/services.rb +0 -162
- data/lib/nucleus/adapters/v1/cloud_control/token.rb +0 -17
- data/lib/nucleus/adapters/v1/cloud_control/vars.rb +0 -88
@@ -114,16 +114,16 @@ module Nucleus
|
|
114
114
|
error_status = e.response.status
|
115
115
|
# arriving here, error could not be processed --> use fallback errors
|
116
116
|
if e.is_a? Excon::Errors::ServerError
|
117
|
-
|
117
|
+
raise Errors::UnknownAdapterCallError, e.message
|
118
118
|
elsif error_status == 404
|
119
119
|
log.error("Resource not found (404) at '#{url}', indicating an adapter issue")
|
120
|
-
|
120
|
+
raise Errors::UnknownAdapterCallError, 'Resource not found, probably the adapter must be updated'
|
121
121
|
elsif error_status == 401
|
122
|
-
|
123
|
-
|
122
|
+
raise Errors::EndpointAuthenticationError,
|
123
|
+
'Auth. failed, probably cache is outdated or permissions were revoked?'
|
124
124
|
else
|
125
125
|
log.error("Fallback error handling (#{error_status}) at '#{url}', indicating an adapter issue")
|
126
|
-
|
126
|
+
raise Errors::UnknownAdapterCallError, e.message
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
@@ -13,7 +13,7 @@ module Nucleus
|
|
13
13
|
# @return [Integer] number of extracted files
|
14
14
|
def extract(file, destination_path, compression_format)
|
15
15
|
compression_method = compression_format_method_name(compression_format)
|
16
|
-
|
16
|
+
raise StandardError, 'Unsupported compression format' unless respond_to?(compression_method, true)
|
17
17
|
|
18
18
|
# be sure that directory exists
|
19
19
|
FileUtils.mkdir_p(destination_path, verbose: false)
|
@@ -12,8 +12,8 @@ module Nucleus
|
|
12
12
|
# @return [StringIO] compressed data of the given input path
|
13
13
|
def compress(path, compression_format)
|
14
14
|
compression_method = compression_format.downcase.tr('.', '_').underscore.to_sym
|
15
|
-
|
16
|
-
|
15
|
+
raise StandardError,
|
16
|
+
"Unsupported compression format #{compression_format}" unless respond_to?(compression_method, true)
|
17
17
|
send(compression_method, path)
|
18
18
|
end
|
19
19
|
|
@@ -1,64 +1,64 @@
|
|
1
|
-
module Nucleus
|
2
|
-
module Adapters
|
3
|
-
module FileManager
|
4
|
-
extend Nucleus::Logging
|
5
|
-
|
6
|
-
# Load the contents of the file.
|
7
|
-
# @param [String] file absolute path of the file to read
|
8
|
-
# @raise [Nucleus::FileExistenceError] if the file does not exist
|
9
|
-
# @return [StringIO] binary contents of the file, rewinded
|
10
|
-
def self.load_file(file)
|
11
|
-
io = StringIO.new('')
|
12
|
-
File.open(file, 'r') do |opened_file|
|
13
|
-
opened_file.binmode
|
14
|
-
io.write opened_file.read
|
15
|
-
end
|
16
|
-
io.rewind
|
17
|
-
io
|
18
|
-
end
|
19
|
-
|
20
|
-
# Save the data from within the {::Data} object to the file.
|
21
|
-
# By default, this replaces already existing files.
|
22
|
-
# If force is set to false, the method call will fail if there already is a file at the destination.
|
23
|
-
# If force is false, but expected_file_md5_hex is specified, the file will be replaced as long as
|
24
|
-
# the hexdigest of the current file is equal to the expected_file_md5_hex param.
|
25
|
-
#
|
26
|
-
# @param [String] file absolute path of the file to write to
|
27
|
-
# @param [Data] io data to write to the file
|
28
|
-
# @param [Boolean] force if true file is replaced, else write fails
|
29
|
-
# @param [String] expected_file_md5_hex MD5 hexdigest of the expected file to be replaced.
|
30
|
-
# If nil, file is not replaced as long as force == false
|
31
|
-
# @raise [Nucleus::FileExistenceError] if the file already existed
|
32
|
-
# @raise [ArgumentError] if expected_file_md5_hex did not match the MD5 hexdigest of the current file
|
33
|
-
# in the repository
|
34
|
-
# @return [void]
|
35
|
-
def self.save_file_from_data(file, io, force = true, expected_file_md5_hex = nil)
|
36
|
-
if File.exist? file
|
37
|
-
unless force
|
38
|
-
# fail if file exists, but shall not be replaced
|
39
|
-
|
40
|
-
|
41
|
-
# do only replace if file is as expected
|
42
|
-
actual_hex = Digest::MD5.file(file).hexdigest
|
43
|
-
unless actual_hex == expected_file_md5_hex
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# rewind IO
|
50
|
-
io.rewind if io.respond_to? :rewind
|
51
|
-
|
52
|
-
# create parent directory
|
53
|
-
dirname = File.dirname(file)
|
54
|
-
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
55
|
-
|
56
|
-
# write file and replace existing
|
57
|
-
File.open(file, 'w') do |opened_file|
|
58
|
-
opened_file.binmode
|
59
|
-
opened_file.write io.read
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
1
|
+
module Nucleus
|
2
|
+
module Adapters
|
3
|
+
module FileManager
|
4
|
+
extend Nucleus::Logging
|
5
|
+
|
6
|
+
# Load the contents of the file.
|
7
|
+
# @param [String] file absolute path of the file to read
|
8
|
+
# @raise [Nucleus::FileExistenceError] if the file does not exist
|
9
|
+
# @return [StringIO] binary contents of the file, rewinded
|
10
|
+
def self.load_file(file)
|
11
|
+
io = StringIO.new('')
|
12
|
+
File.open(file, 'r') do |opened_file|
|
13
|
+
opened_file.binmode
|
14
|
+
io.write opened_file.read
|
15
|
+
end
|
16
|
+
io.rewind
|
17
|
+
io
|
18
|
+
end
|
19
|
+
|
20
|
+
# Save the data from within the {::Data} object to the file.
|
21
|
+
# By default, this replaces already existing files.
|
22
|
+
# If force is set to false, the method call will fail if there already is a file at the destination.
|
23
|
+
# If force is false, but expected_file_md5_hex is specified, the file will be replaced as long as
|
24
|
+
# the hexdigest of the current file is equal to the expected_file_md5_hex param.
|
25
|
+
#
|
26
|
+
# @param [String] file absolute path of the file to write to
|
27
|
+
# @param [Data] io data to write to the file
|
28
|
+
# @param [Boolean] force if true file is replaced, else write fails
|
29
|
+
# @param [String] expected_file_md5_hex MD5 hexdigest of the expected file to be replaced.
|
30
|
+
# If nil, file is not replaced as long as force == false
|
31
|
+
# @raise [Nucleus::FileExistenceError] if the file already existed
|
32
|
+
# @raise [ArgumentError] if expected_file_md5_hex did not match the MD5 hexdigest of the current file
|
33
|
+
# in the repository
|
34
|
+
# @return [void]
|
35
|
+
def self.save_file_from_data(file, io, force = true, expected_file_md5_hex = nil)
|
36
|
+
if File.exist? file
|
37
|
+
unless force
|
38
|
+
# fail if file exists, but shall not be replaced
|
39
|
+
raise Nucleus::FileExistenceError, 'File already exists' if expected_file_md5_hex.nil?
|
40
|
+
|
41
|
+
# do only replace if file is as expected
|
42
|
+
actual_hex = Digest::MD5.file(file).hexdigest
|
43
|
+
unless actual_hex == expected_file_md5_hex
|
44
|
+
raise ArgumentError, "File to replace does exist, but hash sum is different than expected: #{actual_hex}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# rewind IO
|
50
|
+
io.rewind if io.respond_to? :rewind
|
51
|
+
|
52
|
+
# create parent directory
|
53
|
+
dirname = File.dirname(file)
|
54
|
+
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
55
|
+
|
56
|
+
# write file and replace existing
|
57
|
+
File.open(file, 'w') do |opened_file|
|
58
|
+
opened_file.binmode
|
59
|
+
opened_file.write io.read
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,133 +1,133 @@
|
|
1
|
-
module Nucleus
|
2
|
-
module Adapters
|
3
|
-
class GitDeployer
|
4
|
-
include Nucleus::Logging
|
5
|
-
|
6
|
-
# Initialize a new instance of the GitDeployer
|
7
|
-
# @param [String] user_email email address of the user, used as author of commits
|
8
|
-
# @param [String] repo_url address where the repository can be retrieved
|
9
|
-
# @param [String] repo_name name of the directory for the repository that shall be created in the tmp dir
|
10
|
-
# @param [String] repo_branch branch to push to
|
11
|
-
def initialize(repo_name, repo_url, user_email, repo_branch = 'master')
|
12
|
-
@repo_name = repo_name
|
13
|
-
@repo_url = repo_url
|
14
|
-
@repo_branch = repo_branch
|
15
|
-
@user_email = user_email
|
16
|
-
end
|
17
|
-
|
18
|
-
# Force a build using the latest git commit.
|
19
|
-
# To enforce the new build, a file 'nucleus-rebuild-trigger'
|
20
|
-
# gets created or updated in the repository and the changes will be pushed.
|
21
|
-
# @return [void]
|
22
|
-
def trigger_build
|
23
|
-
push_repository_changes do |repo_dir|
|
24
|
-
# add a custom file that always changes the data and triggers a new build
|
25
|
-
build_trigger_file = File.join(repo_dir, 'nucleus-rebuild-trigger')
|
26
|
-
current_md5 = File.exist?(build_trigger_file) ? Digest::MD5.file(build_trigger_file).hexdigest : nil
|
27
|
-
data = StringIO.new("Nucleus rebuild, triggered at #{Time.now}")
|
28
|
-
FileManager.save_file_from_data(build_trigger_file, data, false, current_md5)
|
29
|
-
end
|
30
|
-
nil
|
31
|
-
end
|
32
|
-
|
33
|
-
# Deploys the contents of the archive file to the repository that resides at the repo_url.
|
34
|
-
#
|
35
|
-
# @param [File] file archive file whose contents shall be deployed to the repository
|
36
|
-
# @param [String] file_compression_format compression format of the application archive, e.g. 'zip' or 'tar.gz'
|
37
|
-
# @return [void]
|
38
|
-
def deploy(file, file_compression_format)
|
39
|
-
extractor = Nucleus::ArchiveExtractor.new
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
push_repository_changes do |repo_dir|
|
44
|
-
# now remove all current files, except the git db
|
45
|
-
Find.find(repo_dir) do |f|
|
46
|
-
next if f.start_with?("#{repo_dir}/.git") || f == repo_dir
|
47
|
-
FileUtils.rm_rf(f) if File.directory?(f)
|
48
|
-
FileUtils.rm_f(f) if File.file?(f)
|
49
|
-
end
|
50
|
-
|
51
|
-
# uncompress and extract to
|
52
|
-
extracted = extractor.extract(file, repo_dir, file_compression_format)
|
53
|
-
|
54
|
-
|
55
|
-
# if the application was wrapped within a directory, move all 1st level files and dirs to the root
|
56
|
-
sanitizer = Nucleus::ApplicationRepoSanitizer.new
|
57
|
-
sanitizer.sanitize(repo_dir)
|
58
|
-
end
|
59
|
-
nil
|
60
|
-
end
|
61
|
-
|
62
|
-
# Download the contents of a git repository in the requested format.
|
63
|
-
# @param [String] format compression to be used for the download e.g. 'zip' or 'tar.gz'
|
64
|
-
# @return [StringIO] data requested to be downloaded
|
65
|
-
def download(format, exclude_git = true)
|
66
|
-
with_repository do |repo_dir|
|
67
|
-
# TODO: maybe we can do this directly via SSH and prevent the disk writes?
|
68
|
-
# download files temporarily from the repo
|
69
|
-
Nucleus::Archiver.new(exclude_git).compress(repo_dir, format)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
def with_repository
|
76
|
-
tmp_dir = Dir.tmpdir
|
77
|
-
repo_dir = "#{tmp_dir}/#{@repo_name}"
|
78
|
-
begin
|
79
|
-
repository = Git.clone(@repo_url, @repo_name, path: tmp_dir)
|
80
|
-
# checkout custom branch
|
81
|
-
unless @repo_branch == 'master'
|
82
|
-
begin
|
83
|
-
repository.checkout(repository.branch(@repo_branch))
|
84
|
-
rescue StandardError
|
85
|
-
# catch errors, might occur if no commit has been made and we try to switch the branch
|
86
|
-
repository.checkout(@repo_branch, new_branch: true)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# now execute the actual actions on the repository
|
91
|
-
yield repo_dir, repository
|
92
|
-
ensure
|
93
|
-
# now delete the tmp directory again
|
94
|
-
FileUtils.rm_rf(repo_dir)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def push_repository_changes
|
99
|
-
with_repository do |repo_dir, repository|
|
100
|
-
repository.config('user.name', 'Nucleus')
|
101
|
-
repository.config('user.email', @user_email)
|
102
|
-
# update files
|
103
|
-
yield repo_dir
|
104
|
-
# push changes
|
105
|
-
push(repository)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# Push all contents of the repository to the default remote 'origin'.
|
110
|
-
# The repository will also be pushed if none of the files did change and no new commit was made.
|
111
|
-
# @param [Git::Lib] repository repository whose contents are to be pushed
|
112
|
-
# @return [void]
|
113
|
-
def push(repository)
|
114
|
-
# add all files to the repository
|
115
|
-
repository.add(all: true)
|
116
|
-
|
117
|
-
# commit, but be aware: current version could be identical to previous version resulting in an error
|
118
|
-
begin
|
119
|
-
repository.commit('Application deployment via Nucleus')
|
120
|
-
rescue Git::GitExecuteError => e
|
121
|
-
# usually indicates that no files could be committed, repository is up to date
|
122
|
-
log.debug("Git commit failed: #{e}")
|
123
|
-
end
|
124
|
-
|
125
|
-
# repack to enhance compression
|
126
|
-
repository.repack
|
127
|
-
|
128
|
-
# force push, so that the push is executed even when all files remain unchanged
|
129
|
-
repository.push('origin', @repo_branch, force: true)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
1
|
+
module Nucleus
|
2
|
+
module Adapters
|
3
|
+
class GitDeployer
|
4
|
+
include Nucleus::Logging
|
5
|
+
|
6
|
+
# Initialize a new instance of the GitDeployer
|
7
|
+
# @param [String] user_email email address of the user, used as author of commits
|
8
|
+
# @param [String] repo_url address where the repository can be retrieved
|
9
|
+
# @param [String] repo_name name of the directory for the repository that shall be created in the tmp dir
|
10
|
+
# @param [String] repo_branch branch to push to
|
11
|
+
def initialize(repo_name, repo_url, user_email, repo_branch = 'master')
|
12
|
+
@repo_name = repo_name
|
13
|
+
@repo_url = repo_url
|
14
|
+
@repo_branch = repo_branch
|
15
|
+
@user_email = user_email
|
16
|
+
end
|
17
|
+
|
18
|
+
# Force a build using the latest git commit.
|
19
|
+
# To enforce the new build, a file 'nucleus-rebuild-trigger'
|
20
|
+
# gets created or updated in the repository and the changes will be pushed.
|
21
|
+
# @return [void]
|
22
|
+
def trigger_build
|
23
|
+
push_repository_changes do |repo_dir|
|
24
|
+
# add a custom file that always changes the data and triggers a new build
|
25
|
+
build_trigger_file = File.join(repo_dir, 'nucleus-rebuild-trigger')
|
26
|
+
current_md5 = File.exist?(build_trigger_file) ? Digest::MD5.file(build_trigger_file).hexdigest : nil
|
27
|
+
data = StringIO.new("Nucleus rebuild, triggered at #{Time.now}")
|
28
|
+
FileManager.save_file_from_data(build_trigger_file, data, false, current_md5)
|
29
|
+
end
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# Deploys the contents of the archive file to the repository that resides at the repo_url.
|
34
|
+
#
|
35
|
+
# @param [File] file archive file whose contents shall be deployed to the repository
|
36
|
+
# @param [String] file_compression_format compression format of the application archive, e.g. 'zip' or 'tar.gz'
|
37
|
+
# @return [void]
|
38
|
+
def deploy(file, file_compression_format)
|
39
|
+
extractor = Nucleus::ArchiveExtractor.new
|
40
|
+
raise Errors::AdapterRequestError,
|
41
|
+
'Unsupported format of the application archive' unless extractor.supports? file_compression_format
|
42
|
+
|
43
|
+
push_repository_changes do |repo_dir|
|
44
|
+
# now remove all current files, except the git db
|
45
|
+
Find.find(repo_dir) do |f|
|
46
|
+
next if f.start_with?("#{repo_dir}/.git") || f == repo_dir
|
47
|
+
FileUtils.rm_rf(f) if File.directory?(f)
|
48
|
+
FileUtils.rm_f(f) if File.file?(f)
|
49
|
+
end
|
50
|
+
|
51
|
+
# uncompress and extract to
|
52
|
+
extracted = extractor.extract(file, repo_dir, file_compression_format)
|
53
|
+
raise Errors::AdapterRequestError, 'Invalid application: Archive did not contain any files' if extracted == 0
|
54
|
+
|
55
|
+
# if the application was wrapped within a directory, move all 1st level files and dirs to the root
|
56
|
+
sanitizer = Nucleus::ApplicationRepoSanitizer.new
|
57
|
+
sanitizer.sanitize(repo_dir)
|
58
|
+
end
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
|
62
|
+
# Download the contents of a git repository in the requested format.
|
63
|
+
# @param [String] format compression to be used for the download e.g. 'zip' or 'tar.gz'
|
64
|
+
# @return [StringIO] data requested to be downloaded
|
65
|
+
def download(format, exclude_git = true)
|
66
|
+
with_repository do |repo_dir|
|
67
|
+
# TODO: maybe we can do this directly via SSH and prevent the disk writes?
|
68
|
+
# download files temporarily from the repo
|
69
|
+
Nucleus::Archiver.new(exclude_git).compress(repo_dir, format)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def with_repository
|
76
|
+
tmp_dir = Dir.tmpdir
|
77
|
+
repo_dir = "#{tmp_dir}/#{@repo_name}"
|
78
|
+
begin
|
79
|
+
repository = Git.clone(@repo_url, @repo_name, path: tmp_dir)
|
80
|
+
# checkout custom branch
|
81
|
+
unless @repo_branch == 'master'
|
82
|
+
begin
|
83
|
+
repository.checkout(repository.branch(@repo_branch))
|
84
|
+
rescue StandardError
|
85
|
+
# catch errors, might occur if no commit has been made and we try to switch the branch
|
86
|
+
repository.checkout(@repo_branch, new_branch: true)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# now execute the actual actions on the repository
|
91
|
+
yield repo_dir, repository
|
92
|
+
ensure
|
93
|
+
# now delete the tmp directory again
|
94
|
+
FileUtils.rm_rf(repo_dir)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def push_repository_changes
|
99
|
+
with_repository do |repo_dir, repository|
|
100
|
+
repository.config('user.name', 'Nucleus')
|
101
|
+
repository.config('user.email', @user_email)
|
102
|
+
# update files
|
103
|
+
yield repo_dir
|
104
|
+
# push changes
|
105
|
+
push(repository)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Push all contents of the repository to the default remote 'origin'.
|
110
|
+
# The repository will also be pushed if none of the files did change and no new commit was made.
|
111
|
+
# @param [Git::Lib] repository repository whose contents are to be pushed
|
112
|
+
# @return [void]
|
113
|
+
def push(repository)
|
114
|
+
# add all files to the repository
|
115
|
+
repository.add(all: true)
|
116
|
+
|
117
|
+
# commit, but be aware: current version could be identical to previous version resulting in an error
|
118
|
+
begin
|
119
|
+
repository.commit('Application deployment via Nucleus')
|
120
|
+
rescue Git::GitExecuteError => e
|
121
|
+
# usually indicates that no files could be committed, repository is up to date
|
122
|
+
log.debug("Git commit failed: #{e}")
|
123
|
+
end
|
124
|
+
|
125
|
+
# repack to enhance compression
|
126
|
+
repository.repack
|
127
|
+
|
128
|
+
# force push, so that the push is executed even when all files remain unchanged
|
129
|
+
repository.push('origin', @repo_branch, force: true)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -1,53 +1,53 @@
|
|
1
|
-
module Nucleus
|
2
|
-
module Adapters
|
3
|
-
extend Nucleus::Logging
|
4
|
-
|
5
|
-
# Get all adapter configuration files that are included in the application.
|
6
|
-
# The config files must be located at the +config/adapters+ directory.
|
7
|
-
#
|
8
|
-
# @return [Array<File>] all adapter configuration files
|
9
|
-
def self.configuration_files
|
10
|
-
return @configuration_files if @configuration_files
|
11
|
-
adapter_dir = "#{Nucleus.root}/config/adapters"
|
12
|
-
files = Dir[File.join(adapter_dir, '*.yml')] | Dir[File.join(adapter_dir, '*.yaml')]
|
13
|
-
files = files.flatten.compact
|
14
|
-
files.collect! { |file| File.expand_path(file) }
|
15
|
-
log.debug "... found #{files.size} adapter config file(s)"
|
16
|
-
@configuration_files = files
|
17
|
-
@configuration_files
|
18
|
-
end
|
19
|
-
|
20
|
-
# Get the clazz to the adapter file that matches the adapter_config and api_version.
|
21
|
-
#
|
22
|
-
# @param [String] adapter_config adapter configuration that indicates the adapter's name
|
23
|
-
# @param [String] api_version API version to load the adapter for
|
24
|
-
# @return [String] clazz name of the adapter
|
25
|
-
def self.adapter_clazz(adapter_config, api_version)
|
26
|
-
adapter_file = adapter_file(adapter_config, api_version)
|
27
|
-
return if adapter_file.nil?
|
28
|
-
# transform path to clazz and load an instance
|
29
|
-
adapter_clazz = "Nucleus::Adapters::#{api_version.upcase}::#{File.basename(adapter_file, '.rb').capitalize}"
|
30
|
-
adapter_clazz.camelize.split('::').inject(Object) { |a, e| a.const_get e }
|
31
|
-
end
|
32
|
-
|
33
|
-
# Get the path to the adapter's class file by translation from the adapter configuration's name.
|
34
|
-
# If the adapter configuration is called 'abc-vendor.yml', then the adapter's source file must
|
35
|
-
# be found below +app/adapters/#{api_version}/+ with the name +abc-vendor_adapter.rb+.
|
36
|
-
#
|
37
|
-
# @param [String] adapter_config adapter configuration that indicates the adapter's name
|
38
|
-
# @param [String] api_version API version to load the adapter for
|
39
|
-
# @raise [Nucleus::AmbiguousAdapterError] if more than one adapter was found for an adapter configuration
|
40
|
-
# @return [String] path to the adapter's class file
|
41
|
-
def self.adapter_file(adapter_config, api_version)
|
42
|
-
log.debug "... trying to resolve adapter for config #{adapter_config} and API #{api_version}..."
|
43
|
-
adapter_name = File.basename(adapter_config).sub(/.[^.]+\z/, '.rb')
|
44
|
-
file_search_path = "#{Nucleus.root}/lib/nucleus/adapters/#{api_version}/*/#{adapter_name}"
|
45
|
-
adapter_file = Dir.glob(file_search_path)
|
46
|
-
|
47
|
-
|
48
|
-
return if adapter_file.empty?
|
49
|
-
log.debug "... found '#{adapter_file.first}'"
|
50
|
-
adapter_file.first
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
1
|
+
module Nucleus
|
2
|
+
module Adapters
|
3
|
+
extend Nucleus::Logging
|
4
|
+
|
5
|
+
# Get all adapter configuration files that are included in the application.
|
6
|
+
# The config files must be located at the +config/adapters+ directory.
|
7
|
+
#
|
8
|
+
# @return [Array<File>] all adapter configuration files
|
9
|
+
def self.configuration_files
|
10
|
+
return @configuration_files if @configuration_files
|
11
|
+
adapter_dir = "#{Nucleus.root}/config/adapters"
|
12
|
+
files = Dir[File.join(adapter_dir, '*.yml')] | Dir[File.join(adapter_dir, '*.yaml')]
|
13
|
+
files = files.flatten.compact
|
14
|
+
files.collect! { |file| File.expand_path(file) }
|
15
|
+
log.debug "... found #{files.size} adapter config file(s)"
|
16
|
+
@configuration_files = files
|
17
|
+
@configuration_files
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get the clazz to the adapter file that matches the adapter_config and api_version.
|
21
|
+
#
|
22
|
+
# @param [String] adapter_config adapter configuration that indicates the adapter's name
|
23
|
+
# @param [String] api_version API version to load the adapter for
|
24
|
+
# @return [String] clazz name of the adapter
|
25
|
+
def self.adapter_clazz(adapter_config, api_version)
|
26
|
+
adapter_file = adapter_file(adapter_config, api_version)
|
27
|
+
return if adapter_file.nil?
|
28
|
+
# transform path to clazz and load an instance
|
29
|
+
adapter_clazz = "Nucleus::Adapters::#{api_version.upcase}::#{File.basename(adapter_file, '.rb').capitalize}"
|
30
|
+
adapter_clazz.camelize.split('::').inject(Object) { |a, e| a.const_get e }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get the path to the adapter's class file by translation from the adapter configuration's name.
|
34
|
+
# If the adapter configuration is called 'abc-vendor.yml', then the adapter's source file must
|
35
|
+
# be found below +app/adapters/#{api_version}/+ with the name +abc-vendor_adapter.rb+.
|
36
|
+
#
|
37
|
+
# @param [String] adapter_config adapter configuration that indicates the adapter's name
|
38
|
+
# @param [String] api_version API version to load the adapter for
|
39
|
+
# @raise [Nucleus::AmbiguousAdapterError] if more than one adapter was found for an adapter configuration
|
40
|
+
# @return [String] path to the adapter's class file
|
41
|
+
def self.adapter_file(adapter_config, api_version)
|
42
|
+
log.debug "... trying to resolve adapter for config #{adapter_config} and API #{api_version}..."
|
43
|
+
adapter_name = File.basename(adapter_config).sub(/.[^.]+\z/, '.rb')
|
44
|
+
file_search_path = "#{Nucleus.root}/lib/nucleus/adapters/#{api_version}/*/#{adapter_name}"
|
45
|
+
adapter_file = Dir.glob(file_search_path)
|
46
|
+
raise AmbiguousAdapterError, "More than 1 adapter file found for #{adapter_name}" unless adapter_file.size <= 1
|
47
|
+
|
48
|
+
return if adapter_file.empty?
|
49
|
+
log.debug "... found '#{adapter_file.first}'"
|
50
|
+
adapter_file.first
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|