milestoner 18.4.0 → 18.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f42cba7a4f2b93a05d7fcf25fb973e2a241c8d1813a143baa779c2e1a310f1ed
4
- data.tar.gz: 73635a67814d59b11bae524f45cb4878196aba7e302fa595ecedaaf89e350a6a
3
+ metadata.gz: 013c7206025524458c33b20bceec9005313ae98a1ae4c6f93030548886bf24c2
4
+ data.tar.gz: 95a22be79d0443573db5b347a1f519c99ea2eab1c0298f8098824a1171e0d104
5
5
  SHA512:
6
- metadata.gz: 9fcf5478cee6c0a63811cb133d27ae4bc292da15bacdbdb65f2edd29375057f87c23f15f4780ae68539439ed3c5c2011989477ea4c530b32effa5659f46735b1
7
- data.tar.gz: a9e17509fa39de1247896518da061daa4586afbff8e905b5934728e5269e448ef973c1ffa1ac1136efd6d01a275912fe872c1fe84876c65c25dbaf7e32fed75a
6
+ metadata.gz: ef5612eea45a857439702238c5fc40a5ecdc01d024a60815b07d69ba9eea1fe4eced7e88fc4f62574445dd92df4e6916ec3522d062153280c03c7bdee9fcc111
7
+ data.tar.gz: e6f69f7dea0b85b11af8ee52060692141e27cff663ace8313694ed48745f31671026a9ef5f0afcabc9bdb089e7d5edf5c236b219b28f366a18fc5f0fa1a879d6
checksums.yaml.gz.sig CHANGED
Binary file
data/README.adoc CHANGED
@@ -3,6 +3,7 @@
3
3
  :figure-caption!:
4
4
 
5
5
  :ascii_doc_link: link:https://asciidoctor.org/docs/what-is-asciidoc[ASCII Doc]
6
+ :ascii_doctor_link: link:https://asciidoctor.org[Asciidoctor]
6
7
  :cff_link: link:https://github.com/citation-file-format/ruby-cff[CFF]
7
8
  :etcher_link: link:https://alchemists.io/projects/etcher[Etcher]
8
9
  :firefox_link: link:https://www.mozilla.org/en-US/firefox[Firefox]
@@ -11,8 +12,8 @@
11
12
  :git_commit_anatomy_link: link:https://alchemists.io/articles/git_commit_anatomy[Git Commit Anatomy]
12
13
  :git_link: link:https://git-scm.com[Git]
13
14
  :git_lint_link: link:https://alchemists.io/projects/git-lint[Git Lint]
14
- :git_trailers_link: link:https://alchemists.io/articles/git_trailers[Git Trailers]
15
15
  :git_notes_link: link:https://alchemists.io/articles/git_notes[Git Notes]
16
+ :git_trailers_link: link:https://alchemists.io/articles/git_trailers[Git Trailers]
16
17
  :hanami_link: link:https://hanamirb.org[Hanami]
17
18
  :hanami_views_link: link:https://alchemists.io/articles/hanami_views[Hanami Views]
18
19
  :hanamismith_link: link:https://alchemists.io/projects/hanamismith[Hanamismith]
@@ -21,12 +22,15 @@
21
22
  :markdown_link: link:https://daringfireball.net/projects/markdown[Markdown]
22
23
  :marked_link: link:https://marked2app.com[Marked 2]
23
24
  :net_news_wire_link: link:https://netnewswire.com[NetNewsWire]
25
+ :redcarpet_link: link:https://github.com/vmg/redcarpet[Redcarpet]
26
+ :rouge_link: link:https://rouge.jneen.net[Rouge]
24
27
  :ruby_link: link:https://www.ruby-lang.org[Ruby]
25
28
  :rubygems_link: link:https://rubygems.org[RubyGems]
26
29
  :rubysmith_link: link:https://alchemists.io/projects/rubysmith[Rubysmith]
27
30
  :runcom_link: link:https://alchemists.io/projects/runcom[Runcom]
31
+ :sanitize_link: link:https://github.com/rgrove/sanitize[Sanitize]
28
32
  :strict_semantic_versioning_link: link:https://alchemists.io/articles/strict_semantic_versioning[Strict Semantic Versioning]
29
- :string_formats_link: link:https://ruby-doc.org/3.3.0/format_specifications_rdoc.html[String Formats]
33
+ :string_formats_link: link:https://docs.ruby-lang.org/en/master/format_specifications_rdoc.html[String Formats]
30
34
  :syndication_link: link:https://alchemists.io/articles/syndication[Syndication]
31
35
  :versionaire_link: link:https://alchemists.io/projects/versionaire[Versionaire]
32
36
  :xdg_link: link:https://alchemists.io/projects/xdg[XDG]
@@ -50,7 +54,7 @@ toc::[]
50
54
 
51
55
  The following are screenshots of using this gem to render release notes for the {lode_link} gem. Even though {lode_link} is used for example purposes, keep in mind that Milestoner can be used for _any project and/or programming language_.
