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,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "refinements/hash"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module Project
10
+ # Conditionally updates author based on Git user.
11
+ class Author
12
+ include Import[:git]
13
+ include Dry::Monads[:result]
14
+
15
+ using Refinements::Hash
16
+
17
+ def initialize(key = :project_author, **)
18
+ @key = key
19
+ super(**)
20
+ end
21
+
22
+ def call content
23
+ content.fetch_value(key) { git.get("user.name", nil).value_or(nil) }
24
+ .then { |value| Success content.merge!(key => value) }
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :key
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
+
5
+ module Milestoner
6
+ module Configuration
7
+ module Transformers
8
+ module Project
9
+ # Conditionally updates generator based on gem specification.
10
+ class Generator
11
+ include Import[:specification]
12
+ include Dry::Monads[:result]
13
+
14
+ def initialize(key = :project_generator, **)
15
+ @key = key
16
+ super(**)
17
+ end
18
+
19
+ def call content
20
+ warn "`#{self.class}##{__method__}` is deprecated, use " \
21
+ "`Milestoner::Configuration::Transformers::Generator::Label` or " \
22
+ "`Milestoner::Configuration::Transformers::Generator::URI` instead.",
23
+ category: :deprecated
24
+
25
+ Success({key => specification.labeled_version}.merge!(content))
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :key
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+ require "refinements/hash"
6
+ require "refinements/string"
7
+
8
+ module Milestoner
9
+ module Configuration
10
+ module Transformers
11
+ # Conditionally updates label based on current directory.
12
+ module Project
13
+ using Refinements::String
14
+ using Refinements::Hash
15
+
16
+ Label = lambda do |content, key = :project_label, default: Pathname.pwd.basename.to_s|
17
+ content.fetch_value(key) { default }
18
+ .then { |value| Dry::Monads::Success content.merge!(key => value.titleize) }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ 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
+ # Conditionally updates name based on current directory.
11
+ module Project
12
+ using Refinements::Hash
13
+
14
+ Name = lambda do |content, key = :project_name, default: Pathname.pwd.basename.to_s|
15
+ content.fetch_value(key) { default }
16
+ .then { |value| Dry::Monads::Success content.merge!(key => value) }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "refinements/hash"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module Project
10
+ # Conditionally updates version based on last Git tag.
11
+ class Version
12
+ include Dry::Monads[:result]
13
+
14
+ using Refinements::Hash
15
+
16
+ def initialize key = :project_version, versioner: Commits::Versioner.new
17
+ @key = key
18
+ @versioner = versioner
19
+ end
20
+
21
+ def call content
22
+ content.fetch_value(key) { versioner.call }
23
+ .then { |value| Success content.merge!(key => value) }
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :key, :versioner
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module URI
10
+ Avatar = lambda do |content, key = :avatar_uri|
11
+ domain, uri = content.values_at :avatar_domain, key
12
+
13
+ return Dry::Monads::Success content unless uri
14
+
15
+ content[key] = format uri, domain:, id: "%<id>s"
16
+ Dry::Monads::Success content
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module URI
10
+ Commit = lambda do |content, key = :commit_uri|
11
+ owner, name, domain, uri = content.values_at :project_owner,
12
+ :project_name,
13
+ :commit_domain,
14
+ key
15
+
16
+ return Dry::Monads::Success content unless uri
17
+
18
+ content[key] = format uri, domain:, owner:, name:, id: "%<id>s"
19
+ Dry::Monads::Success content
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module URI
10
+ Profile = lambda do |content, key = :profile_uri|
11
+ domain, uri = content.values_at :profile_domain, key
12
+
13
+ return Dry::Monads::Success content unless uri
14
+
15
+ content[key] = format uri, domain:, id: "%<id>s"
16
+ Dry::Monads::Success content
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module URI
10
+ Review = lambda do |content, key = :review_uri|
11
+ owner, name, domain, uri = content.values_at :project_owner,
12
+ :project_name,
13
+ :review_domain,
14
+ key
15
+
16
+ return Dry::Monads::Success content unless uri
17
+
18
+ content[key] = format uri, domain:, owner:, name:, id: "%<id>s"
19
+ Dry::Monads::Success content
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/monads"
4
+ require "pathname"
5
+
6
+ module Milestoner
7
+ module Configuration
8
+ module Transformers
9
+ module URI
10
+ Tracker = lambda do |content, key = :tracker_uri|
11
+ owner, name, domain, uri = content.values_at :project_owner,
12
+ :project_name,
13
+ :tracker_domain,
14
+ key
15
+
16
+ return Dry::Monads::Success content unless uri
17
+
18
+ content[key] = format uri, domain:, owner:, name:, id: "%<id>s"
19
+ Dry::Monads::Success content
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,7 +4,9 @@ require "cogger"
4
4
  require "dry-container"
