github_diff_parser 1.0.0 → 1.1.1

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: e34f38b28e0e403ba84d95e805bd2a0f97da47d1567893f527f99835b1ce4b87
4
- data.tar.gz: 6eba918c1307b5dd51e48e942041cfa96a0a18f1c438bfde385b88b55b6fc4b7
3
+ metadata.gz: 6bbbd5c441839124ce3eeb13013dfc941bc6bfda629c3245b0a1bd635acfc0b6
4
+ data.tar.gz: 8e4432858065cdf8aeee7516d7cf220381ed312b801434f31ab80cb0cefe2e6c
5
5
  SHA512:
6
- metadata.gz: 34e0ac9ef75f79799cd3eec754e520fe828ba9408c706d6de8bf6c42a728ce79998e1c2305aec4a89f08bf760cee1e8964695e45325643d92c2f6460b42ac684
7
- data.tar.gz: 8ec23e1cde869fe9ad809717d0b7e19290fed6edcb7fc47c4d00fc05eb20bfc2139f0f7e3dec6937810927f2e2e0bf506947b9270cf4251ea4dee8976b06fc61
6
+ metadata.gz: 419ac34a1e4ceb31c909fa1e5d17f886fb53cbc3d3024272de7eb9676e6f5c834315eec0c6066415282fc4da847a770364fe78d1f097000301618ef5f11f436a
7
+ data.tar.gz: a9272715bc0593ca15662852a7a83b1d2aad2619414ce975905ed424330719f9ef5a103c777b4d7b6c8f3615b43fc05b6e29f017b3e59679a7d605927bb45b08
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,34 @@
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.1] - 2024-2-21
10
+ ### Fixed
11
+ - `GithubDiffParser::Diff#new_mode?` and ``GithubDiffParser::Diff#deleted_mode?` would raise
12
+ an error with this kind of diff:
13
+
14
+ ```diff
15
+ diff --git a/blabla.rb b/app/my_file.rb
16
+ similarity index 100%
17
+ rename from blabla.rb
18
+ rename to app/my_file.rb
19
+ ```
20
+
21
+ ## [1.1.0] - 2024-2-21
22
+ ### Added
23
+ - Github Diff Parser parses the permissions bits and you now have have access to various method
24
+ such as:
25
+ - `GithubDiffParser::Diff#normal_file?` when the bits are 100644
26
+ - `GithubDiffParser::Diff#executable?` when the bits are 107555
27
+ - `GithubDiffParser::Diff#symlink?` when the bits are 120000
28
+ - Introduce `GithubDiffParser::Diff#symlink_source`. When the diff applies to a symbolic link, `symlink_source` will
29
+ return the path to where the symbolic link points to.
30
+ - Introduce `GithubDiffParser::Diff#apply`, a simple implementation of `git apply`.
31
+ - Introduce `GithubDiffParser::Diff#revert`, a simple implementation of `git apply -R`.
32
+
33
+ ### Fixed
34
+ - `GithubDiffParser::Line#content` didn't include `\n` (if the line had one).
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- github_diff_parser (1.0.0)
4
+ github_diff_parser (1.1.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -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
 
@@ -20,7 +22,10 @@ module GithubDiffParser
20
22
  attr_reader :new_index
21
23
 
22
24
  # @private
23
- attr_writer :file_mode, :previous_index, :new_index
25
+ attr_writer :previous_index, :new_index
26
+
27
+ # @private
28
+ attr_accessor :mode
24
29
 
25
30
  # @param previous_filename [String] the original filename. Represented by "diff --git /a filename"
26
31
  # @param new_filename [String] the new filename. Represented by "diff --git /b filename"
@@ -73,7 +78,7 @@ module GithubDiffParser
73
78
  #
74
79
  # @return [Boolean]
75
80
  def deleted_mode?
76
- @file_mode == "deleted"
81
+ @mode&.operation == "deleted"
77
82
  end
78
83
 
79
84
  # Check if this Diff is set to new mode.
@@ -89,7 +94,7 @@ module GithubDiffParser
89
94
  #
90
95
  # @return [Boolean]
91
96
  def new_mode?
92
- @file_mode == "new"
97
+ @mode&.operation == "new"
93
98
  end
94
99
 
95
100
  # Check if this Diff is set to rename mode.
@@ -105,6 +110,29 @@ module GithubDiffParser
105
110
  previous_filename != new_filename
106
111
  end
107
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
+
108
136
  # A utility method that returns the current number of a line who might not be present in the diff.
109
137
  # This is useful if you need to keep track of the updated line numbers in a file for every changes.
110
138
  #
@@ -124,6 +152,48 @@ module GithubDiffParser
124
152
  end
125
153
  end
126
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
+
127
197
  private
128
198
 
129
199
  # Check if a line was shifted. A line is considered shifted if its number is superior to the first hunk's start
@@ -28,6 +28,8 @@ module GithubDiffParser
28
28
  add_hunk_to_diff(Regexp.last_match)
29
29
  when Regexes::LINE_DIFF
30
30
  add_line_to_hunk(Regexp.last_match)
31
+ when Regexes::NO_NEWLINE_AT_EOF
32
+ @current_diff.lines.last.content.sub!(/\n$/, "")
31
33
  end
32
34
  end
33
35
 
@@ -57,6 +59,7 @@ module GithubDiffParser
57
59
 
58
60
  @current_diff.previous_index = match_data[:previous_index]
59
61
  @current_diff.new_index = match_data[:new_index]
62
+ @current_diff.mode ||= Diff::Mode.new("modified", match_data[:bits])
60
63
  end
61
64
 
62
65
  # Called when encountering a `new file mode 100644` or `delete file mode 100644` in the Git Diff output.
@@ -67,7 +70,7 @@ module GithubDiffParser
67
70
  def process_diff_file_mode(match_data)
68
71
  validate_diff
69
72
 
70
- @current_diff.file_mode = match_data[:file_mode]
73
+ @current_diff.mode = Diff::Mode.new(match_data[:file_mode], match_data[:bits])
71
74
  end
72
75
 
73
76
  # Called when encountering a `@@ -0,0 +1,10 @@` in the Git Diff output.
@@ -33,7 +33,8 @@ module GithubDiffParser
33
33
  index\s # Match 'index '
34
34
  (?<previous_index>[a-z0-9]+) # Match and capture alphanumerical chars
35
35
  .. # Match '..' literally
36
- (?<new_index>[a-z0-9]+) # Match and captuer alphanumerical chars
36
+ (?<new_index>[a-z0-9]+)\s # Match and capture alphanumerical chars
37
+ (?<bits>\d+)? # Optionaly capture the mode bits
37
38
  }x
