chlog 0.8.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.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/bin/chlog +422 -0
  3. data/lib/chlog.rb +85 -0
  4. metadata +64 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6e0955eb92616d3ab8bbc9a1df682ac61afca55ab2ee8c1dad5d33d7cae7714c
4
+ data.tar.gz: bd22473954d3a15da39117a4b3dfe917526cc6eb7ca91475d31b7e86204e6964
5
+ SHA512:
6
+ metadata.gz: be7404fe7d69f6197bad15a51a893fb7825aff2e7e7c710b4263f225d406c44ff1da0f62e3383021ecaea129c10ec582c31b23e88b0f2272b0063afdcad19772
7
+ data.tar.gz: 0c5ac3d320c75ea464b1a10a016a57d8d25988bc2b13bb350f3927248966c873a4506571c0671e0aeba6f14c0c995c6060130063a749e5af847a9ccf8cc7810a
data/bin/chlog ADDED
@@ -0,0 +1,422 @@
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 : <2023-02-12>
7
+ #
8
+ # chlog:
9
+ #
10
+ # Maintain your project's Changelog on the cli.
11
+ # ------------------------------------------------------
12
+
13
+ require 'chlog'
14
+
15
+ class Chlog::CliHandler
16
+
17
+ def initialize(args)
18
+
19
+ if args.size == 0
20
+ help or exit
21
+ end
22
+
23
+ action = args[0]
24
+
25
+ case action
26
+ when "-h", "--help" then help or exit end
27
+
28
+ logger = Chlog::Logger.new
29
+
30
+ case action
31
+ when "-g" then exit logger.generate_changelog
32
+ when "-r" then exit logger.release_new_version(args[1])
33
+ end
34
+
35
+ if args[1] =~ /^--(.*)/
36
+ logger.sub_category = $1
37
+ logger.log = args[2..].join(' ')
38
+ else
39
+ logger.sub_category = nil
40
+ logger.log = args[1..].join(' ')
41
+ end
42
+
43
+ case action
44
+ when /-[nebscd]/
45
+ logger.take_action(action)
46
+ else
47
+ # action =~ /^-[^-]*$/
48
+ abort "chlog: Unknown option!"
49
+ end
50
+ end
51
+
52
+
53
+ def help
54
+ puts <<~EOH
55
+ chlog (v#{Chlog::GEM_VERSION}): Help maintain the Changelog of your projects
56
+
57
+ Usage:
58
+
59
+ chlog -g Generate CHANGELOG.md in git root
60
+ chlog -r <3.14> Release version to v3.14
61
+
62
+ Add log:
63
+
64
+ chlog <-main category> [--sub category] <log>
65
+
66
+ Main Category:
67
+
68
+ -n Add log to New features
69
+ -e Add log to Enhancements
70
+ -b Add log to Bug fixes
71
+ -s Add log to Security
72
+ -c Add log to Compatibility
73
+ -d Add log to Deprecations
74
+
75
+ EOH
76
+ end
77
+
78
+ end
79
+
80
+
81
+
82
+ class Chlog::Logger
83
+
84
+ def match_unreleased?(str)
85
+ str =~ /^## \[Unreleased\]\(.*\) \(\d{4}-\d\d-\d\d\)/
86
+ end
87
+
88
+ def match_unreleased_fail!(str)
89
+ unless match_unreleased?(str)
90
+ puts "chlog: Unmatched format with chlog"
91
+ puts
92
+ # "#{lns[1][1..]}"
93
+ abort "Unreleased version must be the third line"
94
+ end
95
+ end
96
+
97
+ def match_new_features?(str)
98
+ str =~ /^### New features:/
99
+ end
100
+
101
+ def match_enhancements?(str)
102
+ str =~ /^### Enhancements:/
103
+ end
104
+
105
+ def match_bug_fixes?(str)
106
+ str =~ /^### Bug fixes:/
107
+ end
108
+
109
+ def match_security?(str)
110
+ str =~ /^### Security:/
111
+ end
112
+
113
+ def match_compatibility?(str)
114
+ str =~ /^### Compatibility:/
115
+ end
116
+
117
+ def match_deprecations?(str)
118
+ str =~ /^### Deprecations:/
119
+ end
120
+
121
+
122
+ def next_version_index(lns_array)
123
+ nvi = lns_array[3..].each_with_index {break _2 if _1.start_with?("## [") }
124
+ nvi += 3
125
+ end
126
+
127
+ def next_category_index(lns_array)
128
+ nci = lns_array[3...nvi].each_with_index {break _2 if _1.start_with?("### ") }
129
+
130
+ # The not match return value is not nil!! But an array!!
131
+ if nci.is_a(Integer) then nci += 3
132
+ else nil end
133
+ end
134
+
135
+ =begin
136
+ ### New features:
137
+
138
+ - xaaaaa
139
+ - xbbbbb
140
+ - xccccc [-> this]
141
+ =end
142
+ def find_main_category_last_list_item_index(lns,
143
+ main_cat_index,
144
+ first_lower_order_category_index)
145
+ mci = main_cat_index
146
+ nci = first_lower_order_category_index
147
+
148
+ list_i = lns[mci+2..nci].each_with_index do
149
+ break _2 if _1 !~ /^- .*/
150
+ end
151
+ list_i += mci+2 - 1
152
+ end
153
+
154
+
155
+ LIST__Feature = %w[
156
+ new_features enhancements bug_fixes
157
+ security compatibility deprecations
158
+ ]
159
+
160
+ # New features
161
+ # Enhancements
162
+ # Bug fixes
163
+ # Security
164
+ # Compatibility
165
+ # Deprecations
166
+ LIST__Main_Category = LIST__Feature.map do
167
+ _1.split('_').join(' ').capitalize
168
+ end
169
+
170
+ # match_new_features?
171
+ # match_enhancements?
172
+ # match_ ...
173
+ LIST__Match_Method = LIST__Feature.map do
174
+ ('match_' + _1 + '?').to_sym
175
+ end
176
+
177
+ =begin
178
+ {
179
+ 1 => :add_to_new_features,
180
+ 2 => :add_to_enhancements,
181
+ ...
182
+ }
183
+ =end
184
+ HASH__Order_To_AddTo_Method = ([1,2,3,4,5,6].zip LIST__Feature.map {|m| ('add_to_' + m).to_sym }).to_h
185
+
186
+
187
+
188
+ def take_action(action)
189
+ options = "nebscd"
190
+
191
+ =begin
192
+ {
193
+ "-n" => "new_features", "-e" => "enhancements", "-b" => "bug_fixes",
194
+ "-s" => "security", "-c" => "compatibility", "-d" => "deprecations"
195
+ }
196
+ =end
197
+ action_table = options.chars.map do |op|
198
+ '-' + op
199
+ end.zip(LIST__Feature).to_h
200
+
201
+ public_send "add_to_#{action_table[action]}"
202
+ end
203
+
204
+
205
+ def first_lower_order_category_index(lns_array, category_order)
206
+
207
+ o = category_order
208
+
209
+ nvi = next_version_index(lns_array)
210
+
211
+ while o < LIST__Match_Method.size
212
+ lns_array[0...nvi].each_with_index do
213
+ return _2 if send(LIST__Match_Method[o], _1)
214
+ end
215
+ o += 1
216
+ end
217
+
218
+ # Next version above
219
+ return (nvi - 2)
220
+ end
221
+
222
+
223
+ # A meta function: do the real work other 6 functions delegate
224
+ #
225
+ # This function detect the main category, and then handle the
226
+ # sub category.
227
+ def meta_add_to_a_category(log, main_category_order, category)
228
+
229
+ content = get_changelog
230
+ lns = content.lines
231
+
232
+ match_unreleased_fail!(lns[2])
233
+
234
+ nvi = next_version_index(lns)
235
+ # To find the existing category line
236
+ main_cat_i = lns[0...nvi].each_with_index do
237
+ # Adjust to index of the order table
238
+ break _2 if send(LIST__Match_Method[main_category_order-1], _1)
239
+ end
240
+
241
+ #
242
+ # Always update to latest time when making a log
243
+ #
244
+ # We must add a "\n" because every element of the array
245
+ # is a sentence with a trailing newline, then they can
246
+ # be 'joined' to a working long string
247
+ #
248
+ lns[2] = UNRELEASED_TITLE + "\n"
249
+
250
+ f_l_o_c_i = first_lower_order_category_index(lns, main_category_order)
251
+
252
+ if main_cat_i.class != Integer
253
+ ################################################################################
254
+ # The main category not exists
255
+ ################################################################################
256
+
257
+
258
+ ########################################
259
+ if @sub_category
260
+
261
+ # Because the main category not exists,
262
+ # nor does the sub category
263
+ #
264
+ sub_cat_i = f_l_o_c_i
265
+ to_wr = lns[0...sub_cat_i].join + "### #{category}:\n\n" + "**#{@sub_category}**\n\n" + ' - ' + log + "\n\n"
266
+ File.write(@changelog, to_wr + lns[sub_cat_i..].join)
267
+
268
+ puts "chlog: Add log to #{category}/#{@sub_category}"
269
+ return
270
+ end # end of if @sub_category
271
+ ########################################
272
+
273
+ # situation: no sub category
274
+
275
+ # Not need adjust to the index of the order table
276
+ log_loc = f_l_o_c_i
277
+ puts "chlog: Add '#{category}' category"
278
+ to_wr = lns[0...(log_loc)].join + "### #{category}:\n\n" + '- ' + log + "\n"
279
+ File.write(@changelog, to_wr + lns[log_loc-1..].join)
280
+
281
+ else
282
+ ################################################################################
283
+ # The main category exists
284
+ ################################################################################
285
+
286
+
287
+ ########################################
288
+ if @sub_category
289
+
290
+ # from first list item to next main cat
291
+ # search if sub cat already exists
292
+ sub_cat_i = lns[main_cat_i+2...f_l_o_c_i].each_with_index do
293
+ break _2 if _1 =~ /^\*\*#{@sub_category}\*\*/
294
+ end
295
+
296
+ if !sub_cat_i.is_a?(Integer)
297
+ # the sub category not exists
298
+
299
+ sub_cat_i = 2 + find_main_category_last_list_item_index(lns,main_cat_i,f_l_o_c_i)
300
+ to_wr = lns[0...sub_cat_i].join + "**#{@sub_category}**\n\n" + ' - ' + log + "\n\n"
301
+ File.write(@changelog, to_wr + lns[sub_cat_i..].join)
302
+ else
303
+ # the sub category exists
304
+
305
+ sub_cat_i += main_cat_i+2
306
+ to_wr = lns[0..sub_cat_i+1].join + ' - ' + log + "\n"
307
+ File.write(@changelog, to_wr + lns[sub_cat_i+2..].join)
308
+ end
309
+
310
+ puts "chlog: Add log to #{category}/#{@sub_category}"
311
+ return
312
+ end # end of if @sub_category
313
+ ########################################
314
+
315
+
316
+
317
+ # situation: no sub category
318
+
319
+ to_wr = lns[0..main_cat_i+1].join + '- ' + log + "\n"
320
+
321
+ # main category list should be separated with
322
+ # sub category
323
+ if lns[main_cat_i+2] =~ /\*\*.*/
324
+ to_wr += "\n"
325
+ end
326
+ File.write(@changelog, to_wr + lns[main_cat_i+2..].join)
327
+ end
328
+
329
+ puts "chlog: Add log to #{category}"
330
+ end
331
+
332
+
333
+
334
+ # main category order: 1
335
+ def add_to_new_features
336
+ meta_add_to_a_category(@log, 1, "New features")
337
+ end
338
+
339
+ # main category order: 2
340
+ def add_to_enhancements
341
+ meta_add_to_a_category(@log, 2, "Enhancements")
342
+ end
343
+
344
+ # main_category_order: 3
345
+ def add_to_bug_fixes
346
+ meta_add_to_a_category(@log, 3, "Bug fixes")
347
+ end
348
+
349
+ # main_category_order: 4
350
+ def add_to_security
351
+ meta_add_to_a_category(@log, 4, "Security")
352
+ end
353
+
354
+ # main_category_order: 5
355
+ def add_to_compatibility
356
+ meta_add_to_a_category(@log, 5, "Compatibility")
357
+ end
358
+
359
+ # The last of order table
360
+ # main_category_order: 6
361
+ def add_to_deprecations
362
+ meta_add_to_a_category(@log, 6, "Deprecations")
363
+ end
364
+
365
+ # Release a version
366
+ def release_new_version(ver)
367
+ if ver.nil?
368
+ puts "chlog: No version supplied!"; puts; abort "Use chlog -r <version>!"
369
+ end
370
+
371
+ if !ver.downcase.start_with?('v') and ver[0].match? /\d/
372
+ ver = 'v' + ver
373
+ end
374
+
375
+ content = get_changelog
376
+ lns = content.lines
377
+
378
+ match_unreleased_fail!(lns[2])
379
+
380
+ header = <<~EOF
381
+ # Changelog
382
+
383
+ ## [Unreleased](#) (#{TODAY})
384
+
385
+ <br>
386
+
387
+ EOF
388
+
389
+ new_version = "## [#{ver}](#) (#{TODAY})\n"
390
+ new_cont = header + new_version + lns[3..].join('')
391
+ File.write(@changelog, new_cont)
392
+ puts "chlog: Release #{ver} in Changelog!" or return true
393
+ end
394
+
395
+
396
+ # Help user interactively
397
+ def ask_user_category
398
+ category = @highline.choose do |menu|
399
+ menu.index_color = :rgb_77bbff
400
+ menu.prompt = "What main category?"
401
+ # return number!!! not string!!!
402
+ menu.choices(*LIST__Main_Category)
403
+ end
404
+
405
+ option = LIST__Main_Category.index(category)
406
+
407
+ if @sub_category.nil?
408
+ sub = @highline.ask "What sub category? [NIL/sub]"
409
+ case sub
410
+ when '' then @sub_category = nil
411
+ else @sub_category = sub end
412
+ end
413
+ return option
414
+ end
415
+
416
+ end
417
+
418
+ #############
419
+ # main
420
+ #############
421
+ Chlog::CliHandler.new $*
422
+ exit(true)
data/lib/chlog.rb ADDED
@@ -0,0 +1,85 @@
1
+ # ------------------------------------------------------
2
+ # File : chlog.rb
3
+ # Authors : ccmywish <ccmywish@qq.com>
4
+ # Created on : <2022-04-15>
5
+ # Last modified : <2023-02-12>
6
+ #
7
+ # chlog:
8
+ #
9
+ # Maintain your project's Changelog on the cli.
10
+ # ------------------------------------------------------
11
+
12
+ module Chlog
13
+
14
+ GEM_VERSION = "0.8.1"
15
+
16
+ end
17
+
18
+
19
+ class Chlog::Logger
20
+
21
+ attr_accessor :sub_category, # 存储次标题
22
+ :log, # 存储log
23
+ :highline # HighLine 实例
24
+ :changelog # CHANGELOG.md 位置
25
+
26
+
27
+ def initialize
28
+ require 'highline'
29
+ @highline = HighLine.new
30
+
31
+ require 'open3'
32
+ # Prevent current directory is not git directory
33
+ Open3.popen3("git rev-parse --show-toplevel") do |i, o, err, t|
34
+ if err.read.include?("fatal: not a git repository")
35
+ puts "chlog: Not a git directory!" or exit(false)
36
+ else
37
+ @changelog = `git rev-parse --show-toplevel`.chomp + '/CHANGELOG.md'
38
+ end
39
+ end
40
+ end
41
+
42
+ require 'date'
43
+ TODAY = Date.today.to_s
44
+
45
+ UNRELEASED_TITLE = "## [Unreleased](#) (#{TODAY})"
46
+
47
+ TEMPLATE = <<~EOT
48
+ # Changelog
49
+
50
+ #{UNRELEASED_TITLE}
51
+
52
+ <br>
53
+
54
+ ## [Initialize](#) (#{TODAY})
55
+
56
+ <br>
57
+
58
+ <hr>
59
+
60
+ This Changelog is maintained with [chlog](https://github.com/ccmywish/chlog)
61
+
62
+ EOT
63
+
64
+
65
+ def generate_changelog
66
+ file = @changelog
67
+ if File.exist? file
68
+ puts "chlog: Already exists Changelog (#@changelog)" or return false
69
+ else
70
+ File.write(file, TEMPLATE)
71
+ puts "chlog: Generate #@changelog OK!" or return true
72
+ end
73
+ end
74
+
75
+
76
+ def get_changelog
77
+ file = @changelog
78
+ if File.exist? file
79
+ return File.read file
80
+ else
81
+ abort "chlog: No Changelog exists, use 'chlog -g' to generate!"
82
+ end
83
+ end
84
+
85
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chlog
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.1
5
+ platform: ruby
6
+ authors:
7
+ - ccmywish
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-02-12 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'
27
+ description: 'This command line tool `chlog` helps generate and maintain the Changelog
28
+ of your projects.
29
+
30
+ '
31
+ email: ccmywish@qq.com
32
+ executables:
33
+ - chlog
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - bin/chlog
38
+ - lib/chlog.rb
39
+ homepage: https://github.com/ccmywish/chlog
40
+ licenses:
41
+ - MIT
42
+ metadata:
43
+ bug_tracker_uri: https://github.com/ccmywish/chlog/issues
44
+ source_code_uri: https://github.com/ccmywish/chlog
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubygems_version: 3.3.26
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: 'chlog: help maintain Changelog'
64
+ test_files: []