milestoner 16.2.0 → 17.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -1
  3. data/README.adoc +274 -47
  4. data/lib/milestoner/builders/container.rb +15 -0
  5. data/lib/milestoner/builders/import.rb +9 -0
  6. data/lib/milestoner/builders/stream.rb +29 -0
  7. data/lib/milestoner/builders/web.rb +41 -0
  8. data/lib/milestoner/cli/actions/build/format.rb +24 -0
  9. data/lib/milestoner/cli/actions/build/label.rb +26 -0
  10. data/lib/milestoner/cli/actions/build/layout.rb +36 -0
  11. data/lib/milestoner/cli/actions/build/root.rb +25 -0
  12. data/lib/milestoner/cli/actions/build/version.rb +31 -0
  13. data/lib/milestoner/cli/actions/cache/create.rb +35 -0
  14. data/lib/milestoner/cli/actions/cache/delete.rb +34 -0
  15. data/lib/milestoner/cli/actions/cache/find.rb +34 -0
  16. data/lib/milestoner/cli/actions/cache/info.rb +29 -0
  17. data/lib/milestoner/cli/actions/cache/list.rb +33 -0
  18. data/lib/milestoner/cli/actions/publish.rb +9 -5
  19. data/lib/milestoner/cli/commands/build.rb +55 -0
  20. data/lib/milestoner/cli/commands/cache.rb +27 -0
  21. data/lib/milestoner/cli/shell.rb +3 -2
  22. data/lib/milestoner/commits/categorizer.rb +21 -29
  23. data/lib/milestoner/commits/collector.rb +18 -0
  24. data/lib/milestoner/commits/enricher.rb +52 -0
  25. data/lib/milestoner/commits/enrichers/author.rb +26 -0
  26. data/lib/milestoner/commits/enrichers/body.rb +28 -0
  27. data/lib/milestoner/commits/enrichers/colleague.rb +33 -0
  28. data/lib/milestoner/commits/enrichers/container.rb +25 -0
  29. data/lib/milestoner/commits/enrichers/format.rb +23 -0
  30. data/lib/milestoner/commits/enrichers/import.rb +11 -0
  31. data/lib/milestoner/commits/enrichers/issue.rb +28 -0
  32. data/lib/milestoner/commits/enrichers/milestone.rb +24 -0
  33. data/lib/milestoner/commits/enrichers/note.rb +28 -0
  34. data/lib/milestoner/commits/enrichers/review.rb +23 -0
  35. data/lib/milestoner/commits/enrichers/uri.rb +14 -0
  36. data/lib/milestoner/commits/versioner.rb +48 -0
  37. data/lib/milestoner/configuration/contract.rb +29 -3
  38. data/lib/milestoner/configuration/defaults.yml +31 -8
  39. data/lib/milestoner/configuration/model.rb +24 -1
  40. data/lib/milestoner/configuration/transformers/build/root.rb +21 -0
  41. data/lib/milestoner/configuration/transformers/build/template_paths.rb +35 -0
  42. data/lib/milestoner/configuration/transformers/citations/description.rb +37 -0
  43. data/lib/milestoner/configuration/transformers/citations/label.rb +37 -0
  44. data/lib/milestoner/configuration/transformers/gems/description.rb +36 -0
  45. data/lib/milestoner/configuration/transformers/gems/label.rb +36 -0
  46. data/lib/milestoner/configuration/transformers/gems/name.rb +36 -0
  47. data/lib/milestoner/configuration/transformers/gems/uri.rb +36 -0
  48. data/lib/milestoner/configuration/transformers/project/author.rb +33 -0
  49. data/lib/milestoner/configuration/transformers/project/generator.rb +28 -0
  50. data/lib/milestoner/configuration/transformers/project/label.rb +23 -0
  51. data/lib/milestoner/configuration/transformers/project/name.rb +19 -0
  52. data/lib/milestoner/configuration/transformers/project/version.rb +31 -0
  53. data/lib/milestoner/configuration/transformers/uri/avatar.rb +21 -0
  54. data/lib/milestoner/configuration/transformers/uri/commit.rb +24 -0
  55. data/lib/milestoner/configuration/transformers/uri/profile.rb +21 -0
  56. data/lib/milestoner/configuration/transformers/uri/review.rb +24 -0
  57. data/lib/milestoner/configuration/transformers/uri/tracker.rb +24 -0
  58. data/lib/milestoner/container.rb +51 -9
  59. data/lib/milestoner/models/commit.rb +42 -0
  60. data/lib/milestoner/models/link.rb +12 -0
  61. data/lib/milestoner/models/user.rb +12 -0
  62. data/lib/milestoner/renderers/asciidoc.rb +20 -0
  63. data/lib/milestoner/renderers/markdown.rb +20 -0
  64. data/lib/milestoner/renderers/universal.rb +26 -0
  65. data/lib/milestoner/tags/creator.rb +31 -23
  66. data/lib/milestoner/tags/publisher.rb +5 -5
  67. data/lib/milestoner/tags/pusher.rb +9 -3
  68. data/lib/milestoner/templates/layouts/page.html.erb +29 -0
  69. data/lib/milestoner/templates/layouts/page.stream.erb +1 -0
  70. data/lib/milestoner/templates/milestones/_avatar.html.erb +5 -0
  71. data/lib/milestoner/templates/milestones/_commit.html.erb +104 -0
  72. data/lib/milestoner/templates/milestones/_commit.stream.erb +1 -0
  73. data/lib/milestoner/templates/milestones/_icon.html.erb +6 -0
  74. data/lib/milestoner/templates/milestones/_profile.html.erb +5 -0
  75. data/lib/milestoner/templates/milestones/show.html.erb +46 -0
  76. data/lib/milestoner/templates/milestones/show.stream.erb +5 -0
  77. data/lib/milestoner/templates/public/page.css.erb +356 -0
  78. data/lib/milestoner/views/context.rb +25 -0
  79. data/lib/milestoner/views/milestones/show.rb +46 -0
  80. data/lib/milestoner/views/parts/commit.rb +85 -0
  81. data/lib/milestoner.rb +4 -2
  82. data/milestoner.gemspec +17 -11
  83. data.tar.gz.sig +0 -0
  84. metadata +172 -23
  85. metadata.gz.sig +0 -0
  86. data/lib/milestoner/cli/actions/status.rb +0 -37
  87. data/lib/milestoner/presenters/commit.rb +0 -36
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sod"
4
+
5
+ module Milestoner
6
+ module CLI
7
+ module Actions
8
+ module Cache
9
+ # Handles deleting a user from the cache.
10
+ class Delete < Sod::Action
11
+ include Import[:kernel, :logger, client: :cache]
12
+
13
+ description "Delete user."
14
+
15
+ on %w[-d --delete], argument: "NAME"
16
+
17
+ def call name
18
+ client.commit(:users) { delete name }
19
+ .either(method(:success), method(:failure))
20
+ end
21
+
22
+ private
23
+
24
+ def success(user) = logger.info { "Deleted: #{user.name.inspect}." }
25
+
26
+ def failure message
27
+ logger.error { message }
28
+ kernel.abort
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sod"
4
+
5
+ module Milestoner
6
+ module CLI
7
+ module Actions
8
+ module Cache
9
+ # Handles finding a user in the cache.
10
+ class Find < Sod::Action
11
+ include Import[:kernel, :logger, client: :cache]
12
+
13
+ description "Find user."
14
+
15
+ on %w[-f --find], argument: "NAME"
16
+
17
+ def call name
18
+ client.commit(:users) { find name }
19
+ .either(method(:success), method(:failure))
20
+ end
21
+
22
+ private
23
+
24
+ def success(user) = kernel.puts user.to_h.values.join(", ")
25
+
26
+ def failure message
27
+ logger.error { message }
28
+ kernel.abort
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sod"
4
+
5
+ module Milestoner
6
+ module CLI
7
+ module Actions
8
+ module Cache
9
+ # Handles cache information.
10
+ class Info < Sod::Action
11
+ include Import[:kernel, :logger, client: :cache]
12
+
13
+ description "Show information."
14
+
15
+ on %w[-i --info]
16
+
17
+ def call(*)
18
+ path = client.path
19
+ path.exist? ? log_info("Path: #{path}.") : log_info("No cache found.")
20
+ end
21
+
22
+ private
23
+
24
+ def log_info(message) = logger.info { message }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sod"
4
+
5
+ module Milestoner
6
+ module CLI
7
+ module Actions
8
+ module Cache
9
+ # Handles listing users within the cache.
10
+ class List < Sod::Action
11
+ include Import[:kernel, :logger, client: :cache]
12
+
13
+ description "List users."
14
+
15
+ on %w[-l --list]
16
+
17
+ def call(*)
18
+ logger.info { "Listing users..." }
19
+ client.commit(:users, &:all).bind { |users| print users }
20
+ end
21
+
22
+ private
23
+
24
+ def print users
25
+ return logger.info { "No users found." } if users.empty?
26
+
27
+ users.each { |user| kernel.puts user.to_h.values.join ", " }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "refinements/structs"
3
+ require "refinements/struct"
4
4
  require "sod"
