redmine-installer 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/Gemfile +19 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +273 -0
  6. data/Rakefile +7 -0
  7. data/bin/redmine +8 -0
  8. data/lib/redmine-installer.rb +72 -0
  9. data/lib/redmine-installer/backup.rb +48 -0
  10. data/lib/redmine-installer/cli.rb +90 -0
  11. data/lib/redmine-installer/command.rb +142 -0
  12. data/lib/redmine-installer/config_param.rb +90 -0
  13. data/lib/redmine-installer/error.rb +5 -0
  14. data/lib/redmine-installer/exec.rb +158 -0
  15. data/lib/redmine-installer/ext/module.rb +7 -0
  16. data/lib/redmine-installer/ext/string.rb +15 -0
  17. data/lib/redmine-installer/git.rb +51 -0
  18. data/lib/redmine-installer/helper.rb +5 -0
  19. data/lib/redmine-installer/helpers/generate_config.rb +29 -0
  20. data/lib/redmine-installer/install.rb +56 -0
  21. data/lib/redmine-installer/locales/cs.yml +145 -0
  22. data/lib/redmine-installer/locales/en.yml +146 -0
  23. data/lib/redmine-installer/plugin.rb +9 -0
  24. data/lib/redmine-installer/plugins/base.rb +28 -0
  25. data/lib/redmine-installer/plugins/database.rb +168 -0
  26. data/lib/redmine-installer/plugins/email_sending.rb +82 -0
  27. data/lib/redmine-installer/plugins/redmine_plugin.rb +30 -0
  28. data/lib/redmine-installer/plugins/web_server.rb +26 -0
  29. data/lib/redmine-installer/profile.rb +74 -0
  30. data/lib/redmine-installer/step.rb +15 -0
  31. data/lib/redmine-installer/steps/backup.rb +120 -0
  32. data/lib/redmine-installer/steps/base.rb +60 -0
  33. data/lib/redmine-installer/steps/database_config.rb +15 -0
  34. data/lib/redmine-installer/steps/email_config.rb +11 -0
  35. data/lib/redmine-installer/steps/install.rb +21 -0
  36. data/lib/redmine-installer/steps/load_package.rb +180 -0
  37. data/lib/redmine-installer/steps/move_redmine.rb +22 -0
  38. data/lib/redmine-installer/steps/redmine_root.rb +29 -0
  39. data/lib/redmine-installer/steps/upgrade.rb +55 -0
  40. data/lib/redmine-installer/steps/validation.rb +38 -0
  41. data/lib/redmine-installer/steps/webserver_config.rb +22 -0
  42. data/lib/redmine-installer/task.rb +85 -0
  43. data/lib/redmine-installer/upgrade.rb +68 -0
  44. data/lib/redmine-installer/utils.rb +233 -0
  45. data/lib/redmine-installer/version.rb +5 -0
  46. data/redmine-installer.gemspec +25 -0
  47. data/spec/lib/install_spec.rb +46 -0
  48. data/spec/lib/upgrade_spec.rb +62 -0
  49. data/spec/load_redmine.rb +24 -0
  50. data/spec/spec_helper.rb +30 -0
  51. metadata +130 -0
