mailmap 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d659e60a379065bd575a324d915c318d797f23aecfddf90e9c06486c737813fd
4
- data.tar.gz: 6fc69c39af05df32d2f21239f4aee331b50dae610b6e71aacaefbe21db3ce6c8
3
+ metadata.gz: 1236a9dbb2ff8d02ed3ba7a2929e4528ba188613ad2bcaa8f259f7072d02d795
4
+ data.tar.gz: f9ac429f3be5c2d76192dd4b193e4c40610ad46226c5461cc7fd1094e1647268
5
5
  SHA512:
6
- metadata.gz: e5f8d9ed92f6e40525ee41c6b54fe459ea427c3df589e978a80b7a8dcbafbf91707c590e001493c31a71c3f98c600db058aef7580e2107e2ba3452fe20d5414b
7
- data.tar.gz: '08d9415b709f531e9532bd89698a7a3cac9fdee485061a9ebd42d4daee32f17c2b39c674cde06f5cc0b460518d71ab04a96f9bd056b5509b4785878a477ff22b'
6
+ metadata.gz: 9cbaa85e7523f26fcc8774155f7b7468bf0e1cba53fa3ede308ca4af8f2d37fbe96980cc172ebfc6217da650dfca6640e2d9b27a9fee42738e29581003a1188d
7
+ data.tar.gz: d3e8d3d9055781eafa4aeb89feddac292974db35b380142e27d611a596a88db40abb6ba52121bf5ae1a610792c4e09d3feccb9934d1346822ee37adfed60bcfb
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Ryosuke Ito
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all 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,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # mailmap
2
+
3
+ [![Test](https://github.com/manicmaniac/mailmap/actions/workflows/main.yml/badge.svg)](https://github.com/manicmaniac/mailmap/actions/workflows/main.yml)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/d43e7ca25cb834a37a99/maintainability)](https://codeclimate.com/github/manicmaniac/mailmap/maintainability)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/d43e7ca25cb834a37a99/test_coverage)](https://codeclimate.com/github/manicmaniac/mailmap/test_coverage)
6
+ [![Gem Version](https://badge.fury.io/rb/mailmap.svg)](https://rubygems.org/gems/mailmap)
7
+
8
+ Pure Ruby implementation of [Git mailmap](https://git-scm.com/docs/gitmailmap).
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'mailmap'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle install
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install mailmap
25
+
26
+ ## Usage
27
+
28
+ ```ruby
29
+ require 'mailmap'
30
+
31
+ # Load .mailmap file
32
+ mailmap = Mailmap::Map.load('.mailmap')
33
+
34
+ # Parse string
35
+ mailmap = Mailmap::Map.parse('Proper Name <proper@example.com> <commit@example.com>')
36
+
37
+ # Equivalent to git check-mailmap 'Commit Name' 'commit@example.com'
38
+ mailmap.resolve('Commit Name', 'commit@example.com') # => ['Proper Name', 'proper@example.com']
39
+
40
+ # Equivalent to git check-mailmap 'commit@example.com'
41
+ mailmap.resolve(nil, 'commit@example.com') # => [nil, 'proper@example.com']
42
+
43
+ # Similar to `Map#resolve` but returns nil if not found
44
+ mailmap.lookup('Nonexistent Name', 'nonexistent@example.com') #=> nil
45
+ ```
46
+
47
+ See [API reference](https://www.rubydoc.info/gems/mailmap) for more information.
48
+
49
+ ## Command Line
50
+
51
+ This gem includes command-line tool named `check-mailmap`.
52
+ It is pure Ruby implementation of [`git check-mailmap`](https://git-scm.com/docs/git-check-mailmap) and is intended to be a drop-in replacement for `git check-mailmap`.
53
+
54
+ ```sh
55
+ $ bundle exec check-mailmap --help
56
+ usage: check-mailmap [<options>] <contact>...
57
+ -f, --file=FILE path to the .mailmap file (default: ./.mailmap)
58
+ --stdin also read contacts from stdin
59
+ ```
60
+
61
+ ## Development
62
+
63
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `rake test` to run the tests.
64
+
65
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
66
+
67
+ ## Contributing
68
+
69
+ Bug reports and pull requests are welcome on GitHub at https://github.com/manicmaniac/mailmap.
70
+
71
+ ## License
72
+
73
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/exe/check-mailmap ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
5
+
6
+ require 'mailmap'
7
+ require 'optparse'
8
+
9
+ # An error raised when a contact cannot be parsed.
10
+ class ContactParseError < StandardError
11
+ def initialize(contact)
12
+ super("fatal: unable to parse contact: #{contact}")
13
+ end
14
+ end
15
+
16
+ mailmap_path = '.mailmap'
17
+ parser = OptionParser.new do |opts|
18
+ opts.banner = 'usage: check-mailmap [<options>] <contact>...'
19
+ opts.version = Mailmap::VERSION
20
+
21
+ opts.on('-f FILE', '--file=FILE', 'path to the .mailmap file (default: ./.mailmap)') do |file|
22
+ mailmap_path = file
23
+ end
24
+
25
+ opts.on('--stdin', 'also read contacts from stdin') do
26
+ ARGV.concat($stdin.readlines(chomp: true))
27
+ end
28
+ end
29
+ parser.parse!
30
+ abort(parser.help) if ARGV.empty?
31
+
32
+ begin
33
+ ARGV.each do |contact|
34
+ matched = contact.match(/^(?<name>.+?)?<(?<email>.+?)>$/)
35
+ raise ContactParseError, contact unless matched
36
+
37
+ commit_name_or_nil = matched[:name]&.strip
38
+ commit_email = matched[:email] or abort
39
+ mailmap = Mailmap::Map.load(mailmap_path)
40
+ proper_name, proper_email = mailmap.resolve(commit_name_or_nil, commit_email)
41
+ puts "#{proper_name} <#{proper_email}>".strip
42
+ rescue Mailmap::ParserError
43
+ puts "#{commit_name_or_nil} <#{commit_email}>".strip
44
+ end
45
+ rescue ContactParseError => e
46
+ warn(e.message)
47
+ exit(128)
48
+ rescue StandardError => e
49
+ abort("fatal: #{e.message}")
50
+ end
data/lib/mailmap/map.rb CHANGED
@@ -101,30 +101,44 @@ module Mailmap
101
101
  string.each_line.with_index(1) do |line, line_number|
102
102
  next if line.start_with?('#')
103
103
 
104
- parse_name_and_email(line, line_number)
104
+ tokens = tokenize_name_and_email(line)
105
+ proper_name, proper_email, commit_name, commit_email = parse_name_and_email(tokens, line_number)
106
+ @map[commit_email.downcase][commit_name&.downcase] = [proper_name, proper_email]
105
107
  end
106
108
  end
107
109
 
108
- def parse_name_and_email(line, line_number) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
109
- # @type var names: Array[String]
110
- names = []
111
- # @type var emails: Array[String]
112
- emails = []
110
+ def tokenize_name_and_email(line)
111
+ # @type var tokens: Array[[Symbol, String]]
112
+ tokens = []
113
113
  scanner = StringScanner.new(line)
114
114
  2.times do
115
115
  scanner.skip(/\s+/)
116
- scanner.scan(/[^<]+/).then { |s| names << s.rstrip if s }
117
- scanner.skip(/</)
118
- scanner.scan(/[^>]+/).then { |s| emails << s if s }
119
- scanner.skip(/>/)
116
+ scanner.scan(/[^<]+/)&.then { |s| tokens << [:name, s.rstrip] }
117
+ scanner.scan(/<(.*?)>/)&.then { |s| tokens << [:email, unquote_email(s)] }
118
+ scanner.skip(/\s*#.*$/)
120
119
  end
121
- commit_email = emails.pop&.downcase
122
- raise ParserError, "Missing commit email at line #{line_number}" unless commit_email
120
+ tokens
121
+ end
122
+
123
+ PATTERNS = {
124
+ %i[name email] => %i[proper_name commit_email],
125
+ %i[email email] => %i[proper_email commit_email],
126
+ %i[name email email] => %i[proper_name proper_email commit_email],
127
+ %i[email name email] => %i[proper_email commit_name commit_email],
128
+ %i[name email name email] => %i[proper_name proper_email commit_name commit_email]
129
+ }.freeze
130
+ private_constant :PATTERNS
131
+
132
+ def parse_name_and_email(tokens, line_number)
133
+ types = tokens.map(&:first)
134
+ values = tokens.map(&:last)
135
+ fields = PATTERNS[types] or raise ParserError, "Invalid format at line #{line_number}"
136
+ entry = fields.zip(values).to_h
137
+ [entry[:proper_name], entry[:proper_email], entry[:commit_name], entry.fetch(:commit_email)]
138
+ end
123
139
 
124
- proper_email = emails.pop
125
- proper_name = names.shift
126
- commit_name = names.shift&.downcase
127
- @map[commit_email][commit_name] = [proper_name, proper_email]
140
+ def unquote_email(email)
141
+ email.delete_prefix('<').delete_suffix('>')
128
142
  end
129
143
  end
130
144
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mailmap
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -0,0 +1,3 @@
1
+ class ContactParseError < StandardError
2
+ def initialize: (String contact) -> void
3
+ end
@@ -0,0 +1,5 @@
1
+ class CheckMailmapCompatibilityTest < Minitest::Test
2
+ @mailmap: Tempfile
3
+
4
+ def check_mailmap: (*String args, ?mailmap_path: String?) -> [String, String, Integer?]
5
+ end
@@ -0,0 +1,12 @@
1
+ class CheckMailmapTest < Minitest::Test
2
+ private
3
+
4
+ EXECUTABLE_PATH: String
5
+
6
+ def check_mailmap: (*untyped args, ?mailmap_path: String?, ?stdin_data: String?) -> [String, String, Process::Status]
7
+ end
8
+
9
+ # https://github.com/ruby/rbs/blob/v3.8.1/stdlib/open3/0/open3.rbs
10
+ module Open3
11
+ def self.capture3: (*untyped args) -> [String, String, Process::Status]
12
+ end
@@ -0,0 +1,4 @@
1
+ module Mailmap
2
+ class MapTest < Minitest::Test
3
+ end
4
+ end
@@ -0,0 +1,2 @@
1
+ class MailmapTest < Minitest::Test
2
+ end
@@ -0,0 +1,30 @@
1
+ # TypeProf 0.21.2
2
+
3
+ # Classes
4
+ module Mailmap
5
+ class ParserError < StandardError
6
+ end
7
+
8
+ class Map
9
+ include Enumerable[[String?, String?, String?, String]]
10
+ @map: Hash[String, Hash[String?, [String?, String?]]]
11
+
12
+ def self.load: (String path) -> Map
13
+ alias self.parse self.new
14
+ def initialize: (String string) -> void
15
+ def each: ?{ (String?, String?, String?, String) -> void } -> (Enumerator[[String?, String?, String?, String], void] | Map)
16
+ def lookup: (String? commit_name_or_nil, String commit_email) -> [String?, String?]?
17
+ def resolve: (String commit_name_or_nil, String commit_email) -> [String, String]
18
+ | (nil commit_name_or_nil, String commit_email) -> [String?, String]
19
+ | (String? commit_name_or_nil, String commit_email) -> [String?, String]
20
+ def include_name?: (String name) -> bool
21
+ def include_email?: (String email) -> bool
22
+
23
+ private
24
+ def parse: (String string) -> void
25
+ def tokenize_name_and_email: (String line) -> Array[[Symbol, String]]
26
+ PATTERNS: Hash[Array[Symbol], Array[Symbol]]
27
+ def parse_name_and_email: (Array[[Symbol, String]] tokens, Integer line_number) -> [String?, String?, String?, String]
28
+ def unquote_email: (String email) -> String
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module Mailmap
2
+ VERSION: String
3
+ end
metadata CHANGED
@@ -1,33 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryosuke Ito
8
- autorequire:
9
- bindir: bin
8
+ bindir: exe
10
9
  cert_chain: []
11
- date: 2023-03-29 00:00:00.000000000 Z
10
+ date: 2025-02-09 00:00:00.000000000 Z
12
11
  dependencies: []
13
- description: Parser for Git Mailmap (.mailmap)
12
+ description: |
13
+ A pure Ruby implementation of Git mailmap.
14
+ This library allows you to parse mailmap programmatically without depending on Git.
14
15
  email:
15
16
  - rito.0305@gmail.com
16
- executables: []
17
+ executables:
18
+ - check-mailmap
17
19
  extensions: []
18
20
  extra_rdoc_files: []
19
21
  files:
22
+ - LICENSE.txt
23
+ - README.md
24
+ - exe/check-mailmap
20
25
  - lib/mailmap.rb
21
26
  - lib/mailmap/map.rb
22
27
  - lib/mailmap/version.rb
28
+ - sig/_exe/check-mailmap.rbs
29
+ - sig/_test/exe/check_mailmap_compatibility_test.rbs
30
+ - sig/_test/exe/check_mailmap_test.rbs
31
+ - sig/_test/lib/mailmap/map_test.rbs
32
+ - sig/_test/lib/mailmap_test.rbs
33
+ - sig/lib/mailmap/map.rbs
34
+ - sig/lib/mailmap/version.rbs
23
35
  homepage: https://github.com/manicmaniac/mailmap
24
36
  licenses:
25
37
  - MIT
26
38
  metadata:
27
- rubygems_mfa_required: 'true'
39
+ bug_tracker_uri: https://github.com/manicmaniac/mailmap/issues
40
+ documentation_uri: https://www.rubydoc.info/gems/mailmap
28
41
  homepage_uri: https://github.com/manicmaniac/mailmap
29
- source_code_uri: https://github.com/manicmaniac/mailmap
30
- post_install_message:
42
+ rubygems_mfa_required: 'true'
31
43
  rdoc_options: []
32
44
  require_paths:
33
45
  - lib
@@ -42,8 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
42
54
  - !ruby/object:Gem::Version
43
55
  version: '0'
44
56
  requirements: []
45
- rubygems_version: 3.4.6
46
- signing_key:
57
+ rubygems_version: 3.6.2
47
58
  specification_version: 4
48
59
  summary: Parser for Git Mailmap (.mailmap)
49
60
  test_files: []