redmine-installer 1.0.7 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +3 -15
  5. data/README.md +49 -177
  6. data/bin/redmine +4 -5
  7. data/lib/redmine-installer/backup.rb +13 -40
  8. data/lib/redmine-installer/cli.rb +92 -61
  9. data/lib/redmine-installer/command.rb +63 -117
  10. data/lib/redmine-installer/configuration.rb +148 -0
  11. data/lib/redmine-installer/database.rb +204 -0
  12. data/lib/redmine-installer/environment.rb +21 -0
  13. data/lib/redmine-installer/errors.rb +7 -0
  14. data/lib/redmine-installer/install.rb +37 -42
  15. data/lib/redmine-installer/logger.rb +83 -0
  16. data/lib/redmine-installer/package.rb +180 -0
  17. data/lib/redmine-installer/patches/ruby.rb +35 -0
  18. data/lib/redmine-installer/patches/tty.rb +16 -0
  19. data/lib/redmine-installer/profile.rb +24 -55
  20. data/lib/redmine-installer/redmine.rb +551 -0
  21. data/lib/redmine-installer/spec/spec.rb +81 -0
  22. data/lib/redmine-installer/task.rb +18 -77
  23. data/lib/redmine-installer/task_module.rb +12 -0
  24. data/lib/redmine-installer/upgrade.rb +51 -59
  25. data/lib/redmine-installer/utils.rb +46 -233
  26. data/lib/redmine-installer/version.rb +2 -4
  27. data/lib/redmine-installer.rb +69 -56
  28. data/redmine-installer.gemspec +20 -19
  29. data/spec/custom_matchers.rb +21 -0
  30. data/spec/installer_helper.rb +107 -0
  31. data/spec/installer_process.rb +82 -0
  32. data/spec/lib/backup_restore_spec.rb +81 -0
  33. data/spec/lib/install_spec.rb +125 -36
  34. data/spec/lib/upgrade_spec.rb +73 -52
  35. data/spec/packages/redmine-3.1.0.zip +0 -0
  36. data/spec/packages/redmine-3.2.0.zip +0 -0
  37. data/spec/packages/redmine-3.3.0-bad-migration.zip +0 -0
  38. data/spec/packages/redmine-3.3.0.zip +0 -0
  39. data/spec/packages/something-else.zip +0 -0
  40. data/spec/packages_helper.rb +19 -0
  41. data/spec/shared_contexts.rb +13 -0
  42. data/spec/spec_helper.rb +34 -18
  43. metadata +62 -63
  44. data/lib/redmine-installer/config_param.rb +0 -100
  45. data/lib/redmine-installer/error.rb +0 -5
  46. data/lib/redmine-installer/exec.rb +0 -158
  47. data/lib/redmine-installer/ext/module.rb +0 -7
  48. data/lib/redmine-installer/ext/string.rb +0 -15
  49. data/lib/redmine-installer/git.rb +0 -51
  50. data/lib/redmine-installer/helper.rb +0 -5
  51. data/lib/redmine-installer/helpers/generate_config.rb +0 -29
  52. data/lib/redmine-installer/locales/cs.yml +0 -147
  53. data/lib/redmine-installer/locales/en.yml +0 -154
  54. data/lib/redmine-installer/plugin.rb +0 -9
  55. data/lib/redmine-installer/plugins/base.rb +0 -24
  56. data/lib/redmine-installer/plugins/database.rb +0 -180
  57. data/lib/redmine-installer/plugins/email_sending.rb +0 -82
  58. data/lib/redmine-installer/plugins/redmine_plugin.rb +0 -82
  59. data/lib/redmine-installer/plugins/web_server.rb +0 -26
  60. data/lib/redmine-installer/step.rb +0 -16
  61. data/lib/redmine-installer/steps/backup.rb +0 -125
  62. data/lib/redmine-installer/steps/base.rb +0 -79
  63. data/lib/redmine-installer/steps/database_config.rb +0 -15
  64. data/lib/redmine-installer/steps/email_config.rb +0 -11
  65. data/lib/redmine-installer/steps/env_check.rb +0 -20
  66. data/lib/redmine-installer/steps/install.rb +0 -23
  67. data/lib/redmine-installer/steps/load_package.rb +0 -226
  68. data/lib/redmine-installer/steps/move_redmine.rb +0 -22
  69. data/lib/redmine-installer/steps/redmine_root.rb +0 -52
  70. data/lib/redmine-installer/steps/upgrade.rb +0 -57
  71. data/lib/redmine-installer/steps/validation.rb +0 -38
  72. data/lib/redmine-installer/steps/webserver_config.rb +0 -22
  73. data/spec/load_redmine.rb +0 -24
