github_diff_parser 0.1.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26631fa3bed73629263398b5a5956aeb3f680ecdc3d990a86ff3c68cbb4e93fc
4
- data.tar.gz: 1268de53cf2e150fb1667955c0b4b5b24e045c9b413c81441310f98f4c564046
3
+ metadata.gz: 1d048ece303a1deffcfd8c90f1f9ff01ae8ecd3e4cd933227b4e6fe37b895e82
4
+ data.tar.gz: 81f8202228089acd92296c2504ec8689598a59ff01fdac8df3c089e9d1bb7658
5
5
  SHA512:
6
- metadata.gz: b12c80f92786394271ec785c6b22db9111d20c17c3ee859b23cae2f54a9ef757b01d1cac2666df3b512eeae88524e37646efe98ba51ddcf94c3188d87bc7d42c
7
- data.tar.gz: 53d34cc940811a050a26f214ab18db26acd638adaf26c717a740977cf01394682f0c3b165843449c09587b75dc54cf8e1dcc1d9419b1bda3794b751ddedd6fc2
6
+ metadata.gz: b9edb9abb99bf74763577a06801429e2accb3af1b806a434d83f1ea518a694411fd528c080e5fefeed9ab603ac405861d631e416cbc5236f77b6f6e4ac52fb36
7
+ data.tar.gz: ca25e44f9e0cc56fdc3044ea85b09e4f59e9a2cca5f172f44b50d5570dda436228b1b1c8b905b890a7bdcc7d1097e1c1876d75927291bfe34d3f4619cd7b35b7
data/.rubocop.yml CHANGED
@@ -4,6 +4,8 @@ inherit_gem:
4
4
  AllCops:
5
5
  NewCops: disable
6
6
  SuggestExtensions: false
7
+ Exclude:
8
+ - "test/data/**/*"
7
9
 
8
10
  Style/Documentation:
9
11
  Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## Unreleased