5
+ require "versionaire"
5
6
 
6
7
  module Milestoner
7
8
  module CLI
@@ -10,20 +11,23 @@ module Milestoner
10
11
  class Publish < Sod::Action
11
12
  include Import[:configuration]
12
13
 
13
- using Refinements::Structs
14
+ using Refinements::Struct
15
+ using Versionaire::Cast
14
16
 
15
17
  description "Publish milestone."
16
18
 
17
- ancillary "(tags and pushes to remote repository)"
19
+ ancillary "Build, commit, tag, and push to remote repository."
18
20
 
19
- on %w[-p --publish], argument: "VERSION"
21
+ on %w[-p --publish], argument: "[VERSION]"
22
+
23
+ default { Commits::Versioner.new.call }
20
24
 
21
25
  def initialize(publisher: Tags::Publisher.new, **)
22
26
  super(**)
23
27
  @publisher = publisher
24
28
  end
25
29
 
26
- def call(version) = publisher.call configuration.merge(version:)
30
+ def call(version = nil) = publisher.call Version(version || default)
27
31
 
28
32
  private
29
33
 
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/pathname"
4
+ require "sod"
5
+
6
+ module Milestoner
7
+ module CLI
8
+ module Commands
9
+ # Handles the building of milestone output.
10
+ class Build < Sod::Command
11
+ include Import[:input, :logger, :kernel]
12
+ include Builders::Import[:stream, :web]
13
+
14
+ using Refinements::Pathname
15
+
16
+ handle "build"
17
+
18
+ description "Build milestone."
19
+
20
+ on Actions::Build::Label
21
+ on Actions::Build::Version
22
+ on Actions::Build::Layout
23
+ on Actions::Build::Format
24
+ on Actions::Build::Root
25
+
26
+ def call
27
+ log_info "Building milestone..."
28
+
29
+ format = input.build_format
30
+
31
+ case format
32
+ when "stream" then build_stream
33
+ when "web" then build_web
34
+ else log_error "Invalid build format: #{format}."
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :view, :enricher
41
+
42
+ def build_stream
43
+ kernel.puts
44
+ stream.call
45
+ end
46
+
47
+ def build_web = log_info "Milestone built: #{web.call}."
48
+
49
+ def log_info(message) = logger.info { message }
50
+
51
+ def log_error(message) = logger.error { message }
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/pathname"
4
+ require "sod"
5
+
6
+ module Milestoner
7
+ module CLI
8
+ module Commands
9
+ # Handles the building of milestone output.
10
+ class Cache < Sod::Command
11
+ include Import[:input, :logger]
12
+
13
+ using Refinements::Pathname
14
+
15
+ handle "cache"
16
+
17
+ description "Manage cache."
18
+
19
+ on Actions::Cache::Info
20
+ on Actions::Cache::List
21
+ on Actions::Cache::Find
22
+ on Actions::Cache::Create
23
+ on Actions::Cache::Delete
24
+ end
25
+ end
26
+ end
27
+ end
@@ -6,7 +6,7 @@ module Milestoner
6
6
  module CLI
