milestoner 16.2.1 → 17.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -1
  3. data/README.adoc +333 -57
  4. data/lib/milestoner/builders/ascii_doc.rb +32 -0
  5. data/lib/milestoner/builders/container.rb +17 -0
  6. data/lib/milestoner/builders/import.rb +9 -0
  7. data/lib/milestoner/builders/markdown.rb +32 -0
  8. data/lib/milestoner/builders/stream.rb +29 -0
  9. data/lib/milestoner/builders/web.rb +41 -0
  10. data/lib/milestoner/cli/actions/build/format.rb +24 -0
  11. data/lib/milestoner/cli/actions/build/label.rb +26 -0
  12. data/lib/milestoner/cli/actions/build/layout.rb +36 -0
  13. data/lib/milestoner/cli/actions/build/root.rb +25 -0
  14. data/lib/milestoner/cli/actions/build/version.rb +31 -0
  15. data/lib/milestoner/cli/actions/cache/create.rb +35 -0
  16. data/lib/milestoner/cli/actions/cache/delete.rb +31 -0
  17. data/lib/milestoner/cli/actions/cache/find.rb +31 -0
  18. data/lib/milestoner/cli/actions/cache/info.rb +29 -0
  19. data/lib/milestoner/cli/actions/cache/list.rb +33 -0
  20. data/lib/milestoner/cli/actions/publish.rb +9 -5
  21. data/lib/milestoner/cli/commands/build.rb +60 -0
  22. data/lib/milestoner/cli/commands/cache.rb +27 -0
  23. data/lib/milestoner/cli/shell.rb +3 -2
  24. data/lib/milestoner/commits/categorizer.rb +21 -29
  25. data/lib/milestoner/commits/collector.rb +18 -0
  26. data/lib/milestoner/commits/enricher.rb +51 -0
  27. data/lib/milestoner/commits/enrichers/author.rb +26 -0
  28. data/lib/milestoner/commits/enrichers/body.rb +28 -0
  29. data/lib/milestoner/commits/enrichers/colleague.rb +33 -0
  30. data/lib/milestoner/commits/enrichers/container.rb +25 -0
  31. data/lib/milestoner/commits/enrichers/format.rb +23 -0
  32. data/lib/milestoner/commits/enrichers/import.rb +11 -0
  33. data/lib/milestoner/commits/enrichers/issue.rb +28 -0
  34. data/lib/milestoner/commits/enrichers/milestone.rb +24 -0
  35. data/lib/milestoner/commits/enrichers/note.rb +28 -0
  36. data/lib/milestoner/commits/enrichers/review.rb +23 -0
  37. data/lib/milestoner/commits/enrichers/uri.rb +14 -0
  38. data/lib/milestoner/commits/versioner.rb +48 -0
  39. data/lib/milestoner/configuration/contract.rb +30 -3
  40. data/lib/milestoner/configuration/defaults.yml +31 -8
  41. data/lib/milestoner/configuration/model.rb +26 -1
  42. data/lib/milestoner/configuration/transformers/build/root.rb +21 -0
  43. data/lib/milestoner/configuration/transformers/build/template_paths.rb +32 -0
  44. data/lib/milestoner/configuration/transformers/citations/description.rb +39 -0
  45. data/lib/milestoner/configuration/transformers/citations/label.rb +39 -0
  46. data/lib/milestoner/configuration/transformers/gems/description.rb +34 -0
  47. data/lib/milestoner/configuration/transformers/gems/label.rb +35 -0
  48. data/lib/milestoner/configuration/transformers/gems/name.rb +34 -0
  49. data/lib/milestoner/configuration/transformers/gems/uri.rb +35 -0
  50. data/lib/milestoner/configuration/transformers/generator/label.rb +31 -0
  51. data/lib/milestoner/configuration/transformers/generator/uri.rb +31 -0
  52. data/lib/milestoner/configuration/transformers/project/author.rb +34 -0
  53. data/lib/milestoner/configuration/transformers/project/generator.rb +35 -0
  54. data/lib/milestoner/configuration/transformers/project/label.rb +23 -0
  55. data/lib/milestoner/configuration/transformers/project/name.rb +21 -0
  56. data/lib/milestoner/configuration/transformers/project/version.rb +33 -0
  57. data/lib/milestoner/configuration/transformers/uri/avatar.rb +21 -0
  58. data/lib/milestoner/configuration/transformers/uri/commit.rb +24 -0
  59. data/lib/milestoner/configuration/transformers/uri/profile.rb +21 -0
  60. data/lib/milestoner/configuration/transformers/uri/review.rb +24 -0
  61. data/lib/milestoner/configuration/transformers/uri/tracker.rb +24 -0
  62. data/lib/milestoner/container.rb +52 -9
  63. data/lib/milestoner/models/commit.rb +42 -0
  64. data/lib/milestoner/models/link.rb +12 -0
  65. data/lib/milestoner/models/user.rb +12 -0
  66. data/lib/milestoner/renderers/asciidoc.rb +20 -0
  67. data/lib/milestoner/renderers/markdown.rb +20 -0
  68. data/lib/milestoner/renderers/universal.rb +26 -0
  69. data/lib/milestoner/tags/creator.rb +31 -23
  70. data/lib/milestoner/tags/publisher.rb +5 -5
  71. data/lib/milestoner/tags/pusher.rb +9 -3
  72. data/lib/milestoner/templates/layouts/page.adoc.erb +2 -0
  73. data/lib/milestoner/templates/layouts/page.html.erb +37 -0
  74. data/lib/milestoner/templates/layouts/page.md.erb +2 -0
  75. data/lib/milestoner/templates/layouts/page.stream.erb +2 -0
  76. data/lib/milestoner/templates/milestones/_avatar.html.erb +5 -0
  77. data/lib/milestoner/templates/milestones/_commit.adoc.erb +1 -0
  78. data/lib/milestoner/templates/milestones/_commit.html.erb +104 -0
  79. data/lib/milestoner/templates/milestones/_commit.md.erb +1 -0
  80. data/lib/milestoner/templates/milestones/_commit.stream.erb +1 -0
  81. data/lib/milestoner/templates/milestones/_icon.html.erb +6 -0
  82. data/lib/milestoner/templates/milestones/_profile.html.erb +5 -0
  83. data/lib/milestoner/templates/milestones/show.adoc.erb +9 -0
  84. data/lib/milestoner/templates/milestones/show.html.erb +46 -0
  85. data/lib/milestoner/templates/milestones/show.md.erb +9 -0
  86. data/lib/milestoner/templates/milestones/show.stream.erb +9 -0
  87. data/lib/milestoner/templates/public/page.css.erb +373 -0
  88. data/lib/milestoner/views/context.rb +27 -0
  89. data/lib/milestoner/views/milestones/show.rb +47 -0
  90. data/lib/milestoner/views/parts/commit.rb +85 -0
  91. data/lib/milestoner.rb +1 -1
  92. data/milestoner.gemspec +17 -11
  93. data.tar.gz.sig +0 -0
  94. metadata +182 -26
  95. metadata.gz.sig +1 -1
  96. data/lib/milestoner/cli/actions/status.rb +0 -37
  97. data/lib/milestoner/presenters/commit.rb +0 -36