8
+
9
+ ## [1.1.0] - 2024-2-21
10
+ ### Added
11
+ - Github Diff Parser parses the permissions bits and you now have have access to various method
12
+ such as:
13
+ - `GithubDiffParser::Diff#normal_file?` when the bits are 100644
14
+ - `GithubDiffParser::Diff#executable?` when the bits are 107555
15
+ - `GithubDiffParser::Diff#symlink?` when the bits are 120000
16
+ - Introduce `GithubDiffParser::Diff#symlink_source`. When the diff applies to a symbolic link, `symlink_source` will
17
+ return the path to where the symbolic link points to.
18
+ - Introduce `GithubDiffParser::Diff#apply`, a simple implementation of `git apply`.
19
+ - Introduce `GithubDiffParser::Diff#revert`, a simple implementation of `git apply -R`.
20
+
21
+ ### Fixed
22
+ - `GithubDiffParser::Line#content` didn't include `\n` (if the line had one).
data/Gemfile.lock CHANGED
@@ -1,39 +1,46 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- github_diff_parser (0.1.0)
4
+ github_diff_parser (1.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  ast (2.4.2)
10
10
  byebug (11.1.3)
11
- minitest (5.15.0)
12
- parallel (1.22.1)
13
- parser (3.1.2.0)
11
+ json (2.6.3)
12
+ language_server-protocol (3.17.0.3)
13
+ minitest (5.18.1)
14
+ parallel (1.23.0)
15
+ parser (3.2.2.3)
14
16
  ast (~> 2.4.1)
17
+ racc
18
+ racc (1.7.1)
15
19
  rainbow (3.1.1)
16
20
  rake (13.0.6)
17
- regexp_parser (2.3.0)
21
+ regexp_parser (2.8.1)
18
22
  rexml (3.2.5)
19
- rubocop (1.27.0)
23
+ rubocop (1.53.1)
24
+ json (~> 2.3)
25
+ language_server-protocol (>= 3.17.0)
20
26
  parallel (~> 1.10)
21
- parser (>= 3.1.0.0)
27
+ parser (>= 3.2.2.3)
22
28
  rainbow (>= 2.2.2, < 4.0)
23
29
  regexp_parser (>= 1.8, < 3.0)
24
- rexml
25
- rubocop-ast (>= 1.16.0, < 2.0)
30
+ rexml (>= 3.2.5, < 4.0)
31
+ rubocop-ast (>= 1.28.0, < 2.0)
26
32
  ruby-progressbar (~> 1.7)
27
- unicode-display_width (>= 1.4.0, < 3.0)
28
- rubocop-ast (1.17.0)
29
- parser (>= 3.1.1.0)
30
- rubocop-shopify (2.5.0)
31
- rubocop (~> 1.25)
32
- ruby-progressbar (1.11.0)
33
- unicode-display_width (2.1.0)
33
+ unicode-display_width (>= 2.4.0, < 3.0)
34
+ rubocop-ast (1.29.0)
35
+ parser (>= 3.2.1.0)
36
+ rubocop-shopify (2.14.0)
37
+ rubocop (~> 1.51)
38
+ ruby-progressbar (1.13.0)
39
+ unicode-display_width (2.4.2)
34
40
 
35
41
  PLATFORMS
36
42
  x86_64-darwin-20
43
+ x86_64-darwin-22
37
44
  x86_64-linux
38
45
 
39
46
  DEPENDENCIES
@@ -44,4 +51,4 @@ DEPENDENCIES
44
51
  rubocop-shopify
45
52
 
46
53
  BUNDLED WITH
47
- 2.2.32
54
+ 2.4.14
@@ -2,6 +2,8 @@
2
2
 
3
3
  module GithubDiffParser
4
4
  class Diff
5
+ Mode = Struct.new(:operation, :bits)
6
+
5
7
  # @return [String] (see #initialize)
6
8
  attr_reader :previous_filename
7
9
 
@@ -11,8 +13,19 @@ module GithubDiffParser
11
13
  # @return [Array<GithubDiffParser::Hunk>] the hunks belonging to this diff
12
14
  attr_reader :hunks
13
15
 
16
+ # @return [String] the hash of the previous file. This is indicate in the diff
17
+ # by the line `index abc..def`. The +abc+ part is the previous_index.
18
+ attr_reader :previous_index
19
+
20
+ # @return [String] the hash of the new file. This is indicate in the diff
21
+ # by the line `index abc..def`. The +def+ part is the previous_index.
22
+ attr_reader :new_index
23
+
14
24
  # @private
15
- attr_writer :file_mode
25
+ attr_writer :previous_index, :new_index
26
+
27
+ # @private
28
+ attr_accessor :mode
16
29
 
17
30
  # @param previous_filename [String] the original filename. Represented by "diff --git /a filename"
18
31
  # @param new_filename [String] the new filename. Represented by "diff --git /b filename"
@@ -22,6 +35,11 @@ module GithubDiffParser
22
35
  @hunks = []
23
36
  end
24
37
 
38
+ # Get all the lines in this diff. Shortcut for `diff.hunks.each { |h| h.lines }`
39
+ def lines
40
+ hunks.flat_map(&:lines)
41
+ end
42
+
25
43
  # Add a Git Hunk to the diff.
26
44
  #
27
45
  # @param previous_lino_start [String] the starting line number of the hunk for the original file
@@ -60,7 +78,7 @@ module GithubDiffParser
60
78
  #
61
79
  # @return [Boolean]
62
80
  def deleted_mode?
63
- @file_mode == "deleted"
81
+ @mode.operation == "deleted"
64
82
  end
65
83
 
66
84
  # Check if this Diff is set to new mode.
@@ -76,7 +94,7 @@ module GithubDiffParser
76
94
  #
77
95
  # @return [Boolean]
78
96
  def new_mode?
79
- @file_mode == "new"
97
+ @mode.operation == "new"
80
98
  end
81
99
 
82
100
  # Check if this Diff is set to rename mode.
@@ -92,6 +110,29 @@ module GithubDiffParser
92
110
  previous_filename != new_filename
93
111
  end
94
112
 
113
+ # @return [Boolean] True if this diff applies to a regular file.
114
+ def normal_file?
115
+ @mode.bits == "100644"
116
+ end
117
+
118
+ # @return [Boolean] True if this diff applies to an executable.
119
+ def executable?
120
+ @mode.bits == "100755"
121
+ end
122
+
123
+ # @return [Boolean] True if this diff applies to a symlink.
124
+ def symlink?
125
+ @mode.bits == "120000"
126
+ end
127
+
128
+ # @return [String] The source of the symlink
129
+ # @raise If this diff doesn't apply to a symlink
130
+ def symlink_source
131
+ raise(Error, "This diff doen't apply to a symbolic link") unless symlink?
132
+
133
+ lines.first.content
134
+ end
135
+
95
136
  # A utility method that returns the current number of a line who might not be present in the diff.
96
137
  # This is useful if you need to keep track of the updated line numbers in a file for every changes.
97
138
  #
@@ -111,6 +152,48 @@ module GithubDiffParser
111
152
  end
112
153
  end
113
154
 
155
+ # A naive implementation of `$ git apply`.
156
+ #
157
+ # @param previous_content [String] The previous content related to this diff.
158
+ # @return [String] The content after applying this diff to the `previous_content`.
159
+ def apply(previous_content)
160
+ lines = previous_content.lines
161
+ offset = 0
162
+
163
+ self.lines.each do |line|
164
+ if line.addition?
165
+ lines.insert(line.current_number - 1, line.content)
166
+ offset += 1
167
+ elsif line.deletion?
168
+ lines.delete_at(line.previous_number - 1 + offset)
169
+ offset -= 1
170
+ end
171
+ end
172
+
173
+ lines.join
174
+ end
175
+
176
+ # A naive implementation of `$ git apply -R`.
177
+ #
178
+ # @param current_content [String] The current content related to this diff.
179
+ # @return [String] The content after reverting this diff to the `current_content`.
180
+ def revert(current_content)
181
+ lines = current_content.lines
182
+ offset = 0
183
+
184
+ self.lines.each do |line|
185
+ if line.addition?
186
+ lines.delete_at(line.current_number - 1 + offset)
187
+ offset -= 1
188
+ elsif line.deletion?
189
+ lines.insert(line.previous_number - 1, line.content)
190
+ offset += 1
191
+ end
192
+ end
193
+
194
+ lines.join
195
+ end
196
+
114
197
  private
115
198
 
116
199
  # Check if a line was shifted. A line is considered shifted if its number is superior to the first hunk's start
@@ -18,6 +18,8 @@ module GithubDiffParser
18
18
  case line
19
19
  when Regexes::DIFF_HEADER
20
20
  process_new_diff(Regexp.last_match)
21
+ when Regexes::INDEX_HEADER
22
+ process_index(Regexp.last_match)
21
23
  when Regexes::MODE_HEADER
22
24
  process_diff_file_mode(Regexp.last_match)
23
25
  when Regexes::ORIGINAL_FILE_HEADER, Regexes::NEW_FILE_HEADER
@@ -26,6 +28,8 @@ module GithubDiffParser
26
28
  add_hunk_to_diff(Regexp.last_match)
27
29
  when Regexes::LINE_DIFF
28
30
  add_line_to_hunk(Regexp.last_match)
31
+ when Regexes::NO_NEWLINE_AT_EOF
32
+ @current_diff.lines.last.content.sub!(/\n$/, "")
29
33
  end
30
34
  end
31
35
 
@@ -47,6 +51,17 @@ module GithubDiffParser
47
51
  @current_diff = Diff.new(match_data[:previous_filename], match_data[:new_filename])
48
52
  end
49
53
 
54
+ # Called when encountering a `index abc..def` in the Git Diff output.
55
+ #
56
+ # @param match_data [MatchData]
57
+ def process_index(match_data)
58
+ validate_diff
59
+
60
+ @current_diff.previous_index = match_data[:previous_index]
61
+ @current_diff.new_index = match_data[:new_index]
62
+ @current_diff.mode ||= Diff::Mode.new("modified", match_data[:bits])
63
+ end
64
+
50
65
  # Called when encountering a `new file mode 100644` or `delete file mode 100644` in the Git Diff output.
51
66
  #
52
67
  # @param match_data [MatchData]
@@ -55,7 +70,7 @@ module GithubDiffParser
55
70
  def process_diff_file_mode(match_data)
56
71
  validate_diff
57
72
 
58
- @current_diff.file_mode = match_data[:file_mode]
73
+ @current_diff.mode = Diff::Mode.new(match_data[:file_mode], match_data[:bits])
59
74
  end
60
75
 
61
76
  # Called when encountering a `@@ -0,0 +1,10 @@` in the Git Diff output.
@@ -19,6 +19,24 @@ module GithubDiffParser
19
19
  \Z # End of line
20
20
  }x
