nucleus 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|