chlog 0.9.0 → 1.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of chlog might be problematic. Click here for more details.

Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/bin/chlog +529 -0
  3. metadata +11 -27
  4. data/exe/chlog +0 -82
  5. data/lib/chlog/version.rb +0 -16
  6. data/lib/chlog.rb +0 -417
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c501c040c85ebeba5c6171f5dfb6dcb6fddec08798166cd1beb0fce54dd27df
4
- data.tar.gz: ec9bc451993d99992ae38d5ee2db80190e1fc55e5853d8665e6d31186be941cc
3
+ metadata.gz: 66679728bbf02913b7df67e717462ccd64cc899a23f42aa1959f2c12f5176641
4
+ data.tar.gz: 010c5b8882d3c9293950b774b1dbb45dc1a41e0bf6758ba5ee4790650580b2e9
5
5
  SHA512:
6
- metadata.gz: 2bc058d3d29b835fdfea8577cec9195e75b2b30069f2b8ca4e49f942a228b3de600c741fdf302701dc02579cb9db62685990297a0c330b69d8993ecd838b1ecb
7
- data.tar.gz: d8517e795b3bb1e4d9b9666bbeabcf92ac987e3a280275644ac5779e03e8fd68149f62d28c3c447da38087ddf5c2a6f9de67d55350b18845cdb5a6f531f6407e
6
+ metadata.gz: 69064ad8bb3c1b74d18b636b0db54005626e7fb1bc083879fa0bcabc09245727cfb0c463defd5ba7f2d54095097f278aec86ad74284764c1202037d282d11610
7
+ data.tar.gz: 81d7a3ab70e0ef18ed3d27977a2688e9f44b8e30d7630aef4b6000db17cecc59e768f66ff7b15bfdf0df36863aac2aa2e5f8f2ba977d5b4b29e59605db528f91
data/bin/chlog ADDED
@@ -0,0 +1,529 @@
1
+ #!/usr/bin/env ruby
2
+ # ------------------------------------------------------
3
+ # File : chlog.rb
4
+ # Authors : ccmywish <ccmywish@qq.com>
5
+ # Created on : <2022-03-18>
6
+ # Last modified : <2022-04-09>
7
+ #
8
+ # chlog:
9
+ #
10
+ # Maintain your project's Changelog on the cli.
11
+ #
12
+ # ------------------------------------------------------
13
+
14
+ CHLOG_VERSION = "1.6"
15
+
16
+ require 'date'
17
+ $today = Date.today.to_s
18
+
19
+ UNRELEASED_TITLE = "## [Unreleased](#) (#$today)"
20
+
21
+ CHLOG_TEMPLATE = <<EOT
22
+ # Changelog
23
+
24
+ #{UNRELEASED_TITLE}
25
+
26
+ <br>
27
+
28
+ ## [Initialize](#) (#$today)
29
+
30
+ <br>
31
+
32
+ <hr>
33
+
34
+ This Changelog is maintained with [chlog](https://github.com/ccmywish/chlog)
35
+
36
+ EOT
37
+
38
+ $Changelog_file = `git rev-parse --show-toplevel`.chomp + '/CHANGELOG.md'
39
+
40
+ def get_changelog
41
+ file = $Changelog_file
42
+ if File.exists? file
43
+ return File.read file
44
+ else
45
+ puts "chlog: Auto generate #$Changelog_file"
46
+ File.write(file, CHLOG_TEMPLATE)
47
+ return File.read file
48
+ end
49
+ end
50
+
51
+
52
+ def help
53
+ puts <<EOH
54
+ chlog (v#{CHLOG_VERSION}): Help maintain the Changelog of your projects
55
+
56
+ usage:
57
+
58
+ chlog => Generate CHANGELOG.md in git root
59
+ chlog -g (-m) (--sub) => Reuse last commit log (m category / sub category)
60
+ chlog (--sub) log => Determine main category(fallback Enhancements) (/ sub category) add log
61
+ chlog -n (--sub) log => Add log to New features (/ sub category)
62
+ chlog -e (--sub) log => Add log to Enhancements (/ sub category)
63
+ chlog -b (--sub) log => Add log to Bug fixes (/ sub category)
64
+ chlog -s (--sub) log => Add log to Security (/ sub category)
65
+ chlog -c (--sub) log => Add log to Compatibility(/ sub category)
66
+ chlog -d (--sub) log => Add log to Deprecations (/ sub category)
67
+ chlog -r v3.14 => Release version to v3.14
68
+
69
+ EOH
70
+
71
+ end
72
+
73
+ def match_unreleased?(str)
74
+ str =~ /^## \[Unreleased\]\(.*\) \(\d{4}-\d\d-\d\d\)/
75
+ end
76
+
77
+ def match_unreleased_fail!(str)
78
+ unless match_unreleased?(str)
79
+ puts "chlog: Unmathed format with chlog"
80
+ # "#{lns[1][1..]}"
81
+ puts " Unreleased version must be the third line.", ""
82
+ exit -1
83
+ end
84
+ end
85
+
86
+ def match_new_features?(str)
87
+ str =~ /^### New features:/
88
+ end
89
+
90
+ def match_enhancements?(str)
91
+ str =~ /^### Enhancements:/
92
+ end
93
+
94
+ def match_bug_fixes?(str)
95
+ str =~ /^### Bug fixes:/
96
+ end
97
+
98
+ def match_security?(str)
99
+ str =~ /^### Security:/
100
+ end
101
+
102
+ def match_compatibility?(str)
103
+ str =~ /^### Compatibility:/
104
+ end
105
+
106
+ def match_deprecations?(str)
107
+ str =~ /^### Deprecations:/
108
+ end
109
+
110
+
111
+ def next_version_index(lns_array)
112
+ nvi = lns_array[3..].each_with_index {break _2 if _1.start_with?("## [") }
113
+ nvi += 3
114
+ end
115
+
116
+ def next_category_index(lns_array)
117
+ nci = lns_array[3...nvi].each_with_index {break _2 if _1.start_with?("### ") }
118
+
119
+ # The not match return value is not nil!! But an array!!
120
+ if nci.is_a(Integer)
121
+ nci += 3
122
+ else
123
+ nil
124
+ end
125
+ end
126
+
127
+
128
+ #
129
+ # ### New features:
130
+ #
131
+ # - xaaaaa
132
+ # - xbbbbb
133
+ # - xccccc [-> this]
134
+ #
135
+ def find_main_category_last_list_item_index(lns,
136
+ main_cat_index,
137
+ first_lower_order_category_index)
138
+ mci = main_cat_index
139
+ nci = first_lower_order_category_index
140
+
141
+ list_i = lns[mci+2..nci].each_with_index do
142
+ break _2 if _1 !~ /^- .*/
143
+ end
144
+ list_i += mci+2 - 1
145
+ end
146
+
147
+
148
+
149
+ $order_table = [
150
+ :match_new_features?,
151
+ :match_enhancements?,
152
+ :match_bug_fixes?,
153
+ :match_security?,
154
+ :match_compatibility?,
155
+ :match_deprecations?
156
+ ]
157
+
158
+
159
+ def first_lower_order_category_index(lns_array, category_order)
160
+
161
+ o = category_order
162
+
163
+ nvi = next_version_index(lns_array)
164
+
165
+ while o < $order_table.size
166
+ lns_array[0...nvi].each_with_index do
167
+ if send($order_table[o], _1)
168
+ return _2
169
+ end
170
+ end
171
+ o += 1
172
+ end
173
+
174
+ # Next version above
175
+ return (nvi - 2)
176
+ end
177
+
178
+
179
+
180
+ #
181
+ # A meta function: do the real work other 6 functions delegate
182
+ #
183
+ # This function detect the main category, and then handle the
184
+ # sub category.
185
+ #
186
+ def meta_add_to_a_category(log, main_category_order, category)
187
+
188
+ content = get_changelog
189
+ lns = content.lines
190
+
191
+ match_unreleased_fail!(lns[2])
192
+
193
+ nvi = next_version_index(lns)
194
+ # To find the existing category line
195
+ main_cat_i = lns[0...nvi].each_with_index do
196
+ # Adjust to index of the order table
197
+ break _2 if send($order_table[main_category_order-1], _1)
198
+ end
199
+
200
+ #
201
+ # Always update to latest time when making a log
202
+ #
203
+ # We must add a "\n" because every element of the array
204
+ # is a sentence with a trailing newline, then they can
205
+ # be 'joined' to a working long string
206
+ #
207
+ lns[2] = UNRELEASED_TITLE + "\n"
208
+
209
+ f_l_o_c_i = first_lower_order_category_index(lns, main_category_order)
210
+
211
+ if main_cat_i.class != Integer
212
+ ################################################################################
213
+ # The main category not exists
214
+ ################################################################################
215
+
216
+
217
+ ########################################
218
+ if $sub_category
219
+
220
+ # Because the main category not exists,
221
+ # nor does the sub category
222
+ #
223
+ sub_cat_i = f_l_o_c_i
224
+ to_wr = lns[0...sub_cat_i].join + "### #{category}:\n\n" + "**#{$sub_category}**\n\n" + ' - ' + log + "\n\n"
225
+ File.write($Changelog_file, to_wr + lns[sub_cat_i..].join)
226
+
227
+ puts "chlog: Add log to #{category}/#{$sub_category}"
228
+ return
229
+ end # end of if $sub_category
230
+ ########################################
231
+
232
+
233
+ # situation: no sub category
234
+
235
+ # Not need adjust to the index of the order table
236
+ log_loc = f_l_o_c_i
237
+ puts "chlog: Add '#{category}' category"
238
+ to_wr = lns[0...(log_loc)].join + "### #{category}:\n\n" + '- ' + log + "\n"
239
+ File.write($Changelog_file, to_wr + lns[log_loc-1..].join)
240
+
241
+ else
242
+ ################################################################################
243
+ # The main category exists
244
+ ################################################################################
245
+
246
+
247
+ ########################################
248
+ if $sub_category
249
+
250
+ # from first list item to next main cat
251
+ # search if sub cat already exists
252
+ sub_cat_i = lns[main_cat_i+2...f_l_o_c_i].each_with_index do
253
+ break _2 if _1 =~ /^\*\*#{$sub_category}\*\*/
254
+ end
255
+
256
+ if !sub_cat_i.is_a?(Integer)
257
+ # the sub category not exists
258
+
259
+ sub_cat_i = 2 + find_main_category_last_list_item_index(lns,main_cat_i,f_l_o_c_i)
260
+ to_wr = lns[0...sub_cat_i].join + "**#{$sub_category}**\n\n" + ' - ' + log + "\n\n"
261
+ File.write($Changelog_file, to_wr + lns[sub_cat_i..].join)
262
+ else
263
+ # the sub category exists
264
+
265
+ sub_cat_i += main_cat_i+2
266
+ to_wr = lns[0..sub_cat_i+1].join + ' - ' + log + "\n"
267
+ File.write($Changelog_file, to_wr + lns[sub_cat_i+2..].join)
268
+ end
269
+
270
+ puts "chlog: Add log to #{category}/#{$sub_category}"
271
+ return
272
+ end # end of if $sub_category
273
+ ########################################
274
+
275
+
276
+
277
+ # situation: no sub category
278
+
279
+ to_wr = lns[0..main_cat_i+1].join + '- ' + log + "\n"
280
+
281
+ # main category list should be separated with
282
+ # sub category
283
+ if lns[main_cat_i+2] =~ /\*\*.*/
284
+ to_wr += "\n"
285
+ end
286
+ File.write($Changelog_file, to_wr + lns[main_cat_i+2..].join)
287
+ end
288
+ puts "chlog: Add log to #{category}"
289
+ end
290
+
291
+
292
+ #
293
+ # main category order: 1
294
+ #
295
+ def add_to_new_features(log)
296
+ meta_add_to_a_category(log, 1, "New features")
297
+ end
298
+
299
+ #
300
+ # main category order: 2
301
+ #
302
+ def add_to_enhancements(log)
303
+ meta_add_to_a_category(log, 2, "Enhancements")
304
+ end
305
+
306
+ #
307
+ # main_category_order: 3
308
+ #
309
+ def add_to_bug_fixes(log)
310
+ meta_add_to_a_category(log, 3, "Bug fixes")
311
+ end
312
+
313
+ #
314
+ # main_category_order: 4
315
+ #
316
+ def add_to_security(log)
317
+ meta_add_to_a_category(log, 4, "Security")
318
+ end
319
+
320
+ #
321
+ # main_category_order: 5
322
+ #
323
+ def add_to_compatibility(log)
324
+ meta_add_to_a_category(log, 5, "Compatibility")
325
+ end
326
+
327
+ #
328
+ # The last of order table
329
+ # main_category_order: 6
330
+ #
331
+ def add_to_deprecations(log)
332
+ meta_add_to_a_category(log, 6, "Deprecations")
333
+ end
334
+
335
+
336
+ #
337
+ # Release a version
338
+ #
339
+ def release_new_version(ver)
340
+ if ver.nil?
341
+ puts "chlog: No version supplied! "
342
+ puts " Use chlog -r <version>!",""
343
+ exit 1
344
+ end
345
+
346
+ content = get_changelog
347
+ lns = content.lines
348
+
349
+ match_unreleased_fail!(lns[2])
350
+
351
+ header = <<EOF
352
+ # Changelog
353
+
354
+ ## [Unreleased](#) (#$today)
355
+
356
+ <br>
357
+
358
+ EOF
359
+
360
+ new_version = "## [#{ver}](#) (#$today)\n"
361
+ new_cont = header + new_version + lns[3..].join('')
362
+ File.write($Changelog_file, new_cont)
363
+ puts "Release #{ver} in changelog!"
364
+ end
365
+
366
+
367
+ def add_log_sensitive(log)
368
+
369
+ # Be careful the when statements order
370
+ # Match the case you want first
371
+ case log
372
+ when /deprecat/i, /^remove/i, /^not/i then add_to_deprecations(log)
373
+ when /^new/i, /^add/i, /new feature/i, /^support/i then add_to_new_features(log)
374
+ when /^fix/i, /repair/i, /bug/i then add_to_bug_fixes(log)
375
+ when /compatible/i, /compatibility/i then add_to_compatibility(log)
376
+ when /security/i, /secure/i, /cve/i then add_to_security(log)
377
+ when /feature/i, /update/i, /problem/i, /issue/i then add_to_enhancements(log)
378
+ else
379
+ add_to_enhancements(log)
380
+ end
381
+ end
382
+
383
+
384
+ #
385
+ # reuse git commit log
386
+ #
387
+ def add_with_git(first, second)
388
+
389
+ main_category = nil
390
+
391
+ if first =~ /^-([nebscd])$/
392
+ main_category = $1
393
+ elsif first =~ /^--(.*)/
394
+ $sub_category = $1
395
+ end
396
+
397
+ if second =~ /^-([nebscd])$/
398
+ main_category = $1
399
+ elsif second =~ /^--(.*)/
400
+ $sub_category = $1
401
+ end
402
+
403
+
404
+ gitlog = `git log --oneline -n 1`
405
+ log = gitlog.split(' ')
406
+ log = log[1..].join(' ')
407
+ puts "last commit: #{log}"
408
+
409
+ if $sub_category.nil?
410
+ puts "What sub category? Input or leave it blank"
411
+ print '>'
412
+ sub = STDIN.gets.chomp
413
+ case sub
414
+ when ''
415
+ $sub_category = nil
416
+ else
417
+ $sub_category = sub
418
+ end
419
+ end
420
+
421
+ if main_category.nil?
422
+ puts "What main category? Input number or leave it blank to auto determine"
423
+ puts <<~EOC
424
+ ----------------
425
+ 1. New features
426
+ 2. Enhancements
427
+ 3. Bug fixes
428
+ 4. Security
429
+ 5. Compatibility
430
+ 6. Deprecations
431
+ ----------------
432
+ EOC
433
+
434
+ print '>'
435
+ case STDIN.gets.chomp
436
+ when '1' then add_to_new_features(log)
437
+ when '2' then add_to_enhancements(log)
438
+ when '3' then add_to_bug_fixes(log)
439
+ when '4' then add_to_security(log)
440
+ when '5' then add_to_compatibility(log)
441
+ when '6' then add_to_deprecations(log)
442
+ else
443
+ add_log_sensitive(log)
444
+ end
445
+ else
446
+ tbl = {
447
+ 'n' => :add_to_new_features,
448
+ 'e' => :add_to_enhancements,
449
+ 'b' => :add_to_bug_fixes,
450
+ 's' => :add_to_security,
451
+ 'c' => :add_to_compatibility,
452
+ 'd' => :add_to_deprecations
453
+ }
454
+ send(tbl[main_category], log)
455
+ end
456
+
457
+ # Auto commit
458
+ files = `git diff --exit-code --name-only`
459
+ files = files.split
460
+ if (files.size == 1) && (files[0] == "CHANGELOG.md")
461
+ puts "chlog: Able to commit the new Changelog, input y/yes/blank to agree, or others to refuse"
462
+ print '>'
463
+ case STDIN.gets.chomp.downcase
464
+ when '', 'yes', 'y'
465
+ system("git add #$Changelog_file && git commit -m 'Update the Changelog' ")
466
+ else
467
+ "do nothing"
468
+ end
469
+ end
470
+ end
471
+
472
+
473
+ #############
474
+ # main
475
+ #############
476
+
477
+ if __FILE__ == $0
478
+
479
+ if $*.size == 0
480
+ if File.exists? $Changelog_file
481
+ puts "chlog: Already exists Changelog (#$Changelog_file)"
482
+ puts " Use chlog -h to see options"
483
+ else
484
+ get_changelog
485
+ end
486
+ exit
487
+ end
488
+
489
+ action = $*[0]
490
+ if $*[1] =~ /--(.*)/
491
+ puts "-> DEBUG: #$1"
492
+ $sub_category = $1
493
+ log = $*[2..].join(' ')
494
+ else
495
+ $sub_category = nil
496
+ log = $*[1..].join(' ')
497
+ end
498
+
499
+
500
+ case action
501
+ when "-h", "--help" then help()
502
+ when "-n" then add_to_new_features(log)
503
+ when "-e" then add_to_enhancements(log)
504
+ when "-b" then add_to_bug_fixes(log)
505
+ when "-s" then add_to_security(log)
506
+ when "-c" then add_to_compatibility(log)
507
+ when "-d" then add_to_deprecations(log)
508
+ when "-r" then release_new_version($*[1])
509
+ when "-g" then add_with_git($*[1], $*[2])
510
+ else
511
+ if action =~ /^-[^-]*$/
512
+ puts "chlog: Unknown option!"
513
+ exit 1
514
+ else
515
+ if $*[0] =~ /^--(.*)/
516
+ $sub_category = $1
517
+ log = $*[1..].join(' ')
518
+ else
519
+ $sub_category = nil
520
+ log = $*[0..].join(' ')
521
+ end
522
+ puts "chlog: Auto determine log category"
523
+ add_log_sensitive(log)
524
+ end
525
+ end
526
+
527
+
528
+ # end main
529
+ end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chlog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: '1.6'
5
5
  platform: ruby
6
6
  authors:
7
- - Aoran Zeng
8
- autorequire:
9
- bindir: exe
7
+ - ccmywish
8
+ autorequire:
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-09 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: highline
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.0'
11
+ date: 2022-04-09 00:00:00.000000000 Z
12
+ dependencies: []
27
13
  description: 'This command line tool `chlog` helps generate and maintain the Changelog
28
14
  of your projects.
29
15
 
@@ -34,16 +20,14 @@ executables:
34
20
  extensions: []
35
21
  extra_rdoc_files: []
36
22
  files:
37
- - exe/chlog
38
- - lib/chlog.rb
39
- - lib/chlog/version.rb
23
+ - bin/chlog
40
24
  homepage: https://github.com/ccmywish/chlog
41
25
  licenses:
42
26
  - MIT
43
27
  metadata:
44
28
  bug_tracker_uri: https://github.com/ccmywish/chlog/issues
45
29
  source_code_uri: https://github.com/ccmywish/chlog
46
- post_install_message:
30
+ post_install_message:
47
31
  rdoc_options: []
48
32
  require_paths:
49
33
  - lib
@@ -58,8 +42,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
42
  - !ruby/object:Gem::Version
59
43
  version: '0'
60
44
  requirements: []
61
- rubygems_version: 3.4.8
62
- signing_key:
45
+ rubygems_version: 3.3.7
46
+ signing_key:
63
47
  specification_version: 4
64
- summary: Help maintain Changelog on the command line!
48
+ summary: 'chlog: help maintain Changelog'
65
49
  test_files: []
data/exe/chlog DELETED
@@ -1,82 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # ------------------------------------------------------
3
- # File : chlog.rb
4
- # Authors : Aoran Zeng <ccmywish@qq.com>
5
- # Created on : <2022-03-18>
6
- # Last modified : <2023-05-09>
7
- #
8
- # chlog:
9
- #
10
- # Maintain your project's Changelog on the cli.
11
- # ------------------------------------------------------
12
-
13
- require 'chlog'
14
-
15
- module Chlog::CLI
16
-
17
- def self.run
18
-
19
- args = $*.dup
20
-
21
- if args.size == 0
22
- help or exit
23
- end
24
-
25
- action = args[0]
26
-
27
- case action
28
- when "-h", "--help" then help or exit end
29
-
30
- logger = Chlog::Logger.new
31
-
32
- case action
33
- when "-g" then exit logger.generate_changelog
34
- when "-r" then exit logger.release_new_version(args[1])
35
- end
36
-
37
- if args[1] =~ /^--(.*)/
38
- logger.sub_category = $1
39
- logger.log = args[2..].join(' ')
40
- else
41
- logger.sub_category = nil
42
- logger.log = args[1..].join(' ')
43
- end
44
-
45
- case action
46
- when /-[nebscd]/
47
- logger.take_action(action)
48
- else
49
- # action =~ /^-[^-]*$/
50
- abort "chlog: Unknown option!"
51
- end
52
- end
53
-
54
-
55
- def self.help
56
- puts <<~EOH
57
- chlog (v#{Chlog::GEM_VERSION}): Help maintain the Changelog of your projects
58
-
59
- Usage:
60
-
61
- chlog -g Generate CHANGELOG.md in git root
62
- chlog -r <3.14> Release version to v3.14
63
-
64
- Add log:
65
-
66
- chlog <-main category> [--sub category] <log>
67
-
68
- Main Category:
69
-
70
- -n Add log to New features
71
- -e Add log to Enhancements
72
- -b Add log to Bug fixes
73
- -s Add log to Security
74
- -c Add log to Compatibility
75
- -d Add log to Deprecations
76
-
77
- EOH
78
- end
79
-
80
- end
81
-
82
- Chlog::CLI.run
data/lib/chlog/version.rb DELETED
@@ -1,16 +0,0 @@
1
- # ---------------------------------------------------------------
2
- # File : version.rb
3
- # Authors : Aoran Zeng <ccmywish@qq.com>
4
- # Created on : <2023-05-09>
5
- # Last modified : <2023-05-09>
6
- #
7
- # version:
8
- #
9
- # Lib version
10
- # ---------------------------------------------------------------
11
-
12
- module Chlog
13
-
14
- GEM_VERSION = "0.9.0"
15
-
16
- end
data/lib/chlog.rb DELETED
@@ -1,417 +0,0 @@
1
- # ------------------------------------------------------
2
- # File : chlog.rb
3
- # Authors : Aoran Zeng <ccmywish@qq.com>
4
- # Created on : <2022-04-15>
5
- # Last modified : <2023-05-09>
6
- #
7
- # chlog:
8
- #
9
- # Maintain your project's Changelog on the cli.
10
- # ------------------------------------------------------
11
-
12
- require_relative 'chlog/version'
13
-
14
- class Chlog::Logger
15
-
16
- attr_accessor :sub_category, # 存储次标题
17
- :log, # 存储log
18
- :highline # HighLine 实例
19
- :changelog # CHANGELOG.md 位置
20
-
21
-
22
- def initialize
23
- require 'highline'
24
- @highline = HighLine.new
25
-
26
- require 'open3'
27
- # Prevent current directory is not git directory
28
- Open3.popen3("git rev-parse --show-toplevel") do |i, o, err, t|
29
- if err.read.include?("fatal: not a git repository")
30
- puts "chlog: Not a git directory!" or exit(false)
31
- else
32
- @changelog = `git rev-parse --show-toplevel`.chomp + '/CHANGELOG.md'
33
- end
34
- end
35
- end
36
-
37
- require 'date'
38
- TODAY = Date.today.to_s
39
-
40
- UNRELEASED_TITLE = "## [Unreleased](#) (#{TODAY})"
41
-
42
- TEMPLATE = <<~EOT
43
- # Changelog
44
-
45
- #{UNRELEASED_TITLE}
46
-
47
- <br>
48
-
49
- ## [Initialize](#) (#{TODAY})
50
-
51
- <br>
52
-
53
- <hr>
54
-
55
- This Changelog is maintained with [chlog](https://github.com/ccmywish/chlog)
56
-
57
- EOT
58
-
59
-
60
- def generate_changelog
61
- file = @changelog
62
- if File.exist? file
63
- puts "chlog: Already exists Changelog (#@changelog)" or return false
64
- else
65
- File.write(file, TEMPLATE)
66
- puts "chlog: Generate #@changelog OK!" or return true
67
- end
68
- end
69
-
70
-
71
- def get_changelog
72
- file = @changelog
73
- if File.exist? file
74
- return File.read file
75
- else
76
- abort "chlog: No Changelog exists, use 'chlog -g' to generate!"
77
- end
78
- end
79
-
80
- end
81
-
82
-
83
- class Chlog::Logger
84
-
85
- def match_unreleased?(str)
86
- str =~ /^## \[Unreleased\]\(.*\) \(\d{4}-\d\d-\d\d\)/
87
- end
88
-
89
- def match_unreleased_fail!(str)
90
- unless match_unreleased?(str)
91
- puts "chlog: Unmatched format with chlog"
92
- puts
93
- # "#{lns[1][1..]}"
94
- abort "Unreleased version must be the third line"
95
- end
96
- end
97
-
98
- def match_new_features?(str)
99
- str =~ /^### New features:/
100
- end
101
-
102
- def match_enhancements?(str)
103
- str =~ /^### Enhancements:/
104
- end
105
-
106
- def match_bug_fixes?(str)
107
- str =~ /^### Bug fixes:/
108
- end
109
-
110
- def match_security?(str)
111
- str =~ /^### Security:/
112
- end
113
-
114
- def match_compatibility?(str)
115
- str =~ /^### Compatibility:/
116
- end
117
-
118
- def match_deprecations?(str)
119
- str =~ /^### Deprecations:/
120
- end
121
-
122
-
123
- def next_version_index(lns_array)
124
- nvi = lns_array[3..].each_with_index {break _2 if _1.start_with?("## [") }
125
- nvi += 3
126
- end
127
-
128
- def next_category_index(lns_array)
129
- nci = lns_array[3...nvi].each_with_index {break _2 if _1.start_with?("### ") }
130
-
131
- # The not match return value is not nil!! But an array!!
132
- if nci.is_a(Integer) then nci += 3
133
- else nil end
134
- end
135
-
136
- =begin
137
- ### New features:
138
-
139
- - xaaaaa
140
- - xbbbbb
141
- - xccccc [-> this]
142
- =end
143
- def find_main_category_last_list_item_index(lns,
144
- main_cat_index,
145
- first_lower_order_category_index)
146
- mci = main_cat_index
147
- nci = first_lower_order_category_index
148
-
149
- list_i = lns[mci+2..nci].each_with_index do
150
- break _2 if _1 !~ /^- .*/
151
- end
152
- list_i += mci+2 - 1
153
- end
154
-
155
-
156
- LIST__Feature = %w[
157
- new_features enhancements bug_fixes
158
- security compatibility deprecations
159
- ]
160
-
161
- # New features
162
- # Enhancements
163
- # Bug fixes
164
- # Security
165
- # Compatibility
166
- # Deprecations
167
- LIST__Main_Category = LIST__Feature.map do
168
- _1.split('_').join(' ').capitalize
169
- end
170
-
171
- # match_new_features?
172
- # match_enhancements?
173
- # match_ ...
174
- LIST__Match_Method = LIST__Feature.map do
175
- ('match_' + _1 + '?').to_sym
176
- end
177
-
178
- =begin
179
- {
180
- 1 => :add_to_new_features,
181
- 2 => :add_to_enhancements,
182
- ...
183
- }
184
- =end
185
- HASH__Order_To_AddTo_Method = ([1,2,3,4,5,6].zip LIST__Feature.map {|m| ('add_to_' + m).to_sym }).to_h
186
-
187
-
188
-
189
- def take_action(action)
190
- options = "nebscd"
191
-
192
- =begin
193
- {
194
- "-n" => "new_features", "-e" => "enhancements", "-b" => "bug_fixes",
195
- "-s" => "security", "-c" => "compatibility", "-d" => "deprecations"
196
- }
197
- =end
198
- action_table = options.chars.map do |op|
199
- '-' + op
200
- end.zip(LIST__Feature).to_h
201
-
202
- public_send "add_to_#{action_table[action]}"
203
- end
204
-
205
-
206
- def first_lower_order_category_index(lns_array, category_order)
207
-
208
- o = category_order
209
-
210
- nvi = next_version_index(lns_array)
211
-
212
- while o < LIST__Match_Method.size
213
- lns_array[0...nvi].each_with_index do
214
- return _2 if send(LIST__Match_Method[o], _1)
215
- end
216
- o += 1
217
- end
218
-
219
- # Next version above
220
- return (nvi - 2)
221
- end
222
-
223
-
224
- # A meta function: do the real work other 6 functions delegate
225
- #
226
- # This function detect the main category, and then handle the
227
- # sub category.
228
- def meta_add_to_a_category(log, main_category_order, category)
229
-
230
- content = get_changelog
231
- lns = content.lines
232
-
233
- match_unreleased_fail!(lns[2])
234
-
235
- nvi = next_version_index(lns)
236
- # To find the existing category line
237
- main_cat_i = lns[0...nvi].each_with_index do
238
- # Adjust to index of the order table
239
- break _2 if send(LIST__Match_Method[main_category_order-1], _1)
240
- end
241
-
242
- #
243
- # Always update to latest time when making a log
244
- #
245
- # We must add a "\n" because every element of the array
246
- # is a sentence with a trailing newline, then they can
247
- # be 'joined' to a working long string
248
- #
249
- lns[2] = UNRELEASED_TITLE + "\n"
250
-
251
- f_l_o_c_i = first_lower_order_category_index(lns, main_category_order)
252
-
253
- if main_cat_i.class != Integer
254
- ################################################################################
255
- # The main category not exists
256
- ################################################################################
257
-
258
-
259
- ########################################
260
- if @sub_category
261
-
262
- # Because the main category not exists,
263
- # nor does the sub category
264
- #
265
- sub_cat_i = f_l_o_c_i
266
- to_wr = lns[0...sub_cat_i].join + "### #{category}:\n\n" + "**#{@sub_category}**\n\n" + ' - ' + log + "\n\n"
267
- File.write(@changelog, to_wr + lns[sub_cat_i..].join)
268
-
269
- puts "chlog: Add log to #{category}/#{@sub_category}"
270
- return
271
- end # end of if @sub_category
272
- ########################################
273
-
274
- # situation: no sub category
275
-
276
- # Not need adjust to the index of the order table
277
- log_loc = f_l_o_c_i
278
- puts "chlog: Add '#{category}' category"
279
- to_wr = lns[0...(log_loc)].join + "### #{category}:\n\n" + '- ' + log + "\n"
280
- File.write(@changelog, to_wr + lns[log_loc-1..].join)
281
-
282
- else
283
- ################################################################################
284
- # The main category exists
285
- ################################################################################
286
-
287
-
288
- ########################################
289
- if @sub_category
290
-
291
- # from first list item to next main cat
292
- # search if sub cat already exists
293
- sub_cat_i = lns[main_cat_i+2...f_l_o_c_i].each_with_index do
294
- break _2 if _1 =~ /^\*\*#{@sub_category}\*\*/
295
- end
296
-
297
- if !sub_cat_i.is_a?(Integer)
298
- # the sub category not exists
299
-
300
- sub_cat_i = 2 + find_main_category_last_list_item_index(lns,main_cat_i,f_l_o_c_i)
301
- to_wr = lns[0...sub_cat_i].join + "**#{@sub_category}**\n\n" + ' - ' + log + "\n\n"
302
- File.write(@changelog, to_wr + lns[sub_cat_i..].join)
303
- else
304
- # the sub category exists
305
-
306
- sub_cat_i += main_cat_i+2
307
- to_wr = lns[0..sub_cat_i+1].join + ' - ' + log + "\n"
308
- File.write(@changelog, to_wr + lns[sub_cat_i+2..].join)
309
- end
310
-
311
- puts "chlog: Add log to #{category}/#{@sub_category}"
312
- return
313
- end # end of if @sub_category
314
- ########################################
315
-
316
-
317
-
318
- # situation: no sub category
319
-
320
- to_wr = lns[0..main_cat_i+1].join + '- ' + log + "\n"
321
-
322
- # main category list should be separated with
323
- # sub category
324
- if lns[main_cat_i+2] =~ /\*\*.*/
325
- to_wr += "\n"
326
- end
327
- File.write(@changelog, to_wr + lns[main_cat_i+2..].join)
328
- end
329
-
330
- puts "chlog: Add log to #{category}"
331
- end
332
-
333
-
334
-
335
- # main category order: 1
336
- def add_to_new_features
337
- meta_add_to_a_category(@log, 1, "New features")
338
- end
339
-
340
- # main category order: 2
341
- def add_to_enhancements
342
- meta_add_to_a_category(@log, 2, "Enhancements")
343
- end
344
-
345
- # main_category_order: 3
346
- def add_to_bug_fixes
347
- meta_add_to_a_category(@log, 3, "Bug fixes")
348
- end
349
-
350
- # main_category_order: 4
351
- def add_to_security
352
- meta_add_to_a_category(@log, 4, "Security")
353
- end
354
-
355
- # main_category_order: 5
356
- def add_to_compatibility
357
- meta_add_to_a_category(@log, 5, "Compatibility")
358
- end
359
-
360
- # The last of order table
361
- # main_category_order: 6
362
- def add_to_deprecations
363
- meta_add_to_a_category(@log, 6, "Deprecations")
364
- end
365
-
366
- # Release a version
367
- def release_new_version(ver)
368
- if ver.nil?
369
- puts "chlog: No version supplied!"; puts; abort "Use chlog -r <version>!"
370
- end
371
-
372
- if !ver.downcase.start_with?('v') and ver[0].match? /\d/
373
- ver = 'v' + ver
374
- end
375
-
376
- content = get_changelog
377
- lns = content.lines
378
-
379
- match_unreleased_fail!(lns[2])
380
-
381
- header = <<~EOF
382
- # Changelog
383
-
384
- ## [Unreleased](#) (#{TODAY})
385
-
386
- <br>
387
-
388
- EOF
389
-
390
- new_version = "## [#{ver}](#) (#{TODAY})\n"
391
- new_cont = header + new_version + lns[3..].join('')
392
- File.write(@changelog, new_cont)
393
- puts "chlog: Release #{ver} in Changelog!" or return true
394
- end
395
-
396
-
397
- # Help user interactively
398
- def ask_user_category
399
- category = @highline.choose do |menu|
400
- menu.index_color = :rgb_77bbff
401
- menu.prompt = "What main category?"
402
- # return number!!! not string!!!
403
- menu.choices(*LIST__Main_Category)
404
- end
405
-
406
- option = LIST__Main_Category.index(category)
407
-
408
- if @sub_category.nil?
409
- sub = @highline.ask "What sub category? [NIL/sub]"
410
- case sub
411
- when '' then @sub_category = nil
412
- else @sub_category = sub end
413
- end
414
- return option
415
- end
416
-
417
- end