workarea-upgrade 3.0.2

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.
@@ -0,0 +1,30 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'date'
8
+ require 'tempfile'
9
+
10
+ load 'workarea/changelog.rake'
11
+
12
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
13
+ require 'workarea/upgrade/version'
14
+
15
+ desc "Release version #{Workarea::Upgrade::VERSION} of the gem"
16
+ task :release do
17
+ host = "https://#{ENV['BUNDLE_GEMS__WEBLINC__COM']}@gems.weblinc.com"
18
+
19
+ Rake::Task['workarea:changelog'].execute
20
+ system 'git add CHANGELOG.md'
21
+ system 'git commit -m "Update CHANGELOG"'
22
+
23
+ system "git tag -a v#{Workarea::Upgrade::VERSION} -m 'Tagging #{Workarea::Upgrade::VERSION}'"
24
+ system 'git push origin HEAD --follow-tags'
25
+
26
+ system "gem build workarea-upgrade.gemspec"
27
+ system "gem push workarea-upgrade-#{Workarea::Upgrade::VERSION}.gem #{host}"
28
+ system "gem push workarea-upgrade-#{Workarea::Upgrade::VERSION}.gem --host #{host}"
29
+ system "rm workarea-upgrade-#{Workarea::Upgrade::VERSION}.gem"
30
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails gems
3
+ # installed from the root of your application.
4
+
5
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
6
+ ENGINE_PATH = File.expand_path('../../lib/workarea/upgrade/engine', __FILE__)
7
+
8
+ # Set up gems listed in the Gemfile.
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
10
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
11
+
12
+ require "action_controller/railtie"
13
+ require "action_view/railtie"
14
+ require "action_mailer/railtie"
15
+ require "rails/test_unit/railtie"
16
+ require "sprockets/railtie"
17
+
18
+ require 'rails/engine/commands'
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'workarea/upgrade'
5
+ require 'workarea/upgrade/cli'
6
+
7
+ Workarea::Upgrade::CLI.start(ARGV)
@@ -0,0 +1,26 @@
1
+ require 'active_support/all'
2
+
3
+ require 'workarea'
4
+ require 'workarea/storefront'
5
+ require 'workarea/admin'
6
+
7
+ require 'thor'
8
+ require 'diffy'
9
+ require 'fileutils'
10
+ require 'bundler'
11
+ require 'rake'
12
+
13
+ require 'workarea/upgrade/engine'
14
+
15
+ module Workarea
16
+ module Upgrade
17
+ end
18
+ end
19
+
20
+ require 'workarea/upgrade/diff'
21
+ require 'workarea/upgrade/diff/gem_diff'
22
+ require 'workarea/upgrade/diff/workarea_file'
23
+ require 'workarea/upgrade/diff/current_app'
24
+
25
+ require 'workarea/upgrade/gemfile'
26
+ require 'workarea/upgrade/report'
@@ -0,0 +1,289 @@
1
+ module Workarea
2
+ module Upgrade
3
+ class CLI < Thor
4
+ include Thor::Actions
5
+
6
+ def self.source_root
7
+ Dir.pwd
8
+ end
9
+
10
+ default_task :prepare
11
+
12
+ desc 'prepare', 'Create a Gemfile.next'
13
+ long_desc <<~LONG_DESC
14
+ This plugin uses a special file, that must be present in your
15
+ application's root directory, called Gemfile.next. This file is like
16
+ a regular Gemfile but it contains a list of only the Workarea gems you
17
+ wish to upgrade your application to.
18
+
19
+ You can craft an artisanal Gemfile.next file yourself or use this
20
+ command to walk you through the creation process. If you choose to
21
+ handcraft your own bespoke Gemfile.next you can immediately use any of
22
+ the other commands offered, such as "report" or "diff".
23
+
24
+ If you want to walk through each of the versions available to you and
25
+ customize which to include you can use this "prepare" command to
26
+ generate or regenerate a Gemfile.next file.
27
+ LONG_DESC
28
+ option :latest,
29
+ aliases: :l, type: :boolean,
30
+ desc: 'Just use the latest Workarea gems for the upgrade'
31
+ def prepare
32
+ if gemfile_next.exist?
33
+ say "\nGemfile.next already exists in #{Dir.pwd}.", :green
34
+
35
+ if ask("\nWould you like to regenerate the file? [Yn]").casecmp?('n')
36
+ say "\nLooks like you're ready to upgrade!", :green
37
+ say 'Try running another command, like "diff" or "report":'
38
+ puts
39
+ invoke :help, [], {}
40
+ exit(0)
41
+ else
42
+ remove_file 'Gemfile.next'
43
+ remove_file 'Gemfile.next.lock'
44
+ invoke :prepare, [], {}
45
+ end
46
+ elsif gemfile_next.lockfile_exist?
47
+ remove_file 'Gemfile.next.lock'
48
+ end
49
+
50
+ say "\nPlease be patient; we're hacking The Gibson...", :yellow
51
+
52
+ unless gemfile.outdated.any?
53
+ say "\nYour application is already up to date!", :green
54
+ exit(0)
55
+ end
56
+
57
+ say "\nAvailable updates:", :yellow
58
+ gemfile.outdated.each { |g| say(" * #{g.first} (#{g.last})") }
59
+
60
+ chosen_gems = options[:latest] ? gemfile.outdated : choose_gems
61
+
62
+ copy_file 'Gemfile', 'Gemfile.next'
63
+
64
+ chosen_gems.each do |gem|
65
+ current_version = gemfile.installed.to_h[gem.first]
66
+ gsub_file 'Gemfile.next',
67
+ /#{gem.first}(['"].*)#{current_version}/,
68
+ "#{gem.first}\\1#{gem.last}"
69
+ end
70
+
71
+ if gemfile_next.check_install
72
+ invoke :report, [], {}
73
+ else
74
+ say "\nOh noes! Your Gemfile.next failed to install!", :red
75
+
76
+ puts
77
+ say <<~MESSAGE
78
+ This usually happens when you try to upgrade your project to a new
79
+ minor version. Workarea may be depending on different versions of
80
+ gems than you currently have listed in your Gemfile.
81
+
82
+ All this means is that we'll need a bit of human intervention for
83
+ this next part.
84
+
85
+ What you should do is manually edit the Gemfile.next that we've just
86
+ created in your project. After you've made some edits you can test
87
+ the Gemfile.next by running:
88
+
89
+ $ bundle install --gemfile Gemfile.next
90
+
91
+ Once you've resolved the dependency issues in your Gemfile.next you
92
+ can pick up where you left off by running:
93
+
94
+ $ bundle exec workarea_upgrade report
95
+ MESSAGE
96
+
97
+ say "\nGood luck!", :green
98
+ end
99
+ end
100
+
101
+ desc 'report', 'Display an overview of the complexity of the upgrade'
102
+ def report
103
+ prepared?
104
+
105
+ gems_to_ignore = Gemfile.diff(gemfile, gemfile_next).to_h.keys
106
+
107
+ diff = Diff.new(
108
+ gemfile_next.workarea_version,
109
+ options.merge(plugins: gemfile_next.plugins(gems_to_ignore).to_h)
110
+ )
111
+
112
+ report = Report.new(diff)
113
+
114
+ puts
115
+ puts '###############'
116
+ say 'Diff Statistics', :green
117
+ puts '###############'
118
+
119
+ display_report(report.diff_stats)
120
+
121
+ puts
122
+ puts '###############'
123
+ say ' Report Card', :green
124
+ puts '###############'
125
+
126
+ display_report(report.report_card_stats)
127
+
128
+ puts
129
+ puts '###############'
130
+ say ' Breakdown', :green
131
+ puts '###############'
132
+
133
+ display_report(report.breakdown_customized_stats)
134
+ display_report(report.breakdown_worst_files_stats)
135
+
136
+ puts
137
+ puts '###############'
138
+ say ' Next Steps', :green
139
+ puts '###############'
140
+
141
+ puts
142
+ puts "* View a full diff of all files that will be impacted by this upgrade:"
143
+ puts " $ bundle exec workarea_upgrade diff"
144
+
145
+ puts
146
+ puts "* Replace your Gemfile and Gemfile.lock with the new versions:"
147
+ puts " $ mv Gemfile.next Gemfile"
148
+ puts " $ mv Gemfile.next.lock Gemfile.lock"
149
+
150
+ puts
151
+ puts "* Compare release notes between your version and #{gemfile_next.workarea_version}:"
152
+ puts " https://developer.workarea.com/release-notes.html"
153
+
154
+ puts
155
+ puts "* If you're upgrading to a new minor be sure to read the appropriate Upgrade Guide:"
156
+ puts " https://developer.workarea.com/upgrade-guides.html"
157
+ end
158
+
159
+ desc 'diff', 'Output a diff of changes that will affect your project'
160
+ long_desc <<~LONG_DESC
161
+ The default diff displayed will be based on changes made to the Workarea
162
+ platform that will have an impact on the overridden or decorated files
163
+ found in your project.
164
+
165
+ It's purpose is to allow you to see what has changed in the underlying
166
+ platform and to make decisions based on whether or not a given change
167
+ should be incorporated into your app.
168
+
169
+ To see a full log of change between versions, not just the changes that
170
+ may or may not be relevant to your specific application, pass the
171
+ `--full` option to this command.
172
+ LONG_DESC
173
+ option :format,
174
+ aliases: :f,
175
+ type: :string,
176
+ default: 'color',
177
+ enum: %w[color html]
178
+ option :context,
179
+ alias: :c,
180
+ type: :numeric,
181
+ desc: 'The number of lines displayed around each change in the diff'
182
+ option :full,
183
+ type: :boolean,
184
+ desc: 'Display every change to Workarea, not just the impactful ones'
185
+ option :added,
186
+ type: :boolean,
187
+ desc: 'View a list of files that were added to Workarea'
188
+ option :removed,
189
+ type: :boolean,
190
+ desc: 'View a list of files that were removed from Workarea'
191
+ def diff
192
+ prepared?
193
+
194
+ gems_to_ignore = Gemfile.diff(gemfile, gemfile_next).to_h.keys
195
+
196
+ diff = Diff.new(
197
+ gemfile_next.workarea_version,
198
+ options.merge(plugins: gemfile_next.plugins(gems_to_ignore).to_h)
199
+ )
200
+
201
+ if options[:added]
202
+ puts diff.added.join("\n")
203
+ exit(0)
204
+ end
205
+
206
+ if options[:removed]
207
+ puts diff.removed.join("\n")
208
+ exit(0)
209
+ end
210
+
211
+ if options[:full]
212
+ handle_diff_output(diff.all.join, options[:format])
213
+ else
214
+ handle_diff_output(diff.for_current_app.join, options[:format])
215
+ end
216
+ end
217
+
218
+ private
219
+
220
+ def gemfile
221
+ @gemfile ||= Gemfile.new
222
+ end
223
+
224
+ def gemfile_next
225
+ @gemfile_next ||= Gemfile.new('Gemfile.next')
226
+ end
227
+
228
+ def prepared?
229
+ unless gemfile_next.exist?
230
+ say "\nGemfile.next was not found in #{Dir.pwd}", :red
231
+ say 'Preparing your application for upgrade...'
232
+ invoke :prepare, [], {}
233
+ end
234
+ end
235
+
236
+ def choose_gems
237
+ done = 'n'
238
+
239
+ while done.casecmp?('n')
240
+ say "\nYou can [C]ontinue, [s]kip, or enter a new version number:"
241
+
242
+ gems = gemfile.outdated.each_with_object([]) do |gem, memo|
243
+ choice = ask(" * #{gem.first} (#{gem.last})", :yellow)
244
+
245
+ next if choice.casecmp?('s')
246
+
247
+ if choice.casecmp?('c') || choice.empty?
248
+ memo << gem
249
+ else
250
+ memo << [gem.first, choice]
251
+ end
252
+ end
253
+
254
+ if gems.nil?
255
+ say('You must choose at least one gem to upgrade.', :red)
256
+ else
257
+ say("\nHere's what you chose:")
258
+ gems.each { |gem| say(" * #{gem.first} (#{gem.last})", :green) }
259
+
260
+ done = ask("\nWrite these gems to the Gemfile.next? [Ynq]")
261
+ exit(0) if done.casecmp?('q')
262
+ end
263
+ end
264
+
265
+ gems
266
+ end
267
+
268
+ def handle_diff_output(result, format)
269
+ if format.to_s == 'html'
270
+ puts <<-eos
271
+ <!doctype html>
272
+ <html>
273
+ <head><style>#{Diff::CSS}</style></head>
274
+ <body>#{result}</body>
275
+ </html>
276
+ eos
277
+ else
278
+ puts result
279
+ end
280
+ end
281
+
282
+ def display_report(stats)
283
+ stats.each do |stat|
284
+ say_status stat[:status], stat[:message], stat[:color]
285
+ end
286
+ end
287
+ end
288
+ end
289
+ end
@@ -0,0 +1,87 @@
1
+ module Workarea
2
+ module Upgrade
3
+ class Diff
4
+ CSS = <<-STYLE
5
+ .diff{overflow:auto;}
6
+ .diff ul{background:#fff;overflow:auto;font-size:13px;list-style:none;margin:0;padding:0;display:table;width:100%;}
7
+ .diff del, .diff ins{display:block;text-decoration:none;}
8
+ .diff li{padding:0; display:table-row;margin: 0;height:1em;}
9
+ .diff li.ins{background:#dfd; color:#080}
10
+ .diff li.del{background:#fee; color:#b00}
11
+ .diff li:hover{background:#ffc}
12
+ /* try 'whitespace:pre;' if you don't want lines to wrap */
13
+ .diff del, .diff ins, .diff span{white-space:pre-wrap;font-family:courier;}
14
+ .diff del strong{font-weight:normal;background:#fcc;}
15
+ .diff ins strong{font-weight:normal;background:#9f9;}
16
+ .diff li.diff-comment { background: none repeat scroll 0 0 gray; }
17
+ .diff li.diff-block-info { background: none repeat scroll 0 0 gray; }
18
+ STYLE
19
+
20
+ def initialize(core_to_version, options)
21
+ @core_to_version = core_to_version
22
+ @options = options
23
+ end
24
+
25
+ def plugins
26
+ @options[:plugins].presence || {}
27
+ end
28
+
29
+ def gem_diffs
30
+ @gem_diffs ||= gems.map do |gem, to_version|
31
+ from_path = find_from_path!(gem)
32
+ to_path = find_to_path!(gem, to_version)
33
+
34
+ GemDiff.new(
35
+ from_path,
36
+ to_path,
37
+ @options
38
+ )
39
+ end
40
+ end
41
+
42
+ %w(
43
+ all
44
+ for_current_app
45
+ added
46
+ removed
47
+ overridden
48
+ decorated
49
+ customized_files
50
+ ).each do |method|
51
+ define_method method do
52
+ gem_diffs.map(&method.to_sym).reduce(&:+)
53
+ end
54
+ end
55
+
56
+ def gems
57
+ %w(workarea-core workarea-storefront workarea-admin)
58
+ .each_with_object({}) { |gem, memo| memo[gem] = @core_to_version }
59
+ .merge(plugins)
60
+ .select { |gem, _version| find_from_path!(gem).present? }
61
+ end
62
+
63
+ def find_from_path!(gem)
64
+ Bundler.load.specs.find { |s| s.name == "#{gem}" }&.full_gem_path
65
+ end
66
+
67
+ def find_to_path!(gem, version)
68
+ unless version.to_s =~ /^(\d+\.)(\d+\.)(\d+)/
69
+ raise "#{version} is not a valid version number. Example format: 3.0.5"
70
+ end
71
+
72
+ result = "#{Gem.dir}/gems/#{gem}-#{version}"
73
+
74
+ if !File.directory?(result)
75
+ raise <<-eos.strip_heredoc
76
+
77
+ Couldn't find #{gem} v#{version} in installed gems!
78
+ Looked in #{result}
79
+ Try `gem install #{gem} -v #{version}`.
80
+ eos
81
+ end
82
+
83
+ result
84
+ end
85
+ end
86
+ end
87
+ end