@@ -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
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Commits
5
+ module Enrichers
6
+ # Enriches a commit URI based on trailer information.
7
+ class URI
8
+ include Milestoner::Import[:input]
9
+
10
+ def call(commit) = format input.commit_uri, id: commit.sha
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "versionaire"
5
+
6
+ module Milestoner
7
+ module Commits
8
+ # Calculates next version based on commit trailer version keys.
9
+ class Versioner
10
+ include Import[:git]
11
+ include Dry::Monads[:result]
12
+
13
+ using Versionaire::Cast
14
+
15
+ DEFAULTS = {trailer_key: "Milestone", fallback: Versionaire::Version.new}.freeze
16
+
17
+ def initialize(defaults: DEFAULTS, collector: Collector.new, **)
18
+ @defaults = defaults
19
+ @collector = collector
20
+ super(**)
21
+ end
22
+
23
+ def call
24
+ trailer_milestones.then { |milestones| bump milestones }
25
+ .value_or(fallback)
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :defaults, :collector
31
+
32
+ def trailer_milestones
33
+ collector.call.value_or([]).each.with_object [] do |commit, values|
34
+ commit.trailer_value_for(trailer_key).bind { |milestone| values.append milestone.to_sym }
35
+ end
36
+ end
37
+
38
+ def bump milestones
39
+ target = fallback.members.intersection(milestones).first
40
+ git.tag_last.fmap { |tag| target ? Version(tag).bump(target) : fallback }
41
+ end
42
+
43
+ def trailer_key = defaults.fetch __method__
44
+
45
+ def fallback = defaults.fetch __method__
46
+ end
47
+ end
48
+ end
@@ -8,9 +8,36 @@ Dry::Schema.load_extensions :monads
8
8
  module Milestoner
9
9
  module Configuration
10
10
  Contract = Dry::Schema.Params do