7
7
  # The main Command Line Interface (CLI) object.
8
8
  class Shell
9
- include Import[:defaults_path, :xdg_config, :specification]
9
+ include Import[:defaults_path, :specification, xdg_config: "xdg.config"]
10
10
 
11
11
  def initialize(context: Sod::Context, dsl: Sod, **)
12
12
  super(**)
@@ -25,8 +25,9 @@ module Milestoner
25
25
 
26
26
  dsl.new :milestoner, banner: specification.banner do
27
27
  on(Sod::Prefabs::Commands::Config, context:)
28
+ on Commands::Cache
29
+ on Commands::Build
28
30
  on Actions::Publish
29
- on Actions::Status
30
31
  on(Sod::Prefabs::Actions::Version, context:)
31
32
  on Sod::Prefabs::Actions::Help, self
32
33
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "refinements/array"
3
4
  require "versionaire"
4
5
 
5
6
  module Milestoner
@@ -8,49 +9,40 @@ module Milestoner
8
9
  class Categorizer
9
10
  include Import[:git]
10
11
 
11
- def initialize(expression: Regexp, **)
12
- super(**)
12
+ using Refinements::Array
13
+
14
+ def initialize(collector: Collector.new, expression: Regexp, **)
15
+ @collector = collector
13
16
  @expression = expression
17
+ super(**)
14
18
  end
15
19
 
16
20
  def call configuration = Container[:configuration]
