al_folio_upgrade 1.0.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
+ SHA256:
3
+ metadata.gz: 91910554f7cb55cf4d0183137c940f89c90770981a1094e471b51cd034044fc9
4
+ data.tar.gz: 5c4d24dbbec94b1169f39955a0c33986d43957ac6a9b995f1f324594fca342c8
5
+ SHA512:
6
+ metadata.gz: a2dfa76729a1c268b5d7f0215721833e0caf8112e6e9bcf0550ed79532c1c7889e46ec215ea2a67f85dd723cc87f0acd5eae847f2b5de08a9cbcad3eab3c3e72
7
+ data.tar.gz: 84bd06b00efebb6668cb4992e58f7b2d67a310c120c3d0462700096d1e67392cb12366e9ce2cd1f9a9200438fa97f312cc2d014dcb9e0eba9d24865d5bf8974c
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 - 2026-02-08\n- Initial release.\n- Added `al-folio upgrade audit`, `al-folio upgrade apply --safe`, and `al-folio upgrade report`.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Maruan Al-Shedivat.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # Al-Folio Upgrade
2
+
3
+ Upgrade CLI for al-folio v1.x.
4
+
5
+ ## Commands
6
+
7
+ - `al-folio upgrade audit`
8
+ - `al-folio upgrade apply --safe`
9
+ - `al-folio upgrade report`
10
+
11
+ ## What it checks
12
+
13
+ - Core config contract (`al_folio.*`, Tailwind, Distill)
14
+ - Legacy Bootstrap/jQuery markers
15
+ - Distill remote-loader policy
16
+ - Local override drift when `theme: al_folio_core` is enabled
17
+ - Migration manifest availability from `al_folio_core`
data/exe/al-folio ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "al_folio_upgrade"
5
+
6
+ exit AlFolioUpgrade::CLI.new.run(ARGV)
@@ -0,0 +1,534 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+ require "pathname"
5
+ require "yaml"
6
+ require "date"
7
+
8
+ begin
9
+ require "al_folio_core"
10
+ rescue LoadError
11
+ # Optional at runtime; fallback lookup paths are used if unavailable.
12
+ end
13
+
14
+ module AlFolioUpgrade
15
+ class CLI
16
+ REPORT_PATH = "al-folio-upgrade-report.md"
17
+
18
+ Finding = Struct.new(:id, :severity, :message, :file, :line, :snippet, keyword_init: true)
19
+
20
+ FILE_GLOBS = [
21
+ "_config.yml",
22
+ "_includes/**/*.{liquid,html}",
23
+ "_layouts/**/*.{liquid,html}",
24
+ "_pages/**/*.{md,markdown,liquid,html}",
25
+ "_posts/**/*.{md,markdown,liquid,html}",
26
+ "assets/js/**/*.js",
27
+ "assets/css/**/*.css",
28
+ "assets/tailwind/**/*.css",
29
+ ].freeze
30
+
31
+ IGNORE_PATH_PATTERNS = [
32
+ /\/distillpub\//,
33
+ /\/search\/ninja-footer\.min\.js$/,
34
+ /\/bootstrap\.bundle\.min\.js$/,
35
+ /\/bootstrap-toc\.min\.js$/,
36
+ /\.min\.js$/,
37
+ /\.map$/,
38
+ ].freeze
39
+
40
+ SAFE_REPLACEMENTS = [
41
+ { from: /\bfont-weight-bold\b/, to: "font-bold" },
42
+ { from: /\bfont-weight-medium\b/, to: "font-medium" },
43
+ { from: /\bfont-weight-lighter\b/, to: "font-light" },
44
+ { from: %r{https://distill\.pub/template\.v2\.js}, to: "/assets/js/distillpub/template.v2.js" },
45
+ { from: %r{assets/tailwind/input\.css}, to: "assets/tailwind/app.css" },
46
+ ].freeze
47
+
48
+ CORE_OVERRIDE_FILES = %w[
49
+ _includes/head.liquid
50
+ _includes/scripts.liquid
51
+ _layouts/default.liquid
52
+ _layouts/post.liquid
53
+ _layouts/page.liquid
54
+ _layouts/distill.liquid
55
+ assets/js/common.js
56
+ assets/js/theme.js
57
+ assets/js/tooltips-setup.js
58
+ assets/tailwind/app.css
59
+ tailwind.config.js
60
+ ].freeze
61
+
62
+ def initialize(root: Dir.pwd, stdout: $stdout, stderr: $stderr)
63
+ @root = Pathname.new(root)
64
+ @stdout = stdout
65
+ @stderr = stderr
66
+ end
67
+
68
+ def run(argv)
69
+ return usage(1) if argv.empty?
70
+
71
+ command = argv.shift
72
+ unless command == "upgrade"
73
+ @stderr.puts("Unsupported command: #{command}")
74
+ return usage(1)
75
+ end
76
+
77
+ subcommand = argv.shift
78
+ case subcommand
79
+ when "audit"
80
+ options = { fail_on_blocking: true }
81
+ OptionParser.new do |opts|
82
+ opts.on("--no-fail", "Do not fail even when blocking findings exist") do
83
+ options[:fail_on_blocking] = false
84
+ end
85
+ end.parse!(argv)
86
+
87
+ findings = audit
88
+ write_report(findings)
89
+ print_summary(findings)
90
+ return 1 if options[:fail_on_blocking] && blocking?(findings)
91
+
92
+ 0
93
+ when "apply"
94
+ options = { safe: false }
95
+ OptionParser.new do |opts|
96
+ opts.on("--safe", "Apply only deterministic safe codemods") do
97
+ options[:safe] = true
98
+ end
99
+ end.parse!(argv)
100
+
101
+ unless options[:safe]
102
+ @stderr.puts("Only --safe mode is supported in v1.x.")
103
+ return 1
104
+ end
105
+
106
+ changed_files = apply_safe_codemods
107
+ findings = audit
108
+ write_report(findings)
109
+ @stdout.puts("Applied safe codemods to #{changed_files} file(s).")
110
+ print_summary(findings)
111
+ 0
112
+ when "report"
113
+ findings = audit
114
+ write_report(findings)
115
+ print_summary(findings)
116
+ 0
117
+ else
118
+ @stderr.puts("Unsupported subcommand: #{subcommand.inspect}")
119
+ usage(1)
120
+ end
121
+ end
122
+
123
+ private
124
+
125
+ def usage(code)
126
+ @stdout.puts("Usage: al-folio upgrade [audit|apply --safe|report] [--no-fail]")
127
+ code
128
+ end
129
+
130
+ def blocking?(findings)
131
+ findings.any? { |finding| finding.severity == :blocking }
132
+ end
133
+
134
+ def audit
135
+ findings = []
136
+ check_manifest_contract(findings)
137
+ check_config_contract(findings)
138
+ check_legacy_assets(findings)
139
+ check_legacy_patterns(findings)
140
+ check_distill_runtime(findings)
141
+ check_core_override_drift(findings)
142
+ findings
143
+ end
144
+
145
+ def check_manifest_contract(findings)
146
+ manifests = manifest_paths
147
+ if manifests.empty?
148
+ findings << Finding.new(
149
+ id: "missing_migration_manifests",
150
+ severity: :warning,
151
+ message: "No migration manifests found. Install/update `al_folio_core` to get release contracts.",
152
+ file: "migrations/",
153
+ line: 1,
154
+ snippet: "Expected at least one `x.y.z_to_a.b.c.yml` manifest."
155
+ )
156
+ end
157
+ end
158
+
159
+ def check_config_contract(findings)
160
+ config_path = @root.join("_config.yml")
161
+ return unless config_path.file?
162
+
163
+ content = config_path.read
164
+ parsed = begin
165
+ parse_yaml(content) || {}
166
+ rescue StandardError => e
167
+ findings << Finding.new(
168
+ id: "invalid_config_yaml",
169
+ severity: :blocking,
170
+ message: "_config.yml could not be parsed: #{e.message}",
171
+ file: "_config.yml",
172
+ line: 1,
173
+ snippet: "Fix YAML syntax before running upgrade codemods."
174
+ )
175
+ return
176
+ end
177
+
178
+ al_folio = parsed.is_a?(Hash) ? parsed["al_folio"] : nil
179
+ unless al_folio.is_a?(Hash)
180
+ findings << Finding.new(
181
+ id: "missing_al_folio_namespace",
182
+ severity: :blocking,
183
+ message: "Missing `al_folio` config namespace required for v1.x.",
184
+ file: "_config.yml",
185
+ line: 1,
186
+ snippet: "Add al_folio.api_version, style_engine, compat, and upgrade keys."
187
+ )
188
+ return
189
+ end
190
+
191
+ unless al_folio["style_engine"] == "tailwind"
192
+ findings << Finding.new(
193
+ id: "style_engine_not_tailwind",
194
+ severity: :blocking,
195
+ message: "`al_folio.style_engine` should be set to `tailwind` for v1.x.",
196
+ file: "_config.yml",
197
+ line: 1,
198
+ snippet: "Set al_folio.style_engine: tailwind"
199
+ )
200
+ end
201
+
202
+ unless al_folio["tailwind"].is_a?(Hash)
203
+ findings << Finding.new(
204
+ id: "missing_tailwind_namespace",
205
+ severity: :warning,
206
+ message: "Missing `al_folio.tailwind` namespace for v1 tailwind runtime contract.",
207
+ file: "_config.yml",
208
+ line: 1,
209
+ snippet: "Add al_folio.tailwind.version/preflight/css_entry."
210
+ )
211
+ end
212
+
213
+ unless al_folio["distill"].is_a?(Hash)
214
+ findings << Finding.new(
215
+ id: "missing_distill_namespace",
216
+ severity: :warning,
217
+ message: "Missing `al_folio.distill` namespace for Distill runtime contract.",
218
+ file: "_config.yml",
219
+ line: 1,
220
+ snippet: "Add al_folio.distill.engine/source/allow_remote_loader."
221
+ )
222
+ end
223
+ end
224
+
225
+ def check_legacy_assets(findings)
226
+ files = ["_includes/head.liquid", "_includes/scripts.liquid"]
227
+ patterns = [
228
+ /bootstrap\.min\.css/,
229
+ /mdbootstrap|mdb\.min\.(?:css|js)/,
230
+ /third_party_libraries\.jquery/,
231
+ /bootstrap\.bundle\.min\.js/,
232
+ ]
233
+
234
+ files.each do |file|
235
+ path = @root.join(file)
236
+ next unless path.file?
237
+
238
+ path.each_line.with_index(1) do |line, number|
239
+ next unless patterns.any? { |pattern| line.match?(pattern) }
240
+
241
+ findings << Finding.new(
242
+ id: "legacy_bootstrap_runtime_asset",
243
+ severity: :blocking,
244
+ message: "Legacy Bootstrap/jQuery/MDB runtime assets are still referenced in core includes.",
245
+ file: file,
246
+ line: number,
247
+ snippet: line.strip
248
+ )
249
+ end
250
+ end
251
+ end
252
+
253
+ def check_legacy_patterns(findings)
254
+ each_candidate_file do |relative, line, number|
255
+ if line.match?(/data-toggle\s*=\s*["'](?:collapse|dropdown|tooltip|popover|table)["']/)
256
+ findings << Finding.new(
257
+ id: "legacy_data_toggle",
258
+ severity: :warning,
259
+ message: "Legacy Bootstrap `data-toggle` marker found.",
260
+ file: relative,
261
+ line: number,
262
+ snippet: line.strip
263
+ )
264
+ end
265
+
266
+ if line.match?(/\$\(|jQuery\b/)
267
+ findings << Finding.new(
268
+ id: "legacy_jquery_usage",
269
+ severity: :warning,
270
+ message: "jQuery usage found; migrate to vanilla JS APIs.",
271
+ file: relative,
272
+ line: number,
273
+ snippet: line.strip
274
+ )
275
+ end
276
+ end
277
+ end
278
+
279
+ def check_distill_runtime(findings)
280
+ config_path = @root.join("_config.yml")
281
+ allow_remote_loader = false
282
+ if config_path.file?
283
+ begin
284
+ parsed = parse_yaml(config_path.read) || {}
285
+ allow_remote_loader = parsed.dig("al_folio", "distill", "allow_remote_loader") == true
286
+ rescue StandardError
287
+ allow_remote_loader = false
288
+ end
289
+ end
290
+
291
+ return if allow_remote_loader
292
+
293
+ distill_runtime_paths.each do |transforms_path|
294
+ report_file = if transforms_path.to_s.start_with?("#{@root}#{File::SEPARATOR}")
295
+ transforms_path.relative_path_from(@root).to_s
296
+ else
297
+ "al_folio_distill:#{transforms_path}"
298
+ end
299
+
300
+ transforms_path.each_line.with_index(1) do |line, number|
301
+ next unless line.match?(%r{https://distill\.pub/template\.v2\.js})
302
+
303
+ findings << Finding.new(
304
+ id: "distill_remote_loader_enabled",
305
+ severity: :blocking,
306
+ message: "Distill runtime still references remote template loader while allow_remote_loader is false.",
307
+ file: report_file,
308
+ line: number,
309
+ snippet: line.strip
310
+ )
311
+ end
312
+ end
313
+ end
314
+
315
+ def distill_runtime_paths
316
+ paths = [@root.join("assets/js/distillpub/transforms.v2.js")]
317
+ specs = []
318
+ specs << Gem.loaded_specs["al_folio_distill"] if Gem.loaded_specs.key?("al_folio_distill")
319
+ begin
320
+ specs << Gem::Specification.find_by_name("al_folio_distill")
321
+ rescue Gem::LoadError
322
+ # Optional gem; ignore when not installed.
323
+ end
324
+
325
+ specs.compact.uniq(&:full_gem_path).each do |spec|
326
+ paths << Pathname.new(File.join(spec.full_gem_path, "assets/js/distillpub/transforms.v2.js"))
327
+ end
328
+ paths.select(&:file?).uniq
329
+ end
330
+
331
+ def check_core_override_drift(findings)
332
+ return unless using_core_theme?
333
+
334
+ CORE_OVERRIDE_FILES.each do |relative|
335
+ path = @root.join(relative)
336
+ next unless path.file?
337
+
338
+ findings << Finding.new(
339
+ id: "core_override_drift",
340
+ severity: :warning,
341
+ message: "Local override shadows `al_folio_core` theme file and may need manual review during upgrades.",
342
+ file: relative,
343
+ line: 1,
344
+ snippet: "Local override present."
345
+ )
346
+ end
347
+ end
348
+
349
+ def each_candidate_file
350
+ FILE_GLOBS.each do |glob|
351
+ Dir.glob(@root.join(glob)).sort.each do |path|
352
+ next unless File.file?(path)
353
+ next if ignored_path?(path)
354
+
355
+ rel = Pathname.new(path).relative_path_from(@root).to_s
356
+ File.foreach(path).with_index(1) do |line, number|
357
+ yield rel, line, number
358
+ end
359
+ end
360
+ end
361
+ end
362
+
363
+ def apply_safe_codemods
364
+ changed_files = 0
365
+
366
+ each_text_file do |path|
367
+ original = File.read(path)
368
+ updated = original.dup
369
+
370
+ SAFE_REPLACEMENTS.each do |rule|
371
+ updated = updated.gsub(rule[:from], rule[:to])
372
+ end
373
+
374
+ if Pathname.new(path).relative_path_from(@root).to_s == "_config.yml"
375
+ updated = ensure_al_folio_namespace(updated)
376
+ end
377
+
378
+ next if updated == original
379
+
380
+ File.write(path, updated)
381
+ changed_files += 1
382
+ end
383
+
384
+ changed_files
385
+ end
386
+
387
+ def ensure_al_folio_namespace(content)
388
+ if content.match?(/^al_folio:\s*$/)
389
+ content = ensure_tailwind_namespace(content)
390
+ content = ensure_distill_namespace(content)
391
+ return content
392
+ end
393
+
394
+ block = <<~YAML
395
+
396
+ al_folio:
397
+ api_version: 1
398
+ style_engine: tailwind
399
+ tailwind:
400
+ version: 4.1.18
401
+ preflight: false
402
+ css_entry: assets/tailwind/app.css
403
+ distill:
404
+ engine: distillpub-template
405
+ source: al-org-dev/distill-template#al-folio
406
+ allow_remote_loader: true
407
+ compat:
408
+ bootstrap:
409
+ enabled: false
410
+ support_window: v1.0-v1.2
411
+ deprecates_in: v1.3
412
+ removed_in: v2.0
413
+ upgrade:
414
+ channel: stable
415
+ auto_apply_safe_fixes: false
416
+ YAML
417
+ content + block
418
+ end
419
+
420
+ def ensure_tailwind_namespace(content)
421
+ return content if nested_namespace_present?(content, "tailwind")
422
+
423
+ insertion = [
424
+ " tailwind:",
425
+ " version: 4.1.18",
426
+ " preflight: false",
427
+ " css_entry: assets/tailwind/app.css",
428
+ ].join("\n")
429
+ content.sub(/^al_folio:\s*$/) { |match| "#{match}\n#{insertion}" }
430
+ end
431
+
432
+ def ensure_distill_namespace(content)
433
+ return content if nested_namespace_present?(content, "distill")
434
+
435
+ insertion = [
436
+ " distill:",
437
+ " engine: distillpub-template",
438
+ " source: al-org-dev/distill-template#al-folio",
439
+ " allow_remote_loader: true",
440
+ ].join("\n")
441
+ content.sub(/^al_folio:\s*$/) { |match| "#{match}\n#{insertion}" }
442
+ end
443
+
444
+ def nested_namespace_present?(content, key)
445
+ parsed = parse_yaml(content) || {}
446
+ return false unless parsed.is_a?(Hash)
447
+
448
+ al_folio = parsed["al_folio"]
449
+ al_folio.is_a?(Hash) && al_folio[key].is_a?(Hash)
450
+ rescue StandardError
451
+ false
452
+ end
453
+
454
+ def using_core_theme?
455
+ config_path = @root.join("_config.yml")
456
+ return false unless config_path.file?
457
+
458
+ begin
459
+ parsed = parse_yaml(config_path.read) || {}
460
+ parsed["theme"] == "al_folio_core" || Array(parsed["plugins"]).include?("al_folio_core")
461
+ rescue StandardError
462
+ false
463
+ end
464
+ end
465
+
466
+ def parse_yaml(content)
467
+ YAML.safe_load(content, permitted_classes: [Date, Time], aliases: true)
468
+ end
469
+
470
+ def manifest_paths
471
+ if defined?(AlFolioCore) && AlFolioCore.respond_to?(:migration_manifest_paths)
472
+ return Array(AlFolioCore.migration_manifest_paths).select { |path| File.file?(path) }
473
+ end
474
+
475
+ Dir.glob(@root.join("migrations/*.yml")).sort
476
+ end
477
+
478
+ def each_text_file
479
+ FILE_GLOBS.each do |glob|
480
+ Dir.glob(@root.join(glob)).sort.each do |path|
481
+ next unless File.file?(path)
482
+ next if ignored_path?(path)
483
+
484
+ yield path
485
+ end
486
+ end
487
+ end
488
+
489
+ def ignored_path?(path)
490
+ normalized = path.to_s
491
+ IGNORE_PATH_PATTERNS.any? { |pattern| normalized.match?(pattern) }
492
+ end
493
+
494
+ def write_report(findings)
495
+ by_severity = findings.group_by(&:severity)
496
+ blocking = by_severity.fetch(:blocking, [])
497
+ warning = by_severity.fetch(:warning, [])
498
+
499
+ File.write(@root.join(REPORT_PATH), <<~MD)
500
+ # al-folio upgrade report
501
+
502
+ Generated by `bundle exec al-folio upgrade report`.
503
+
504
+ ## Summary
505
+
506
+ - Blocking findings: #{blocking.count}
507
+ - Non-blocking findings: #{warning.count}
508
+
509
+ ## Blocking
510
+
511
+ #{format_findings(blocking)}
512
+
513
+ ## Non-blocking
514
+
515
+ #{format_findings(warning)}
516
+ MD
517
+ end
518
+
519
+ def format_findings(findings)
520
+ return "- None\n" if findings.empty?
521
+
522
+ findings.map do |finding|
523
+ "- [#{finding.id}] #{finding.message} (`#{finding.file}:#{finding.line}`)\n - Snippet: `#{finding.snippet}`"
524
+ end.join("\n") + "\n"
525
+ end
526
+
527
+ def print_summary(findings)
528
+ blocking = findings.count { |finding| finding.severity == :blocking }
529
+ warning = findings.count { |finding| finding.severity == :warning }
530
+ @stdout.puts("Upgrade audit complete. Blocking: #{blocking}, Non-blocking: #{warning}.")
531
+ @stdout.puts("Report: #{REPORT_PATH}")
532
+ end
533
+ end
534
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AlFolioUpgrade
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "al_folio_upgrade/version"
4
+ require_relative "al_folio_upgrade/cli"
5
+
6
+ module AlFolioUpgrade
7
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: al_folio_upgrade
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - al-folio maintainers
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2026-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jekyll
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.9'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.9'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: liquid
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '4.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '6.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '4.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '6.0'
53
+ - !ruby/object:Gem::Dependency
54
+ name: al_folio_core
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 1.0.0
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 1.0.0
67
+ - !ruby/object:Gem::Dependency
68
+ name: bundler
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '2.0'
74
+ - - "<"
75
+ - !ruby/object:Gem::Version
76
+ version: '3.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '2.0'
84
+ - - "<"
85
+ - !ruby/object:Gem::Version
86
+ version: '3.0'
87
+ - !ruby/object:Gem::Dependency
88
+ name: rake
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: '13.0'
94
+ type: :development
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '13.0'
101
+ description: Provides audit, report, and safe codemod commands for al-folio upgrades.
102
+ email:
103
+ - maintainers@al-folio.dev
104
+ executables:
105
+ - al-folio
106
+ extensions: []
107
+ extra_rdoc_files: []
108
+ files:
109
+ - CHANGELOG.md
110
+ - LICENSE
111
+ - README.md
112
+ - exe/al-folio
113
+ - lib/al_folio_upgrade.rb
114
+ - lib/al_folio_upgrade/cli.rb
115
+ - lib/al_folio_upgrade/version.rb
116
+ homepage: https://github.com/al-org-dev/al-folio-upgrade
117
+ licenses:
118
+ - MIT
119
+ metadata:
120
+ allowed_push_host: https://rubygems.org
121
+ homepage_uri: https://github.com/al-org-dev/al-folio-upgrade
122
+ source_code_uri: https://github.com/al-org-dev/al-folio-upgrade
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '2.7'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubygems_version: 3.4.10
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Upgrade tooling for al-folio v1.x
142
+ test_files: []