52
56
 
53
- === ASCII Doc Format
57
+ === ASCII Doc
54
58
 
55
59
  image:https://alchemists.io/images/projects/milestoner/screenshots/build-ascii_doc-collapsed.png[Release Notes,width=1149,height=830,role=focal_point]
56
60
 
@@ -59,7 +63,7 @@ image:https://alchemists.io/images/projects/milestoner/screenshots/build-ascii_d
59
63
  * *Command*: `milestoner build --format ascii_doc`
60
64
  * *Renderer*: {ascii_doc_link}
61
65
 
62
- === Feed Format
66
+ === Feed
63
67
 
64
68
  image:https://alchemists.io/images/projects/milestoner/screenshots/build-feed-collapsed.png[Release Notes,width=1109,height=1143,role=focal_point]
65
69
 
@@ -75,14 +79,14 @@ image:https://alchemists.io/images/projects/milestoner/screenshots/build-markdow
75
79
  * *Command*: `milestoner build --format markdown`
76
80
  * *Renderer*: {marked_link}
77
81
 
78
- === Stream Format
82
+ === Stream
79
83
 
80
84
  image:https://alchemists.io/images/projects/milestoner/screenshots/build-stream.png[Release Notes,width=586,height=341,role=focal_point]
81
85
 
82
86
  * *Command*: `milestoner build --format stream`
83
87
  * *Renderer*: {iterm_link}
84
88
 
85
- === Web Format
89
+ === Web
86
90
 
87
91
  image:https://alchemists.io/images/projects/milestoner/screenshots/build-web-collapsed.png[Release Notes,width=1195,height=878,role=focal_point]
88
92
 
@@ -112,7 +116,7 @@ image:https://alchemists.io/images/projects/milestoner/screenshots/build-web-exp
112
116
  ** Stream (console)
113
117
  ** link:https://html.spec.whatwg.org/multipage[Web]
114
118
  * Supports {git_notes_link}.
115
- * Supports customization via your personal {xdg_link} and {hanami_views_link} configuration.
119
+ * Supports customization via your personal {xdg_link}, {runcom_link}, and/or {hanami_views_link} configuration.
116
120
 
117
121
  == Requirements
118
122
 
@@ -297,34 +301,38 @@ User information should be sourced from whatever service you use for managing yo
297
301
  [source,bash]
298
302
  ----
299
303
  milestoner cache --list
300
- # 🟢 Listing users...
301
- # 🟢 No users found.
304
+ # 🟢 [milestoner] Listing users...
305
+ # 🟢 [milestoner] No users found.
302
306
 
303
307
  milestoner cache --create "111,jsmith,Jane Smith"
304
- # 🟢 Created: "Jane Smith"
308
+ # 🟢 [milestoner] Created: "Jane Smith"
305
309
 
306
310
  milestoner cache --create "222,jdoe,John Doe"
307
- # 🟢 Created: "John Doe"
311
+ # 🟢 [milestoner] Created: "John Doe"
308
312
 
309
313
  milestoner cache --create "333,jgrey,Jill Grey"
310
- # 🟢 Created: "Jill Grey"
314
+ # 🟢 [milestoner] Created: "Jill Grey"
311
315
 
312
316
  milestoner cache --list
313
- # 🟢 Listing users...
314
- # 111, jsmith, Jane Smith
315
- # 222, jdoe, John Doe
316
- # 333, jgrey, Jill Grey
317
+ # 🟢 [milestoner] Listing users...
318
+ # External ID, Handle, Name
319
+ # -------------------------
320
+ # "111", "jsmith", "Jane Smith"
321
+ # "222", "jdoe", "John Doe"
322
+ # "333", "jgrey", "Jill Grey"
317
323
 
318
324
  milestoner cache --delete "Jill Grey"
319
- 🟢 Deleted: "Jill Grey".
325
+ # 🟢 [milestoner] Deleted: "Jill Grey".
320
326
 
321
327
  milestoner cache --list
322
- # 🟢 Listing users...
323
- # 111, jsmith, Jane Smith
324
- # 222, jdoe, John Doe
328
+ # 🟢 [milestoner] Listing users...
329
+ # External ID, Handle, Name
330
+ # -------------------------
331
+ # "111", "jsmith", "Jane Smith"
332
+ # "222", "jdoe", "John Doe"
325
333
 
326
334
  milestoner cache --info
327
- # 🟢 Path: /Users/demo/.cache/milestoner/database.store.
335
+ # 🟢 [milestoner] Path: /Users/bkuhlmann/.cache/milestoner/database.store.
328
336
  ----
329
337
 
330
338
  💡 Use `+https://api.github.com/users/<handle>+` to acquire the external ID for any GitHub user.
@@ -333,7 +341,7 @@ Once team member information is stored in your cache, you'll be able to build re
333
341
 
334
342
  If you don't use the cache, your release notes use a question mark (?) and _unknown_ for team members as highlighted below:
335
343
 
336
- image:https://alchemists.io/images/projects/milestoner/screenshots/no_cache.png[Usage,width=851,height=571,role=focal_point]
344
+ image:https://alchemists.io/images/projects/milestoner/screenshots/no_cache.png[Usage,width=916,height=397,role=focal_point]
337
345
 
338
346
  === Build
339
347
 
@@ -344,8 +352,9 @@ The build command allows you to quickly build release notes to check the current
344
352
  [source,bash]
345
353
  ----
346
354
  milestoner build --format web
347
- # 🟢 Building milestone...
348
- # 🟢 Milestone built: /Users/bkuhlmann/Engineering/OSS/milestoner/tmp/milestone
355
+ # 🟢 [milestoner] Building Milestoner (web)...
356
+ # 🟢 [milestoner] Built: /Users/bkuhlmann/Engineering/OSS/milestoner/tmp/milestones/page.css.
357
+ # 🟢 [milestoner] Built: /Users/bkuhlmann/Engineering/OSS/milestoner/tmp/milestones/index.html.
349
358
  ----
350
359
 
351
360
  The above command is so useful that I use the following `msw` (i.e. Milestoner Web) Bash alias to build current release notes or release notes for several tags:
@@ -357,22 +366,113 @@ The above command is so useful that I use the following `msw` (i.e. Milestoner W
357
366
  # Parameters: $1 (optional): Maximum tags to build. Default: 1.
358
367
  msw() {
359
368
  local max=${1:-1}
369
+ local root="tmp/milestones"
370
+ local path="$root/index.html"
360
371
 
361
372
  rm -rf tmp/milestones
362
373
 
363
374
  if [[ "$max" == 1 ]]; then
364
- milestoner build --max "$max" --format web && open "tmp/milestones/index.html"
375
+ milestoner build --max "$max" --format web
376
+
377
+ if [[ -f "$path" ]]; then
378
+ open "$path"
379
+ fi
365
380
  else
366
381
  milestoner build --max "$max" --stylesheet "../page" --format web
367
- ruby -run -e httpd "tmp/milestones" --port 3030 &
368
- open "http://localhost:3030"
369
- fg
382
+
383
+ if [[ -d "$root" ]]; then
384
+ ruby -run -e httpd "tmp/milestones" --port 3030 &
385
+ open "http://localhost:3030"
386
+ fg
387
+ fi
370
388
  fi
371
389
  }
372
390
  ----
373
391
 
374
392
  Check out the help documentation (i.e. `milestoner build --help`) for addition usage that explains what command line options you can use to overwrite the current configuration.
375
393
 
394
+ ==== Commits
395
+
396
+ By default, all {git_link} commit messages support {ascii_doc_link} syntax but you can use {markdown_link} if customized.
397
+
398
+ {ascii_doc_link} is rendered using the {ascii_doctor_link} gem while {markdown_link} is rendered using the {redcarpet_link} gem. Regardless of what renderer you choose, each supports syntax highlighting via the {rouge_link} gem. This also means you can customize the {rouge_style} stylesheet as documented in the xref:_templates[Templates] section below.
399
+
400
+ Here's a couple examples of commit messages using {ascii_doc_link} and {markdown_link} syntax:
401
+
402
+ *ASCII Doc*
403
+
404
+ image:https://alchemists.io/images/projects/milestoner/screenshots/syntax-ascii_doc.png[ASCII Doc,width=950,height=763,role=focal_point]
405
+
406
+ *Markdown*
407
+
408
+ image:https://alchemists.io/images/projects/milestoner/screenshots/syntax-markdown.png[Markdown,width=933,height=921,role=focal_point]
409
+
410
+ 💡 To see an example of what this renders to HTML as, see the xref:_formats[Formats] section below.
411
+
412
+ ==== Sanitization
413
+
414
+ Sanitization of commit messages is handled by the {sanitize_link} gem. This means you can only use a limited set of HTML elements (this includes {ascii_doc_link} and {markdown_link} rendering). Here's what's allowed:
415
+
416
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/b[b]
417
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em[em]
418
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/i[i]
419
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong[strong]
420
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/u[u]
421
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a[a]
422
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/abbr[abbr]
423
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote[blockquote]
424
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/br[br]
425
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite[cite]
426
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code[code]
427
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dd[dd]
428
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dfn[dfn]
429
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl[dl]
430
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt[dt]
431
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd[kbd]
432
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li[li]
433
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark[mark]
434
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol[ol]
435
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/p[p]
436
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre[pre]
437
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q[q]
438
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/s[s]
439
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/samp[samp]
440
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/small[small]
441
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strike[strike]
442
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sub[sub]
443
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sup[sup]
444
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time[time]
445
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul[ul]
446
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/var[var]
447
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio[audio]
448
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details[details]
449
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img[img]
450
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source[source]
451
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span[span]
452
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary[summary]
453
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video[video]
454
+
455
+ The following global attributes are allowed for all elements:
456
+
457
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id[id]
458
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class[class]
459
+
460
+ The following attributes are limited to only a few elements like `a`, `abbr`, and `dfn` for the most part.
461
+
462
+ * link:https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title[title]
463
+
464
+ Other attributes are allowed as well but are specific to each element. Ultimately, if you don't see an attribute being rendered then it's because it's not allowed.
465
+
466
+ ==== Trailers
467
+
468
+ Multiple {git_trailers_link} for your commits are supported which are detailed in the linked article. At a minimum, the `Milestone` trailer is highly recommended since this is how Milestoner handles xref:_automatic_versioning[Automatic Versioning] for you.
469
+
470
+ One of the more powerful features of using {git_trailers_link} in your commit messages is they give you the ability to fully resolve what is defined in your default global xref:_customization[configuration]. Here's a more detailed breakdown:
471
+
472
+ * *Format* (optional): Use `ascii_doc` or `markdown` for the value to control what syntax used to render your commit message. The default is `ascii_doc` but if your configuration uses a different default you can override that per commit message if desired.
473
+ * *Issue* (optional): When supplied, Milestoner will automatically associate your commit with the corresponding issue ID you provide as a value. This works in conjunction with your xref:_customization[configuration].
474
+ * *Milestone* (optional): This is detailed in the xref:_automatic_versioning[Automatic Versioning] section below.
475
+
376
476
  ==== Automatic Versioning
377
477
 
378
478
  As mentioned earlier, the calculation of version information happens automatically based on your last {git_link} tag and any {git_link} commit trailer metadata used. If none of this information is present, then the default version of `0.0.0` is used instead. All of this information is available to you via the following command:
@@ -494,23 +594,27 @@ Of all build formats supported, the web format is the most powerful and feature
494
594
 
495
595
  *With Basic Git Commit*
496
596
 
497
- image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-overview.png[Overview,width=1119,height=910,role=focal_point]
597
+ image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-overview.png[Overview,width=1119,height=902,role=focal_point]
498
598
 
499
599
  *With Collaborators and Signers*
500
600
 
501
- image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-collaborators_and_signers.png[Collaborators and Signers,width=1118,height=1003,role=focal_point]
601
+ image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-collaborators_and_signers.png[Collaborators and Signers,width=903,height=903,role=focal_point]
502
602
 
503
603
  *With Invalid Tag*
504
604
 
505
- image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-tag_invalid.png[Invalid Tag,width=1119,height=910,role=focal_point]
605
+ image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-tag_invalid.png[Invalid Tag,width=881,height=403,role=focal_point]
506
606
 
507
607
  *With Valid Tag*
508
608
 
509
- image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-tag_valid.png[Valid Tag,width=1119,height=910,role=focal_point]
609
+ image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-tag_valid.png[Valid Tag,width=688,height=771,role=focal_point]
510
610
 
511
611
  *With Notes*
512
612
 
513
- image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-notes.png[Notes,width=1119,height=910,role=focal_point]
613
+ image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-notes.png[Notes,width=903,height=757,role=focal_point]
614
+
615
+ *With ASCII Doc/Markdown*
616
+
617
+ image:https://alchemists.io/images/projects/milestoner/screenshots/web_format-asdcii_doc[ASCII Doc,width=908,height=1938,role=focal_point]
514
618
 
515
619
  💡 See {git_notes_link} to learn more.
516
620
 
@@ -8,7 +8,6 @@ module Milestoner
8
8
  # Builds syndicated feed output.
9
9
  class Feed
10
10
  include Milestoner::Import[:settings, :logger]
11
- include Dry::Monads[:result]
12
11
 
13
12
  using Refinements::Pathname
14
13
 
@@ -17,9 +17,6 @@ module Milestoner
17
17
  end
18
18
 
19
19
  def call
20
- settings.build_root.make_path
21
- copy_stylesheet
22
-
23
20
  tagger.call
24
21
  .fmap { |tags| build tags }
25
22
  .alt_map { |message| failure message }
@@ -30,10 +27,14 @@ module Milestoner
30
27
  attr_reader :tagger, :view
31
28
 
32
29
  def build tags
30
+ make_root
31
+ copy_stylesheet
33
32
  tags.each { |tag| write tag }
34
33
  settings.build_root
35
34
  end
36
35
 
36
+ def make_root = settings.build_root.make_path
37
+
37
38
  def copy_stylesheet
38
39
  return unless settings.build_stylesheet
39
40
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "core"
3
4
  require "sod"
4
5
 
5
6
  module Milestoner
@@ -17,17 +18,22 @@ module Milestoner
17
18
  on %w[-c --create], argument: "external_id,handle,name"
18
19
 
19
20
  def call values
20
- process(values).bind { |user| log_info "Created: #{user.name.inspect}" }
21
+ case values.split ","
22
+ in String => external_id, String => handle, String => name
23
+ client.write(:users) { upsert({external_id:, handle:, name:}) }
24
+ .bind { |user| log_info "Created: #{user.name.inspect}" }
25
+ in String, String then log_error "Name must be supplied."
26
+ in [String] then log_error "Handle and Name must be supplied."
27
+ in Core::EMPTY_ARRAY then log_error "No values given."
28
+ else log_error "Too many values given."
29
+ end
21
30
  end
22
31
 
23
32
  private
24
33
 
25
- def process values
26
- external_id, handle, name = values.split ","
27
- client.write(:users) { upsert({external_id:, handle:, name:}) }
28
- end
29
-
30
34
  def log_info(message) = logger.info { message }
35
+
36
+ def log_error(message) = logger.error { message }
31
37
  end
32
38
  end
33
39
  end
@@ -24,7 +24,15 @@ module Milestoner
24
24
  def print users
25
25
  return logger.info { "No users found." } if users.empty?
26
26
 
27
- users.each { |user| io.puts user.to_h.values.join ", " }
27
+ header
28
+ users.each { |user| io.puts user.to_h.values.map(&:inspect).join ", " }
29
+ end
30
+
31
+ def header
32
+ header = "External ID, Handle, Name"
33
+
34
+ io.puts header
35
+ io.puts "-" * header.size
28
36
  end
29
37
  end
30
38
  end
@@ -24,15 +24,17 @@ module Milestoner
24
24
  end
25
25
 
26
26
  def call
27
- git.tags("--sort=taggerdate")
28
- .fmap { |tags| tail tags.last(settings.build_max).map(&:version) }
29
- .fmap { |references| slice(references).reverse }
27
+ collect.fmap { |tags| tail tags.last(settings.build_max).map(&:version) }
28
+ .fmap { |references| slice(references).reverse }
29
+ .bind { |tags| tags.empty? ? Failure("No tags or commits.") : Success(tags) }
30
30
  end
31
31
 
32
32
  private
33
33
 
34
34
  attr_reader :enricher, :model
35
35
 
36
+ def collect = git.tagged? ? git.tags("--sort=taggerdate") : placeholder_with_commits
37
+
36
38
  def tail references
37
39
  references.append "HEAD" if settings.build_tail == "head"
38
40
  references
@@ -68,6 +70,21 @@ module Milestoner
68
70
  ]
