lita-capistrano_rails 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 71bda2653837504766b7a01f7f7d6e1075d54bfb
4
+ data.tar.gz: 3ca22fd088d1e55c39a15b06548bb0df97d2b5d1
5
+ SHA512:
6
+ metadata.gz: e7f05e1e58c7d72bc00510d9a62ba946606c339e7c7ab05abc9f38f2e528332b1d377c135ae9cf647b4fec7b9213c5713c6064ff494f95d6831b0173f5c76465
7
+ data.tar.gz: a13f8af62d235bc1e9c22b4b0d54eafd7c79c23d472d5e892e2d1d9904a26115ef04292a9b31e949fc3470059177cddcbcd1256a4ca84887fadb0be1ba0d245e
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # lita-capistrano_rails
2
+
3
+ TODO: Add a description of the plugin.
4
+
5
+ ## Installation
6
+
7
+ Add lita-capistrano_rails to your Lita instance's Gemfile:
8
+
9
+ ``` ruby
10
+ gem "lita-capistrano_rails"
11
+ ```
12
+
13
+ ## Configuration
14
+
15
+ TODO: Describe any configuration attributes the plugin exposes.
16
+
17
+ ## Usage
18
+
19
+ TODO: Describe the plugin's features and how to use them.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,233 @@
1
+ require "step_flow"
2
+ require "open3"
3
+
4
+ module Lita
5
+ module Handlers
6
+ class CapistranoRails < Handler
7
+ include StepFlow
8
+
9
+ # example:
10
+ # config.handlers.capistrano_rails.apps = {
11
+ # 'app1' => {
12
+ # git: 'git@git.example.com:account/app1.git',
13
+ # }, # this will use "production" as rails env and using "master" branch
14
+ # 'app2' => {
15
+ # git: 'git@git.example.com:account/app2.git',
16
+ # envs: {
17
+ # 'production' => 'master',
18
+ # 'staging' => 'develop',
19
+ # }
20
+ # },
21
+ # }
22
+ config :apps, type: Hash, required: true
23
+
24
+ on :loaded, :define_routes
25
+
26
+ def define_routes(payload)
27
+ define_static_routes
28
+ define_dinamic_routes
29
+ end
30
+
31
+ # command: "deploy list"
32
+ def deploy_list_apps(response)
33
+ response.reply_privately('Available apps:')
34
+ apps = config.apps.map do |app, app_config|
35
+ envs = app_config[:envs] ? app_config[:envs].keys.join(",") : 'production'
36
+ "#{app}(#{envs})"
37
+ end
38
+ response.reply_privately(apps )
39
+ end
40
+
41
+ # command: "deploy #{env} for #{app}"
42
+ def deploy_env_for_app(response)
43
+ env = response.matches[0][0]
44
+ app = response.matches[0][1]
45
+ deploy_app(app, env, response)
46
+ end
47
+
48
+ # command: "deploy #{app}"
49
+ def deploy_production_for_app(response)
50
+ env = 'production'
51
+ app = response.matches[0][0]
52
+ deploy_app(app, env, response)
53
+ end
54
+
55
+ private
56
+
57
+ def deploy_app(app, env, response)
58
+ app_config = config.apps[app]
59
+
60
+ # check env
61
+ branch = \
62
+ step :validate_deploy_request, :first_step do
63
+ app_envs = app_config[:envs] ? app_config[:envs].keys : ['production'] # use "production" as default env
64
+ if !app_envs.include?(env)
65
+ return response.reply(%{"#{env}" is not available env for #{app}, available env is: #{app_envs.join("|")}})
66
+ end
67
+
68
+ branch = app_config[:envs] ? app_config[:envs][env] : 'master' # use "master" as default branch
69
+
70
+ response.reply("I'm deploying #{env} using #{branch} branch for #{app} ...")
71
+ branch
72
+ end
73
+
74
+ app_path, app_source_path, bundle_path = \
75
+ step :prepare_tmp_dirs do
76
+ # prepare the dirs
77
+ app_path = File.expand_path("tmp/capistrano_rails/apps/#{app}")
78
+ app_source_path = File.expand_path("#{app_path}/source")
79
+ bundle_path = File.expand_path("tmp/capistrano_rails/bundle") # sharing bundle to reduce space usage and reuse gems
80
+ FileUtils.mkdir_p(app_path)
81
+ [app_path, app_source_path, bundle_path]
82
+ end
83
+
84
+ step :get_source_code do
85
+ # if dir ".git" exists, use `git pull`
86
+ if File.exists?("#{app_source_path}/.git")
87
+ step_log 'Found ".git" exists, run `git pull`'
88
+ # run_in_dir("git checkout #{branch} && git pull", app_source_path)
89
+ revision = "origin/#{branch}"
90
+ # since we're in a local branch already, just reset to specified revision rather than merge
91
+ run_in_dir("git fetch #{verbose} && git reset #{verbose} --hard #{revision}", app_source_path)
92
+ else
93
+ step_log 'not found ".git", run `git clone`'
94
+ run_in_dir("git clone -b #{branch} #{app_config[:git]} source", app_path)
95
+ end
96
+
97
+ # TODO: if ".git" exists but repo url changed, clean up the dir then run `git clone`
98
+ end
99
+
100
+ step :hack_gemfile do
101
+ # disable "ruby 'x.y.z'" config in Gemfile
102
+ # to avoid errors like "Your Ruby version is 2.2.4, but your Gemfile specified 2.1.2 (Bundler::RubyVersionMismatch)"
103
+ gemfile_path = "#{app_source_path}/Gemfile"
104
+ gemfile_content = File.read gemfile_path
105
+ if gemfile_content.match(/^ruby .+/)
106
+ gemfile_content.sub!(/(^ruby .+)/, '# \1 # hacked by Lita::Handlers::CapistranoRails to avoid "Bundler::RubyVersionMismatch" problem')
107
+ File.open(gemfile_path, 'w') { |gemfile| gemfile.write(gemfile_content) }
108
+ end
109
+ end
110
+
111
+ step :run_bundle_install do
112
+ # run_in_dir("bundle install --quiet", app_source_path)
113
+ run_in_dir("bundle install --gemfile #{app_source_path}/Gemfile --path #{bundle_path} --deployment --without darwin test", app_source_path)
114
+ # TODO: check result, reply failure message
115
+ # TODO: check result, auto retry 1 time if timeout as "Gem::RemoteFetcher::FetchError: Errno::ETIMEDOUT: Operation timed out"
116
+ end
117
+
118
+ step :run_cap_deploy do
119
+ # TODO: check "Capfile"
120
+ # if "Capfile" not exits, reply "not a capistrano project"
121
+ result = run_in_dir("bundle exec cap #{env} deploy", app_source_path)
122
+ if result[:exit_status] != 0 # could be 256
123
+ failure = %{errrors while executing: "#{result[:cmd]}"\n}
124
+ failure << result[:stderr]
125
+ step_fails(response, failure)
126
+ end
127
+ end
128
+
129
+ step :reply_deploy_success, :last_step do
130
+ deploy_success = "deploy #{env} for #{app} finished!"
131
+
132
+ # TODO: get "app_url"
133
+ app_url = ""
134
+ deploy_success += ", please visit #{app_url}" if !app_url.empty?
135
+
136
+ response.reply(deploy_success)
137
+ end
138
+ end
139
+
140
+ def run_in_dir(cmd, dir)
141
+ lita_mark = "LITA=#{Lita::VERSION}"
142
+ _cmd = "cd #{dir} && #{lita_mark} #{cmd}"
143
+ # log.info _cmd
144
+ # running bundle install inside a bundle-managed shell to avoid "RuntimeError: Specs already loaded"
145
+ # see https://github.com/bundler/bundler/issues/1981#issuecomment-6292686
146
+ Bundler.with_clean_env do
147
+ # system(_cmd) # can't catch output
148
+ execute_command(_cmd)
149
+ end
150
+ end
151
+
152
+ # execute commandline and catch stdout and stderr
153
+ def execute_command(cmd)
154
+ log.debug "execute: #{cmd}"
155
+ full_stdout = String.new
156
+ full_stderr = String.new
157
+ started_at = Time.now
158
+
159
+ Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
160
+ stdout_thread = Thread.new do
161
+ while (line = stdout.gets) do
162
+ full_stdout += line
163
+ # printf line
164
+ end
165
+ end
166
+
167
+ stderr_thread = Thread.new do
168
+ while (line = stderr.gets) do
169
+ full_stderr += line
170
+ end
171
+ end
172
+
173
+ stdout_thread.join
174
+ stderr_thread.join
175
+
176
+ exit_status = wait_thr.value.to_i
177
+ finished_at = Time.now
178
+ runtime = finished_at - started_at
179
+
180
+ {
181
+ cmd: cmd,
182
+ started_at: started_at,
183
+ finished_at: finished_at,
184
+ exit_status: exit_status,
185
+ runtime: runtime,
186
+ stdout: full_stdout,
187
+ stderr: full_stderr,
188
+ }
189
+ end
190
+ end
191
+
192
+ def verbose
193
+ # config.scm_verbose ? nil : "-q"
194
+ end
195
+
196
+ def define_static_routes
197
+ self.class.route(
198
+ %r{deploy\s+list},
199
+ :deploy_list_apps,
200
+ command: true,
201
+ help: { "deploy list" => "List available apps for deploy"}
202
+ )
203
+ end
204
+
205
+ # define route for each rapporteur
206
+ def define_dinamic_routes
207
+ config.apps.each do |app, app_config|
208
+ # define command "deploy APP"
209
+ self.class.route(
210
+ %r{deploy (#{app})$},
211
+ :deploy_production_for_app,
212
+ command: true,
213
+ # restrict_to: [:admins, value[:deploy_group]],
214
+ help: { "deploy #{app}" => "deploy produciton for #{app}"}
215
+ )
216
+
217
+ # define command "deploy ENV for APP"
218
+ # puts "define route: ^deploy\s+(#{app})\s+(#{area})\s+(.+)\s+(.+)"
219
+ envs = app_config[:envs] ? app_config[:envs].keys : ['production']
220
+ self.class.route(
221
+ %r{deploy +(\w+) +for +(#{app})$},
222
+ :deploy_env_for_app,
223
+ command: true,
224
+ # restrict_to: [:admins, value[:deploy_group]],
225
+ help: { "deploy #{envs.join("|")} for #{app}" => "deploy ENV for #{app}"}
226
+ )
227
+ end
228
+ end
229
+
230
+ Lita.register_handler(self)
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,12 @@
1
+ require "lita"
2
+
3
+ Lita.load_locales Dir[File.expand_path(
4
+ File.join("..", "..", "locales", "*.yml"), __FILE__
5
+ )]
6
+
7
+ require "lita/handlers/capistrano_rails"
8
+
9
+ Lita::Handlers::CapistranoRails.template_root File.expand_path(
10
+ File.join("..", "..", "templates"),
11
+ __FILE__
12
+ )
data/lib/step_flow.rb ADDED
@@ -0,0 +1,55 @@
1
+ module StepFlow
2
+ # store steps for flow
3
+ # for example:
4
+ # {
5
+ # "deploy_app" [:valid_request, :prepare_dirs]
6
+ # }
7
+ attr_reader :flow_steps
8
+ attr_reader :step_failed
9
+
10
+ private
11
+
12
+ def step(step_key, first_or_last = nil, &block)
13
+ return if @step_failed
14
+ is_first = (first_or_last == :first_step)
15
+ is_last = (first_or_last == :last_step)
16
+ flow = caller_locations(1,1)[0].label # # get from caller
17
+
18
+ # init
19
+ @flow_steps ||= {}
20
+ if @flow_steps[flow].nil?
21
+ if is_first
22
+ @flow_steps[flow] = []
23
+ else
24
+ raise "should specific which is the first step"
25
+ end
26
+ end
27
+
28
+ @flow_steps[flow].push step_key
29
+ step_no = @flow_steps[flow].size
30
+ log.info "#{flow} flow start:" if is_first
31
+ log.info " #{flow} #{step_no}):#{step_key}"
32
+ result = nil
33
+ # capture_stdout do
34
+ result = yield
35
+ # end
36
+ # step_log step_stdout
37
+ log.info "#{flow} flow end" if is_last
38
+ result
39
+ end
40
+
41
+ def step_log(message)
42
+ log.info " #{message}"
43
+ end
44
+
45
+ # mark a step fails, reply errors message, stop rest steps
46
+ def step_fails(response, failure)
47
+ @step_failed = true
48
+ flow = @flow_steps.keys.last
49
+ step_no = @flow_steps[flow].size
50
+ step_key = @flow_steps[flow].last
51
+ failure = %{deploy faild on #{flow}(#{step_no}):#{step_key}\n} + failure
52
+ response.reply(failure)
53
+ end
54
+
55
+ end
@@ -0,0 +1,24 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lita-capistrano_rails"
3
+ spec.version = "0.1.0"
4
+ spec.authors = ["RainChen"]
5
+ spec.email = ["hirainchen@gmail.com"]
6
+ spec.description = "A Lita handler to integrate with Capistrano for rails project"
7
+ spec.summary = "A Lita handler to integrate with Capistrano for rails project"
8
+ spec.homepage = "https://github.com/rainchen/lita-capistrano_rails"
9
+ spec.license = "TODO: Add a license"
10
+ spec.metadata = { "lita_plugin_type" => "handler" }
11
+
12
+ spec.files = `git ls-files`.split($/)
13
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_runtime_dependency "lita", ">= 4.6"
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "pry-byebug"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rack-test"
23
+ spec.add_development_dependency "rspec", ">= 3.0.0"
24
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,4 @@
1
+ en:
2
+ lita:
3
+ handlers:
4
+ capistrano_rails:
@@ -0,0 +1,4 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Handlers::CapistranoRails, lita_handler: true do
4
+ end
@@ -0,0 +1,6 @@
1
+ require "lita-capistrano_rails"
2
+ require "lita/rspec"
3
+
4
+ # A compatibility mode is provided for older plugins upgrading from Lita 3. Since this plugin
5
+ # was generated with Lita 4, the compatibility mode should be left disabled.
6
+ Lita.version_3_compatibility_mode = false
File without changes
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lita-capistrano_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - RainChen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lita
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack-test
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 3.0.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 3.0.0
97
+ description: A Lita handler to integrate with Capistrano for rails project
98
+ email:
99
+ - hirainchen@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - Gemfile
106
+ - README.md
107
+ - Rakefile
108
+ - lib/lita-capistrano_rails.rb
109
+ - lib/lita/handlers/capistrano_rails.rb
110
+ - lib/step_flow.rb
111
+ - lita-capistrano_rails.gemspec
112
+ - locales/en.yml
113
+ - spec/lita/handlers/capistrano_rails_spec.rb
114
+ - spec/spec_helper.rb
115
+ - templates/.gitkeep
116
+ homepage: https://github.com/rainchen/lita-capistrano_rails
117
+ licenses:
118
+ - 'TODO: Add a license'
119
+ metadata:
120
+ lita_plugin_type: handler
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.5.1
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: A Lita handler to integrate with Capistrano for rails project
141
+ test_files:
142
+ - spec/lita/handlers/capistrano_rails_spec.rb
143
+ - spec/spec_helper.rb