milestoner 18.4.0 → 18.5.0

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.
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