Class: GitCoauthor::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/git_coauthor/cli.rb

Constant Summary collapse

TEMPLATE_FILE_NAME =
'.git-coauthors-template'
CONFIG_FILE_NAME =
'.git-coauthors'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv = ARGV, stdout = $stdout, stderr = $stderr) ⇒ CLI

Returns a new instance of CLI.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/git_coauthor/cli.rb', line 18

def initialize(argv = ARGV, stdout = $stdout, stderr = $stderr)
  @argv = argv
  @stdout = stdout
  @stderr = stderr
  @options = {
    add: false, list: false, delete: false, session: false, config: false, global: false
  }
  @parser = OptionParser.new do |opts|
    opts.banner = <<~DOC
      Manages Git coauthors.

      Usage: git coauthor <args>

      Installation:
        brew tap nicholasdower/formulas
        brew install git-coauthor

      Uninstallation:
        brew uninstall git-coauthor
        brew untap nicholasdower/formulas

      Example Usage:
          git coauthor alias...                                   # Add one or more coauthors to the previous commit
          git coauthor                                            # List the coauthors on the previous commit
          git coauthor --delete                                   # Delete all coauthors from the previous commit
          git coauthor --delete alias...                          # Delete one or more coauthors from the previous commit

          git coauthor --config "alias: Name <email>"...          # Add a coauthor to the local config
          git coauthor --config --global "alias: Name <email>"... # Add a coauthor to the global config
          git coauthor --config                                   # List the local config
          git coauthor --config --global                          # List the global config
          git coauthor --config --delete                          # Delete the local config
          git coauthor --config --delete --global                 # Delete the global config
          git coauthor --config --delete alias...                 # Delete one or more coauthors from the local config
          git coauthor --config --delete --global alias...        # Delete one or more coauthors from the global config

          git coauthor --session alias...                         # Add one or more coauthors to the current session
          git coauthor --session                                  # List the coauthors in the current session
          git coauthor --session --delete                         # Delete the current session
          git coauthor --session --delete alias...                # Delete one or more coauthors from the current session

      Options:
    DOC

    opts.on('-d', '--delete', 'Delete coauthors') do
      @options[:delete] = true
    end

    opts.on('-s', '--session', 'Updat, delete or print  session') do
      @options[:session] = true
    end

    opts.on('-c', '--config', 'Update, delete or print configuration') do
      @options[:config] = true
    end

    opts.on('-g', '--global', 'Update or print the global coauthor configuration') do
      @options[:global] = true
    end

    opts.on('-v', '--version', 'Print version') do
      stdout.puts("git-coauthor version #{GitCoauthor::VERSION}")
      Kernel.exit(0)
    end

    opts.on('-h', 'Print help') do
      stdout.puts(parser.help)
      Kernel.exit(0)
    end
  end
end

Instance Attribute Details

#argvObject (readonly)

Returns the value of attribute argv.



16
17
18
# File 'lib/git_coauthor/cli.rb', line 16

def argv
  @argv
end

#optionsObject (readonly)

Returns the value of attribute options.



16
17
18
# File 'lib/git_coauthor/cli.rb', line 16

def options
  @options
end

#parserObject (readonly)

Returns the value of attribute parser.



16
17
18
# File 'lib/git_coauthor/cli.rb', line 16

def parser
  @parser
end

#stderrObject (readonly)

Returns the value of attribute stderr.



16
17
18
# File 'lib/git_coauthor/cli.rb', line 16

def stderr
  @stderr
end

#stdoutObject (readonly)

Returns the value of attribute stdout.



16
17
18
# File 'lib/git_coauthor/cli.rb', line 16

def stdout
  @stdout
end

Instance Method Details

#runObject



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/git_coauthor/cli.rb', line 90