21
21
 
22
+ # This Regexp is used to match the sha of the previous and the file
23
+ #
24
+ # @example
25
+ #
26
+ # diff --git a/app/my_file.rb b/app/my_file.rb
27
+ # index d3dfbe4..ac0e8b3 100644 <-- Match this line -->
28
+ # --- a/app/my_file.rb
29
+ # +++ b/app/my_file.rb
30
+ # @@ -5,6 +5,6 @@ def test1
31
+ INDEX_HEADER = %r{
32
+ \A # Start of line
33
+ index\s # Match 'index '
34
+ (?<previous_index>[a-z0-9]+) # Match and capture alphanumerical chars
35
+ .. # Match '..' literally
36
+ (?<new_index>[a-z0-9]+)\s # Match and capture alphanumerical chars
37
+ (?<bits>\d+)? # Optionaly capture the mode bits
38
+ }x
39
+
22
40
  # This Regexp is used to match the header containing the original filename.
23
41
  #
24
42
  # @example Possible header on a diff.
@@ -71,7 +89,7 @@ module GithubDiffParser
71
89
  MODE_HEADER = %r{
72
90
  \A # Start of line
73
91
  (?<file_mode>new|deleted) # Match 'new' or 'deleted' and capture the group
74
- \sfile\smode\s\d+ # Match ' file mode 100655'
92
+ \sfile\smode\s(?<bits>\d+) # Match ' file mode 100655' and capture the "100655" part
75
93
  \Z # End of line
76
94
  }x