5
5
  require "etcher"
6
6
  require "gitt"
7
+ require "lode"
7
8
  require "runcom"
9
+ require "sanitize"
8
10
  require "spek"
9
11
 
10
12
  module Milestoner
@@ -12,21 +14,62 @@ module Milestoner
12
14
  module Container
13
15
  extend Dry::Container::Mixin
14
16
 
15
- register :configuration do
16
- self[:defaults].add_loader(Etcher::Loaders::YAML.new(self[:xdg_config].active))
17
+ namespace :xdg do
18
+ register(:cache, memoize: true) { Runcom::Cache.new "milestoner/database.store" }
19
+ register(:config, memoize: true) { Runcom::Config.new "milestoner/configuration.yml" }
20
+ end
21
+
22
+ register :cache, memoize: true do
23
+ # :nocov:
24
+ Lode.new self["xdg.cache"].passive do |config|
25
+ config.mode = :max
26
+ config.table = Lode::Tables::Value
27
+ config.register :users, model: Models::User, primary_key: :name
28
+ end
29
+ end
30
+
31
+ register :configuration, memoize: true do
32
+ self[:defaults].add_loader(Etcher::Loaders::YAML.new(self["xdg.config"].active))
17
33
  .then { |registry| Etcher.call registry }
18
34
  end
19
35
 
20
- register :defaults do
36
+ register :defaults, memoize: true do
21
37
  Etcher::Registry.new(contract: Configuration::Contract, model: Configuration::Model)
22
38
  .add_loader(Etcher::Loaders::YAML.new(self[:defaults_path]))
39
+ .add_transformer(Configuration::Transformers::Build::Root)
40
+ .add_transformer(Configuration::Transformers::Build::TemplatePaths.new)
41
+ .add_transformer(Configuration::Transformers::Gems::Label.new)
42
+ .add_transformer(Configuration::Transformers::Gems::Description.new)
43
+ .add_transformer(Configuration::Transformers::Gems::Name.new)
44
+ .add_transformer(Configuration::Transformers::Gems::URI.new)
45
+ .add_transformer(Configuration::Transformers::Citations::Label.new)
46
+ .add_transformer(Configuration::Transformers::Citations::Description.new)
47
+ .add_transformer(Configuration::Transformers::Project::Author.new)
48
+ .add_transformer(Configuration::Transformers::Project::Label)
49
+ .add_transformer(Configuration::Transformers::Project::Name)
50
+ .add_transformer(Configuration::Transformers::Project::Version.new)
51
+ .add_transformer(Configuration::Transformers::Generator::Label.new)
52
+ .add_transformer(Configuration::Transformers::Generator::URI.new)
53
+ .add_transformer(Configuration::Transformers::URI::Avatar)
54
+ .add_transformer(Configuration::Transformers::URI::Commit)
55
+ .add_transformer(Configuration::Transformers::URI::Profile)
56
+ .add_transformer(Configuration::Transformers::URI::Review)
57
+ .add_transformer(Configuration::Transformers::URI::Tracker)
58
+ end
59
+
60
+ register :specification, memoize: true do
61
+ self[:spec_loader].call "#{__dir__}/../../milestoner.gemspec"
62
+ end
63
+
64
+ register :sanitizer, memoize: true do
65
+ -> content { Sanitize.fragment content, Sanitize::Config::BASIC }
23
66
  end
24
67
 
25
- register(:git) { Gitt::Repository.new }
26
- register(:defaults_path) { Pathname(__dir__).join("configuration/defaults.yml") }
27
- register(:xdg_config) { Runcom::Config.new "milestoner/configuration.yml" }
28
- register(:specification) { Spek::Loader.call "#{__dir__}/../../milestoner.gemspec" }
29
- register(:kernel) { Kernel }
30
- register(:logger) { Cogger.new id: :milestoner }
68
+ register(:spec_loader, memoize: true) { Spek::Loader.new }
69
+ register(:git, memoize: true) { Gitt::Repository.new }
70
+ register(:input, memoize: true) { self[:configuration].dup }
71
+ register(:defaults_path, memoize: true) { Pathname(__dir__).join("configuration/defaults.yml") }
72
+ register(:logger, memoize: true) { Cogger.new id: :milestoner }
73
+ register :kernel, Kernel
31
74
  end
