rails-diff 0.5.0 → 0.6.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 +4 -4
- data/CHANGELOG.md +10 -1
- data/README.md +16 -1
- data/lib/rails/diff/cli.rb +63 -0
- data/lib/rails/diff/file_tracker.rb +39 -0
- data/lib/rails/diff/logger.rb +21 -0
- data/lib/rails/diff/rails_app_generator.rb +95 -0
- data/lib/rails/diff/rails_repo.rb +88 -0
- data/lib/rails/diff/version.rb +1 -1
- data/lib/rails/diff.rb +25 -221
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebc8de5879d978edc4129cae7ec7bf8b71dc0b49ab8b5ff9bc6df8cb74baabf8
|
4
|
+
data.tar.gz: bf3f60595d842e247cf1219c8c48ad86d020a791f8d47475cce486fa63a85efc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4022acb24a1b2ca674ed1e8c5d20797a641e8d20e571d138c99b98cb5a23212e4df06301a9362fa3bbcd0275d2ae384c93a836080ac3f1e4abbaef116f00871a
|
7
|
+
data.tar.gz: aff70125214849a5416b197d4060faba06a23262fc20f49c250dbb78c0d5df47d2d65f2f05e9f30a45f79d9bfb3dd622fed927b1791df3816e14de057f749266
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
-
## [0.
|
3
|
+
## [0.6.0] - 2025-07-25
|
4
|
+
|
5
|
+
- Add `--only` option to only include specific files or directories in the diff.
|
6
|
+
- Add `rails-diff dotfiles` to compare dotfiles (configuration files) in the repository.
|
7
|
+
- [BUGFIX] --fail-on-diff wasn't aborting with errors on diff.
|
8
|
+
|
9
|
+
## [0.5.0] - 2025-03-10
|
4
10
|
|
5
11
|
- Don't abort process on bundle check failure.
|
6
12
|
- Add optional debug logs.
|
@@ -64,6 +70,9 @@ M## [0.1.1] - 2025-02-21
|
|
64
70
|
|
65
71
|
- Initial release
|
66
72
|
|
73
|
+
[0.6.0]: https://github.com/matheusrich/rails-diff/releases/tag/v0.6.0
|
74
|
+
[0.5.0]: https://github.com/matheusrich/rails-diff/releases/tag/v0.5.0
|
75
|
+
[0.4.1]: https://github.com/matheusrich/rails-diff/releases/tag/v0.4.1
|
67
76
|
[0.4.1]: https://github.com/matheusrich/rails-diff/releases/tag/v0.4.1
|
68
77
|
[0.4.0]: https://github.com/matheusrich/rails-diff/releases/tag/v0.4.0
|
69
78
|
[0.3.0]: https://github.com/matheusrich/rails-diff/releases/tag/v0.3.0
|
data/README.md
CHANGED
@@ -67,7 +67,14 @@ rails-diff generated scaffold Post --fail-on-diff
|
|
67
67
|
rails-diff generated authentication --commit 7df1b8
|
68
68
|
```
|
69
69
|
|
70
|
-
###
|
70
|
+
### Compare dotfiles (configuration files)
|
71
|
+
|
72
|
+
```bash
|
73
|
+
# Compare configuration files like .gitignore, .rspec, .rubocop.yml
|
74
|
+
rails-diff dotfiles
|
75
|
+
```
|
76
|
+
|
77
|
+
### Global Options
|
71
78
|
|
72
79
|
#### --fail-on-diff
|
73
80
|
|
@@ -96,6 +103,14 @@ Skip specific files or directories during the diff.
|
|
96
103
|
rails-diff generated scaffold Post --skip app/views app/helpers
|
97
104
|
```
|
98
105
|
|
106
|
+
#### --only <files/directories>
|
107
|
+
|
108
|
+
Only include specific files or directories in the diff.
|
109
|
+
|
110
|
+
```bash
|
111
|
+
rails-diff generated scaffold Post --only app/models app/controllers
|
112
|
+
```
|
113
|
+
|
99
114
|
#### --clear-cache/--no-cache
|
100
115
|
|
101
116
|
Clear the cache directory to force cloning Rails and regenerating the Rails template app.
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module Diff
|
5
|
+
class CLI < Thor
|
6
|
+
class_option :no_cache, type: :boolean, desc: "Clear cache before running", aliases: ["--clear-cache"]
|
7
|
+
class_option :fail_on_diff, type: :boolean, desc: "Fail if there are differences"
|
8
|
+
class_option :commit, type: :string, desc: "Compare against a specific commit"
|
9
|
+
class_option :new_app_options, type: :string, desc: "Options to pass to the rails new command"
|
10
|
+
class_option :debug, type: :boolean, desc: "Print debug information", aliases: ["-d"]
|
11
|
+
|
12
|
+
def self.exit_on_failure? = true
|
13
|
+
|
14
|
+
desc "file FILE [FILE ...]", "Compare one or more files from your repository with Rails' generated version"
|
15
|
+
def file(*files)
|
16
|
+
abort "Please provide at least one file to compare" if files.empty?
|
17
|
+
ENV["DEBUG"] = "true" if options[:debug]
|
18
|
+
|
19
|
+
diff = Rails::Diff.file(
|
20
|
+
*files,
|
21
|
+
no_cache: options[:no_cache],
|
22
|
+
commit: options[:commit],
|
23
|
+
new_app_options: options[:new_app_options]
|
24
|
+
)
|
25
|
+
return if diff.empty?
|
26
|
+
|
27
|
+
options[:fail_on_diff] ? abort(diff) : puts(diff)
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "dotfiles", "Compare dotfiles in your repository with the ones generated by Rails"
|
31
|
+
def dotfiles
|
32
|
+
dotfiles = `git ls-files --cached --others --exclude-standard -- '.*'`.split("\n")
|
33
|
+
|
34
|
+
file(*dotfiles)
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "generated GENERATOR [args]", "Compare files that would be created by a Rails generator"
|
38
|
+
option :skip, type: :array, desc: "Skip specific files or directories", aliases: ["-s"], default: []
|
39
|
+
option :only, type: :array, desc: "Only include specific files or directories", aliases: ["-o"], default: []
|
40
|
+
def generated(generator_name, *args)
|
41
|
+
ENV["DEBUG"] = "true" if options[:debug]
|
42
|
+
diff = Rails::Diff.generated(
|
43
|
+
generator_name,
|
44
|
+
*args,
|
45
|
+
no_cache: options[:no_cache],
|
46
|
+
skip: options[:skip],
|
47
|
+
only: options[:only],
|
48
|
+
commit: options[:commit],
|
49
|
+
new_app_options: options[:new_app_options]
|
50
|
+
)
|
51
|
+
return if diff.empty?
|
52
|
+
|
53
|
+
options[:fail_on_diff] ? abort(diff) : puts(diff)
|
54
|
+
end
|
55
|
+
|
56
|
+
map %w[--version -v] => :__version
|
57
|
+
desc "--version, -v", "print the version"
|
58
|
+
def __version
|
59
|
+
puts VERSION
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module Diff
|
5
|
+
class FileTracker
|
6
|
+
def initialize(base_dir, skip = [], only = [])
|
7
|
+
@base_dir = base_dir
|
8
|
+
@skip = skip
|
9
|
+
@only = only
|
10
|
+
end
|
11
|
+
|
12
|
+
def new_files
|
13
|
+
files_before = list_files(@base_dir)
|
14
|
+
yield
|
15
|
+
files_after = list_files(@base_dir, @skip, @only)
|
16
|
+
files_after - files_before
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def list_files(dir, skip = [], only = [])
|
22
|
+
files = Dir.glob("#{dir}/**/*", File::FNM_DOTMATCH).reject do |it|
|
23
|
+
File.directory?(it) ||
|
24
|
+
it.start_with?("#{dir}/.git") ||
|
25
|
+
it.start_with?("#{dir}/tmp") ||
|
26
|
+
it.start_with?("#{dir}/log") ||
|
27
|
+
it.start_with?("#{dir}/test") ||
|
28
|
+
skip.any? { |s| it.start_with?("#{dir}/#{s}") }
|
29
|
+
end
|
30
|
+
|
31
|
+
if only.any?
|
32
|
+
files.select { |it| only.any? { |o| it.start_with?("#{dir}/#{o}") } }
|
33
|
+
else
|
34
|
+
files
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Rails
|
2
|
+
module Diff
|
3
|
+
module Logger
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def info(message)
|
7
|
+
puts "\e[1;34minfo:\e[0m\t#{message}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def debug(message)
|
11
|
+
return unless ENV["DEBUG"]
|
12
|
+
|
13
|
+
puts "\e[1;33mdebug:\e[0m\t#{message}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def error(label, message)
|
17
|
+
warn "\e[1;31m#{label}\e[0m #{message}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "digest"
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module Diff
|
5
|
+
class RailsAppGenerator
|
6
|
+
RAILSRC_PATH = "#{ENV["HOME"]}/.railsrc"
|
7
|
+
|
8
|
+
def initialize(commit: nil, new_app_options: nil, no_cache: false, logger: Logger, cache_dir: Rails::Diff::CACHE_DIR)
|
9
|
+
@new_app_options = new_app_options.to_s.split
|
10
|
+
@rails_repo = RailsRepo.new(logger:, cache_dir:)
|
11
|
+
@commit = commit
|
12
|
+
@logger = logger
|
13
|
+
@cache_dir = cache_dir
|
14
|
+
clear_cache if no_cache
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear_cache
|
18
|
+
logger.info "Clearing cache"
|
19
|
+
FileUtils.rm_rf(cache_dir, secure: true)
|
20
|
+
FileUtils.mkdir_p(cache_dir)
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_template_app
|
24
|
+
return if cached_app?
|
25
|
+
|
26
|
+
create_new_rails_app
|
27
|
+
end
|
28
|
+
|
29
|
+
def template_app_path
|
30
|
+
@template_app_path ||= File.join(cache_dir, rails_cache_dir_key, rails_new_options_hash, app_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def install_app_dependencies
|
34
|
+
Dir.chdir(template_app_path) do
|
35
|
+
unless Rails::Diff.system!("bundle check", abort: false, logger: logger)
|
36
|
+
logger.info "Installing application dependencies"
|
37
|
+
Rails::Diff.system!("bundle install", logger: logger)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def run_generator(generator_name, *args, skip, only)
|
43
|
+
Dir.chdir(template_app_path) do
|
44
|
+
Rails::Diff.system!("bin/rails", "destroy", generator_name, *args, logger: logger)
|
45
|
+
logger.info "Running generator: rails generate #{generator_name} #{args.join(" ")}"
|
46
|
+
|
47
|
+
FileTracker.new(template_app_path, skip, only)
|
48
|
+
.new_files { Rails::Diff.system!("bin/rails", "generate", generator_name, *args, logger: logger) }
|
49
|
+
.map { |it| it.delete_prefix("#{template_app_path}/") }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_reader :new_app_options, :rails_repo, :logger, :cache_dir
|
56
|
+
|
57
|
+
def commit = @commit ||= rails_repo.latest_commit
|
58
|
+
|
59
|
+
def rails_cache_dir_key = "rails-#{commit.first(10)}"
|
60
|
+
|
61
|
+
def railsrc_options
|
62
|
+
@railsrc_options ||= File.exist?(RAILSRC_PATH) ? File.readlines(RAILSRC_PATH) : []
|
63
|
+
end
|
64
|
+
|
65
|
+
def app_name = @app_name ||= File.basename(Dir.pwd)
|
66
|
+
|
67
|
+
def cached_app?
|
68
|
+
File.exist?(template_app_path) && rails_repo.up_to_date?
|
69
|
+
end
|
70
|
+
|
71
|
+
def create_new_rails_app
|
72
|
+
checkout_rails_commit
|
73
|
+
generate_app
|
74
|
+
end
|
75
|
+
|
76
|
+
def generate_app
|
77
|
+
rails_repo.install_dependencies
|
78
|
+
if railsrc_options.any?
|
79
|
+
logger.info "Using default options from #{RAILSRC_PATH}:\n\t > #{railsrc_options.join(" ")}"
|
80
|
+
end
|
81
|
+
rails_repo.new_app(template_app_path, rails_new_options)
|
82
|
+
end
|
83
|
+
|
84
|
+
def checkout_rails_commit = rails_repo.checkout(commit)
|
85
|
+
|
86
|
+
def rails_new_options
|
87
|
+
@rails_new_options ||= (new_app_options + railsrc_options).compact
|
88
|
+
end
|
89
|
+
|
90
|
+
def rails_new_options_hash
|
91
|
+
Digest::MD5.hexdigest(rails_new_options.join(" "))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Rails
|
2
|
+
module Diff
|
3
|
+
class RailsRepo
|
4
|
+
RAILS_REPO = "https://github.com/rails/rails.git"
|
5
|
+
|
6
|
+
def initialize(logger:, cache_dir: Rails::Diff::CACHE_DIR, rails_repo: RAILS_REPO)
|
7
|
+
@logger = logger
|
8
|
+
@cache_dir = cache_dir
|
9
|
+
@rails_repo = rails_repo
|
10
|
+
end
|
11
|
+
|
12
|
+
def checkout(commit)
|
13
|
+
on_rails_dir do
|
14
|
+
logger.info "Checking out Rails (at commit #{commit[0..6]})"
|
15
|
+
Rails::Diff.system!("git", "checkout", commit, logger: logger)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def latest_commit
|
20
|
+
@latest_commit ||= on_rails_dir do
|
21
|
+
Rails::Diff.system!("git fetch origin main", logger: logger)
|
22
|
+
`git rev-parse origin/main`.strip
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def up_to_date?
|
27
|
+
File.exist?(rails_path) && on_latest_commit?
|
28
|
+
end
|
29
|
+
|
30
|
+
def install_dependencies
|
31
|
+
within "railties" do
|
32
|
+
unless Rails::Diff.system!("bundle check", abort: false, logger: logger)
|
33
|
+
logger.info "Installing Rails dependencies"
|
34
|
+
Rails::Diff.system!("bundle install", logger: logger)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def new_app(name, options)
|
40
|
+
within "railties" do
|
41
|
+
command = rails_new_command(name, options)
|
42
|
+
logger.info "Generating new Rails application\n\t > #{command.join(" ")}"
|
43
|
+
Rails::Diff.system!(*command, logger: logger)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def within(dir, &block) = on_rails_dir { Dir.chdir(dir, &block) }
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_reader :logger, :cache_dir, :rails_repo
|
52
|
+
|
53
|
+
def rails_path
|
54
|
+
File.join(cache_dir, "rails")
|
55
|
+
end
|
56
|
+
|
57
|
+
def on_latest_commit?
|
58
|
+
if current_commit == latest_commit
|
59
|
+
true
|
60
|
+
else
|
61
|
+
remove_repo
|
62
|
+
false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def on_rails_dir(&block)
|
67
|
+
clone_repo unless File.exist?(rails_path)
|
68
|
+
Dir.chdir(rails_path, &block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def current_commit = on_rails_dir { `git rev-parse HEAD`.strip }
|
72
|
+
|
73
|
+
def remove_repo = FileUtils.rm_rf(rails_path, secure: true)
|
74
|
+
|
75
|
+
def clone_repo
|
76
|
+
logger.info "Cloning Rails repository"
|
77
|
+
Rails::Diff.system!("git", "clone", "--depth", "1", rails_repo, rails_path, logger: logger)
|
78
|
+
end
|
79
|
+
|
80
|
+
def rails_new_command(name, options)
|
81
|
+
[
|
82
|
+
"bundle", "exec", "rails", "new", name,
|
83
|
+
"--main", "--skip-bundle", "--force", "--quiet", *options
|
84
|
+
]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/rails/diff/version.rb
CHANGED
data/lib/rails/diff.rb
CHANGED
@@ -1,147 +1,64 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "diff/version"
|
4
3
|
require "rails"
|
5
|
-
require "thor"
|
6
4
|
require "diffy"
|
7
5
|
require "fileutils"
|
8
6
|
require "open3"
|
7
|
+
require_relative "diff/cli"
|
8
|
+
require_relative "diff/file_tracker"
|
9
|
+
require_relative "diff/logger"
|
10
|
+
require_relative "diff/rails_app_generator"
|
11
|
+
require_relative "diff/rails_repo"
|
12
|
+
require_relative "diff/version"
|
9
13
|
|
10
14
|
module Rails
|
11
15
|
module Diff
|
12
|
-
class Error < StandardError; end
|
13
|
-
|
14
|
-
RAILS_REPO = "https://github.com/rails/rails.git"
|
15
16
|
CACHE_DIR = File.expand_path("#{ENV["HOME"]}/.rails-diff/cache")
|
16
|
-
RAILSRC_PATH = "#{ENV["HOME"]}/.railsrc"
|
17
17
|
|
18
18
|
class << self
|
19
19
|
def file(*files, no_cache: false, commit: nil, new_app_options: nil)
|
20
|
-
|
21
|
-
|
20
|
+
app_generator = RailsAppGenerator.new(commit:, new_app_options:, no_cache:)
|
21
|
+
app_generator.create_template_app
|
22
22
|
|
23
|
-
files
|
23
|
+
files
|
24
|
+
.filter_map { |it| diff_with_header(it, app_generator.template_app_path) }
|
25
|
+
.join("\n")
|
24
26
|
end
|
25
27
|
|
26
|
-
def generated(generator_name, *args, no_cache: false, skip: [], commit: nil, new_app_options: nil)
|
27
|
-
|
28
|
-
|
29
|
-
install_app_dependencies
|
28
|
+
def generated(generator_name, *args, no_cache: false, skip: [], only: [], commit: nil, new_app_options: nil)
|
29
|
+
app_generator = RailsAppGenerator.new(commit:, new_app_options:, no_cache:)
|
30
|
+
app_generator.create_template_app
|
31
|
+
app_generator.install_app_dependencies
|
30
32
|
|
31
|
-
|
32
|
-
.map { |it| diff_with_header(it) }
|
33
|
+
app_generator.run_generator(generator_name, *args, skip, only)
|
34
|
+
.map { |it| diff_with_header(it, app_generator.template_app_path) }
|
33
35
|
.join("\n\n")
|
34
36
|
end
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
-
def system!(*cmd, abort: true)
|
38
|
+
def system!(*cmd, logger:, abort: true)
|
39
39
|
_, stderr, status = Open3.capture3(*cmd)
|
40
|
-
|
41
|
-
debug cmd.join(" ")
|
42
|
-
|
40
|
+
logger.debug(cmd.join(" "))
|
43
41
|
if status.success?
|
44
42
|
true
|
45
43
|
elsif abort
|
46
|
-
|
44
|
+
logger.error("Command failed:", cmd.join(" "))
|
47
45
|
abort stderr
|
48
46
|
else
|
49
47
|
false
|
50
48
|
end
|
51
49
|
end
|
52
50
|
|
53
|
-
|
54
|
-
puts "\e[1;34minfo:\e[0m\t#{message}"
|
55
|
-
end
|
56
|
-
|
57
|
-
def debug(message)
|
58
|
-
return unless ENV["DEBUG"]
|
59
|
-
|
60
|
-
puts "\e[1;33mdebug:\e[0m\t#{message}"
|
61
|
-
end
|
62
|
-
|
63
|
-
def clear_cache
|
64
|
-
info "Clearing cache"
|
65
|
-
FileUtils.rm_rf(CACHE_DIR)
|
66
|
-
end
|
67
|
-
|
68
|
-
def ensure_template_app_exists(commit, new_app_options)
|
69
|
-
FileUtils.mkdir_p(CACHE_DIR)
|
70
|
-
@new_app_options = new_app_options
|
71
|
-
@commit = commit || latest_commit
|
72
|
-
return if cached_app?
|
73
|
-
|
74
|
-
create_new_rails_app
|
75
|
-
end
|
76
|
-
|
77
|
-
def template_app_path
|
78
|
-
@template_app_path ||= File.join(CACHE_DIR, "rails-#{commit.first(10)}", rails_new_options_hash, app_name)
|
79
|
-
end
|
80
|
-
|
81
|
-
def rails_path
|
82
|
-
@rails_path ||= begin
|
83
|
-
File.join(CACHE_DIR, "rails").tap do |path|
|
84
|
-
unless File.exist?(path)
|
85
|
-
info "Cloning Rails repository"
|
86
|
-
system!("git", "clone", "--depth", "1", RAILS_REPO, path)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def railsrc_options
|
93
|
-
return @railsrc_options if defined?(@railsrc_options)
|
94
|
-
|
95
|
-
@railsrc_options = File.read(RAILSRC_PATH).lines if File.exist?(RAILSRC_PATH)
|
96
|
-
end
|
97
|
-
|
98
|
-
def app_name = @app_name ||= File.basename(Dir.pwd)
|
99
|
-
|
100
|
-
def list_files(dir, skip = [])
|
101
|
-
Dir.glob("#{dir}/**/*", File::FNM_DOTMATCH).reject do |it|
|
102
|
-
File.directory?(it) ||
|
103
|
-
it.start_with?("#{dir}/.git") ||
|
104
|
-
it.start_with?("#{dir}/tmp") ||
|
105
|
-
it.start_with?("#{dir}/log") ||
|
106
|
-
it.start_with?("#{dir}/test") ||
|
107
|
-
skip.any? { |s| it.start_with?("#{dir}/#{s}") }
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def track_new_files(skip)
|
112
|
-
files_before = list_files(template_app_path)
|
113
|
-
yield
|
114
|
-
files_after = list_files(template_app_path, skip)
|
115
|
-
files_after - files_before
|
116
|
-
end
|
117
|
-
|
118
|
-
def generated_files(generator_name, *args, skip)
|
119
|
-
Dir.chdir(template_app_path) do
|
120
|
-
system!("bin/rails", "destroy", generator_name, *args)
|
121
|
-
info "Running generator: rails generate #{generator_name} #{args.join(' ')}"
|
122
|
-
track_new_files(skip) { system!("bin/rails", "generate", generator_name, *args) }
|
123
|
-
.map { |it| it.delete_prefix("#{template_app_path}/") }
|
124
|
-
end
|
125
|
-
end
|
51
|
+
private
|
126
52
|
|
127
|
-
def diff_with_header(file)
|
128
|
-
diff = diff_file(file)
|
53
|
+
def diff_with_header(file, template_app_path)
|
54
|
+
diff = diff_file(file, template_app_path)
|
129
55
|
return if diff.empty?
|
130
56
|
|
131
57
|
header = "#{file} diff:"
|
132
58
|
[header, "=" * header.size, diff].join("\n")
|
133
59
|
end
|
134
60
|
|
135
|
-
def
|
136
|
-
Dir.chdir(template_app_path) do
|
137
|
-
unless system!("bundle check", abort: false)
|
138
|
-
info "Installing application dependencies"
|
139
|
-
system!("bundle install")
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
def diff_file(file)
|
61
|
+
def diff_file(file, template_app_path)
|
145
62
|
rails_file = File.join(template_app_path, file)
|
146
63
|
repo_file = File.join(Dir.pwd, file)
|
147
64
|
|
@@ -152,122 +69,9 @@ module Rails
|
|
152
69
|
rails_file,
|
153
70
|
repo_file,
|
154
71
|
context: 2,
|
155
|
-
source:
|
72
|
+
source: "files"
|
156
73
|
).to_s(:color).chomp
|
157
74
|
end
|
158
|
-
|
159
|
-
def cached_app?
|
160
|
-
File.exist?(template_app_path) && !out_of_date_rails?
|
161
|
-
end
|
162
|
-
|
163
|
-
def out_of_date_rails?
|
164
|
-
return true unless File.exist?(rails_path)
|
165
|
-
|
166
|
-
Dir.chdir(rails_path) do
|
167
|
-
system!("git fetch origin main")
|
168
|
-
current = `git rev-parse HEAD`.strip
|
169
|
-
latest = `git rev-parse origin/main`.strip
|
170
|
-
|
171
|
-
if current != latest
|
172
|
-
FileUtils.rm_rf(rails_path)
|
173
|
-
return true
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
false
|
178
|
-
end
|
179
|
-
|
180
|
-
def create_new_rails_app
|
181
|
-
Dir.chdir(rails_path) do
|
182
|
-
checkout_rails
|
183
|
-
generate_app
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def generate_app
|
188
|
-
Dir.chdir("railties") do
|
189
|
-
unless system!("bundle check", abort: false)
|
190
|
-
info "Installing Rails dependencies"
|
191
|
-
system!("bundle install")
|
192
|
-
end
|
193
|
-
|
194
|
-
if railsrc_options
|
195
|
-
info "Using default options from #{RAILSRC_PATH}:\n\t > #{railsrc_options.join(' ')}"
|
196
|
-
end
|
197
|
-
|
198
|
-
info "Generating new Rails application\n\t > #{rails_new_command.join(' ')}"
|
199
|
-
system!(*rails_new_command)
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def checkout_rails
|
204
|
-
info "Checking out Rails (at commit #{commit[0..6]})"
|
205
|
-
system!("git", "checkout", commit)
|
206
|
-
end
|
207
|
-
|
208
|
-
def commit = @commit
|
209
|
-
|
210
|
-
def new_app_options = @new_app_options
|
211
|
-
|
212
|
-
def latest_commit
|
213
|
-
Dir.chdir(rails_path) do
|
214
|
-
`git rev-parse origin/main`.strip
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
def rails_new_command = @rails_new_command ||= [
|
219
|
-
"bundle",
|
220
|
-
"exec",
|
221
|
-
"rails",
|
222
|
-
"new",
|
223
|
-
template_app_path,
|
224
|
-
"--main",
|
225
|
-
"--skip-bundle",
|
226
|
-
"--force",
|
227
|
-
"--quiet",
|
228
|
-
*rails_new_options
|
229
|
-
]
|
230
|
-
|
231
|
-
def rails_new_options = @rails_new_options ||= [*new_app_options, *railsrc_options].compact
|
232
|
-
|
233
|
-
def rails_new_options_hash = Digest::MD5.hexdigest(rails_new_options.join(" "))
|
234
|
-
end
|
235
|
-
|
236
|
-
class CLI < Thor
|
237
|
-
class_option :no_cache, type: :boolean, desc: "Clear cache before running", aliases: ["--clear-cache"]
|
238
|
-
class_option :fail_on_diff, type: :boolean, desc: "Fail if there are differences"
|
239
|
-
class_option :commit, type: :string, desc: "Compare against a specific commit"
|
240
|
-
class_option :new_app_options, type: :string, desc: "Options to pass to the rails new command"
|
241
|
-
class_option :debug, type: :boolean, desc: "Print debug information", aliases: ["-d"]
|
242
|
-
|
243
|
-
def self.exit_on_failure? = true
|
244
|
-
|
245
|
-
desc "file FILE [FILE ...]", "Compare one or more files from your repository with Rails' generated version"
|
246
|
-
def file(*files)
|
247
|
-
abort "Please provide at least one file to compare" if files.empty?
|
248
|
-
ENV["DEBUG"] = "true" if options[:debug]
|
249
|
-
|
250
|
-
diff = Rails::Diff.file(*files, no_cache: options[:no_cache], commit: options[:commit], new_app_options: options[:new_app_options])
|
251
|
-
return if diff.empty?
|
252
|
-
|
253
|
-
options[:fail] ? abort(diff) : puts(diff)
|
254
|
-
end
|
255
|
-
|
256
|
-
desc "generated GENERATOR [args]", "Compare files that would be created by a Rails generator"
|
257
|
-
option :skip, type: :array, desc: "Skip specific files or directories", aliases: ["-s"], default: []
|
258
|
-
def generated(generator_name, *args)
|
259
|
-
ENV["DEBUG"] = "true" if options[:debug]
|
260
|
-
diff = Rails::Diff.generated(generator_name, *args, no_cache: options[:no_cache], skip: options[:skip], commit: options[:commit], new_app_options: options[:new_app_options])
|
261
|
-
return if diff.empty?
|
262
|
-
|
263
|
-
options[:fail] ? abort(diff) : puts(diff)
|
264
|
-
end
|
265
|
-
|
266
|
-
map %w[--version -v] => :__version
|
267
|
-
desc "--version, -v", "print the version"
|
268
|
-
def __version
|
269
|
-
puts VERSION
|
270
|
-
end
|
271
75
|
end
|
272
76
|
end
|
273
77
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-diff
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matheus Richard
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-07-25 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rails
|
@@ -69,6 +69,11 @@ files:
|
|
69
69
|
- Rakefile
|
70
70
|
- exe/rails-diff
|
71
71
|
- lib/rails/diff.rb
|
72
|
+
- lib/rails/diff/cli.rb
|
73
|
+
- lib/rails/diff/file_tracker.rb
|
74
|
+
- lib/rails/diff/logger.rb
|
75
|
+
- lib/rails/diff/rails_app_generator.rb
|
76
|
+
- lib/rails/diff/rails_repo.rb
|
72
77
|
- lib/rails/diff/version.rb
|
73
78
|
homepage: https://github.com/matheusrich/rails-diff
|
74
79
|
licenses:
|