Skip to content

Commit

Permalink
Merge pull request #10 from CatanaCorp/ec-mode-bits
Browse files Browse the repository at this point in the history
Add a way to check if the diff applies to a symlink or an executable
  • Loading branch information
Edouard-chin authored Feb 20, 2024
2 parents 71a47b0 + 1c7446b commit 4facbf2
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 6 deletions.
1 change: 1 addition & 0 deletions lib/github_diff_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require_relative "github_diff_parser/version"

module GithubDiffParser
Error = Class.new(StandardError)
InvalidDiff = Class.new(ArgumentError)

autoload :Parser, "github_diff_parser/parser"
Expand Down
34 changes: 31 additions & 3 deletions lib/github_diff_parser/diff.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module GithubDiffParser
class Diff
Mode = Struct.new(:operation, :bits)

# @return [String] (see #initialize)
attr_reader :previous_filename

Expand All @@ -20,7 +22,10 @@ class Diff
attr_reader :new_index

# @private
attr_writer :file_mode, :previous_index, :new_index
attr_writer :previous_index, :new_index

# @private
attr_accessor :mode

# @param previous_filename [String] the original filename. Represented by "diff --git /a filename"
# @param new_filename [String] the new filename. Represented by "diff --git /b filename"
Expand Down Expand Up @@ -73,7 +78,7 @@ def add_line(line_content, type:)
#
# @return [Boolean]
def deleted_mode?
@file_mode == "deleted"
@mode.operation == "deleted"
end

# Check if this Diff is set to new mode.
Expand All @@ -89,7 +94,7 @@ def deleted_mode?
#
# @return [Boolean]
def new_mode?
@file_mode == "new"
@mode.operation == "new"
end

# Check if this Diff is set to rename mode.
Expand All @@ -105,6 +110,29 @@ def rename_mode?
previous_filename != new_filename
end

# @return [Boolean] True if this diff applies to a regular file.
def normal_file?
@mode.bits == "100644"
end

# @return [Boolean] True if this diff applies to an executable.
def executable?
@mode.bits == "100755"
end

# @return [Boolean] True if this diff applies to a symlink.
def symlink?
@mode.bits == "120000"
end

# @return [String] The source of the symlink
# @raise If this diff doesn't apply to a symlink
def symlink_source
raise(Error, "This diff doen't apply to a symbolic link") unless symlink?

lines.first.content
end

# A utility method that returns the current number of a line who might not be present in the diff.
# This is useful if you need to keep track of the updated line numbers in a file for every changes.
#
Expand Down
3 changes: 2 additions & 1 deletion lib/github_diff_parser/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def process_index(match_data)

@current_diff.previous_index = match_data[:previous_index]
@current_diff.new_index = match_data[:new_index]
@current_diff.mode ||= Diff::Mode.new("modified", match_data[:bits])
end

# Called when encountering a `new file mode 100644` or `delete file mode 100644` in the Git Diff output.
Expand All @@ -67,7 +68,7 @@ def process_index(match_data)
def process_diff_file_mode(match_data)
validate_diff

@current_diff.file_mode = match_data[:file_mode]
@current_diff.mode = Diff::Mode.new(match_data[:file_mode], match_data[:bits])
end

# Called when encountering a `@@ -0,0 +1,10 @@` in the Git Diff output.
Expand Down
5 changes: 3 additions & 2 deletions lib/github_diff_parser/regexes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ module Regexes
index\s # Match 'index '
(?<previous_index>[a-z0-9]+) # Match and capture alphanumerical chars
.. # Match '..' literally
(?<new_index>[a-z0-9]+) # Match and captuer alphanumerical chars
(?<new_index>[a-z0-9]+)\s # Match and capture alphanumerical chars
(?<bits>\d+)? # Optionaly capture the mode bits
}x

# This Regexp is used to match the header containing the original filename.
Expand Down Expand Up @@ -88,7 +89,7 @@ module Regexes
MODE_HEADER = %r{
\A # Start of line
(?<file_mode>new|deleted) # Match 'new' or 'deleted' and capture the group
\sfile\smode\s\d+ # Match ' file mode 100655'
\sfile\smode\s(?<bits>\d+) # Match ' file mode 100655' and capture the "100655" part
\Z # End of line
}x

Expand Down
11 changes: 11 additions & 0 deletions test/data/file_modes.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
diff --git a/my_executable.rb b/my_executable.rb
new file mode 100755
index 0000000..e69de29
diff --git a/some_other_file b/some_other_file
new file mode 120000
index 0000000..c2e492f
--- /dev/null
+++ b/some_other_file
@@ -0,0 +1 @@
+some_file.rb
\ No newline at end of file
18 changes: 18 additions & 0 deletions test/github_diff_parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def test_line_added
expected_lines.each_with_index do |expected_line, index|
assert_line(expected_line, hunk.lines[index])
end
assert_predicate(parsed_diff, :normal_file?)
end

def test_line_removed
Expand Down Expand Up @@ -57,6 +58,7 @@ def test_line_removed
expected_lines.each_with_index do |expected_line, index|
assert_line(expected_line, hunk.lines[index])
end
assert_predicate(parsed_diff, :normal_file?)
end

def test_line_changed
Expand Down Expand Up @@ -87,6 +89,7 @@ def test_line_changed
expected_lines.each_with_index do |expected_line, index|
assert_line(expected_line, hunk.lines[index])
end
assert_predicate(parsed_diff, :normal_file?)
end

def test_file_added
Expand Down Expand Up @@ -119,6 +122,7 @@ def test_file_added
expected_lines.each_with_index do |expected_line, index|
assert_line(expected_line, hunk.lines[index])
end
assert_predicate(parsed_diff, :normal_file?)
end

def test_file_removed
Expand Down Expand Up @@ -152,6 +156,7 @@ def test_file_removed
expected_lines.each_with_index do |expected_line, index|
assert_line(expected_line, hunk.lines[index])
end
assert_predicate(parsed_diff, :normal_file?)
end

def test_file_moved
Expand Down Expand Up @@ -192,6 +197,7 @@ def test_rails_diff
expected_lines.each_with_index do |expected_line, index|
assert_line(expected_line, hunk.lines[index])
end
assert_predicate(parsed_diff, :normal_file?)

hunk = parsed_diff.hunks[1]
assert_equal(18, hunk.lines.count)
Expand Down Expand Up @@ -223,6 +229,7 @@ def test_rails_diff
expected_lines.each_with_index do |expected_line, index|
assert_line(expected_line, hunk.lines[index])
end
assert_predicate(parsed_diff, :normal_file?)
end

def test_when_range_header_has_no_comma
Expand Down Expand Up @@ -255,6 +262,17 @@ def test_when_range_header_has_no_comma
end
end

def test_mode_bits
parsed_diffs = GithubDiffParser.parse(read_diff("file_modes"))

assert_equal(2, parsed_diffs.count)
assert_predicate(parsed_diffs.first, :executable?)
assert_raises(GithubDiffParser::Error) { parsed_diffs.first.symlink_source }

assert_predicate(parsed_diffs[1], :symlink?)
assert_equal("some_file.rb", parsed_diffs[1].symlink_source)
end

def test_raise_when_diff_is_not_a_diff
assert_raises(GithubDiffParser::InvalidDiff) do
GithubDiffParser.parse(read_diff("invalid"))
Expand Down

0 comments on commit 4facbf2

Please sign in to comment.