69
71
  end
70
72
 
73
+ def placeholder_with_commits = enricher.call.fmap { |commits| placeholder_for commits }
74
+
75
+ def placeholder_for commits
76
+ return commits if commits.empty?
77
+
78
+ [
79
+ model[
80
+ author: commits.last.author,
81
+ commits:,
82
+ committed_at: Time.now,
83
+ version: settings.project_version
84
+ ]
85
+ ]
86
+ end
87
+
71
88
  def author tag
72
89
  author_enricher.call tag.with(author_name: tag.author_name || settings.project_author)
73
90
  end
@@ -6,15 +6,24 @@ module Milestoner
6
6
  module Renderers
7
7
  # Renders ASCII Doc as HTML.
8
8
  class Asciidoc
9
- def initialize client: Asciidoctor
9
+ SETTINGS = {
10
+ safe: :safe,
11
+ attributes: {
12
+ "source-highlighter" => "rouge",
13
+ "rouge-linenums-mode" => "inline"
14
+ }
15
+ }.freeze
16
+
17
+ def initialize settings: SETTINGS, client: Asciidoctor
18
+ @settings = settings
10
19
  @client = client
11
20
  end
12
21
 
13
- def call(content) = client.convert content
22
+ def call(content) = client.convert content, settings
14
23
 
