chlog 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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: []