11
- required(:documentation_format).filled :string
12
- required(:prefixes).array :string
13
- optional(:version).filled :string
11
+ required(:avatar_domain).filled :string
12
+ required(:avatar_uri).filled :string
13
+ required(:build_format).filled :string
14
+ required(:build_layout) { str? | bool? }
15
+ required(:build_root).filled Etcher::Types::Pathname
16
+ required(:build_template_paths).array Etcher::Types::Pathname
17
+
18
+ required(:commit_categories).array(:hash) do
19
+ required(:emoji).filled :string
20
+ required(:label).filled :string
21
+ end
22
+
23
+ required(:commit_domain).filled :string
24
+ required(:commit_format).filled :string
25
+ required(:commit_uri).filled :string
26
+ required(:generator_label).filled :string
27
+ required(:generator_uri).filled :string
28
+ required(:profile_domain).filled :string
29
+ required(:profile_uri).filled :string
30
+ required(:project_author).filled :string
31
+ optional(:project_description).maybe :string
32
+ optional(:project_label).filled :string
33
+ required(:project_name).filled :string
34
+ optional(:project_owner).filled :string
35
+ optional(:project_uri).maybe :string
36
+ required(:project_version).filled Etcher::Types::Version
37
+ required(:review_domain).filled :string
38
+ required(:review_uri).filled :string
39
+ required(:tracker_domain).filled :string
40
+ required(:tracker_uri).filled :string
14
41
  end
15
42
  end
16
43
  end
@@ -1,8 +1,31 @@
1
- documentation:
2
- format: "adoc"
3
- prefixes:
4
- - Fixed
5
- - Added
6
- - Updated
7
- - Removed
8
- - Refactored
1
+ avatar:
2
+ domain: https://avatars.githubusercontent.com
3
+ uri: "%<domain>s/u/%<id>s"
4
+ build:
5
+ format: web
6
+ layout: page
7
+ root: tmp/milestone
8
+ commit:
9
+ categories:
10
+ - emoji: ✅
11
+ label: Fixed
12
+ - emoji: 🟢
13
+ label: Added
14
+ - emoji: 🔼
15
+ label: Updated
16
+ - emoji: ⛔️
17
+ label: Removed
18
+ - emoji: 🔁
19
+ label: Refactored
20
+ domain: https://github.com
21
+ format: asciidoc
22
+ uri: "%<domain>s/%<owner>s/%<name>s/commit/%<id>s"
23
+ profile:
24
+ domain: https://github.com
25
+ uri: "%<domain>s/%<id>s"
26
+ review:
27
+ domain: https://github.com
28
+ uri: "%<domain>s/%<owner>s/%<name>s/pulls/%<id>s"
29
+ tracker:
30
+ domain: https://github.com
31
+ uri: "%<domain>s/%<owner>s/%<name>s/issues/%<id>s"
@@ -3,6 +3,31 @@
3
3
  module Milestoner
4
4
  module Configuration
5
5
  # Defines configuration content as the primary source of truth for use throughout the gem.
6
- Model = Struct.new :documentation_format, :prefixes, :version
6
+ Model = Struct.new :avatar_domain,
7
+ :avatar_uri,
8
+ :build_format,
9
+ :build_layout,
10
+ :build_root,
11
+ :build_template_paths,
12
+ :commit_categories,
13
+ :commit_domain,
14
+ :commit_format,
15
+ :commit_uri,
16
+ :generator_label,
17
+ :generator_uri,
18
+ :profile_domain,
19
+ :profile_uri,
20
+ :project_author,
21
+ :project_description,
22
+ :project_generator,
23
+ :project_label,
24
+ :project_name,
25
+ :project_owner,
26
+ :project_uri,
27
+ :project_version,
28
+ :review_domain,
29
+ :review_uri,
30
+ :tracker_domain,
31
+ :tracker_uri
7
32
  end