@@ -1,82 +0,0 @@
1
- module Redmine::Installer::Plugin
2
- class RedminePlugin < Base
3
-
4
- # Search plugins folder
5
- def self.am_i_there?
6
- records = Dir.glob(File.join('plugins', '*'))
7
- records.map! do |record|
8
- File.basename(record)
9
- end
10
-
11
- records.include?(self.class_name.downcase)
12
- end
13
-
14
- def self.final(*)
15
- end
16
-
17
- end
18
- end
19
-
20
- ##
21
- # EasyProject
22
- #
23
- # http://www.easyredmine.com
24
- #
25
- # Easy Redmine is complex project management web application best suited to project teams between
26
- # 10 - 100 users. Whether you manage just yourself or a huge team of software developers,
27
- # Easy Redmine will provide all necessary project management features to complete your projects
28
- # on time, scope and budget.
29
- #
30
- class EasyProject < Redmine::Installer::Plugin::RedminePlugin
31
-
32
- class Redmine::Installer::Command
33
- def rake_easyproject_install(env)
34
- run(RAKE, 'easyproject:install', get_rails_env(env), :'plugin.redmine_plugin.easyproject.install')
35
- end
36
- end
37
-
38
- def self.install(base)
39
- command.rake_easyproject_install(base.env) if am_i_there?
40
- end
41
-
42
- def self.upgrade(base)
43
- # Copy client modification folders
44
- # plugins/easyproject/easy_plugins/modification_*
45
- unless base.options['skip-old-modifications']
46
- easy_plugins_dir = File.join('plugins', 'easyproject', 'easy_plugins')
47
- old_modifications = Dir.glob(File.join(base.redmine_root, easy_plugins_dir, 'modification_*'))
48
- new_modifications = Dir.glob(File.join(base.tmp_redmine_root, easy_plugins_dir, 'modification_*'))
49
-
50
- # Modifications which are on old redmine but not new
51
- missing_modifications = old_modifications - new_modifications
52
-
53
- FileUtils.cp_r(missing_modifications, File.join(base.tmp_redmine_root, easy_plugins_dir))
54
- end
55
-
56
- install(base)
57
- end
58
-
59
- def self.final(base)
60
- return unless am_i_there?
61
-
62
- say %{
63
- <bright>EasyRedmine notes:</bright>
64
- You should create a maintenance task to CRON (on Linux) or Scheduled Tasks (on Windows)
65
- that will be running every 5-15 minutes. This one task aggregates all required tasks
66
- such as mail receiving, alerts evaluation etc. You should set up required parameters via
67
- administration -> scheduled tasks.
68
- Do not run this task under root, use same user that is used for web server.:
69
-
70
- <bright>bundle exec rake easyproject:scheduler:run_tasks RAILS_ENV=production</bright>
71
-
72
- For example:
73
- 1. Edit crontab
74
- crontab -e
75
-
76
- 2. Add:
77
- */15 * * * * cd #{base.redmine_root} && bundle exec rake easyproject:scheduler:run_tasks RAILS_ENV=production
78
-
79
-
80
- }
81
- end
82
- end
@@ -1,26 +0,0 @@
1
- module Redmine::Installer::Plugin
2
- class WebServer < Base
3
-
4
- # Generate config based on class and redmine_root.
5
- # Texts are in lang files.
6
- def self.generate_config(redmine_root)
7
- translate("plugin.#{self.superclass.class_name.downcase}.#{self.class_name.downcase}.configuration", redmine_root: redmine_root)
8
- end
9
-
10
- class Webrick < WebServer
11
- end
12
-
13
- class Thin < WebServer
14
- end
15
-
16
- class ApachePassenger < WebServer
17
- end
18
-
19
- class NginxPassenger < WebServer
20
- end
21
-
22
- class Puma < WebServer
23
- end
24
-
25
- end
26
- end
@@ -1,16 +0,0 @@
1
- module Redmine::Installer
2
- module Step
3
- autoload :Base, 'redmine-installer/steps/base'
4
- autoload :LoadPackage, 'redmine-installer/steps/load_package'
5
- autoload :DatabaseConfig, 'redmine-installer/steps/database_config'
6
- autoload :EmailConfig, 'redmine-installer/steps/email_config'
7
- autoload :Install, 'redmine-installer/steps/install'
8
- autoload :MoveRedmine, 'redmine-installer/steps/move_redmine'
9
- autoload :WebserverConfig, 'redmine-installer/steps/webserver_config'
10
- autoload :Validation, 'redmine-installer/steps/validation'
11
- autoload :Backup, 'redmine-installer/steps/backup'
12
- autoload :Upgrade, 'redmine-installer/steps/upgrade'
13
- autoload :RedmineRoot, 'redmine-installer/steps/redmine_root'
14
- autoload :EnvCheck, 'redmine-installer/steps/env_check'
15
- end
16
- end
@@ -1,125 +0,0 @@
1
- require 'fileutils'
2
- require 'zip'
3
-
4
- module Redmine::Installer::Step
5
- class Backup < Base
6
-
7
- DEFAULT_BACKUP_DIR = File.join(Dir.home, 'redmine-backups')
8
-
9
- def up
10
- choices = {}
11
- choices[:full_backup] = t(:full_backup)
12
- choices[:backup] = t(:backup)
13
- choices[:only_database] = t(:only_database)
14
- choices[:skip] = t(:skip)
15
-
16
- @backup_type ||= choose(:do_you_want_backup_redmine, choices, default: :backup)
17
-
18
- case @backup_type
19
- when :full_backup
20
- do_full_backup
21
- when :backup
22
- do_backup
23
- when :only_database
24
- database_backup
25
- end
26
- end
27
-
28
- def down
29
- # It could be dangerous
30
- #
31
- # if @database_backed_up
32
- # say(:restoring_database)
33
- # database_restore
34
- # end
35
- end
36
-
37
- def final
38
- if @current_backup_dir
39
- say t(:backup_is_stored_at, dir: @current_backup_dir), 2
40
- end
41
- end
42
-
43
- def save(configuration)
44
- configuration['backup_type'] = @backup_type
45
- configuration['backup_dir'] = @backup_dir
46
- end
47
-
48
- def load(configuration)
49
- @backup_type = configuration['backup_type']
50
- @backup_dir = configuration['backup_dir']
51
- end
52
-
53
- private
54
-
55
- def check_backup_dir
56
- if @backup_dir.nil?
57
- dir = ask(:what_dir_for_backups, default: DEFAULT_BACKUP_DIR)
58
- dir = File.expand_path(dir)
59
-
60
- try_create_dir(dir) unless Dir.exist?(dir)
61
-
62
- @backup_dir = dir
63
- end
64
- end
65
-
66
- def create_current_backup_dir
67
- return if @current_backup_dir
68
-
69
- check_backup_dir
70
- @current_backup_dir = File.join(@backup_dir, Time.now.strftime('backup_%d%m%Y_%H%M%S'))
71
- try_create_dir(@current_backup_dir)
72
- end
73
-
74
- def database_backup
75
- create_current_backup_dir
76
-
77
- plugin::Database.backup_all(base.redmine_root, @current_backup_dir)
78
- @database_backed_up = true
79
- end
80
-
81
- def database_restore
82
- plugin::Database.restore_all(base.redmine_root, @current_backup_dir)
83
- end
84
-
85
- def do_full_backup
86
- create_current_backup_dir
87
-
88
- zipfile_name = File.join(@current_backup_dir, 'redmine.zip')
89
-
90
- Dir.chdir(base.redmine_root) do
91
- Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
92
- Dir.glob(File.join('**', '{*,.*}')).each do |entry|
93
- next if entry.end_with?('.') || entry.end_with?('..')
94
-
95
- zipfile.add(entry, entry)
96
- end
97
- end
98
- end
99
-
100
- database_backup
101
- end
102
-
103
- def do_backup
104
- create_current_backup_dir
105
-
106
- # create config dir
107
- config_dir = File.join(@current_backup_dir, 'config')
108
- FileUtils.mkdir(config_dir)
109
-
110
- # database.yml
111
- database_file = File.join(base.redmine_root, plugin::Database::DATABASE_YML_PATH)
112
- FileUtils.cp(database_file, config_dir) if File.exist?(database_file)
113
-
114
- # configuration.yml
115
- configuration_file = File.join(base.redmine_root, plugin::EmailSending::CONFIGURATION_YML_PATH)
116
- FileUtils.cp(configuration_file, config_dir) if File.exist?(configuration_file)
117
-
118
- # files
119
- FileUtils.cp_r(File.join(base.redmine_root, 'files'), @current_backup_dir)
120
-
121
- database_backup
122
- end
123
-
124
- end
125
- end
@@ -1,79 +0,0 @@
1
- module Redmine::Installer::Step
2
- ##
3
- # Base
4
- #
5
- # == Steps:
6
- # prepare::
7
- # used for argument validation
8
- #
9
- # up::
10
- # actions
11
- #
12
- # final::
13
- # for printing informations
14
- #
15
- # down::
16
- # if something went wrong
17
- #
18
- class Base
19
-
20
- include Redmine::Installer::Utils
21
-
22
- attr_accessor :index
23
- attr_accessor :base
24
- attr_accessor :ran
25
-
26
- def initialize(index, base)
27
- self.index = index
28
- self.base = base
29
- self.ran = false
30
- end
31
-
32
- def print_title
33
- title = '<bright><on_black><white>'
34
- title << "#{index}. "
35
- title << translate("step.#{self.class.class_name.underscore}.title"
36
- )
37
- title << '</white></on_black></bright>'
38
-
39
- say(title, 1)
40
- end
41
-
42
- def print_header
43
- end
44
-
45
- def print_footer
46
- end
47
-
48
- def prepare
49
- end
50
-
51
- def up
52
- end
53
-
54
- def final
55
- end
56
-
57
- def down
58
- end
59
-
60
- def save(*)
61
- end
62
-
63
- def load(*)
64
- end
65
-
66
- def redmine_plugins
67
- @redmine_plugins ||= _redmine_plugins
68
- end
69
-
70
- private
71
-
72
- def _redmine_plugins
73
- Dir.glob(File.join(base.redmine_root, 'plugins', '*')).select do |entry|
74
- File.directory?(entry)
75
- end
76
- end
77
-
78
- end
79
- end
@@ -1,15 +0,0 @@
1
- module Redmine::Installer::Step
2
- class DatabaseConfig < Base
3
-
4
- include Redmine::Installer::Helper::GenerateConfig
5
-
6
- def up
7
- if create_for(plugin::Database)
8
- # continue
9
- else
10
- base.settings[:skip_migration] = true
11
- end
12
- end
13
-
14
- end
15
- end
@@ -1,11 +0,0 @@
1
- module Redmine::Installer::Step
2
- class EmailConfig < Base
3
-
4
- include Redmine::Installer::Helper::GenerateConfig
5
-
6
- def up
7
- create_for(plugin::EmailSending)
8
- end
9
-
10
- end
11
- end
@@ -1,20 +0,0 @@
1
- module Redmine::Installer::Step
2
- class EnvCheck < Base
3
-
4
- def prepare
5
- # Check if windows
6
- # if windows?
7
- # confirm(:do_you_want_continue_if_windows, false)
8
- # end
9
-
10
- if root? && !confirm(:installer_run_as_root, false)
11
- error(:terminated_by_user)
12
- end
13
- end
14
-
15
- def up
16
- say '<green>... OK</green>', 1
17
- end
18
-
19
- end
20
- end
@@ -1,23 +0,0 @@
1
- module Redmine::Installer::Step
2
- class Install < Base
3
-
4
- def up
5
- Dir.chdir(base.tmp_redmine_root) do
6
- command.bundle_install(base.env)
7
-
8
- return if base.settings[:skip_migration]
9
-
10
- command.rake_db_create(base.env)
11
- command.rake_db_migrate(base.env)
12
- command.rake_redmine_plugin_migrate(base.env) if some_plugins?
13
- command.rake_generate_secret_token(base.env)
14
-
15
- # Other plugins can have post-install procedure
16
- plugin::RedminePlugin.all.each do |plugin|
17
- plugin.install(base)
18
- end
19
- end
20
- end
21
-
22
- end
23
- end
@@ -1,226 +0,0 @@
1
- require 'rubygems/package'
2
- require 'ruby-progressbar'
3
- require 'fileutils'
4
- require 'net/http'
5
- require 'tmpdir'
6
- require 'zlib'
7
- require 'zip'
8
- require 'uri'
9
-
10
- module Redmine::Installer::Step
11
- class LoadPackage < Base
12
-
13
- SUPPORTED_ARCHIVE_FORMATS = ['.zip', '.gz', '.tgz']
14
- TAR_LONGLINK = '././@LongLink'
15
- PROGRESSBAR_FORMAT = '%a [%b>%i] %p%% %t'
16
-
17
- def prepare
18
- case base.options[:source]
19
- when 'file'
20
-
21
- unless File.exist?(base.package)
22
- if base.package =~ /\Av?(\d\.\d\.\d)\Z/
23
- download_redmine($1)
24
- end
25
- end
26
-
27
- unless File.exist?(base.package)
28
- error :file_not_exist, file: base.package
29
- end
30
-
31
- @type = File.extname(base.package)
32
- unless SUPPORTED_ARCHIVE_FORMATS.include?(@type)
33
- error :file_must_have_format, file: base.package, formats: SUPPORTED_ARCHIVE_FORMATS.join(', ')
34
- end
35
-
36
- when 'git'
37
- nil
38
- else
39
- error :error_unsupported_source, source: base.options[:source]
40
- end
41
- end
42
-
43
- def up
44
- case base.options[:source]
45
- when 'file'
46
- load_from_archive
47
- when 'git'
48
- load_from_git
49
- end
50
- end
51
-
52
- def down
53
- FileUtils.remove_entry_secure(@tmpdir) if @tmpdir
54
- FileUtils.safe_unlink(@tmpfile) if @tmpfile
55
- end
56
-
57
- def final
58
- down
59
- say(t(:redmine_was_installed_to, dir: base.redmine_root), 1)
60
- end
61
-
62
- private
63
-
64
- # =======================================================================
65
- # General
66
-
67
- # Move files from temp dir to target. First check
68
- # if folder contains redmine or contains
69
- # folder which contains redmine :-)
70
- #
71
- # Package can have format:
72
- # |-- redmine-2
73
- # |-- app
74
- # `-- config
75
- # ...
76
- #
77
- def get_tmp_redmine_root
78
- base.tmp_redmine_root = @tmpdir
79
-
80
- loop {
81
- ls = Dir.glob(File.join(base.tmp_redmine_root, '*'))
82
-
83
- if ls.size == 1
84
- base.tmp_redmine_root = ls.first
85
- else
86
- break
87
- end
88
- }
89
- end
90
-
91
-
92
- # =======================================================================
93
- # File
94
-
95
- def load_from_archive
96
- # Make temp directory and extract archive + move it to the redmine_folder
97
- extract_to_tmp
98
-
99
- # Locate redmine_root in tmpdir
100
- get_tmp_redmine_root
101
- end
102
-
103
- def download_redmine(version)
104
- @tmpfile = Tempfile.new(['redmine', '.zip'])
105
- @tmpfile.binmode
106
-
107
- uri = URI("http://www.redmine.org/releases/redmine-#{version}.zip")
108
-
109
- Net::HTTP.start(uri.host, uri.port) do |http|
110
- head = http.request_head(uri)
111
-
112
- unless head.is_a?(Net::HTTPSuccess)
113
- error :cannot_download_redmine_version, version: version
114
- end
115
-
116
- say(:redmine_downloading, 1)
117
- progressbar = ProgressBar.create(format: PROGRESSBAR_FORMAT, total: head['content-length'].to_i)
118
-
119
- http.get(uri) do |data|
120
- @tmpfile.write(data)
121
- progressbar.progress += data.size
122
- end
123
-
124
- progressbar.finish
125
- say(nil, 1)
126
- end
127
-
128
- @tmpfile.close
129
-
130
- base.package = @tmpfile.path
131
- end
132
-
133
- def extract_to_tmp
134
- @tmpdir = Dir.mktmpdir
135
-
136
- case @type
137
- when '.zip'
138
- extract_zip
139
- when '.gz', '.tgz'
140
- extract_tar_gz
141
- end
142
- end
143
-
144
- def extract_zip
145
- Zip::File.open(base.package) do |zip_file|
146
- # Progressbar
147
- progressbar = ProgressBar.create(format: PROGRESSBAR_FORMAT, total: zip_file.size)
148
-
149
- zip_file.each do |entry|
150
- dest_file = File.join(@tmpdir, entry.name)
151
- FileUtils.mkdir_p(File.dirname(dest_file))
152
-
153
- entry.extract(dest_file)
154
- progressbar.increment
155
- end
156
- end
157
- end
158
-
159
- # Extract .tar.gz archive
160
- # based on http://dracoater.blogspot.cz/2013/10/extracting-files-from-targz-with-ruby.html
161
- #
162
- # Originally tar did not support paths longer than 100 chars. GNU tar is better and they
163
- # implemented support for longer paths, but it was made through a hack called ././@LongLink.
164
- # Shortly speaking, if you stumble upon an entry in tar archive which path equals to above
165
- # mentioned ././@LongLink, that means that the following entry path is longer than 100 chars and
166
- # is truncated. The full path of the following entry is actually the value of the current entry.
167
- #
168
- def extract_tar_gz
169
- Gem::Package::TarReader.new(Zlib::GzipReader.open(base.package)) do |tar|
170
-
171
- # Progressbar
172
- progressbar = ProgressBar.create(format: PROGRESSBAR_FORMAT, total: tar.count)
173
-
174
- # tar.count move position pointer to end
175
- tar.rewind
176
-
177
- dest_file = nil
178
- tar.each do |entry|
179
- if entry.full_name == TAR_LONGLINK
180
- dest_file = File.join(@tmpdir, entry.read.strip)
181
- next
182
- end
183
- dest_file ||= File.join(@tmpdir, entry.full_name)
184
- if entry.directory?
185
- FileUtils.rm_rf(dest_file) unless File.directory?(dest_file)
186
- FileUtils.mkdir_p(dest_file, mode: entry.header.mode, verbose: false)
187
- elsif entry.file?
188
- FileUtils.rm_rf(dest_file) unless File.file?(dest_file)
189
- File.open(dest_file, 'wb') do |f|
190
- f.write(entry.read)
191
- end
192
- FileUtils.chmod(entry.header.mode, dest_file, verbose: false)
193
- elsif entry.header.typeflag == '2' # symlink
194
- File.symlink(entry.header.linkname, dest_file)
195
- end
196
-
197
- dest_file = nil
198
- progressbar.increment
199
- end
200
- end
201
- end
202
-
203
-
204
- # =======================================================================
205
- # Git
206
-
207
- def load_from_git
208
- @tmpdir = Dir.mktmpdir
209
-
210
- # Package is remote url to git repository
211
- remote = base.package
212
-
213
- if remote
214
- # Clone repository
215
- Git.clone(remote, @tmpdir, base.options['branch'])
216
- else
217
- # Copy current repository to tmp and run pull
218
- Git.copy_and_fetch(base.redmine_root, @tmpdir)
219
- end
220
-
221
- # Locate redmine_root in tmpdir
222
- get_tmp_redmine_root
223
- end
224
-
225
- end
226
- end