metanorma-release 0.2.1

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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +1 -0
  4. data/.rubocop_todo.yml +504 -0
  5. data/CHANGELOG.md +15 -0
  6. data/PROMPT.md +282 -0
  7. data/README.adoc +430 -0
  8. data/Rakefile +8 -0
  9. data/exe/mn-release +6 -0
  10. data/lib/metanorma/release/aggregation_interfaces.rb +33 -0
  11. data/lib/metanorma/release/aggregation_pipeline.rb +155 -0
  12. data/lib/metanorma/release/asset_processor.rb +58 -0
  13. data/lib/metanorma/release/cache_store.rb +86 -0
  14. data/lib/metanorma/release/change_detector.rb +20 -0
  15. data/lib/metanorma/release/channel.rb +64 -0
  16. data/lib/metanorma/release/channel_audience.rb +24 -0
  17. data/lib/metanorma/release/channel_config.rb +55 -0
  18. data/lib/metanorma/release/channel_filter.rb +26 -0
  19. data/lib/metanorma/release/channel_manifest.rb +192 -0
  20. data/lib/metanorma/release/channel_registry.rb +60 -0
  21. data/lib/metanorma/release/cli.rb +129 -0
  22. data/lib/metanorma/release/commands/aggregate.rb +126 -0
  23. data/lib/metanorma/release/commands/package.rb +46 -0
  24. data/lib/metanorma/release/commands/publish.rb +51 -0
  25. data/lib/metanorma/release/config_fetcher.rb +11 -0
  26. data/lib/metanorma/release/config_locator.rb +37 -0
  27. data/lib/metanorma/release/config_resolver.rb +37 -0
  28. data/lib/metanorma/release/content_hash.rb +51 -0
  29. data/lib/metanorma/release/delta_state.rb +108 -0
  30. data/lib/metanorma/release/document_id.rb +45 -0
  31. data/lib/metanorma/release/document_index.rb +183 -0
  32. data/lib/metanorma/release/document_metadata.rb +39 -0
  33. data/lib/metanorma/release/document_stage.rb +86 -0
  34. data/lib/metanorma/release/document_type.rb +55 -0
  35. data/lib/metanorma/release/document_version.rb +50 -0
  36. data/lib/metanorma/release/file_routing.rb +51 -0
  37. data/lib/metanorma/release/interfaces.rb +47 -0
  38. data/lib/metanorma/release/naming_strategy.rb +158 -0
  39. data/lib/metanorma/release/platform/github/config_fetcher.rb +40 -0
  40. data/lib/metanorma/release/platform/github/manifest_reader.rb +32 -0
  41. data/lib/metanorma/release/platform/github/publisher.rb +73 -0
  42. data/lib/metanorma/release/platform/github/release_fetcher.rb +52 -0
  43. data/lib/metanorma/release/platform/github/topic_discoverer.rb +29 -0
  44. data/lib/metanorma/release/platform/github.rb +25 -0
  45. data/lib/metanorma/release/platform/local/config_fetcher.rb +20 -0
  46. data/lib/metanorma/release/platform/local/directory_discoverer.rb +26 -0
  47. data/lib/metanorma/release/platform/local/fetcher.rb +76 -0
  48. data/lib/metanorma/release/platform/local/publisher.rb +44 -0
  49. data/lib/metanorma/release/platform/local.rb +14 -0
  50. data/lib/metanorma/release/platform/null/publisher.rb +17 -0
  51. data/lib/metanorma/release/platform/null.rb +11 -0
  52. data/lib/metanorma/release/platform.rb +11 -0
  53. data/lib/metanorma/release/platform_factory.rb +78 -0
  54. data/lib/metanorma/release/rake_tasks.rb +71 -0
  55. data/lib/metanorma/release/relaton_enricher.rb +138 -0
  56. data/lib/metanorma/release/release_metadata.rb +79 -0
  57. data/lib/metanorma/release/release_pipeline.rb +115 -0
  58. data/lib/metanorma/release/release_tag.rb +49 -0
  59. data/lib/metanorma/release/repo_ref.rb +34 -0
  60. data/lib/metanorma/release/rxl_extractor.rb +115 -0
  61. data/lib/metanorma/release/stage_filter.rb +18 -0
  62. data/lib/metanorma/release/version.rb +7 -0
  63. data/lib/metanorma/release/zip_packager.rb +37 -0
  64. data/lib/metanorma/release.rb +116 -0
  65. metadata +156 -0
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Release
5
+ class ReleasePipeline
6
+ Dependencies = Struct.new(
7
+ :extractor, :filters, :change_detector,
8
+ :packager, :publisher, :naming_registry,
9
+ :manifest, :channel_override, :channel_config,
10
+ keyword_init: true
11
+ )
12
+
13
+ Config = Struct.new(
14
+ :output_dir, :manifest_path, :force, :force_replace_patterns,
15
+ :concurrency, :default_visibility,
16
+ keyword_init: true
17
+ )
18
+
19
+ def initialize(deps)
20
+ @deps = deps
21
+ end
22
+
23
+ def run(config)
24
+ documents = @deps.extractor.discover(config.output_dir)
25
+ filtered = apply_filters(documents)
26
+ results = phase_one(filtered, config)
27
+ phase_two(results, config)
28
+ end
29
+
30
+ private
31
+
32
+ def apply_filters(documents)
33
+ return documents unless @deps.filters && !@deps.filters.empty?
34
+
35
+ @deps.filters.reduce(documents) { |docs, filter| filter.apply(docs) }
36
+ end
37
+
38
+ def phase_one(documents, config)
39
+ documents.map do |doc|
40
+ strategy = @deps.naming_registry.resolve(doc.document_type)
41
+ tag = strategy.compute_tag(doc.id.to_s, doc.version)
42
+ canonical_base = strategy.compute_canonical_base(doc.id.to_s, doc.version)
43
+ change = @deps.change_detector.detect(doc, tag, force: config.force)
44
+
45
+ { document: doc, tag: tag, canonical_base: canonical_base,
46
+ changed: change.changed?, change_result: change }
47
+ end
48
+ end
49
+
50
+ def phase_two(candidates, config)
51
+ released = []
52
+ skipped = []
53
+ failed = []
54
+ released_artifacts = []
55
+
56
+ candidates.each do |candidate|
57
+ doc = candidate[:document]
58
+ tag = candidate[:tag]
59
+
60
+ unless candidate[:changed]
61
+ skipped << doc
62
+ next
63
+ end
64
+
65
+ begin
66
+ policy = resolve_policy(doc, config)
67
+ unless policy.release?
68
+ skipped << doc
69
+ next
70
+ end
71
+
72
+ artifact = @deps.packager.package(doc, canonical_base: candidate[:canonical_base])
73
+ channels = resolve_channels(doc, policy)
74
+ metadata_json = ReleaseMetadata.from_document(doc, channels: channels)
75
+ force = config.force_replace_patterns&.any? { |p| File.fnmatch?(p, doc.id.to_s) } || false
76
+
77
+ result = @deps.publisher.publish(tag, artifact, metadata_json, channels: channels, force_replace: force)
78
+ released << doc
79
+ released_artifacts << ReleasedArtifact.new(
80
+ id: doc.id.to_s, tag: tag.to_s,
81
+ url: result.url, channels: channels.map(&:to_s)
82
+ )
83
+ rescue StandardError => e
84
+ failed << { document: doc, error: e.message }
85
+ end
86
+ end
87
+
88
+ ReleaseResult.new(released: released, skipped: skipped, failed: failed,
89
+ released_artifacts: released_artifacts)
90
+ end
91
+
92
+ def resolve_policy(doc, _config)
93
+ return @deps.manifest.resolve(doc) if @deps.manifest
94
+
95
+ DocumentReleasePolicy.from_defaults('public', [Channel.public('default')])
96
+ end
97
+
98
+ def resolve_channels(_doc, policy)
99
+ channels = if @deps.channel_override && !@deps.channel_override.empty?
100
+ @deps.channel_override
101
+ else
102
+ policy.channels
103
+ end
104
+
105
+ validate_channels(channels)
106
+ end
107
+
108
+ def validate_channels(channels)
109
+ return channels unless @deps.channel_config
110
+
111
+ channels.select { |ch| @deps.channel_config.registry.valid?(ch) }
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Release
5
+ class ReleaseTag
6
+ PRE_RELEASE_SUFFIXES = %w[-wd -cd -ds -fd -proposal].freeze
7
+
8
+ def self.from(doc_id, version)
9
+ tag = "#{doc_id}/#{version.tag_component}"
10
+ new(tag: tag, pre_release: version.pre_release?)
11
+ end
12
+
13
+ def self.create(tag, pre_release:)
14
+ raise ArgumentError, 'Tag must contain a slash separator' unless tag.include?('/')
15
+
16
+ new(tag: tag, pre_release: pre_release)
17
+ end
18
+
19
+ def self.parse(tag)
20
+ raise ArgumentError, 'Tag must contain a slash separator' unless tag.include?('/')
21
+
22
+ pre = PRE_RELEASE_SUFFIXES.any? { |s| tag.include?(s) }
23
+ new(tag: tag, pre_release: pre)
24
+ end
25
+
26
+ def initialize(tag:, pre_release:)
27
+ @tag = tag
28
+ @pre_release = pre_release
29
+ freeze
30
+ end
31
+
32
+ def to_s
33
+ @tag
34
+ end
35
+
36
+ def pre_release?
37
+ @pre_release
38
+ end
39
+
40
+ def eql?(other)
41
+ other.is_a?(self.class) && @tag == other.to_s
42
+ end
43
+
44
+ def hash
45
+ @tag.hash
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Release
5
+ class RepoRef
6
+ attr_reader :owner, :repo
7
+
8
+ def self.from_string(str)
9
+ parts = str.split('/', 2)
10
+ raise ArgumentError, "Invalid repo reference: #{str}" unless parts.length == 2
11
+
12
+ new(owner: parts[0], repo: parts[1])
13
+ end
14
+
15
+ def initialize(owner:, repo:)
16
+ @owner = owner
17
+ @repo = repo
18
+ freeze
19
+ end
20
+
21
+ def to_s
22
+ "#{owner}/#{repo}"
23
+ end
24
+
25
+ def eql?(other)
26
+ other.is_a?(self.class) && owner == other.owner && repo == other.repo
27
+ end
28
+
29
+ def hash
30
+ [owner, repo].hash
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'nokogiri'
5
+ rescue LoadError
6
+ raise LoadError, "The nokogiri gem is required for RxlExtractor. Add `gem 'nokogiri'` to your Gemfile."
7
+ end
8
+
9
+ module Metanorma
10
+ module Release
11
+ class RxlExtractor
12
+ def initialize(fallback_flavor: nil)
13
+ @fallback_flavor = fallback_flavor
14
+ end
15
+
16
+ def discover(output_dir)
17
+ rxl_files = Dir.glob(File.join(output_dir, '**', '*.rxl'))
18
+ rxl_files.filter_map do |path|
19
+ extract(path)
20
+ rescue StandardError => e
21
+ warn "Warning: Skipping #{path}: #{e.message}"
22
+ nil
23
+ end
24
+ end
25
+
26
+ def extract(rxl_path)
27
+ raise ArgumentError, "RXL file not found: #{rxl_path}" unless File.exist?(rxl_path)
28
+
29
+ content = File.read(rxl_path)
30
+ doc = Nokogiri::XML(content, nil, 'UTF-8', Nokogiri::XML::ParseOptions::STRICT)
31
+ extract_from_xml(doc, rxl_path)
32
+ rescue Nokogiri::XML::SyntaxError => e
33
+ warn "Warning: Failed to parse RXL #{rxl_path}: #{e.message}"
34
+ fallback_metadata(rxl_path)
35
+ end
36
+
37
+ private
38
+
39
+ def extract_from_xml(xml, rxl_path)
40
+ bibdata = xml.at_xpath('/bibdata') || xml.root
41
+ raw_id = text_of(bibdata, 'docidentifier') || derive_id_from_path(rxl_path)
42
+ id = DocumentId.from_raw(raw_id)
43
+ title = text_of(bibdata, 'title') || ''
44
+ edition = text_of(bibdata, 'edition') || '1'
45
+ stage_node = bibdata.at_xpath('status/stage')
46
+ stage = if stage_node
47
+ DocumentStage.from_iso_stage(stage_node.text.to_i)
48
+ else
49
+ DocumentStage.published
50
+ end
51
+ version = DocumentVersion.from(edition, stage)
52
+ doctype = text_of(bibdata, 'ext/doctype') || ''
53
+ revdate = extract_revdate(bibdata)
54
+ flavor = @fallback_flavor || detect_flavor(raw_id)
55
+ output_dir = File.dirname(rxl_path)
56
+ file_base_name = File.basename(rxl_path, '.rxl')
57
+ formats = detect_formats(output_dir, file_base_name)
58
+ document_type = DocumentType.from_identifier(raw_id)
59
+
60
+ DocumentMetadata.new(
61
+ id: id, title: title, version: version, doctype: doctype,
62
+ document_type: document_type, flavor: flavor, revdate: revdate,
63
+ source_path: derive_source_path(rxl_path), output_dir: output_dir,
64
+ formats: formats, file_base_name: file_base_name
65
+ )
66
+ end
67
+
68
+ def fallback_metadata(rxl_path)
69
+ file_base_name = File.basename(rxl_path, '.rxl')
70
+ id = DocumentId.from_raw(file_base_name)
71
+ DocumentMetadata.new(
72
+ id: id, title: '', version: DocumentVersion.published(edition: '0'),
73
+ doctype: '', document_type: 'standard', flavor: nil, revdate: nil,
74
+ source_path: rxl_path, output_dir: File.dirname(rxl_path),
75
+ formats: [], file_base_name: file_base_name
76
+ )
77
+ end
78
+
79
+ def text_of(node, xpath)
80
+ n = node.at_xpath(xpath)
81
+ n&.text&.strip
82
+ end
83
+
84
+ def extract_revdate(bibdata)
85
+ date_node = bibdata.at_xpath("date[@type='published']/on") ||
86
+ bibdata.at_xpath('date/on')
87
+ date_node&.text&.strip
88
+ end
89
+
90
+ def detect_formats(output_dir, base_name)
91
+ extensions = []
92
+ %w[html pdf xml rxl doc].each do |ext|
93
+ path = File.join(output_dir, "#{base_name}.#{ext}")
94
+ extensions << ext if File.exist?(path)
95
+ end
96
+ extensions
97
+ end
98
+
99
+ def detect_flavor(raw_id)
100
+ return nil if raw_id.nil?
101
+
102
+ parts = raw_id.split(/\s|-/)
103
+ parts.first&.downcase
104
+ end
105
+
106
+ def derive_id_from_path(rxl_path)
107
+ File.basename(rxl_path, '.rxl')
108
+ end
109
+
110
+ def derive_source_path(rxl_path)
111
+ rxl_path.sub(/\.rxl$/, '.adoc')
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Release
5
+ class StageFilter
6
+ def initialize(stages)
7
+ @stages = Set.new(stages.map(&:downcase))
8
+ @all = @stages.empty?
9
+ end
10
+
11
+ def matches?(release_metadata)
12
+ return true if @all
13
+
14
+ @stages.include?(release_metadata['stage'].to_s.downcase)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Release
5
+ VERSION = '0.2.1'
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'zip'
5
+ rescue LoadError
6
+ raise LoadError, "The rubyzip gem is required for ZipPackager. Add `gem 'rubyzip'` to your Gemfile."
7
+ end
8
+
9
+ module Metanorma
10
+ module Release
11
+ class ZipPackager
12
+ include Packager
13
+
14
+ def package(metadata, canonical_base:)
15
+ dir = metadata.output_dir
16
+ base = metadata.file_base_name
17
+ files = Dir.glob(File.join(dir, "#{base}.*")).reject { |f| File.directory?(f) }
18
+
19
+ zip_path = File.join(dir, "#{canonical_base}.zip")
20
+ File.delete(zip_path) if File.exist?(zip_path)
21
+ Zip::File.open(zip_path, Zip::File::CREATE) do |zipfile|
22
+ files.each do |file|
23
+ ext = File.extname(file)
24
+ entry_name = "#{canonical_base}#{ext}"
25
+ zipfile.add(entry_name, file)
26
+ end
27
+ end
28
+
29
+ Artifact.new(
30
+ zip_path: zip_path,
31
+ asset_name: "#{canonical_base}.zip",
32
+ size: File.size(zip_path)
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Release
5
+ require_relative 'release/version'
6
+
7
+ # Domain value objects
8
+ autoload :ChannelAudience, 'metanorma/release/channel_audience'
9
+ autoload :Channel, 'metanorma/release/channel'
10
+ autoload :ChannelRegistry, 'metanorma/release/channel_registry'
11
+ autoload :ChannelConfig, 'metanorma/release/channel_config'
12
+ autoload :ConfigLocator, 'metanorma/release/config_locator'
13
+ autoload :ContentHash, 'metanorma/release/content_hash'
14
+ autoload :DocumentId, 'metanorma/release/document_id'
15
+ autoload :DocumentStage, 'metanorma/release/document_stage'
16
+ autoload :DocumentType, 'metanorma/release/document_type'
17
+ autoload :DocumentVersion, 'metanorma/release/document_version'
18
+ autoload :ReleaseTag, 'metanorma/release/release_tag'
19
+ autoload :RepoRef, 'metanorma/release/repo_ref'
20
+
21
+ # Domain strategies
22
+ autoload :NamingStrategy, 'metanorma/release/naming_strategy'
23
+ autoload :EditionNaming, 'metanorma/release/naming_strategy'
24
+ autoload :VersionNaming, 'metanorma/release/naming_strategy'
25
+ autoload :InternetDraftNaming, 'metanorma/release/naming_strategy'
26
+ autoload :RfcNaming, 'metanorma/release/naming_strategy'
27
+ autoload :DraftSuffixNaming, 'metanorma/release/naming_strategy'
28
+ autoload :NamingRegistry, 'metanorma/release/naming_strategy'
29
+
30
+ # Manifest & policy
31
+ autoload :ChannelManifest, 'metanorma/release/channel_manifest'
32
+ autoload :DocumentReleasePolicy, 'metanorma/release/channel_manifest'
33
+ autoload :ManifestEntry, 'metanorma/release/channel_manifest'
34
+
35
+ # Metadata
36
+ autoload :DocumentMetadata, 'metanorma/release/document_metadata'
37
+ autoload :ReleaseMetadata, 'metanorma/release/release_metadata'
38
+ autoload :RxlExtractor, 'metanorma/release/rxl_extractor'
39
+
40
+ # Interfaces
41
+ autoload :Extractor, 'metanorma/release/interfaces'
42
+ autoload :Filter, 'metanorma/release/interfaces'
43
+ autoload :ChangeDetector, 'metanorma/release/interfaces'
44
+ autoload :Packager, 'metanorma/release/interfaces'
45
+ autoload :Publisher, 'metanorma/release/interfaces'
46
+
47
+ # Pipeline components
48
+ autoload :ChangeResult, 'metanorma/release/interfaces'
49
+ autoload :Artifact, 'metanorma/release/interfaces'
50
+ autoload :PublishResult, 'metanorma/release/interfaces'
51
+ autoload :ReleasedArtifact, 'metanorma/release/interfaces'
52
+ autoload :ReleaseResult, 'metanorma/release/interfaces'
53
+ autoload :ContentHashChangeDetector, 'metanorma/release/change_detector'
54
+ autoload :ZipPackager, 'metanorma/release/zip_packager'
55
+ autoload :ReleasePipeline, 'metanorma/release/release_pipeline'
56
+
57
+ # Cache
58
+ autoload :CacheStore, 'metanorma/release/cache_store'
59
+ autoload :FileCacheStore, 'metanorma/release/cache_store'
60
+ autoload :NullCacheStore, 'metanorma/release/cache_store'
61
+
62
+ # Aggregation filters
63
+ autoload :ChannelFilter, 'metanorma/release/channel_filter'
64
+ autoload :ConfigFetcher, 'metanorma/release/config_fetcher'
65
+ autoload :StageFilter, 'metanorma/release/stage_filter'
66
+ autoload :DeltaState, 'metanorma/release/delta_state'
67
+ autoload :NullDeltaState, 'metanorma/release/delta_state'
68
+
69
+ # Document index
70
+ autoload :DocumentFile, 'metanorma/release/document_index'
71
+ autoload :DocumentSource, 'metanorma/release/document_index'
72
+ autoload :IndexParameters, 'metanorma/release/document_index'
73
+ autoload :IndexSummary, 'metanorma/release/document_index'
74
+ autoload :AggregatedDocument, 'metanorma/release/document_index'
75
+ autoload :DocumentIndex, 'metanorma/release/document_index'
76
+
77
+ # Asset processing
78
+ autoload :FileRouting, 'metanorma/release/file_routing'
79
+ autoload :ByDocument, 'metanorma/release/file_routing'
80
+ autoload :Flat, 'metanorma/release/file_routing'
81
+ autoload :ByFormat, 'metanorma/release/file_routing'
82
+ autoload :FileRoutingFactory, 'metanorma/release/file_routing'
83
+ autoload :AssetProcessor, 'metanorma/release/asset_processor'
84
+
85
+ # Aggregation
86
+ autoload :RepoDiscoverer, 'metanorma/release/aggregation_interfaces'
87
+ autoload :ReleaseFetcher, 'metanorma/release/aggregation_interfaces'
88
+ autoload :ManifestReader, 'metanorma/release/aggregation_interfaces'
89
+ autoload :IndexGenerator, 'metanorma/release/aggregation_interfaces'
90
+ autoload :FetchResult, 'metanorma/release/aggregation_interfaces'
91
+ autoload :RepoReport, 'metanorma/release/aggregation_interfaces'
92
+ autoload :RepoError, 'metanorma/release/aggregation_interfaces'
93
+ autoload :AggregationPipeline, 'metanorma/release/aggregation_pipeline'
94
+
95
+ # Platform namespace
96
+ autoload :Platform, 'metanorma/release/platform'
97
+
98
+ # Platform factory
99
+ autoload :PlatformFactory, 'metanorma/release/platform_factory'
100
+
101
+ # Relaton enrichment
102
+ autoload :RelatonEnricher, 'metanorma/release/relaton_enricher'
103
+
104
+ # CLI & Rake
105
+ autoload :CLI, 'metanorma/release/cli'
106
+ autoload :RakeTasks, 'metanorma/release/rake_tasks'
107
+
108
+ # Commands
109
+ autoload :PackageCommand, 'metanorma/release/commands/package'
110
+ autoload :PublishCommand, 'metanorma/release/commands/publish'
111
+ autoload :AggregateCommand, 'metanorma/release/commands/aggregate'
112
+
113
+ # Config resolution
114
+ autoload :ConfigResolver, 'metanorma/release/config_resolver'
115
+ end
116
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: metanorma-release
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Ribose Inc.
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2026-05-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: relaton-bib
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.13'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.13'
55
+ description: 'Manages the full release lifecycle of Metanorma documents: discover
56
+ compiled documents, extract metadata, detect changes, package as zip, publish to
57
+ platforms (GitHub Releases, GitLab, local filesystem), and aggregate published releases
58
+ into index.json with a file tree for any site generator.'
59
+ email:
60
+ - open.source@ribose.com
61
+ executables:
62
+ - mn-release
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - ".rspec"
67
+ - ".rubocop.yml"
68
+ - ".rubocop_todo.yml"
69
+ - CHANGELOG.md
70
+ - PROMPT.md
71
+ - README.adoc
72
+ - Rakefile
73
+ - exe/mn-release
74
+ - lib/metanorma/release.rb
75
+ - lib/metanorma/release/aggregation_interfaces.rb
76
+ - lib/metanorma/release/aggregation_pipeline.rb
77
+ - lib/metanorma/release/asset_processor.rb
78
+ - lib/metanorma/release/cache_store.rb
79
+ - lib/metanorma/release/change_detector.rb
80
+ - lib/metanorma/release/channel.rb
81
+ - lib/metanorma/release/channel_audience.rb
82
+ - lib/metanorma/release/channel_config.rb
83
+ - lib/metanorma/release/channel_filter.rb
84
+ - lib/metanorma/release/channel_manifest.rb
85
+ - lib/metanorma/release/channel_registry.rb
86
+ - lib/metanorma/release/cli.rb
87
+ - lib/metanorma/release/commands/aggregate.rb
88
+ - lib/metanorma/release/commands/package.rb
89
+ - lib/metanorma/release/commands/publish.rb
90
+ - lib/metanorma/release/config_fetcher.rb
91
+ - lib/metanorma/release/config_locator.rb
92
+ - lib/metanorma/release/config_resolver.rb
93
+ - lib/metanorma/release/content_hash.rb
94
+ - lib/metanorma/release/delta_state.rb
95
+ - lib/metanorma/release/document_id.rb
96
+ - lib/metanorma/release/document_index.rb
97
+ - lib/metanorma/release/document_metadata.rb
98
+ - lib/metanorma/release/document_stage.rb
99
+ - lib/metanorma/release/document_type.rb
100
+ - lib/metanorma/release/document_version.rb
101
+ - lib/metanorma/release/file_routing.rb
102
+ - lib/metanorma/release/interfaces.rb
103
+ - lib/metanorma/release/naming_strategy.rb
104
+ - lib/metanorma/release/platform.rb
105
+ - lib/metanorma/release/platform/github.rb
106
+ - lib/metanorma/release/platform/github/config_fetcher.rb
107
+ - lib/metanorma/release/platform/github/manifest_reader.rb
108
+ - lib/metanorma/release/platform/github/publisher.rb
109
+ - lib/metanorma/release/platform/github/release_fetcher.rb
110
+ - lib/metanorma/release/platform/github/topic_discoverer.rb
111
+ - lib/metanorma/release/platform/local.rb
112
+ - lib/metanorma/release/platform/local/config_fetcher.rb
113
+ - lib/metanorma/release/platform/local/directory_discoverer.rb
114
+ - lib/metanorma/release/platform/local/fetcher.rb
115
+ - lib/metanorma/release/platform/local/publisher.rb
116
+ - lib/metanorma/release/platform/null.rb
117
+ - lib/metanorma/release/platform/null/publisher.rb
118
+ - lib/metanorma/release/platform_factory.rb
119
+ - lib/metanorma/release/rake_tasks.rb
120
+ - lib/metanorma/release/relaton_enricher.rb
121
+ - lib/metanorma/release/release_metadata.rb
122
+ - lib/metanorma/release/release_pipeline.rb
123
+ - lib/metanorma/release/release_tag.rb
124
+ - lib/metanorma/release/repo_ref.rb
125
+ - lib/metanorma/release/rxl_extractor.rb
126
+ - lib/metanorma/release/stage_filter.rb
127
+ - lib/metanorma/release/version.rb
128
+ - lib/metanorma/release/zip_packager.rb
129
+ homepage: https://github.com/metanorma/metanorma-release
130
+ licenses:
131
+ - BSD-2-Clause
132
+ metadata:
133
+ homepage_uri: https://github.com/metanorma/metanorma-release
134
+ source_code_uri: https://github.com/metanorma/metanorma-release
135
+ changelog_uri: https://github.com/metanorma/metanorma-release/blob/main/CHANGELOG.md
136
+ rubygems_mfa_required: 'true'
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '3.2'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubygems_version: 3.5.22
153
+ signing_key:
154
+ specification_version: 4
155
+ summary: Release lifecycle management for Metanorma documents
156
+ test_files: []