@@ -0,0 +1,85 @@
1
+ ##
2
+ # Parent for all commands (Install, Upgrade, Backup)
3
+ #
4
+ module Redmine::Installer
5
+ class Task
6
+
7
+ attr_accessor :redmine_root
8
+ attr_accessor :tmp_redmine_root
9
+ attr_accessor :options
10
+ attr_accessor :settings
11
+ attr_accessor :env
12
+
13
+ attr_reader :steps
14
+
15
+ def initialize(options={})
16
+ self.options = options
17
+ self.settings = {}
18
+ self.env = options[:env]
19
+
20
+ # Initialize steps for task
21
+ @steps = {}
22
+ index = 1
23
+ self.class::STEPS.each do |step|
24
+ @steps[index] = step.new(index, self)
25
+ index += 1
26
+ end
27
+ end
28
+
29
+ def run
30
+ @steps.each do |id, step|
31
+ step.print_title
32
+ step.print_header
33
+ step.up
34
+ step.print_footer
35
+ step.ran = true
36
+ puts # new line
37
+ end
38
+
39
+ @steps.each do |id, step|
40
+ step.final_step
41
+ end
42
+ rescue Redmine::Installer::Error => e
43
+ # Rescue from error comes from installer
44
+ # run steps again for cleaning
45
+ @steps.values.reverse.each do |step|
46
+ next unless step.ran
47
+ step.down
48
+ end
49
+
50
+ $stderr.puts(ANSI.red, e.message, ANSI.clear)
51
+ $stderr.flush
52
+ exit(1)
53
+ end
54
+
55
+ # Package is required for install task and
56
+ # upgrade with source file
57
+ def check_package
58
+ if package.nil?
59
+ raise Redmine::Installer::Error, I18n.translate(:error_argument_package_is_missing)
60
+ end
61
+ end
62
+
63
+ def self.step
64
+ Redmine::Installer::Step
65
+ end
66
+
67
+ # Creating methods for recognition type of task
68
+ #
69
+ # == Examples:
70
+ # class Install < Task
71
+ # end
72
+ #
73
+ # Install.new.install? #=> true
74
+ #
75
+ def self.inherited(child)
76
+ method_name = "#{child.class_name.downcase}?".to_sym
77
+
78
+ define_method(method_name) { false }
79
+ child.send(:define_method, method_name) { true }
80
+
81
+ super
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,68 @@
1
+ ##
2
+ # Backup redmine
3
+ #
4
+ # You can upgrade current redmine by archive or currently defined git repository.
5
+ # If your redmine contain plugins which are not part of new package - all these
6
+ # plugins will be kept otherwise are replaced with those from package.
7
+ #
8
+ # Final step will ask you if you want save steps configuration.
9
+ # If you say YES, configuration will be stored as profile so next time
10
+ # you can upgrade redmine faster.
11
+ #
12
+ # redmine upgrade PACKAGE --profile PROFILE_ID
13
+ # Profiles are stored on HOME_FOLDER/.redmine-installer-profiles.yml.
14
+ #
15
+ # == Steps:
16
+ # 1. Redmine root - where should be new redmine located
17
+ # 2. Load package - extract package
18
+ # 3. Validation - current redmine should be valid
19
+ # 4. Backup - backup current redmine (see backup section)
20
+ # 5. Upgrading - install commands are executed
21
+ # 6. Moving redmine - redmine is moved from temporarily folder to given redmine_root
22
+ # 7. Profile saving - generating profile (see profile section)
23
+ #
24
+ # == Usage:
25
+ #
26
+ # From archive::
27
+ # # minimal
28
+ # redmine upgrade PATH_TO_PACKAGE
29
+ #
30
+ # # full
31
+ # redmine upgrade PATH_TO_PACKAGE --env ENV1,ENV2,ENV3
32
+ #
33
+ # From git::
34
+ # # minimal
35
+ # redmine upgrade --source git
36
+ #
37
+ # # full
38
+ # redmine upgrade --source git --env ENV1,ENV2,ENV3
39
+ #
40
+ module Redmine::Installer
41
+ class Upgrade < Task
42
+
43
+ STEPS = [
44
+ step::RedmineRoot,
45
+ step::LoadPackage,
46
+ step::Validation,
47
+ step::Backup,
48
+ step::Upgrade,
49
+ step::MoveRedmine
50
+ ]
51
+
52
+ attr_accessor :package
53
+
54
+ def initialize(package, options={})
55
+ self.package = package
56
+ super(options)
57
+
58
+ check_package if options[:source] == 'file'
59
+ end
60
+
61
+ def run
62
+ Redmine::Installer::Profile.load(self, options[:profile])
63
+ super
64
+ Redmine::Installer::Profile.save(self) if options[:profile].nil?
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,233 @@
1
+ require 'fileutils'
2
+ require 'notifier'
3
+ require 'ansi'
4
+
5
+ module Redmine::Installer
6
+ module Utils
7
+
8
+ def self.included(base)
9
+ base.send :extend, Methods
10
+ base.send :include, Methods
11
+
12
+ base.class_eval do
13
+ self.send(:const_set, 'Git', Redmine::Installer::Git)
14
+ end
15
+ end
16
+
17
+ module Methods
18
+
19
+ # =======================================================================
20
+ # Generals
21
+
22
+ def plugin
23
+ Redmine::Installer::Plugin
24
+ end
25
+
26
+ def command
27
+ Redmine::Installer::Command.instance
28
+ end
29
+
30
+ def error(*args)
31
+ # Translate message
32
+ if args.first.is_a?(Symbol)
33
+ message = translate(*args)
34
+ else
35
+ message = args.first
36
+ end
37
+
38
+ # Colorize message
39
+ colorize(message)
40
+
41
+ raise Redmine::Installer::Error, message
42
+ end
43
+
44
+ # Try create a dir
45
+ # When mkdir raise an error (permission problem) method
46
+ # ask user if wants exist or try again
47
+ def try_create_dir(dir)
48
+ begin
49
+ FileUtils.mkdir_p(dir)
50
+ rescue
51
+ choices = {}
52
+ choices[:exit] = t(:exit)
53
+ choices[:try_again] = t(:try_again)
54
+
55
+ answer = choose(t(:dir_not_exist_and_cannot_be_created, dir: dir), choices, default: :exit)
56
+
57
+ case answer
58
+ when :exit
59
+ error ''
60
+ when :try_again
61
+ try_create_dir(dir)
62
+ end
63
+ end
64
+ end
65
+
66
+ # Check if there are plugins in plugin dir
67
+ def some_plugins?
68
+ Dir.glob(File.join('plugins', '*')).select{|record| File.directory?(record)}.any?
69
+ end
70
+
71
+
72
+ # =======================================================================
73
+ # Input, output
74
+
75
+ # Print message to stdout
76
+ def say(message, lines=0)
77
+ # Translate message
78
+ if message.is_a?(Symbol)
79
+ message = translate(message)
80
+ end
81
+
82
+ # Colorize message
83
+ colorize(message)
84
+
85
+ $stdout.print(message)
86
+ lines.times { $stdout.puts }
87
+ $stdout.flush
88
+ end
89
+
90
+ # Colorize text based on XML marks
91
+ #
92
+ # == Examples:
93
+ # colorize("<bright><on_black><white>text</white></on_black></bright>")
94
+ # # => "\e[1m\e[40m\e[37mtext\e[0m\e[0m\e[0m"
95
+ #
96
+ def colorize(text)
97
+ return unless text.is_a?(String)
98
+
99
+ text.gsub!(/<([a-zA-Z0-9_]+)>/) do
100
+ if ANSI::CHART.has_key?($1.to_sym)
101
+ ANSI.send($1)
102
+ else
103
+ "<#{$1}>"
104
+ end
105
+ end
106
+ text.gsub!(/<\/([a-zA-Z0-9_]+)>/) do
107
+ if ANSI::CHART.has_key?($1.to_sym)
108
+ ANSI.clear
109
+ else
110
+ "</#{$1}>"
111
+ end
112
+ end
113
+ end
114
+
115
+ # Instead of `super` take only what I need
116
+ def gets
117
+ $stdin.gets.to_s.chomp
118
+ end
119
+
120
+ # Asking on 1 line
121
+ def ask(message=nil, options={})
122
+ # Translate message
123
+ if message.is_a?(Symbol)
124
+ message = translate(message)
125
+ end
126
+ default = options[:default]
127
+
128
+ if default
129
+ message << " [#{default}]"
130
+ end
131
+
132
+ if !options[:without_colon]
133
+ message << ': '
134
+ end
135
+
136
+ say(message)
137
+ input = gets
138
+
139
+ # Ctrl-D or enter was pressed
140
+ return default if input.empty?
141
+
142
+ input
143
+ end
144
+
145
+ # User can choose from selection
146
+ def choose(message, choices, options={})
147
+ choices = choices.to_a
148
+ default = options[:default]
149
+ index = 1
150
+
151
+ say(message, 1) unless message.nil?
152
+ choices.each do |(key, message)|
153
+ if key == default
154
+ pre = '*'
155
+ else
156
+ pre = ' '
157
+ end
158
+
159
+ say(" #{pre}#{index}) #{message}", 1)
160
+ index += 1
161
+ end
162
+
163
+ input = ask('> ', without_colon: true).to_i
164
+ puts
165
+
166
+ # Without default is input 0
167
+ return default if input.zero? || input > choices.size
168
+
169
+ choices[input-1][0]
170
+ end
171
+
172
+ # Say 'Do you want?'
173
+ # -> YES, NO
174
+ #
175
+ def confirm(message, default=true)
176
+ # Translate message
177
+ if message.is_a?(Symbol)
178
+ message = translate(message)
179
+ end
180
+
181
+ # Colorize message
182
+ colorize(message)
183
+
184
+ yes = t(:yes_t)
185
+ no = t(:no_t)
186
+
187
+ if default
188
+ yes.upcase!
189
+ else
190
+ no.upcase!
191
+ end
192
+
193
+ message << " (#{yes}/#{no}): "
194
+
195
+ $stdout.print(message)
196
+ answer = gets
197
+
198
+ return default if answer.empty?
199
+
200
+ if answer[0].downcase == yes[0].downcase
201
+ return true
202
+ else
203
+ return false
204
+ end
205
+ end
206
+
207
+
208
+ # =======================================================================
209
+ # Localizations
210
+
211
+ def translate(*args)
212
+ I18n.translate(*args)
213
+ end
214
+ alias_method :t, :translate
215
+
216
+
217
+ # =======================================================================
218
+ # Notifications
219
+
220
+ def notif(title, message=nil, image=nil)
221
+ return unless Redmine::Installer.config.notif
222
+
223
+ thread = ::Notifier.notify(
224
+ title: title.to_s,
225
+ message: message.to_s,
226
+ image: image.to_s
227
+ )
228
+ thread.join
229
+ end
230
+
231
+ end # Methods
232
+ end # Utils
233
+ end # Redmine::Installer
@@ -0,0 +1,5 @@
1
+ module Redmine
2
+ module Installer
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'redmine-installer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "redmine-installer"
8
+ spec.version = Redmine::Installer::VERSION
9
+ spec.authors = ["Ondřej Moravčík"]
10
+ spec.email = ["moravcik.ondrej@gmail.com"]
11
+ spec.summary = %q{Easy way how install/upgrade redmine or plugin.}
12
+ spec.description = %q{Redmine-installer can fully install/upgrade redmine and will
13
+ generate template for different server. All actions can be saved
14
+ for further use.}
15
+ spec.homepage = "https://github.com/ondra-m/redmine-installer"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Redmine::Installer::Install do
4
+
5
+ before(:example) do
6
+ @dir = Dir.mktmpdir
7
+ end
8
+
9
+ after(:example) do
10
+ FileUtils.remove_entry_secure(@dir)
11
+ end
12
+
13
+ let(:package1) { LoadRedmine.get('2.4.7') }
14
+
15
+ context 'mysql' do
16
+ let(:host) { RSpec.configuration.mysql[:host] }
17
+ let(:port) { RSpec.configuration.mysql[:port] }
18
+ let(:username) { RSpec.configuration.mysql[:username] }
19
+ let(:password) { RSpec.configuration.mysql[:password] }
20
+
21
+ before(:example) do
22
+ system("mysql -h #{host} --port #{port} -u #{username} -p#{password} -e 'drop database test1'")
23
+ end
24
+
25
+ it 'install' do
26
+ # redmine root -> temp dir
27
+ # type of db -> mysql
28
+ # database -> test1
29
+ # host -> configuration
30
+ # username -> configuration
31
+ # password -> configuration
32
+ # encoding -> utf8
33
+ # port -> configuration
34
+ # email configuration -> skip
35
+ # webserver -> skip
36
+
37
+ allow($stdin).to receive(:gets).and_return(
38
+ @dir, '1', 'test1', host, username, password, 'utf8', port, '999', '999'
39
+ )
40
+
41
+ r_installer = Redmine::Installer::Install.new(package1, {})
42
+ expect { r_installer.run }.to_not raise_error
43
+ end
44
+ end
45
+
46
+ end