32
75
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gitt"
4
+
5
+ module Milestoner
6
+ module Models
7
+ COMMIT_COMMON_ATTRIBUTES = %i[
8
+ authored_at
9
+ body
10
+ deletions
11
+ files_changed
12
+ insertions
13
+ notes
14
+ sha
15
+ signature
16
+ subject
17
+ ].freeze
18
+
19
+ COMMIT_ENRICHED_ATTRIBUTES = %i[
20
+ author
21
+ collaborators
22
+ format
23
+ issue
24
+ milestone
25
+ review
26
+ signers
27
+ uri
28
+ ].freeze
29
+
30
+ # Represents an enriched commit.
31
+ Commit = Struct.new(*COMMIT_COMMON_ATTRIBUTES, *COMMIT_ENRICHED_ATTRIBUTES) do
32
+ include Gitt::Directable
33
+
34
+ def self.for(commit, **) = new(**commit.to_h.slice(*COMMIT_COMMON_ATTRIBUTES), **)
35
+
36
+ def initialize(**)
37
+ super
38
+ freeze
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Models
5
+ # Represents a hyperlink.
6
+ Link = Data.define :id, :uri do
7
+ def initialize id: nil, uri: nil
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Models
5
+ # Represents an external user.
6
+ User = Data.define :external_id, :handle, :name do
7
+ def initialize external_id: nil, handle: nil, name: nil
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "asciidoctor"
4
+
5
+ module Milestoner
6
+ module Renderers
7
+ # Renders ASCII Doc as HTML.
8
+ class Asciidoc
9
+ def initialize client: Asciidoctor
10
+ @client = client
11
+ end
12
+
13
+ def call(content) = client.convert content
14
+
15
+ private
16
+
17
+ attr_reader :client
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "redcarpet"
4
+
5
+ module Milestoner
6
+ module Renderers
7
+ # Renders Markdown as HTML.
8
+ class Markdown
9
+ def initialize client: Redcarpet::Markdown.new(Redcarpet::Render::HTML.new)
10
+ @client = client
11
+ end
12
+
13
+ def call(content) = client.render content
14
+
15
+ private
16
+
17
+ attr_reader :client
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Milestoner
4
+ module Renderers
5
+ # The primary renderer for multiple input formats as HTML.
6
+ class Universal
7
+ include Import[:input]
8
+
9
+ DELEGATES = {asciidoc: Asciidoc.new, markdown: Markdown.new}.freeze
10
+
11
+ def initialize(delegates: DELEGATES, **)
12
+ super(**)
13
+ @delegates = delegates
14
+ @default_format = input.commit_format.to_sym
15
+ end
16
+
17
+ def call content, for: default_format
18
+ delegates.fetch(binding.local_variable_get(:for)).call content
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :delegates, :default_format
24
+ end
25
+ end
26
+ end
@@ -1,38 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "gitt"
4
+ require "refinements/string_io"
4
5
  require "versionaire"
5
6
 
6
7
  module Milestoner
7
8
  module Tags
8
9
  # Handles the creation of project repository tags.
9
10
  class Creator
10
- include Import[:git, :logger]
11
+ include Import[:input, :git, :logger]
11
12
 
13
+ using Refinements::StringIO
12
14
  using Versionaire::Cast
13
15
 
14
- def initialize(categorizer: Commits::Categorizer.new, presenter: Presenters::Commit, **)
16
+ def initialize(
17
+ collector: Commits::Collector.new,
18
+ builder: Builders::Stream.new(kernel: StringIO.new),
19
+ **
20
+ )
21
+ @collector = collector
22
+ @builder = builder
15
23
  super(**)
16
- @categorizer = categorizer
17
- @presenter = presenter
18
24
  end
19
25
 
20
- def call configuration = Container[:configuration]
21
- return false if local? configuration
22
- fail Error, "Unable to tag without commits." if categorizer.call.empty?
26
+ def call override = nil
27
+ version = compute_version override
23
28
 
24
- create configuration
25
- rescue Versionaire::Error => error
26
- raise Error, error.message
29
+ return false if local? version
30
+ fail Error, "Unable to tag without commits." if collector.call.value_or([]).empty?
31
+
32
+ create version
27
33
  end
28
34
 
29
35
  private
30
36
 
31
- attr_reader :categorizer, :presenter
37
+ attr_reader :collector, :builder
32
38
 
33
- def local? configuration
34
- version = Version configuration.version
39
+ def compute_version value
40
+ Version value || input.project_version
41
+ rescue Versionaire::Error => error
42
+ raise Error, error
43
+ end
35
44
 