77
95
 
@@ -153,8 +171,10 @@ module GithubDiffParser
153
171
  | # OR
154
172
  \s # Match empty space ' ' (Considered as a contextual line)
155
173
  ) # End of named group
156
- (?<line>.*) # Match the content of the line itself
174
+ (?<line>.*\n?) # Match the content of the line itself
157
175
  \Z # End of line
158
176
  }x
177
+
178
+ NO_NEWLINE_AT_EOF = /\/
159
179
  end
160
180
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GithubDiffParser
4
- VERSION = "0.1.0"
4
+ VERSION = "1.1.0"
5
5
  end
@@ -3,6 +3,7 @@
3
3
  require_relative "github_diff_parser/version"
4
4
 
5
5
  module GithubDiffParser
6
+ Error = Class.new(StandardError)
6
7
  InvalidDiff = Class.new(ArgumentError)
7
8
 
8
9
  autoload :Parser, "github_diff_parser/parser"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: github_diff_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Edouard CHIN
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-22 00:00:00.000000000 Z
11
+ date: 2024-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -46,6 +46,7 @@ extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
48
  - ".rubocop.yml"
49
+ - CHANGELOG.md
49
50
  - CODE_OF_CONDUCT.md
50
51
  - Gemfile
51
52
  - Gemfile.lock
@@ -61,13 +62,13 @@ files:
61
62
  - lib/github_diff_parser/parser.rb
62
63
  - lib/github_diff_parser/regexes.rb
63
64
  - lib/github_diff_parser/version.rb
64
- homepage: https://github.com/Edouard-chin/git_diff_parser
65
+ homepage: https://github.com/CatanaCorp/github_diff_parser
65
66
  licenses:
66
67
  - MIT
67
68
  metadata:
68
69
  allowed_push_host: https://rubygems.org
69
- homepage_uri: https://github.com/Edouard-chin/git_diff_parser
70
- source_code_uri: https://github.com/Edouard-chin/git_diff_parser
70
+ homepage_uri: https://github.com/CatanaCorp/github_diff_parser
71
+ source_code_uri: https://github.com/CatanaCorp/github_diff_parser
71
72
  rubygems_mfa_required: 'true'
72
73
  post_install_message:
73
74
  rdoc_options: []
@@ -77,14 +78,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
77
78
  requirements:
78
79
  - - ">="
79
80
  - !ruby/object:Gem::Version
80
- version: 2.6.0
81
+ version: 3.0.0
81
82
  required_rubygems_version: !ruby/object:Gem::Requirement
82
83
  requirements:
83
84
  - - ">="
84
85
  - !ruby/object:Gem::Version
85
86
  version: '0'
86
87
  requirements: []
87
- rubygems_version: 3.2.32
88
+ rubygems_version: 3.5.4
88
89
  signing_key:
89
90
  specification_version: 4
90
91
  summary: A Ruby Gem to parse unified git diff output.