8
33
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "refinements/hash"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ # Ensures build root is expanded.
11
+ module Build
12
+ using Refinements::Hash
13
+
14
+ Root = lambda do |content, key = :build_root|
15
+ content.transform_with! key => -> value { Pathname(value).expand_path }
16
+ Dry::Monads::Success content
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "runcom"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Build
11
+ # Ensures XDG configuration and gem template paths are configured.
12
+ class TemplatePaths
13
+ include Dry::Monads[:result]
14
+
15
+ def initialize key = :build_template_paths,
16
+ default: Pathname(__dir__).join("../../../templates"),
17
+ xdg_config: Runcom::Config.new("milestoner/templates")
18
+ @key = key
19
+ @default = default
20
+ @xdg_config = xdg_config
21
+ end
22
+
23
+ def call(content) = Success content.merge!(key => xdg_config.all.append(default))
24
+
25
+ private
26
+
27
+ attr_reader :key, :default, :xdg_config
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cff"
4
+ require "dry/monads"
5
+ require "pathname"
6
+ require "refinements/hash"
7
+
8
+ module Milestoner
9
+ module Configuration
10
+ module Transformers
11
+ module Citations
12
+ # Conditionally updates project description based on citation details.
13
+ class Description
14
+ include Dry::Monads[:result]
15
+
16
+ using Refinements::Hash
17
+
18
+ def initialize key = :project_description,
19
+ path: Pathname.pwd.join("CITATION.cff"),
20
+ citation: CFF::File
21
+ @key = key
22
+ @path = path
23
+ @citation = citation
24
+ end
25
+
26
+ def call content
27
+ content.fetch_value(key) { citation.open(path).abstract }
28
+ .then { |value| value unless String(value).empty? }
29
+ .then { |value| Success content.merge!(key => value) }
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :key, :path, :citation
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cff"
4
+ require "dry/monads"
5
+ require "pathname"
6
+ require "refinements/hash"
7
+
8
+ module Milestoner
9
+ module Configuration
10
+ module Transformers
11
+ module Citations
12
+ # Conditionally updates project label based on citation details.
13
+ class Label
14
+ include Dry::Monads[:result]
15
+
16
+ using Refinements::Hash
17
+
18
+ def initialize key = :project_label,
19
+ path: Pathname.pwd.join("CITATION.cff"),
20
+ citation: CFF::File
21
+ @key = key
22
+ @path = path
23
+ @citation = citation
24
+ end
25
+
26
+ def call content
27
+ content.fetch_value(key) { citation.open(path).title }
28
+ .then { |value| value unless String(value).empty? }
29
+ .then { |value| Success content.merge!(key => value) }
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :key, :path, :citation
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "spek"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Gems
11
+ # Conditionally updates project description based on specification summary.
12
+ class Description
13
+ include Import[:spec_loader]
14
+ include Dry::Monads[:result]
15
+
16
+ def initialize(key = :project_description, path: "#{Pathname.pwd.basename}.gemspec", **)
17
+ @key = key
18
+ @path = path
19
+ super(**)
20
+ end
21
+
22
+ def call content
23
+ content.fetch(key) { spec_loader.call(path).summary }
24
+ .then { |value| Success content.merge!(key => value) }
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :key, :path
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "spek"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Gems
11
+ # Conditionally updates project label based on specification label.
12
+ class Label
13
+ include Import[:spec_loader]
14
+ include Dry::Monads[:result]
15
+
16
+ def initialize(key = :project_label, path: "#{Pathname.pwd.basename}.gemspec", **)
17
+ @key = key
18
+ @path = path
19
+ super(**)
20
+ end
21
+
22
+ def call content
23
+ content.fetch(key) { spec_loader.call(path).label }
24
+ .then { |value| value unless value == "Undefined" }
25
+ .then { |value| Success content.merge!(key => value) }
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :key, :path
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "spek"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Gems
11
+ # Conditionally updates project name based on specification name.
12
+ class Name
13
+ include Import[:spec_loader]
14
+ include Dry::Monads[:result]
15
+
16
+ def initialize(key = :project_name, path: "#{Pathname.pwd.basename}.gemspec", **)
17
+ @key = key
18
+ @path = path
19
+ super(**)
20
+ end
21
+
22
+ def call content
23
+ content.fetch(key) { spec_loader.call(path).name }
24
+ .then { |value| Success content.merge!(key => value) }
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :key, :path
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "spek"
6
+
7
+ module Milestoner
8
+ module Configuration
9
+ module Transformers
10
+ module Gems
11
+ # Conditionally updates project URI based on specification home page URL.
12
+ class URI
13
+ include Import[:spec_loader]
14
+ include Dry::Monads[:result]
15
+
16
+ def initialize(key = :project_uri, path: "#{Pathname.pwd.basename}.gemspec", **)
17
+ @key = key
18
+ @path = path
19
+ super(**)
20
+ end
21
+
22
+ def call content
23
+ content.fetch(key) { spec_loader.call(path).homepage_url }
24
+ .then { |value| value unless String(value).empty? }
25
+ .then { |value| Success content.merge!(key => value) }
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :key, :path
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+
5
+ module Milestoner
6
+ module Configuration
7
+ module Transformers
8
+ module Generator
9
+ # Conditionally updates generator label based on gem specification.
10
+ class Label
11
+ include Import[:specification]
12
+ include Dry::Monads[:result]
13
+
14
+ def initialize(key = :generator_label, **)
15
+ @key = key
16
+ super(**)
17
+ end
18
+
19
+ def call content
20
+ content.fetch(key) { specification.labeled_version }
21
+ .then { |value| Success content.merge!(key => value) }
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :key
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+
5
+ module Milestoner
6
+ module Configuration
7
+ module Transformers
8
+ module Generator
9
+ # Conditionally updates generator URI based on gem specification.
10
+ class URI
11
+ include Import[:specification]
12
+ include Dry::Monads[:result]
13
+
14
+ def initialize(key = :generator_uri, **)
15
+ @key = key
16
+ super(**)
17
+ end
18
+
19
+ def call content
20
+ content.fetch(key) { specification.homepage_url }
21
+ .then { |value| Success content.merge!(key => value) }
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :key
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end