17
- prefixes = configuration.prefixes
18
-
19
- prefixes.reduce({}) { |group, prefix| group.merge prefix => [] }
20
- .merge("Unknown" => [])
21
- .then { |groups| group_by_prefix prefixes, groups }
22
- .each_value { |commits| commits.sort_by!(&:subject) }
23
- .values
24
- .flatten
25
- .uniq(&:subject)
21
+ categories = configuration.commit_categories.pluck :label
22
+
23
+ categories.reduce({}) { |group, prefix| group.merge prefix => [] }
24
+ .merge("Unknown" => [])
25
+ .then { |groups| group_by_category categories, groups }
26
+ .each_value { |commits| commits.sort_by!(&:subject) }
27
+ .values
28
+ .flatten
26
29
  end
27
30
 
28
31
  private
29
32
 
30
- attr_reader :expression
33
+ attr_reader :collector, :expression
31
34
 
32
- def group_by_prefix prefixes, groups
33
- computed_commits.each.with_object groups do |commit, collection|
34
- prefix = commit.subject[subject_pattern(prefixes)]
35
- key = collection.key?(prefix) ? prefix : "Unknown"
35
+ def group_by_category categories, groups
36
+ collector.call.value_or([]).each.with_object groups do |commit, collection|
37
+ category = commit.subject[subject_pattern(categories)]
38
+ key = collection.key?(category) ? category : "Unknown"
36
39
  collection[key] << commit
37
40
  end
38
41
  end
39
42
 