15
24
  private
16
25
 
17
- attr_reader :client
26
+ attr_reader :settings, :client
18
27
  end
19
28
  end
20
29
  end
@@ -1,12 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "redcarpet"
4
+ require "rouge"
5
+ require "rouge/plugins/redcarpet"
4
6
 
5
7
  module Milestoner
6
8
  module Renderers
7
9
  # Renders Markdown as HTML.
8
10
  class Markdown
9
- def initialize client: Redcarpet::Markdown.new(Redcarpet::Render::HTML.new)
11
+ CLIENT = Redcarpet::Markdown.new Class.new(Redcarpet::Render::HTML)
12
+ .include(Rouge::Plugins::Redcarpet)
13
+ .set_temporary_name("redcarpet_html_rouge")
14
+ .new,
15
+ disable_indented_code_blocks: true,
16
+ fenced_code_blocks: true,
17
+ footnotes: true,
18
+ highlight: true,
19
+ superscript: true,
20
+ tables: true
21
+
22
+ def initialize client: CLIENT
10
23
  @client = client
11
24
  end
12
25
 
@@ -19,13 +19,22 @@ module Milestoner
19
19
 
20
20
  attr_reader :defaults, :client
21
21
 
22
- def configuration
23
- client::Config.merge defaults,
24
- elements: defaults[:elements].including("img", "video"),
25
- attributes: defaults[:attributes].merge(
26
- "img" => %w[alt class height id loading src width],
27
- "video" => %w[class controls height id poster src width]
28
- )
22
+ def configuration = client::Config.merge(defaults, elements:, attributes:)
23
+
24
+ def elements
25
+ defaults[:elements].including "audio", "details", "img", "source", "span", "summary", "video"
26
+ end
27
+
28
+ def attributes
29
+ defaults[:attributes].merge(
30
+ all: %w[class id],
31
+ "a" => %w[href title],
32
+ "audio" => %w[autoplay controls controlslist crossorigin loop muted preload src],
33
+ "details" => %w[name open],
34
+ "img" => %w[alt height loading src width],
35
+ "source" => %w[type src srcset sizes media height width],
36
+ "video" => %w[controls height poster src width]
37
+ )
29
38
  end