def run
  parser.parse!(argv)

  case params
  when %i[config add args]
    # git coauthor --config "foo: Foo <[email protected]>"
    argv.each do |arg|
      parts = arg.split(':').map(&:strip)
      fail('fatal: invalid config') unless parts.size == 2

      repo_config[parts[0]] = parts[1]
    end
    write_config(repo_file, repo_config)
    print_config(CONFIG_FILE_NAME, repo_config)
  when %i[config add global args]
    # git coauthor --config --global "foo: Foo <[email protected]>"
    argv.each do |arg|
      parts = arg.split(':').map(&:strip)
      fail('fatal: invalid config') unless parts.size == 2

      user_config[parts[0]] = parts[1]
    end
    write_config(user_file, user_config)
    print_config(user_file, user_config)
  when %i[config list]
    # git coauthor --config
    print_config(CONFIG_FILE_NAME, repo_config)
  when %i[config list global]
    # git coauthor --config --global
    print_config(user_file, user_config)
  when %i[config delete]
    # git coauthor --config --delete
    File.write(repo_file, "\n")
    print_config(CONFIG_FILE_NAME, {})
  when %i[config delete global]
    # git coauthor --config --delete --global
    File.write(user_file, "\n")
    print_config(user_file, {})
  when %i[config delete args]
    # git coauthor --config --delete foo
    config = repo_config.reject { |k, _| argv.include?(k) }
    write_config(repo_file, config)
    print_config(CONFIG_FILE_NAME, config)
  when %i[config delete global args]
    # git coauthor --config --delete --global foo
    config = user_config.reject { |k, _| argv.include?(k) }
    write_config(user_file, config)
    print_config(user_file, config)
  when %i[default add args]
    # git coauthor foo
    previous_message = commit_message('HEAD')
    msg_without_coauthors = without_coauthors(previous_message)
    coauthors_to_add = args_as_coauthors
    previous_coauthors = previous_message.split("\n").select { _1.match(/^Co-authored-by:.*/) }
    coauthors = Set.new(previous_coauthors + coauthors_to_add).to_a.sort
    message = "#{msg_without_coauthors}\n#{coauthors.join("\n")}\n"
    amend_commit_message(message)
    stdout.puts('Commit:')
    coauthors.each { stdout.puts("  #{_1}") }
  when %i[default list]
    # git coauthor
    message = commit_message('HEAD')
    stdout.puts('Commit:')
    message.scan(/^ *Co-authored-by:.*$/).sort.map { stdout.puts("  #{_1}") }
  when %i[default delete]
    # git coauthor --delete
    message = without_coauthors(commit_message('HEAD'))
    amend_commit_message(message)
    stdout.puts('Commit:')
  when %i[default delete args]
    # git coauthor --delete foo
    previous_message = commit_message('HEAD')
    msg_without_coauthors = without_coauthors(previous_message)
    to_remove = args_as_coauthors
    previous_coauthors = previous_message.split("\n").select { _1.match(/^Co-authored-by:.*/) }
    coauthors = previous_coauthors - to_remove
    message = if coauthors.any?
                "#{msg_without_coauthors}\n#{coauthors.join("\n")}\n"
              else
                msg_without_coauthors
              end

    success = Git.amend_commit_message(message)
    fail('fatal: cannot amend the previous commit message') unless success

    stdout.puts('Commit:')
    coauthors.each { stdout.puts("  #{_1}") }
  when %i[session add args]
    # git coauthor --session foo
    success, template_path = Git.config_get('commit.template')

    coauthors = args_as_coauthors
    existing_template = ['', '']

    if success && template_path != TEMPLATE_FILE_NAME
      fail("fatal: commit template not found: #{template_path}") unless File.exist?(template_path)

      existing_template = File.read(template_path).split("\n")
      success = Git.config_set('commit.template.backup', template_path)
      fail("fatal: failed to set commit.template.backup to #{template_path}") unless success

      existing_template << '' while existing_template.size < 2
    elsif success && template_path == TEMPLATE_FILE_NAME
      fail("fatal: commit template not found: #{template_path}") unless File.exist?(template_path)

      existing_template = File.read(template_path).split("\n")
      previous_coauthors = existing_template.select { _1.match(/^Co-authored-by:.*/) }
      existing_template = existing_template.reject { _1.match(/^Co-authored-by:.*/) }
      coauthors = Set.new(coauthors + previous_coauthors).to_a
    end

    coauthors = coauthors.sort
    template = existing_template + coauthors
    File.write(TEMPLATE_FILE_NAME, "#{template.join("\n")}\n")
    success = Git.config_set('commit.template', TEMPLATE_FILE_NAME)
    fail('fatal: cannot set git commit template') unless success

    stdout.puts('Session:')
    coauthors.each { stdout.puts("  #{_1}") }
  when %i[session list]
    # git coauthor --session
    success, template_path = Git.config_get('commit.template')
    unless success && template_path == TEMPLATE_FILE_NAME
      stdout.puts('Session:')
      Kernel.exit(0)
    end
    fail("fatal: git commit template not exist: #{template_path}") unless File.exist?(template_path)

    template = File.read(template_path).strip
    coauthors = template.split("\n").select { _1.match(/^Co-authored-by:.*/) }.sort
    stdout.puts('Session:')
    coauthors.each { stdout.puts("  #{_1}") }
  when %i[session delete]
    # git coauthor --session --delete
    success, template_path = Git.config_get('commit.template')
    delete_session(template_path) if success && template_path == TEMPLATE_FILE_NAME
    stdout.puts('Session:')
  when %i[session delete args]
    # git coauthor --session --delete foo
    _, template_path = Git.config_get('commit.template')
    unless template_path == TEMPLATE_FILE_NAME
      stdout.puts('Session:')
      Kernel.exit(0)
    end

    unless File.exist?(TEMPLATE_FILE_NAME)
      delete_session(TEMPLATE_FILE_NAME)
      stdout.puts('Session:')
      Kernel.exit(0)
    end

    to_remove = args_as_coauthors
    template = File.read(template_path).strip
    previous_coauthors = template.split("\n").select { _1.match(/^Co-authored-by:.*/) }
    coauthors = previous_coauthors - to_remove
    if coauthors.any?
      File.write(template_path, "\n\n#{coauthors.join("\n")}\n")
    else
      delete_session(template_path)
    end
    stdout.puts('Session:')
    coauthors.each { stdout.puts("  #{_1}") }
  else
    fail('fatal: unexpected arguments or options')
  end

  Kernel.exit(0)
rescue OptionParser::ParseError => e
  fail("fatal: #{e}")
end