chlog 0.9.0 → 1.6.1.alpha

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