30
39
  end
31
40
  end
@@ -21,7 +21,7 @@ module Milestoner
21
21
  end
22
22
 
23
23
  def call tags
24
- return Failure "No content." if tags.empty?
24
+ return Failure "No tags or commits." if tags.empty?
25
25
 
26
26
  Success build_feed(tags).to_s
27
27
  rescue NoMethodError, RSS::Error => error
@@ -2,6 +2,308 @@
2
2
  --font-family: Verdana;
3
3
  }
4
4
 
5
+ /* Rouge (https://rouge.jneen.net) */
6
+ .rouge.highlight {
7
+ --color-berry: hsl(240, 18%, 40%);
8
+ --color-blue: hsl(223, 100%, 74%);
9
+ --color-cold: hsl(189, 100%, 93%);
10
+ --color-dark: hsl(191, 12%, 27%);
11
+ --color-eclipse: hsl(0, 3%, 21%);
12
+ --color-enoki: hsl(60, 30%, 95%);
13
+ --color-goblin: hsl(84, 82%, 49%);
14
+ --color-green: hsl(140, 67%, 66%);
15
+ --color-grey: hsl(0, 0%, 65%);
16
+ --color-ice: hsl(184, 74%, 83%);
17
+ --color-ink: hsl(210, 4%, 11%);
18
+ --color-khaki: hsl(35, 26%, 75%);
19
+ --color-lime: hsl(82, 100%, 58%);
20
+ --color-purple: hsl(259, 60%, 79.4%);
21
+ --color-red: hsl(0, 100%, 73%);
22
+ --color-sea: hsl(190, 100%, 60%);
23
+ --color-sky: hsl(203, 93%, 74%);
24
+ --color-teal: hsl(189, 23%, 53%);
25
+ --color-white: hsl(0, 0%, 100%);
26
+ --color-yellow: hsl(49, 100%, 59%);
27
+
28
+ table {
29
+ td {
30
+ padding: 5px;
31
+ }
32
+
33
+ pre {
34
+ margin: 0;
35
+ }
36
+ }
37
+
38
+ .c, .ch, .cd, .cpf {
39
+ color: var(--color-grey);
40
+ font-style: italic;
41
+ }
42
+
43
+ .cm {
44
+ color: var(--color-berry);
45
+ font-style: italic;
46
+ }
47
+
48
+ .c1 {
49
+ color: var(--color-grey);
50
+ font-style: italic;
51
+ }
52
+
53
+ .cp {
54
+ color: var(--color-teal);
55
+ font-weight: bold;
56
+ }
57
+
58
+ .cs {
59
+ color: var(--color-dark);
60
+ font-weight: bold;
61
+ font-style: italic;
62
+ }
63
+
64
+ .err {
65
+ color: var(--color-enoki);
66
+ background-color: var(--color-eclipse);
67
+ }
68
+
69
+ .gi {
70
+ color: var(--color-lime);
71
+ }
72
+
73
+ .gd {
74
+ color: var(--color-blue);
75
+ }
76
+
77
+ .ge {
78
+ color: var(--color-ink);
79
+ font-style: italic;
80
+ }
81
+
82
+ .gr {
83
+ color: var(--color-blue);
84
+ }
85
+
86
+ .gt {
87
+ color: var(--color-blue);
88
+ }
89
+
90
+ .gh {
91
+ color: var(--color-eclipse);
92
+ }
93
+
94
+ .go {
95
+ color: var(--color-eclipse);
96
+ }
97
+
98
+ .gp {
99
+ color: var(--color-sea);
100
+ }
101
+
102
+ .gs {
103
+ font-weight: bold;
104
+ }
105
+
106
+ .gu {
107
+ color: var(--color-dark);
108
+ }
109
+
110
+ .k, .kv {
111
+ color: var(--color-sky);
112
+ font-weight: bold;
113
+ }
114
+
115
+ .kc {
116
+ color: var(--color-sea);
117
+ font-weight: bold;
118
+ }
119
+
120
+ .kd {
121
+ color: var(--color-sea);
122
+ font-weight: bold;
123
+ }
124
+
125
+ .kp {
126
+ color: var(--color-ice);
127
+ font-weight: bold;
128
+ }
129
+
130
+ .kr {
131
+ color: var(--color-sea);
132
+ font-weight: bold;
133
+ }
134
+
135
+ .kt {
136
+ color: var(--color-sea);
137
+ font-weight: bold;
138
+ }
139
+
140
+ .kn {
141
+ color: var(--color-blue);
142
+ font-weight: bold;
143
+ }
144
+
145
+ .ow {
146
+ color: var(--color-blue);
147
+ font-weight: bold;
148
+ }
149
+
150
+ .o {
151
+ color: var(--color-blue);
152
+ font-weight: bold;
153
+ }
154
+
155
+ .mf {
156
+ color: var(--color-ice);
157
+ }
158
+
159
+ .mh {
160
+ color: var(--color-purple);
161
+ }
162
+
163
+ .il {
164
+ color: var(--color-purple);
165
+ }
166
+
167
+ .mi {
168
+ color: var(--color-ice);
169
+ }
170
+
171
+ .mo {
172
+ color: var(--color-purple);
173
+ }
174
+
175
+ .m, .mb, .mx {
176
+ color: var(--color-purple);
177
+ }
178
+
179
+ .se {
180
+ color: var(--color-purple);
181
+ }
182
+
183
+ .sb {
184
+ color: var(--color-khaki);
185
+ }
186
+
187
+ .sc {
188
+ color: var(--color-khaki);
189
+ }
190
+
191
+ .sd {
192
+ color: var(--color-khaki);
193
+ }
194
+
195
+ .s2 {
196
+ color: var(--color-khaki);
197
+ }
198
+
199
+ .sh {
200
+ color: var(--color-khaki);
201
+ }
202
+
203
+ .si {
204
+ color: var(--color-purple);
205
+ }
206
+
207
+ .sx {
208
+ color: var(--color-green);
209
+ }
210
+
211
+ .sr {
212
+ color: var(--color-ice);
213
+ }
214
+
215
+ .s1 {
216
+ color: var(--color-khaki);
217
+ }
218
+
219
+ .ss {
220
+ color: var(--color-green);
221
+ }
222
+
223
+ .s, .sa, .dl {
224
+ color: var(--color-khaki);
225
+ }
226
+
227
+ .n {
228
+ color: var(--color-white);
229
+ }
230
+
231
+ .na {
232
+ color: var(--color-lime);
233
+ }
234
+
235
+ .nc {
236
+ color: var(--color-lime);
237
+ font-weight: bold;
238
+ }
239
+
240
+ .nd {
241
+ color: var(--color-lime);
242
+ font-weight: bold;
243
+ }
244
+
245
+ .ne {
246
+ color: var(--color-lime);
247
+ font-weight: bold;
248
+ }
249
+
250
+ .nf, .fm {
251
+ color: var(--color-goblin);
252
+ font-weight: bold;
253
+ }
254
+
255
+ .no {
256
+ color: var(--color-sea);
257
+ }
258
+
259
+ .bp {
260
+ color: var(--color-enoki);
261
+ }
262
+
263
+ .nb {
264
+ color: var(--color-cold);
265
+ }
266
+
267
+ .ni {
268
+ color: var(--color-enoki);
269
+ }
270
+
271
+ .nn {
272
+ color: var(--color-lime);
273
+ }
274
+
275
+ .vc {
276
+ color: var(--color-red);
277
+ }
278
+
279
+ .vg {
280
+ color: var(--color-enoki);
281
+ }
282
+
283
+ .vi {
284
+ color: var(--color-yellow);
285
+ }
286
+
287
+ .nv, .vm {
288
+ color: var(--color-enoki);
289
+ }
290
+
291
+ .w {
292
+ color: var(--color-enoki);
293
+ }
294
+
295
+ .nl {
296
+ color: var(--color-enoki);
297
+ font-weight: bold;
298
+ }
299
+
300
+ .nt {
301
+ color: var(--color-cold);
302
+ }
303
+
304
+ color: var(--color-enoki);
305
+ }
306
+
5
307
  .milestone {
6
308
  --border-width: 0.15rem;
7
309
  --color-black: hsl(0, 0%, 0%);
@@ -15,10 +317,12 @@
15
317
  --color-ice: hsl(216, 100%, 98%);
16
318
  --color-major: hsl(7, 79%, 32%);
17
319
  --color-minor: hsl(221, 79%, 32%);
320
+ --color-night: hsl(216, 9%, 21%);
18
321
  --color-orange: hsl(24.8, 100%, 50.2%);
19
322
  --color-patch: hsl(156, 79%, 32%);
20
323
  --color-powder: hsl(0, 0%, 98%);
21
324
  --color-red: hsl(0, 84.1%, 44.5%);
325
+ --color-silver: hsl(224, 33%, 94%);
22
326
  --color-slate: hsl(211, 23%, 41%);
23
327
  --color-smoke: hsl(229, 31%, 93%);
24
328
  --color-white: hsl(0, 0%, 100%);
@@ -29,6 +333,62 @@
29
333
  font-family: var(--font-family);
30
334
  margin: 0 12vw;
31
335
 
336
+ blockquote {
337
+ background-color: var(--color-silver);
338
+ border-left: 0.5rem solid var(--color-slate);
339
+ border-radius: 0.5rem;
340
+ padding: 0.5rem 1rem;
341
+
342
+ p {
343
+ margin: 0;
344
+ quotes: "\201C""\201D";
345
+
346
+ &::before, &::after {
347
+ font-family: cursive;
348
+ font-size: 1.5rem;
349
+ }
350
+
351
+ &::before {
352
+ content: open-quote;
353
+ padding-right: 0.3rem;
354
+ }
355
+
356
+ &::after {
357
+ content: close-quote;
358
+ padding-left: 0.1rem;
359
+ }
360
+ }
361
+ }
362
+
363
+ :not(pre) > code {
364
+ background-color: var(--color-night);
365
+ border-radius: 0.3rem;
366
+ color: var(--color-white);
367
+ font-size: 0.95rem;
368
+ padding: 0.1rem 0.3rem;
369
+ }
370
+
371
+ pre:not([class^=language]) {
372
+ background-color: var(--color-night);
373
+ color: var(--color-ghost);
374
+ line-height: 1.5rem;
375
+ padding: 0.5rem 1rem;
376
+ font-size: 0.9rem;
377
+ white-space: pre-wrap;
378
+ }
379
+
380
+ pre {
381
+ border-radius: 0.5rem;
382
+ font-weight: 400;
383
+ padding: 0.5rem;
384
+ }
385
+
386
+ img, video {
387
+ max-width: 100%;
388
+ height: auto;
389
+ object-fit: cover;
390
+ }
391
+
32
392
  .normal {
33
393
  border-bottom-color: var(--color-ghost);
34
394
  border-color: transparent;
@@ -46,6 +406,7 @@
46
406
 
47
407
  .avatar {
48
408
  border-radius: 50%;
409
+ height: fit-content;
49
410
  }
50
411
 
51
412
  .pill {
@@ -138,8 +499,9 @@
138
499
  }
139
500
 
140
501
  .overview {
141
- display: flex;
142
502
  align-items: center;
503
+ display: flex;
504
+ flex-wrap: wrap;
143
505
  justify-content: space-between;
144
506
  margin-bottom: 0.5rem;
145
507
  }
data/milestoner.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "milestoner"
5
- spec.version = "18.4.0"
5
+ spec.version = "18.5.0"
6
6
  spec.authors = ["Brooke Kuhlmann"]
7
7
  spec.email = ["brooke@alchemists.io"]
8
8
  spec.homepage = "https://alchemists.io/projects/milestoner"
@@ -37,6 +37,7 @@ Gem::Specification.new do |spec|
37
37
  spec.add_dependency "lode", "~> 1.8"
38
38
  spec.add_dependency "redcarpet", "~> 3.6"
39
39
  spec.add_dependency "refinements", "~> 12.8"
40
+ spec.add_dependency "rouge", "~> 4.3"
40
41
  spec.add_dependency "rss", "~> 0.3"
41
42
  spec.add_dependency "runcom", "~> 11.5"
42
43
  spec.add_dependency "sanitize", "~> 6.1"
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: milestoner
3
3
  version: !ruby/object:Gem::Version
4
- version: 18.4.0
4
+ version: 18.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -35,7 +35,7 @@ cert_chain:
35
35
  3n5C8/6Zh9DYTkpcwPSuIfAga6wf4nXc9m6JAw8AuMLaiWN/r/2s4zJsUHYERJEu
36
36
  gZGm4JqtuSg8pYjPeIJxS960owq+SfuC+jxqmRA54BisFCv/0VOJi7tiJVY=
37
37
  -----END CERTIFICATE-----
38
- date: 2024-09-07 00:00:00.000000000 Z
38
+ date: 2024-09-15 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: asciidoctor
@@ -233,6 +233,20 @@ dependencies:
233
233
  - - "~>"
234
234
  - !ruby/object:Gem::Version
235
235
  version: '12.8'
236
+ - !ruby/object:Gem::Dependency
237
+ name: rouge
238
+ requirement: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - "~>"
241
+ - !ruby/object:Gem::Version
242
+ version: '4.3'
243
+ type: :runtime
244
+ prerelease: false
245
+ version_requirements: !ruby/object:Gem::Requirement
246
+ requirements:
247
+ - - "~>"
248
+ - !ruby/object:Gem::Version
249
+ version: '4.3'
236
250
  - !ruby/object:Gem::Dependency
237
251
  name: rss
238
252
  requirement: !ruby/object:Gem::Requirement
metadata.gz.sig CHANGED
Binary file