40
- def subject_pattern prefixes
41
- prefixes.empty? ? expression.new(//) : expression.union(prefixes)
43
+ def subject_pattern categories
44
+ categories.empty? ? expression.new(//) : expression.union(categories)
42
45
  end
43
-
44
- def computed_commits = git.tagged? ? tagged_commits : saved_commits
45
-
46
- def tagged_commits
47
- git.tag_last
48
- .value_or(nil)
49
- .then { |tag| git.commits "#{tag}..HEAD" }
50
- .value_or([])
51
- end
52
-
53
- def saved_commits = git.commits.value_or([])
54
46
  end
55
47
  end
56
48
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Commits
5
+ # Collects commits since last tag or all commits if untagged.
6
+ class Collector
7
+ include Import[:git]
8
+
9
+ def call = git.tagged? ? latest : all
10
+
11
+ private
12
+
13
+ def latest = git.tag_last.bind { |tag| git.commits "#{tag}..HEAD" }
14
+
15
+ def all = git.commits
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+
5
+ module Milestoner
6
+ module Commits
7
+ # Enriches commits and associated trailers for final processing.
8
+ class Enricher
9
+ include Import[:input]
10
+
11
+ include Enrichers::Import[
12
+ :author,
13
+ :body,
14
+ :collaborators,
15
+ :format,
16
+ :issue,
17
+ :milestone,
18
+ :notes,
19
+ :review,
20
+ :signers,
21
+ :uri
22
+ ]
23
+
24
+ include Dry::Monads[:result]
25
+
26
+ def initialize(categorizer: Commits::Categorizer.new, model: Models::Commit, **)
27
+ @categorizer = categorizer
28
+ @model = model
29
+ super(**)
30
+ @commands = %i[author body collaborators format issue milestone notes review signers uri]
31
+ end
32
+
33
+ def call
34
+ categorizer.call
35
+ .map { |commit| record_for commit }
36
+ .then { |commits| Success commits }
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :categorizer, :model, :commands
42
+
43
+ def record_for(commit) = model.for(commit, **build_attributes(commit))
44
+
45
+ def build_attributes commit
46
+ commands.each.with_object({}) do |command, attributes|
47
+ attributes[command] = __send__(command).call commit
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Commits
5
+ module Enrichers
6
+ # Enriches a commit author by using cache.
7
+ class Author
8
+ include Milestoner::Import[:cache]
9
+
10
+ def initialize(model: Models::User, **)
11
+ @model = model
12
+ super(**)
13
+ end
14
+
15
+ def call commit
16
+ cache.commit(:users) { |table| table.find commit.author_name }
17
+ .value_or(model.new)
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :model
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Commits
5
+ module Enrichers
6
+ # Enriches commit text by rendering as HTML based on trailer information.
7
+ class Body
8
+ include Milestoner::Import[:input]
9
+
10
+ def initialize(key: "Format", renderer: Renderers::Universal.new, **)
11
+ @key = key
12
+ @renderer = renderer
13
+ super(**)
14
+ end
15
+
16
+ def call commit
17
+ commit.trailer_value_for(key)
18
+ .value_or(input.commit_format)
19
+ .then { |format| renderer.call commit.body, for: format.to_sym }
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :key, :renderer
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gitt"
4
+
5
+ module Milestoner
6
+ module Commits
7
+ module Enrichers
8
+ # Enriches a commit colleague by using cache.
9
+ class Colleague
10
+ include Milestoner::Import[:cache]
11
+
12
+ def initialize(key:, parser: Gitt::Parsers::Person.new, **)
13
+ @key = key
14
+ @parser = parser
15
+ super(**)
16
+ end
17
+
18
+ def call(commit) = commit.find_trailers(key).bind { |trailers| users_for(trailers).compact }
19
+
20
+ private
21
+
22
+ attr_reader :key, :parser
23
+
24
+ def users_for(trailers) = trailers.map { |trailer| user_for parser.call(trailer.value) }
25
+
26
+ def user_for person
27
+ cache.commit(:users) { find person.name }
28
+ .value_or(nil)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-container"
4
+
5
+ module Milestoner
6
+ module Commits
7
+ module Enrichers
8
+ # Registers all enrichers for injection.
9
+ module Container
10
+ extend Dry::Container::Mixin
11
+
12
+ register(:author, memoize: true) { Author.new }
13
+ register(:body, memoize: true) { Body.new }
14
+ register(:collaborators, memoize: true) { Colleague.new key: "Co-authored-by" }
15
+ register(:format, memoize: true) { Format.new }
16
+ register(:issue, memoize: true) { Issue.new }
17
+ register(:milestone) { Milestone.new }
18
+ register(:notes, memoize: true) { Note.new }
19
+ register(:review, memoize: true) { Review.new }
20
+ register(:signers, memoize: true) { Colleague.new key: "Signed-off-by" }
21
+ register(:uri, memoize: true) { URI.new }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Commits
5
+ module Enrichers
6
+ # Enriches a commit format based on trailer information.
7
+ class Format
8
+ include Milestoner::Import[:input]
9
+
10
+ def initialize(key: "Format", **)
11
+ @key = key
12
+ super(**)
13
+ end
14
+
15
+ def call(commit) = commit.trailer_value_for(key).value_or(input.commit_format)
16
+
17
+ private
18
+
19
+ attr_reader :key
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "infusible"
4
+
5
+ module Milestoner
6
+ module Commits
7
+ module Enrichers
8
+ Import = Infusible.with Container
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Commits
5
+ module Enrichers
6
+ # Enriches a commit issue based on trailer information.
7
+ class Issue
8
+ include Milestoner::Import[:input]
9
+
10
+ def initialize(key: "Issue", model: Models::Link, **)
11
+ @key = key
12
+ @model = model
13
+ super(**)
14
+ end
15
+
16
+ def call commit
17
+ commit.trailer_value_for(key)
18
+ .fmap { |value| model[id: value, uri: format(input.tracker_uri, id: value)] }
19
+ .value_or(model.new)
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :key, :model
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Commits
5
+ module Enrichers
6
+ # Enriches a commit milestone based on trailer information.
7
+ class Milestone
8
+ include Milestoner::Import[:input]
9
+
10
+ def initialize(key: "Milestone", default: "unknown", **)
11
+ @key = key
12
+ @default = default
13
+ super(**)
14
+ end
15
+
16
+ def call(commit) = commit.trailer_value_for(key).value_or(default)
17
+
18
+ private
19
+
20
+ attr_reader :key, :default
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Commits
5
+ module Enrichers
6
+ # Enriches commit notes by rendering as HTML based on trailer information.
7
+ class Note
8
+ include Milestoner::Import[:input]
9
+
10
+ def initialize(key: "Format", renderer: Renderers::Universal.new, **)
11
+ @key = key
12
+ @renderer = renderer
13
+ super(**)
14
+ end
15
+
16
+ def call commit
17
+ commit.trailer_value_for(key)
18
+ .value_or(input.commit_format)
19
+ .then { |format| renderer.call commit.notes, for: format.to_sym }
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :key, :renderer
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Commits
5
+ module Enrichers
6
+ # Enriches a commit review based on trailer information.
7
+ class Review
8
+ include Milestoner::Import[:input]
9
+
10
+ def initialize(model: Models::Link, **)
11
+ @model = model
12
+ super(**)
13
+ end
14
+
15
+ def call(*) = model[id: "All", uri: format(input.review_uri, id: nil)]
16
+
17
+ private
18
+
19
+ attr_reader :model
20
+ end
21
+ end
22
+ end
23
+ end