38
39
 
39
40
  # This Regexp is used to match the header containing the original filename.
@@ -88,7 +89,7 @@ module GithubDiffParser
88
89
  MODE_HEADER = %r{
89
90
  \A # Start of line
90
91
  (?<file_mode>new|deleted) # Match 'new' or 'deleted' and capture the group
91
- \sfile\smode\s\d+ # Match ' file mode 100655'
92
+ \sfile\smode\s(?<bits>\d+) # Match ' file mode 100655' and capture the "100655" part
92
93
  \Z # End of line
93
94
  }x
94
95
 
@@ -170,8 +171,10 @@ module GithubDiffParser
170
171
  | # OR
171
172
  \s # Match empty space ' ' (Considered as a contextual line)
172
173
  ) # End of named group
173
- (?<line>.*) # Match the content of the line itself
174
+ (?<line>.*\n?) # Match the content of the line itself
174
175
  \Z # End of line
175
176
  }x
177
+
178
+ NO_NEWLINE_AT_EOF = /\/
176
179
  end
177
180
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GithubDiffParser
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.1"
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: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Edouard CHIN
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-27 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
@@ -84,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
85
  - !ruby/object:Gem::Version
85
86
  version: '0'
86
87
  requirements: []
87
- rubygems_version: 3.4.10
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.