45
+ def local? version
36
46
  if git.tag_local? version
37
47
  logger.warn { "Local tag exists: #{version}. Skipped." }
38
48
  true
@@ -41,18 +51,16 @@ module Milestoner
41
51
  end
42
52
  end
43
53
 
44
- def create configuration
45
- git.tag_create(configuration.version, message(configuration))
46
- .or { |error| fail Error, error }
47
- .bind { true }
54
+ def create version
55
+ build(version).fmap { |body| git.tag_create version, body }
56
+ .or { |error| fail Error, error }
57
+ .bind { true }
48
58
  end
49
59
 
50
- def message configuration
51
- categorizer.call(configuration)
52
- .map { |record| presenter.new(record).line_item }
53
- .then do |line_items|
54
- %(Version #{configuration.version}\n\n#{line_items.join "\n"}\n\n)
55
- end
60
+ def build version
61
+ builder.call.fmap do |body|
62
+ "Version #{version}\n\n#{body.reread}\n\n"
63
+ end
56
64
  end
57
65
  end
58
66
  end
@@ -4,7 +4,7 @@ module Milestoner
4
4
  module Tags
5
5
  # Handles the tagging and pushing of a tag to a remote repository.
6
6
  class Publisher
7
- include Import[:logger]
7
+ include Import[:input, :logger]
8
8
 
9
9
  def initialize(creator: Tags::Creator.new, pusher: Tags::Pusher.new, **)
10
10
  super(**)
@@ -12,10 +12,10 @@ module Milestoner
12
12
  @pusher = pusher
13
13
  end
14
14
 
15
- def call configuration = Container[:configuration]
16
- creator.call configuration
17
- pusher.call configuration
18
- logger.info { "Published: #{configuration.version}!" }
15
+ def call override = nil
16
+ creator.call override
17
+ pusher.call override
18
+ logger.info { "Published: #{input.project_version}!" }
19
19
  end
20
20
 
21
21
  private
@@ -6,12 +6,12 @@ module Milestoner
6
6
  module Tags
7
7
  # Handles publishing of tags to a remote repository.
8
8
  class Pusher
9
- include Import[:git, :logger]
9
+ include Import[:input, :git, :logger]
10
10
 
11
11
  using Versionaire::Cast
12
12
 
13
- def call configuration = Container[:configuration]
14
- version = Version configuration.version
13
+ def call override = nil
14
+ version = compute_version override
15
15
 
16
16
  fail Error, "Remote repository not configured." unless git.origin?
17
17
  fail Error, "Remote tag exists: #{version}." if git.tag_remote? version
@@ -19,6 +19,12 @@ module Milestoner
19
19
 
20
20
  logger.debug "Local tag pushed: #{version}."
21
21
  end
22
+
23
+ def compute_version value
24
+ Version value || input.project_version
25
+ rescue Versionaire::Error => error
26
+ raise Error, error
27
+ end
22
28
  end
23
29
  end
24
30
  end
@@ -0,0 +1,2 @@
1
+ <%= yield %>
2
+ _Generated by link:<%= generator_uri %>[<%= generator_label %>]._
@@ -0,0 +1,37 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html lang="en">
4
+ <head>
5
+ <title><%= project_title %></title>
6
+
7
+ <meta charset="utf-8">
8
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
9
+ <meta name="description" content="<%= project_description %>">
10
+ <meta name="author" content="<%= project_author %>">
11
+ <meta name="generator" content="<%= generator_label %>">
12
+
13
+ <link title="<%= project_label %>: Favorite Icon"
14
+ rel="icon"
15
+ href="https://alchemists.io/images/projects/milestoner/icons/brand/favicon.ico"
16
+ sizes="32x32">
17
+ <link title="<%= project_label %>: Apple Icon"
18
+ rel="apple-touch-icon"
19
+ href="https://alchemists.io/images/projects/milestoner/icons/brand/apple.png"
20
+ type="image/png">
21
+ <link title="<%= project_label %>: Stylesheet" rel="stylesheet" href="page.css" type="text/css">
22
+
23
+ <script src="https://unpkg.com/alpinejs@3.13" defer></script>
24
+ </head>
25
+
26
+ <body>
27
+ <main>
28
+ <%= yield %>
29
+ </main>
30
+
31
+ <footer class="footer">
32
+ <p class="generator">
33
+ Generated by <a href="<%= generator_uri %>" class="link"><%= generator_label %></a>.
34
+ </p>
35
+ </footer>
36
+ </body>
37
+ </html>