luban 0.5.1 → 0.5.5
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/CHANGELOG.md +13 -0
- data/lib/luban/deployment/cli/application/base.rb +40 -21
- data/lib/luban/deployment/cli/application/configurator.rb +9 -0
- data/lib/luban/deployment/cli/application/{builder.rb → constructor.rb} +2 -4
- data/lib/luban/deployment/cli/application/controller.rb +9 -0
- data/lib/luban/deployment/cli/application/publisher.rb +8 -10
- data/lib/luban/deployment/cli/application/repository.rb +12 -12
- data/lib/luban/deployment/cli/application/worker.rb +22 -0
- data/lib/luban/deployment/cli/application.rb +5 -1
- data/lib/luban/deployment/cli/command.rb +15 -0
- data/lib/luban/deployment/cli/service/base.rb +9 -44
- data/lib/luban/deployment/cli/service/configurator.rb +70 -38
- data/lib/luban/deployment/cli/service/controller.rb +157 -153
- data/lib/luban/deployment/cli/service/installer.rb +2 -2
- data/lib/luban/deployment/cli/service/worker.rb +55 -25
- data/lib/luban/deployment/cli.rb +1 -1
- data/lib/luban/deployment/helpers/generator.rb +34 -30
- data/lib/luban/deployment/version.rb +1 -1
- data/lib/luban/deployment/worker/paths.rb +0 -46
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 22f7040c1da873d1aa03672d4918506c4c6eef8d
|
4
|
+
data.tar.gz: 6df3eeefecd1377d4e0b6db086f57859f08cc5d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 299133650c4099b5f8e61f45998d91388b87edfb168676eee5ad07eda8c5e2652c358984e464551bea814826ae01b87eca6326ccaf77ad881e29d63a428c3e05
|
7
|
+
data.tar.gz: 9dcb174a692218a5f921af3e58c1b017ec1362b220b9bc19bfecaa13ae6fc1ecb95b6a89d64760f1cbed84bcdcb7ddac46cf3a32ad4108a436461972354b7698
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## Version 0.5.5 (WIP)
|
4
|
+
|
5
|
+
Minor enhancements:
|
6
|
+
* Refactored app/service profile templates initialization
|
7
|
+
* Refactored Service::Worker to abstract general behavior for Service/Application
|
8
|
+
* Refactored Service::Configurator to abstract general configuration for Service/Application
|
9
|
+
* Refactored Service::Controller to abstract general control for Service/Application
|
10
|
+
* Changed attribute :name to :type in Application::Repository for better naming
|
11
|
+
* Changed attribute :release_name to :release_type in Application::Publisher for better naming
|
12
|
+
* Removed deploy commands in Service because deploy commands exist ONLY in application level
|
13
|
+
* Renamed application Builder to Constructor for better naming convention in Luban
|
14
|
+
* Minor refactoring
|
15
|
+
|
3
16
|
## Version 0.5.1 (Jun 24, 2016)
|
4
17
|
|
5
18
|
Minor enhancements:
|
@@ -46,11 +46,20 @@ module Luban
|
|
46
46
|
alias_method :require_package, :package
|
47
47
|
|
48
48
|
def source(from = nil, **opts)
|
49
|
-
|
49
|
+
return @source if from.nil?
|
50
|
+
@source = opts.merge(type: 'app', from: from)
|
51
|
+
if source_version.nil?
|
52
|
+
abort "Aborted! Please specify the source version with :tag, :branch or :ref."
|
53
|
+
end
|
54
|
+
@source
|
55
|
+
end
|
56
|
+
|
57
|
+
def source_version
|
58
|
+
@source[:tag] || @source[:branch] || @source[:ref]
|
50
59
|
end
|
51
60
|
|
52
61
|
def profile(from = nil, **opts)
|
53
|
-
from.nil? ? @profile : (@profile = opts.merge(
|
62
|
+
from.nil? ? @profile : (@profile = opts.merge(type: 'profile', from: from))
|
54
63
|
end
|
55
64
|
|
56
65
|
def password_for(user); parent.password_for(user); end
|
@@ -64,7 +73,7 @@ module Luban
|
|
64
73
|
def setup(args:, opts:)
|
65
74
|
show_app_environment
|
66
75
|
promptless_authen(args: args, opts: opts)
|
67
|
-
|
76
|
+
setup!(args: args, opts: opts)
|
68
77
|
end
|
69
78
|
|
70
79
|
def build(args:, opts:)
|
@@ -118,22 +127,23 @@ module Luban
|
|
118
127
|
|
119
128
|
def init_profiles(args:, opts:)
|
120
129
|
show_app_environment
|
121
|
-
|
122
|
-
|
123
|
-
elsif opts[:service].nil?
|
124
|
-
init_profile(args: args, opts: opts)
|
125
|
-
init_service_profiles(args: args, opts: opts)
|
126
|
-
elsif opts[:service].is_a?(TrueClass)
|
127
|
-
init_service_profiles(args: args, opts: opts)
|
128
|
-
else
|
129
|
-
services[opts[:service]].init_profile(args: args, opts: opts)
|
130
|
-
end
|
130
|
+
init_profile(args: args, opts: opts)
|
131
|
+
init_service_profiles(args: args, opts: opts)
|
131
132
|
end
|
132
133
|
|
133
|
-
def init_profile(args:, opts:)
|
134
|
+
def init_profile(args:, opts:)
|
135
|
+
if opts[:app] or opts[:service].nil?
|
136
|
+
init_profile!(args: args, opts: opts.merge(default_templates: default_templates))
|
137
|
+
end
|
138
|
+
end
|
134
139
|
|
135
140
|
def init_service_profiles(args:, opts:)
|
136
|
-
|
141
|
+
return if opts[:app]
|
142
|
+
if services.has_key?(opts[:service])
|
143
|
+
services[opts[:service]].init_profile(args: args, opts: opts)
|
144
|
+
else
|
145
|
+
services.values.each { |s| s.init_profile(args: args, opts: opts) }
|
146
|
+
end
|
137
147
|
end
|
138
148
|
|
139
149
|
protected
|
@@ -184,8 +194,8 @@ module Luban
|
|
184
194
|
|
185
195
|
def setup_init_profiles
|
186
196
|
_services = services.keys
|
187
|
-
|
188
|
-
desc 'Initialize deployment
|
197
|
+
task :init do
|
198
|
+
desc 'Initialize deployment app/service profiles'
|
189
199
|
switch :app, "Application profile ONLY", short: :a
|
190
200
|
option :service, "Service profile ONLY", short: :s, nullable: true,
|
191
201
|
within: _services.push(nil), type: :symbol
|
@@ -193,12 +203,18 @@ module Luban
|
|
193
203
|
end
|
194
204
|
end
|
195
205
|
|
206
|
+
def compose_task_options(opts)
|
207
|
+
super.merge(name: 'app').tap do |o|
|
208
|
+
o.merge!(version: source_version) if has_source?
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
196
212
|
def show_app_environment
|
197
213
|
puts "#{display_name} in #{parent.class.name}"
|
198
214
|
end
|
199
215
|
|
200
|
-
%i(
|
201
|
-
dispatch_task "#{task}!", to: :
|
216
|
+
%i(setup destroy cleanup).each do |task|
|
217
|
+
dispatch_task "#{task}!", to: :constructor, as: task
|
202
218
|
end
|
203
219
|
|
204
220
|
def build_repositories(args:, opts:)
|
@@ -207,11 +223,12 @@ module Luban
|
|
207
223
|
end
|
208
224
|
|
209
225
|
def deploy_profile(args:, opts:)
|
210
|
-
update_profile
|
226
|
+
update_profile(args: args, opts: opts)
|
211
227
|
deploy_profile!(args: args, opts: opts.merge(repository: profile))
|
212
228
|
end
|
213
229
|
|
214
|
-
def update_profile
|
230
|
+
def update_profile(args:, opts:)
|
231
|
+
update_profile!(args: args, opts: opts)
|
215
232
|
services.each_value { |s| s.send(:update_profile, args: args, opts: opts) }
|
216
233
|
end
|
217
234
|
|
@@ -230,6 +247,8 @@ module Luban
|
|
230
247
|
|
231
248
|
dispatch_task :promptless_authen!, to: :authenticator, as: :promptless_authen
|
232
249
|
dispatch_task :public_key!, to: :authenticator, as: :public_key, locally: true
|
250
|
+
dispatch_task :init_profile!, to: :configurator, as: :init_profile, locally: true
|
251
|
+
dispatch_task :update_profile!, to: :configurator, as: :update_profile, locally: true
|
233
252
|
dispatch_task :build_repository!, to: :repository, as: :build, locally: true
|
234
253
|
dispatch_task :package_release!, to: :repository, as: :package, locally: true
|
235
254
|
dispatch_task :publish_release!, to: :publisher, as: :publish
|
@@ -1,9 +1,7 @@
|
|
1
1
|
module Luban
|
2
2
|
module Deployment
|
3
3
|
class Application
|
4
|
-
class
|
5
|
-
include Luban::Deployment::Worker::Paths::Remote
|
6
|
-
|
4
|
+
class Constructor < Worker
|
7
5
|
def envrc_template_file
|
8
6
|
@envrc_template_file ||= find_template_file("envrc.erb")
|
9
7
|
end
|
@@ -12,7 +10,7 @@ module Luban
|
|
12
10
|
@unset_envrc_template_file ||= find_template_file("unset_envrc.erb")
|
13
11
|
end
|
14
12
|
|
15
|
-
def
|
13
|
+
def setup
|
16
14
|
bootstrap
|
17
15
|
create_envrc_files
|
18
16
|
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
module Luban
|
2
2
|
module Deployment
|
3
3
|
class Application
|
4
|
-
class Publisher <
|
5
|
-
|
6
|
-
|
7
|
-
def release_name; task.opts.release[:name]; end
|
4
|
+
class Publisher < Worker
|
5
|
+
def release_type; task.opts.release[:type]; end
|
8
6
|
def release_tag; task.opts.release[:tag]; end
|
9
7
|
def release_package_path; task.opts.release[:path]; end
|
10
8
|
def release_md5; task.opts.release[:md5]; end
|
@@ -13,15 +11,15 @@ module Luban
|
|
13
11
|
def gems_source; bundled_gems[:gems_cache]; end
|
14
12
|
def gems; bundled_gems[:gems]; end
|
15
13
|
|
16
|
-
def publish_app?;
|
17
|
-
def publish_profile?;
|
14
|
+
def publish_app?; release_type == 'app'; end
|
15
|
+
def publish_profile?; release_type == 'profile'; end
|
18
16
|
|
19
17
|
def display_name
|
20
|
-
@display_name ||= "#{application} #{
|
18
|
+
@display_name ||= "#{application} #{release_type} (release: #{release_tag})"
|
21
19
|
end
|
22
20
|
|
23
21
|
def releases_path
|
24
|
-
@releases_path ||= super.join(
|
22
|
+
@releases_path ||= super.join(release_type)
|
25
23
|
end
|
26
24
|
|
27
25
|
def release_path
|
@@ -119,7 +117,7 @@ module Luban
|
|
119
117
|
end
|
120
118
|
|
121
119
|
def create_symlinks
|
122
|
-
send("create_#{
|
120
|
+
send("create_#{release_type}_symlinks")
|
123
121
|
create_shared_symlinks_for(:directory, linked_dirs)
|
124
122
|
create_shared_symlinks_for(:directory, bundle_linked_dirs) if file?(gemfile)
|
125
123
|
end
|
@@ -136,7 +134,7 @@ module Luban
|
|
136
134
|
end
|
137
135
|
|
138
136
|
def create_release_symlink(target_dir)
|
139
|
-
assure_symlink(release_path, target_dir.join(
|
137
|
+
assure_symlink(release_path, target_dir.join(release_type))
|
140
138
|
end
|
141
139
|
|
142
140
|
def create_shared_symlinks_for(type, linked_paths)
|
@@ -7,7 +7,7 @@ module Luban
|
|
7
7
|
|
8
8
|
DefaultRevisionSize = 12
|
9
9
|
|
10
|
-
attr_reader :
|
10
|
+
attr_reader :type
|
11
11
|
attr_reader :from
|
12
12
|
attr_reader :scm
|
13
13
|
attr_reader :revision
|
@@ -23,11 +23,11 @@ module Luban
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def clone_path
|
26
|
-
@clone_path ||= workspace_path.join('repositories').join(
|
26
|
+
@clone_path ||= workspace_path.join('repositories').join(type)
|
27
27
|
end
|
28
28
|
|
29
29
|
def releases_path
|
30
|
-
@releases_path ||= workspace_path.join('releases').join(
|
30
|
+
@releases_path ||= workspace_path.join('releases').join(type)
|
31
31
|
end
|
32
32
|
|
33
33
|
def release_package_path
|
@@ -47,7 +47,7 @@ module Luban
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def release_prefix
|
50
|
-
@release_prefix ||= "#{stage}-#{project}-#{application}-#{
|
50
|
+
@release_prefix ||= "#{stage}-#{project}-#{application}-#{type}"
|
51
51
|
end
|
52
52
|
|
53
53
|
def release_tag
|
@@ -75,17 +75,17 @@ module Luban
|
|
75
75
|
assure_dirs(clone_path, releases_path)
|
76
76
|
if cloned? and !force?
|
77
77
|
update_revision
|
78
|
-
update_result "Skipped! Local #{
|
78
|
+
update_result "Skipped! Local #{type} repository has been built ALREADY.", status: :skipped
|
79
79
|
else
|
80
80
|
if available?
|
81
81
|
if build!
|
82
82
|
update_revision
|
83
|
-
update_result "Successfully built local #{
|
83
|
+
update_result "Successfully built local #{type} repository."
|
84
84
|
else
|
85
|
-
update_result "FAILED to build local #{
|
85
|
+
update_result "FAILED to build local #{type} repository!", status: :failed, level: :error
|
86
86
|
end
|
87
87
|
else
|
88
|
-
update_result "Aborted! Remote #{
|
88
|
+
update_result "Aborted! Remote #{type} repository is NOT available.", status: :failed, level: :error
|
89
89
|
end
|
90
90
|
end
|
91
91
|
end
|
@@ -94,16 +94,16 @@ module Luban
|
|
94
94
|
if cloned?
|
95
95
|
if package!
|
96
96
|
cleanup_releases
|
97
|
-
update_result "Successfully package local #{
|
98
|
-
release: {
|
97
|
+
update_result "Successfully package local #{type} repository to #{release_package_path}.",
|
98
|
+
release: { type: type, tag: release_tag,
|
99
99
|
path: release_package_path,
|
100
100
|
md5: md5_for_file(release_package_path),
|
101
101
|
bundled_gems: bundle_gems }
|
102
102
|
else
|
103
|
-
update_result "FAILED to package local #{
|
103
|
+
update_result "FAILED to package local #{type} repository!", status: :failed, level: :error
|
104
104
|
end
|
105
105
|
else
|
106
|
-
update_result "Aborted! Local #{
|
106
|
+
update_result "Aborted! Local #{type} package is NOT built yet!", status: :failed, level: :error
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
class Application
|
4
|
+
class Worker < Luban::Deployment::Worker::Base
|
5
|
+
include Luban::Deployment::Worker::Paths::Remote
|
6
|
+
include Luban::Deployment::Service::Worker::Base
|
7
|
+
|
8
|
+
def service_name
|
9
|
+
@service_name ||= task.opts.name
|
10
|
+
end
|
11
|
+
|
12
|
+
def service_version
|
13
|
+
@service_version ||= task.opts.version
|
14
|
+
end
|
15
|
+
|
16
|
+
def service_full_name
|
17
|
+
@service_full_name ||= "#{service_name}-#{service_version}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,5 +1,9 @@
|
|
1
1
|
require_relative 'application/base'
|
2
|
+
require_relative 'application/worker'
|
2
3
|
require_relative 'application/authenticator'
|
3
|
-
require_relative 'application/
|
4
|
+
require_relative 'application/constructor'
|
4
5
|
require_relative 'application/repository'
|
5
6
|
require_relative 'application/publisher'
|
7
|
+
require_relative 'application/configurator'
|
8
|
+
require_relative 'application/controller'
|
9
|
+
|
@@ -208,6 +208,12 @@ module Luban
|
|
208
208
|
locally ? result.first[:__return__] : result
|
209
209
|
end
|
210
210
|
|
211
|
+
def default_templates_path; end
|
212
|
+
|
213
|
+
def default_templates
|
214
|
+
default_templates_path.nil? ? [] : default_templates_path.children
|
215
|
+
end
|
216
|
+
|
211
217
|
protected
|
212
218
|
|
213
219
|
def on_configure
|
@@ -217,6 +223,7 @@ module Luban
|
|
217
223
|
load_configuration
|
218
224
|
validate_parameters
|
219
225
|
load_libraries
|
226
|
+
include_default_templates_path unless default_templates_path.nil?
|
220
227
|
setup_cli
|
221
228
|
end
|
222
229
|
|
@@ -249,6 +256,14 @@ module Luban
|
|
249
256
|
|
250
257
|
def load_libraries; end
|
251
258
|
|
259
|
+
def include_default_templates_path
|
260
|
+
if default_templates_path.is_a?(Pathname)
|
261
|
+
default_templates_paths.unshift(default_templates_path)
|
262
|
+
else
|
263
|
+
abort "Aborted! Default templates path for #{self.class.name} MUST be a Pathname."
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
252
267
|
def setup_cli
|
253
268
|
setup_descriptions
|
254
269
|
setup_tasks
|
@@ -2,11 +2,10 @@ module Luban
|
|
2
2
|
module Deployment
|
3
3
|
module Service
|
4
4
|
class Base < Luban::Deployment::Package::Base
|
5
|
-
include Luban::Deployment::Command::Tasks::Deploy
|
6
5
|
include Luban::Deployment::Command::Tasks::Control
|
7
6
|
|
8
|
-
def self.service_action(
|
9
|
-
define_method(
|
7
|
+
def self.service_action(action, dispatch_to: nil, as: action, locally: false, &blk)
|
8
|
+
define_method(action) do |args:, opts:|
|
10
9
|
if current_version
|
11
10
|
send("#{__method__}!", args: args, opts: opts.merge(version: current_version))
|
12
11
|
else
|
@@ -14,64 +13,30 @@ module Luban
|
|
14
13
|
end
|
15
14
|
end
|
16
15
|
unless dispatch_to.nil?
|
17
|
-
dispatch_task "#{
|
18
|
-
protected "#{
|
16
|
+
dispatch_task "#{action}!", to: dispatch_to, as: as, locally: locally, &blk
|
17
|
+
protected "#{action}!"
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
21
|
Luban::Deployment::Command::Tasks::Control::Actions.each do |action|
|
23
22
|
service_action action, dispatch_to: :controller
|
24
23
|
end
|
25
|
-
|
26
|
-
|
27
|
-
def has_templates?
|
28
|
-
respond_to?(:default_templates_path, true)
|
24
|
+
%i(init_profile update_profile).each do |action|
|
25
|
+
service_action action, dispatch_to: :configurator, locally: true
|
29
26
|
end
|
30
27
|
|
28
|
+
alias_method :orig_init_profile, :init_profile
|
29
|
+
|
31
30
|
def init_profile(args:, opts:)
|
32
|
-
|
33
|
-
require 'fileutils'
|
34
|
-
puts " Initializing #{name} profile"
|
35
|
-
templates_path = config_finder[:application].profile_templates_path.join(name.to_s)
|
36
|
-
profile_path = config_finder[:application].stage_profile_path.join(name.to_s)
|
37
|
-
[templates_path, profile_path].each { |p| FileUtils.mkdir(p) unless p.directory? }
|
38
|
-
init_profile_templates.each do |src_path|
|
39
|
-
next unless src_path.file?
|
40
|
-
dst_path = (src_path.extname == '.erb' ? templates_path : profile_path).
|
41
|
-
join(src_path.basename)
|
42
|
-
print " - #{dst_path.basename}"
|
43
|
-
if dst_path.file?
|
44
|
-
puts " [skipped]"
|
45
|
-
else
|
46
|
-
FileUtils.cp(src_path, dst_path)
|
47
|
-
puts " [created]"
|
48
|
-
end
|
49
|
-
end
|
31
|
+
orig_init_profile(args: args, opts: opts.merge(default_templates: default_templates))
|
50
32
|
end
|
51
33
|
|
52
34
|
protected
|
53
35
|
|
54
|
-
def on_configure
|
55
|
-
super
|
56
|
-
include_default_templates_path if has_templates?
|
57
|
-
end
|
58
|
-
|
59
|
-
def include_default_templates_path
|
60
|
-
if default_templates_path.is_a?(Pathname)
|
61
|
-
default_templates_paths.unshift(default_templates_path)
|
62
|
-
else
|
63
|
-
abort "Aborted! Default templates path for #{self.class.name} MUST be a Pathname."
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
36
|
def set_parameters
|
68
37
|
super
|
69
38
|
linked_dirs.push('log', 'pids')
|
70
39
|
end
|
71
|
-
|
72
|
-
def init_profile_templates
|
73
|
-
default_templates_path.children
|
74
|
-
end
|
75
40
|
end
|
76
41
|
end
|
77
42
|
end
|
@@ -2,55 +2,87 @@ module Luban
|
|
2
2
|
module Deployment
|
3
3
|
module Service
|
4
4
|
class Configurator < Worker
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
module Base
|
6
|
+
def stage_profile_path
|
7
|
+
@stage_profile_path ||=
|
8
|
+
config_finder[:application].stage_profile_path.join(service_name)
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def profile_templates_path
|
12
|
+
@profile_templates_path ||=
|
13
|
+
config_finder[:application].profile_templates_path.join(service_name)
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def stage_profile_templates_path
|
17
|
+
@stage_profile_templates_path ||=
|
18
|
+
config_finder[:application].stage_profile_templates_path.join(service_name)
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
def profile_templates(format: "erb")
|
22
|
+
return @profile_templates unless @profile_templates.nil?
|
23
|
+
@profile_templates = []
|
24
|
+
[profile_templates_path, stage_profile_templates_path].each do |path|
|
25
|
+
Dir.chdir(path) { @profile_templates |= Dir["**/*.#{format}"] } if path.directory?
|
26
|
+
end
|
27
|
+
@profile_templates
|
25
28
|
end
|
26
|
-
@profile_templates
|
27
|
-
end
|
28
29
|
|
29
|
-
|
30
|
-
assure_dirs(stage_profile_path)
|
31
|
-
render_profile
|
32
|
-
update_logrotate_files
|
33
|
-
end
|
30
|
+
def default_templates; task.opts.default_templates; end
|
34
31
|
|
35
|
-
|
32
|
+
def init_profile
|
33
|
+
return if default_templates.empty?
|
34
|
+
puts " Initializing #{service_name} profile"
|
35
|
+
assure_dirs(profile_templates_path, stage_profile_path)
|
36
|
+
upload_profile_templates
|
37
|
+
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
def update_profile
|
40
|
+
assure_dirs(stage_profile_path)
|
41
|
+
render_profile
|
42
|
+
update_logrotate_files
|
43
|
+
end
|
40
44
|
|
41
|
-
|
42
|
-
profile_file = stage_profile_path.join(template_file).sub_ext('')
|
43
|
-
assure_dirs(profile_file.dirname)
|
44
|
-
upload_by_template(file_to_upload: profile_file,
|
45
|
-
template_file: find_template_file(File.join(service_name, template_file)),
|
46
|
-
auto_revision: true)
|
47
|
-
end
|
45
|
+
protected
|
48
46
|
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
def upload_profile_templates
|
48
|
+
default_templates.each do |src_path|
|
49
|
+
next unless file?(src_path)
|
50
|
+
basename = src_path.basename
|
51
|
+
dst_path = if src_path.extname == '.erb'
|
52
|
+
profile_templates_path
|
53
|
+
else
|
54
|
+
stage_profile_path
|
55
|
+
end.join(basename)
|
56
|
+
print " - #{basename}"
|
57
|
+
if file?(dst_path)
|
58
|
+
puts " [skipped]"
|
59
|
+
else
|
60
|
+
upload!(src_path, dst_path)
|
61
|
+
puts " [created]"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def render_profile
|
67
|
+
profile_templates.each { |template_file| render_profile_by_template(template_file) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def render_profile_by_template(template_file)
|
71
|
+
profile_file = stage_profile_path.join(template_file).sub_ext('')
|
72
|
+
assure_dirs(profile_file.dirname)
|
73
|
+
upload_by_template(file_to_upload: profile_file,
|
74
|
+
template_file: find_template_file(File.join(service_name, template_file)),
|
75
|
+
auto_revision: true)
|
76
|
+
end
|
77
|
+
|
78
|
+
def update_logrotate_files
|
79
|
+
if file?(stage_profile_path.join(logrotate_file_name))
|
80
|
+
logrotate_files.push(logrotate_file_path)
|
81
|
+
end
|
52
82
|
end
|
53
83
|
end
|
84
|
+
|
85
|
+
include Base
|
54
86
|
end
|
55
87
|
end
|
56
88
|
end
|
@@ -2,210 +2,214 @@ module Luban
|
|
2
2
|
module Deployment
|
3
3
|
module Service
|
4
4
|
class Controller < Worker
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def process_started?
|
10
|
-
!!process_grep.keys.first
|
11
|
-
end
|
12
|
-
|
13
|
-
def process_stopped?
|
14
|
-
!process_started?
|
15
|
-
end
|
16
|
-
|
17
|
-
def pid_file_orphaned?
|
18
|
-
process_stopped? and pid_file_exists?
|
19
|
-
end
|
5
|
+
module Base
|
6
|
+
def pid
|
7
|
+
capture(:cat, "#{pid_file_path} 2>/dev/null")
|
8
|
+
end
|
20
9
|
|
21
|
-
|
22
|
-
|
23
|
-
|
10
|
+
def process_started?
|
11
|
+
!!process_grep.keys.first
|
12
|
+
end
|
24
13
|
|
25
|
-
|
26
|
-
|
27
|
-
|
14
|
+
def process_stopped?
|
15
|
+
!process_started?
|
16
|
+
end
|
28
17
|
|
29
|
-
|
30
|
-
|
31
|
-
raise NotImplementedError, "#{self.class.name}##{__method__} is an abstract method."
|
18
|
+
def pid_file_orphaned?
|
19
|
+
process_stopped? and pid_file_exists?
|
32
20
|
end
|
33
|
-
end
|
34
21
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
22
|
+
def pid_file_missing?
|
23
|
+
process_started? and !pid_file_exists?
|
24
|
+
end
|
39
25
|
|
40
|
-
|
41
|
-
|
42
|
-
|
26
|
+
def pid_file_exists?
|
27
|
+
file?(pid_file_path, "-s") # file is NOT zero size
|
28
|
+
end
|
43
29
|
|
44
|
-
|
45
|
-
|
46
|
-
|
30
|
+
%i(process_pattern start_command stop_command).each do |m|
|
31
|
+
define_method(m) do
|
32
|
+
raise NotImplementedError, "#{self.class.name}##{__method__} is an abstract method."
|
33
|
+
end
|
34
|
+
end
|
47
35
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
return
|
36
|
+
def monitor_executable
|
37
|
+
@monitor_executable ||= env_path.join("#{stage}.#{process_monitor[:env]}").
|
38
|
+
join('bin').join(process_monitor[:name])
|
52
39
|
end
|
53
40
|
|
54
|
-
|
55
|
-
|
56
|
-
update_result "Start #{package_full_name}: [OK] #{output}"
|
57
|
-
monitor_process
|
58
|
-
else
|
59
|
-
remove_orphaned_pid_file
|
60
|
-
update_result "Start #{package_full_name}: [FAILED] #{output}",
|
61
|
-
status: :failed, level: :error
|
41
|
+
def monitor_command
|
42
|
+
@monitor_command ||= "#{monitor_executable} monitor #{service_entry}"
|
62
43
|
end
|
63
|
-
end
|
64
44
|
|
65
|
-
|
66
|
-
|
67
|
-
update_result "Skipped! Already stopped #{package_full_name}", status: :skipped
|
68
|
-
return
|
45
|
+
def unmonitor_command
|
46
|
+
@unmonitor_command ||= "#{monitor_executable} unmonitor #{service_entry}"
|
69
47
|
end
|
70
48
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
49
|
+
def start_process
|
50
|
+
if process_started?
|
51
|
+
update_result "Skipped! Already started #{service_full_name}", status: :skipped
|
52
|
+
return
|
53
|
+
end
|
54
|
+
|
55
|
+
output = start_process!
|
56
|
+
if check_until { process_started? }
|
57
|
+
update_result "Start #{service_full_name}: [OK] #{output}"
|
58
|
+
monitor_process
|
59
|
+
else
|
60
|
+
remove_orphaned_pid_file
|
61
|
+
update_result "Start #{service_full_name}: [FAILED] #{output}",
|
62
|
+
status: :failed, level: :error
|
63
|
+
end
|
79
64
|
end
|
80
|
-
end
|
81
65
|
|
82
|
-
|
83
|
-
|
66
|
+
def stop_process
|
67
|
+
if process_stopped?
|
68
|
+
update_result "Skipped! Already stopped #{service_full_name}", status: :skipped
|
69
|
+
return
|
70
|
+
end
|
71
|
+
|
84
72
|
unmonitor_process
|
85
|
-
output = stop_process!
|
73
|
+
output = stop_process! || 'OK'
|
86
74
|
if check_until { process_stopped? }
|
87
|
-
|
75
|
+
update_result "Stop #{service_full_name}: [OK] #{output}"
|
88
76
|
else
|
89
77
|
remove_orphaned_pid_file
|
90
|
-
update_result "Stop #{
|
78
|
+
update_result "Stop #{service_full_name}: [FAILED] #{output}",
|
91
79
|
status: :failed, level: :error
|
92
|
-
return
|
93
80
|
end
|
94
81
|
end
|
95
82
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
83
|
+
def restart_process
|
84
|
+
if process_started?
|
85
|
+
unmonitor_process
|
86
|
+
output = stop_process!
|
87
|
+
if check_until { process_stopped? }
|
88
|
+
info "Stop #{service_full_name}: [OK] #{output}"
|
89
|
+
else
|
90
|
+
remove_orphaned_pid_file
|
91
|
+
update_result "Stop #{service_full_name}: [FAILED] #{output}",
|
92
|
+
status: :failed, level: :error
|
93
|
+
return
|
94
|
+
end
|
95
|
+
end
|
110
96
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
97
|
+
output = start_process!
|
98
|
+
if check_until { process_started? }
|
99
|
+
update_result "Restart #{service_full_name}: [OK] #{output}"
|
100
|
+
monitor_process
|
101
|
+
else
|
102
|
+
remove_orphaned_pid_file
|
103
|
+
update_result "Restart #{service_full_name}: [FAILED] #{output}",
|
104
|
+
status: :failed, level: :error
|
105
|
+
end
|
115
106
|
end
|
116
107
|
|
117
|
-
|
118
|
-
|
119
|
-
if check_until { process_stopped? }
|
120
|
-
remove_orphaned_pid_file
|
121
|
-
update_result "Kill #{package_full_name}: [OK] #{output}"
|
122
|
-
else
|
123
|
-
update_result "Kill #{package_full_name}: [FAILED] #{output}"
|
108
|
+
def check_process
|
109
|
+
update_result check_process!
|
124
110
|
end
|
125
|
-
end
|
126
111
|
|
127
|
-
|
128
|
-
|
129
|
-
|
112
|
+
def kill_process
|
113
|
+
if process_stopped?
|
114
|
+
update_result "Skipped! Already stopped #{service_full_name}", status: :skipped
|
115
|
+
return
|
116
|
+
end
|
130
117
|
|
131
|
-
|
132
|
-
|
133
|
-
if
|
134
|
-
|
118
|
+
unmonitor_process
|
119
|
+
output = kill_process!
|
120
|
+
if check_until { process_stopped? }
|
121
|
+
remove_orphaned_pid_file
|
122
|
+
update_result "Kill #{service_full_name}: [OK] #{output}"
|
135
123
|
else
|
136
|
-
|
124
|
+
update_result "Kill #{service_full_name}: [FAILED] #{output}"
|
137
125
|
end
|
138
126
|
end
|
139
|
-
end
|
140
127
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
128
|
+
def process_monitor_defined?
|
129
|
+
!process_monitor[:name].nil?
|
130
|
+
end
|
131
|
+
|
132
|
+
def monitor_process
|
133
|
+
if process_monitor_defined?
|
134
|
+
if monitor_process!
|
135
|
+
info "Turned on process monitor for #{service_entry}"
|
136
|
+
else
|
137
|
+
info "Failed to turn on process monitor for #{service_entry}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def unmonitor_process
|
143
|
+
if process_monitor_defined?
|
144
|
+
if unmonitor_process!
|
145
|
+
info "Turned off process monitor for #{service_entry}"
|
146
|
+
else
|
147
|
+
info "Failed to turn off process monitor for #{service_entry}"
|
148
|
+
end
|
147
149
|
end
|
148
150
|
end
|
149
|
-
end
|
150
151
|
|
151
|
-
|
152
|
-
|
152
|
+
def default_pending_seconds; 30; end
|
153
|
+
def default_pending_interval; 1; end
|
153
154
|
|
154
|
-
|
155
|
+
protected
|
155
156
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
157
|
+
def check_until(pending_seconds: default_pending_seconds,
|
158
|
+
pending_interval: default_pending_interval)
|
159
|
+
succeeded = false
|
160
|
+
(pending_seconds/pending_interval).times do
|
161
|
+
sleep pending_interval
|
162
|
+
break if (succeeded = yield)
|
163
|
+
end
|
164
|
+
succeeded
|
162
165
|
end
|
163
|
-
succeeded
|
164
|
-
end
|
165
166
|
|
166
|
-
|
167
|
-
|
168
|
-
|
167
|
+
def start_process!
|
168
|
+
capture("#{start_command} 2>&1")
|
169
|
+
end
|
169
170
|
|
170
|
-
|
171
|
-
|
172
|
-
|
171
|
+
def stop_process!
|
172
|
+
capture("#{stop_command} 2>&1")
|
173
|
+
end
|
173
174
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
175
|
+
def check_process!
|
176
|
+
if pid_file_missing?
|
177
|
+
"#{service_full_name}: started but PID file does NOT exist - #{pid_file_path}"
|
178
|
+
elsif process_started?
|
179
|
+
"#{service_full_name}: started (PID #{pid})"
|
180
|
+
elsif pid_file_orphaned?
|
181
|
+
"#{service_full_name}: stopped but PID file exists - #{pid_file_path}"
|
182
|
+
else
|
183
|
+
"#{service_full_name}: stopped"
|
184
|
+
end
|
183
185
|
end
|
184
|
-
end
|
185
186
|
|
186
|
-
|
187
|
-
|
188
|
-
|
187
|
+
def kill_process!(pattern = process_pattern)
|
188
|
+
capture(:pkill, "-9 -f \"#{pattern}\"")
|
189
|
+
end
|
189
190
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
191
|
+
def process_grep(pattern = process_pattern)
|
192
|
+
capture(:pgrep, "-l -f \"#{pattern}\" 2>/dev/null").split.inject({}) do |h, p|
|
193
|
+
pid, pname = p.split(' ', 2)
|
194
|
+
h[pid] = pname
|
195
|
+
h
|
196
|
+
end
|
195
197
|
end
|
196
|
-
end
|
197
198
|
|
198
|
-
|
199
|
-
|
200
|
-
|
199
|
+
def remove_orphaned_pid_file
|
200
|
+
rm(pid_file_path) if pid_file_orphaned?
|
201
|
+
end
|
201
202
|
|
202
|
-
|
203
|
-
|
204
|
-
|
203
|
+
def monitor_process!
|
204
|
+
test("#{monitor_command} 2>&1")
|
205
|
+
end
|
205
206
|
|
206
|
-
|
207
|
-
|
207
|
+
def unmonitor_process!
|
208
|
+
test("#{unmonitor_command} 2>&1")
|
209
|
+
end
|
208
210
|
end
|
211
|
+
|
212
|
+
include Base
|
209
213
|
end
|
210
214
|
end
|
211
215
|
end
|
@@ -1,40 +1,70 @@
|
|
1
1
|
module Luban
|
2
2
|
module Deployment
|
3
3
|
module Service
|
4
|
-
|
5
|
-
|
4
|
+
class Worker < Luban::Deployment::Package::Worker
|
5
|
+
module Base
|
6
|
+
def service_name
|
7
|
+
@service_name ||= package_name
|
8
|
+
end
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
+
def service_version
|
11
|
+
@service_version ||= package_version
|
12
|
+
end
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
+
def service_full_name
|
15
|
+
@service_full_name ||= package_full_name
|
16
|
+
end
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
def service_entry
|
19
|
+
@service_entry ||= "#{env_name.gsub('/', '.')}.#{service_name}"
|
20
|
+
end
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
+
def profile_path
|
23
|
+
@profile_path ||= shared_path.join('profile').join(service_name)
|
24
|
+
end
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
def log_path
|
27
|
+
@log_path ||= shared_path.join('log')
|
28
|
+
end
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
+
def log_file_path
|
31
|
+
@log_file_path ||= log_path.join(log_file_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def log_file_name
|
35
|
+
@log_file_name ||= "#{service_name}.log"
|
36
|
+
end
|
30
37
|
|
31
|
-
|
32
|
-
|
38
|
+
def pids_path
|
39
|
+
@pids_path ||= shared_path.join('pids')
|
40
|
+
end
|
41
|
+
|
42
|
+
def pid_file_path
|
43
|
+
@pid_file_path ||= pids_path.join(pid_file_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def pid_file_name
|
47
|
+
@pid_file_name ||= "#{service_name}.pid"
|
48
|
+
end
|
49
|
+
|
50
|
+
def control_file_path
|
51
|
+
@control_file_path ||= profile_path.join(control_file_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def control_file_name
|
55
|
+
@control_file_name ||= "#{service_name}.conf"
|
56
|
+
end
|
57
|
+
|
58
|
+
def logrotate_file_path
|
59
|
+
@logrotate_file_path ||= profile_path.join(logrotate_file_name)
|
60
|
+
end
|
61
|
+
|
62
|
+
def logrotate_file_name
|
63
|
+
@logrotate_file_name ||= "#{service_name}.logrotate"
|
64
|
+
end
|
33
65
|
end
|
34
|
-
end
|
35
66
|
|
36
|
-
|
37
|
-
include Paths
|
67
|
+
include Base
|
38
68
|
end
|
39
69
|
end
|
40
70
|
end
|
data/lib/luban/deployment/cli.rb
CHANGED
@@ -6,9 +6,43 @@ module Luban
|
|
6
6
|
module Generator
|
7
7
|
using Luban::CLI::CoreRefinements
|
8
8
|
|
9
|
+
module Utils
|
10
|
+
def mkdir(path)
|
11
|
+
if path.directory?
|
12
|
+
puts " [skipped]"
|
13
|
+
else
|
14
|
+
FileUtils.mkdir(path)
|
15
|
+
puts " [created]"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def copy_file(src_path, dst_path)
|
20
|
+
if dst_path.file?
|
21
|
+
puts " [skipped]"
|
22
|
+
else
|
23
|
+
FileUtils.cp(src_path, dst_path)
|
24
|
+
puts " [created]"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def render_file(template_path, output_path, context: binding)
|
29
|
+
if output_path.file?
|
30
|
+
puts " [skipped]"
|
31
|
+
else
|
32
|
+
require 'erb'
|
33
|
+
File.open(output_path, 'w') do |f|
|
34
|
+
f.write ERB.new(File.read(template_path), nil, '<>').result(context)
|
35
|
+
end
|
36
|
+
puts " [created]"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
9
41
|
module Base
|
10
42
|
protected
|
11
43
|
|
44
|
+
include Utils
|
45
|
+
|
12
46
|
def skeletons_path
|
13
47
|
@skeletons_path ||=
|
14
48
|
Pathname.new(__FILE__).dirname.join('..').join('templates').realpath
|
@@ -52,36 +86,6 @@ module Luban
|
|
52
86
|
end
|
53
87
|
end
|
54
88
|
|
55
|
-
def mkdir(path)
|
56
|
-
if path.directory?
|
57
|
-
puts " [skipped]"
|
58
|
-
else
|
59
|
-
FileUtils.mkdir(path)
|
60
|
-
puts " [created]"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def copy_file(src_path, dst_path)
|
65
|
-
if dst_path.file?
|
66
|
-
puts " [skipped]"
|
67
|
-
else
|
68
|
-
FileUtils.cp(src_path, dst_path)
|
69
|
-
puts " [created]"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def render_file(template_path, output_path, context: binding)
|
74
|
-
if output_path.file?
|
75
|
-
puts " [skipped]"
|
76
|
-
else
|
77
|
-
require 'erb'
|
78
|
-
File.open(output_path, 'w') do |f|
|
79
|
-
f.write ERB.new(File.read(template_path), nil, '<>').result(context)
|
80
|
-
end
|
81
|
-
puts " [created]"
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
89
|
def placeholder?(basename)
|
86
90
|
basename.to_s =~ /^__stage/
|
87
91
|
end
|
@@ -72,52 +72,6 @@ module Luban
|
|
72
72
|
def luban_install_path
|
73
73
|
@luban_install_path ||= project_path.join('.luban')
|
74
74
|
end
|
75
|
-
|
76
|
-
module Service
|
77
|
-
def profile_path
|
78
|
-
@profile_path ||= shared_path.join('profile')
|
79
|
-
end
|
80
|
-
|
81
|
-
def log_path
|
82
|
-
@log_path ||= shared_path.join('log')
|
83
|
-
end
|
84
|
-
|
85
|
-
def log_file_path
|
86
|
-
@log_file_path ||= log_path.join(log_file_name)
|
87
|
-
end
|
88
|
-
|
89
|
-
def log_file_name
|
90
|
-
raise NotImplementedError, "#{self.class.name}#log_file_name is an abstract method."
|
91
|
-
end
|
92
|
-
|
93
|
-
def pids_path
|
94
|
-
@pids_path ||= shared_path.join('pids')
|
95
|
-
end
|
96
|
-
|
97
|
-
def pid_file_path
|
98
|
-
@pid_file_path ||= pids_path.join(pid_file_name)
|
99
|
-
end
|
100
|
-
|
101
|
-
def pid_file_name
|
102
|
-
raise NotImplementedError, "#{self.class.name}#pid_file_name is an abstract method."
|
103
|
-
end
|
104
|
-
|
105
|
-
def control_file_path
|
106
|
-
@control_file_path ||= profile_path.join(control_file_name)
|
107
|
-
end
|
108
|
-
|
109
|
-
def control_file_name
|
110
|
-
raise NotImplementedError, "#{self.class.name}#control_file_name is an abstract method."
|
111
|
-
end
|
112
|
-
|
113
|
-
def logrotate_file_path
|
114
|
-
@logrotate_file_path ||= profile_path.join(logrotate_file_name)
|
115
|
-
end
|
116
|
-
|
117
|
-
def logrotate_file_name
|
118
|
-
raise NotImplementedError, "#{self.class.name}#logrotate_file_name is an abstract method."
|
119
|
-
end
|
120
|
-
end
|
121
75
|
end
|
122
76
|
end
|
123
77
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: luban
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rubyist Lei
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: luban-cli
|
@@ -103,11 +103,14 @@ files:
|
|
103
103
|
- lib/luban/deployment/cli/application.rb
|
104
104
|
- lib/luban/deployment/cli/application/authenticator.rb
|
105
105
|
- lib/luban/deployment/cli/application/base.rb
|
106
|
-
- lib/luban/deployment/cli/application/
|
106
|
+
- lib/luban/deployment/cli/application/configurator.rb
|
107
|
+
- lib/luban/deployment/cli/application/constructor.rb
|
108
|
+
- lib/luban/deployment/cli/application/controller.rb
|
107
109
|
- lib/luban/deployment/cli/application/publisher.rb
|
108
110
|
- lib/luban/deployment/cli/application/repository.rb
|
109
111
|
- lib/luban/deployment/cli/application/scm/git.rb
|
110
112
|
- lib/luban/deployment/cli/application/scm/rsync.rb
|
113
|
+
- lib/luban/deployment/cli/application/worker.rb
|
111
114
|
- lib/luban/deployment/cli/command.rb
|
112
115
|
- lib/luban/deployment/cli/package.rb
|
113
116
|
- lib/luban/deployment/cli/package/base.rb
|