metanorma-release 0.2.2 → 0.2.3

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +19 -1
  3. data/.rubocop_todo.yml +250 -319
  4. data/README.adoc +120 -233
  5. data/Rakefile +2 -2
  6. data/exe/metanorma-release +2 -2
  7. data/lib/metanorma/release/aggregation_pipeline.rb +59 -45
  8. data/lib/metanorma/release/asset_processor.rb +10 -8
  9. data/lib/metanorma/release/cache_store.rb +6 -6
  10. data/lib/metanorma/release/change_detector.rb +7 -3
  11. data/lib/metanorma/release/channel.rb +13 -39
  12. data/lib/metanorma/release/channel_filter.rb +26 -10
  13. data/lib/metanorma/release/cli.rb +129 -100
  14. data/lib/metanorma/release/commands/aggregate.rb +39 -54
  15. data/lib/metanorma/release/commands/package.rb +20 -12
  16. data/lib/metanorma/release/commands/{publish.rb → release_command.rb} +20 -12
  17. data/lib/metanorma/release/config.rb +104 -0
  18. data/lib/metanorma/release/content_hash.rb +11 -3
  19. data/lib/metanorma/release/delta_state.rb +55 -18
  20. data/lib/metanorma/release/file_routing.rb +8 -5
  21. data/lib/metanorma/release/index.rb +132 -0
  22. data/lib/metanorma/release/interfaces.rb +15 -15
  23. data/lib/metanorma/release/platform/github/manifest_reader.rb +4 -4
  24. data/lib/metanorma/release/platform/github/publisher.rb +23 -11
  25. data/lib/metanorma/release/platform/github/release_fetcher.rb +12 -3
  26. data/lib/metanorma/release/platform/github.rb +10 -7
  27. data/lib/metanorma/release/platform/local/directory_discoverer.rb +1 -1
  28. data/lib/metanorma/release/platform/local/fetcher.rb +17 -12
  29. data/lib/metanorma/release/platform/local/publisher.rb +9 -7
  30. data/lib/metanorma/release/platform/local.rb +4 -4
  31. data/lib/metanorma/release/platform/null/publisher.rb +3 -2
  32. data/lib/metanorma/release/platform/null.rb +1 -1
  33. data/lib/metanorma/release/platform.rb +3 -3
  34. data/lib/metanorma/release/platform_factory.rb +48 -29
  35. data/lib/metanorma/release/publication.rb +335 -0
  36. data/lib/metanorma/release/release_pipeline.rb +85 -52
  37. data/lib/metanorma/release/repo_ref.rb +5 -2
  38. data/lib/metanorma/release/site.rb +66 -0
  39. data/lib/metanorma/release/slug_strategy.rb +163 -0
  40. data/lib/metanorma/release/version.rb +1 -1
  41. data/lib/metanorma/release/zip_packager.rb +31 -8
  42. data/lib/metanorma/release.rb +68 -94
  43. metadata +22 -26
  44. data/lib/metanorma/release/aggregation_interfaces.rb +0 -27
  45. data/lib/metanorma/release/channel_audience.rb +0 -24
  46. data/lib/metanorma/release/channel_config.rb +0 -55
  47. data/lib/metanorma/release/channel_manifest.rb +0 -192
  48. data/lib/metanorma/release/channel_registry.rb +0 -60
  49. data/lib/metanorma/release/config_fetcher.rb +0 -11
  50. data/lib/metanorma/release/config_locator.rb +0 -37
  51. data/lib/metanorma/release/config_resolver.rb +0 -37
  52. data/lib/metanorma/release/document_id.rb +0 -45
  53. data/lib/metanorma/release/document_index.rb +0 -183
  54. data/lib/metanorma/release/document_metadata.rb +0 -39
  55. data/lib/metanorma/release/document_stage.rb +0 -86
  56. data/lib/metanorma/release/document_type.rb +0 -55
  57. data/lib/metanorma/release/document_version.rb +0 -50
  58. data/lib/metanorma/release/naming_strategy.rb +0 -158
  59. data/lib/metanorma/release/platform/github/config_fetcher.rb +0 -40
  60. data/lib/metanorma/release/platform/local/config_fetcher.rb +0 -20
  61. data/lib/metanorma/release/rake_tasks.rb +0 -71
  62. data/lib/metanorma/release/relaton_enricher.rb +0 -138
  63. data/lib/metanorma/release/release_metadata.rb +0 -79
  64. data/lib/metanorma/release/release_tag.rb +0 -49
  65. data/lib/metanorma/release/rxl_extractor.rb +0 -115
  66. data/lib/metanorma/release/stage_filter.rb +0 -18
@@ -1,86 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Metanorma
4
- module Release
5
- class DocumentStage
6
- PUBLISHED_NAMES = %w[published in-force approved standard].freeze
7
-
8
- STAGE_ABBREVS = {
9
- 'working-draft' => 'wd',
10
- 'committee-draft' => 'cd',
11
- 'draft-standard' => 'ds',
12
- 'final-draft' => 'fd',
13
- 'proposal' => 'proposal',
14
- 'informational' => 'info',
15
- 'withdrawn' => 'withdrawn',
16
- 'cancelled' => 'cancelled'
17
- }.freeze
18
-
19
- ISO_STAGE_MAP = {
20
- 20 => 'working-draft',
21
- 30 => 'committee-draft',
22
- 40 => 'draft-standard',
23
- 50 => 'final-draft',
24
- 60 => 'published',
25
- 95 => 'withdrawn'
26
- }.freeze
27
-
28
- def self.from_status(status_string)
29
- raise ArgumentError, 'Stage cannot be empty' if status_string.nil? || status_string.strip.empty?
30
-
31
- normalized = status_string.to_s.downcase.strip.gsub(/\s+/, '-')
32
- new(normalized)
33
- end
34
-
35
- def self.from_iso_stage(stage, _substage = nil)
36
- name = ISO_STAGE_MAP[stage.to_i] || ISO_STAGE_MAP.values.first
37
- new(name)
38
- end
39
-
40
- def self.published
41
- new('published')
42
- end
43
-
44
- def self.working_draft
45
- new('working-draft')
46
- end
47
-
48
- def initialize(name)
49
- @name = name
50
- freeze
51
- end
52
-
53
- def to_s
54
- @name
55
- end
56
-
57
- def published?
58
- PUBLISHED_NAMES.include?(@name)
59
- end
60
-
61
- def draft?
62
- !published? && @name != 'withdrawn' && @name != 'cancelled'
63
- end
64
-
65
- def withdrawn?
66
- @name == 'withdrawn'
67
- end
68
-
69
- def cancelled?
70
- @name == 'cancelled'
71
- end
72
-
73
- def tag_suffix
74
- STAGE_ABBREVS[@name].to_s
75
- end
76
-
77
- def eql?(other)
78
- other.is_a?(self.class) && @name == other.to_s
79
- end
80
-
81
- def hash
82
- @name.hash
83
- end
84
- end
85
- end
86
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Metanorma
4
- module Release
5
- module DocumentType
6
- STANDARD = 'standard'
7
- IETF_DRAFT = 'ietf-draft'
8
- IETF_RFC = 'ietf-rfc'
9
- ISO = 'iso'
10
- IEC = 'iec'
11
- IEEE = 'ieee'
12
- ITU = 'itu'
13
- BIPM = 'bipm'
14
- IHO = 'iho'
15
- OGC = 'ogc'
16
- OIML = 'oiml'
17
- UN = 'un'
18
- CSA = 'csa'
19
- PDFA = 'pdfa'
20
- MPFA = 'mpfa'
21
- M3AAWG = 'm3aawg'
22
- RIBOSE = 'ribose'
23
-
24
- DETECTION_RULES = [
25
- [/^RFC\s/i, IETF_RFC],
26
- [/^draft-/i, IETF_DRAFT],
27
- [/^ISO/i, ISO],
28
- [/^IEC/i, IEC],
29
- [/^IEEE/i, IEEE],
30
- [/^ITU-/i, ITU],
31
- [/^BIPM/i, BIPM],
32
- [/^[A-Z]-\d/i, IHO],
33
- [/^\d{2}-\d{2,3}/, OGC],
34
- [/^OIML/i, OIML],
35
- [/^GE\./i, UN],
36
- [/^csa-/i, CSA],
37
- [/^(AN|BPG|TN)\s/i, PDFA],
38
- [%r{^SU/}i, MPFA],
39
- [/^M3AAWG/i, M3AAWG],
40
- [/^Ribose/i, RIBOSE]
41
- ].freeze
42
-
43
- def self.from_identifier(raw_id)
44
- id = raw_id.to_s.strip
45
- return STANDARD if id.empty?
46
-
47
- DETECTION_RULES.each do |pattern, type|
48
- return type if id.match?(pattern)
49
- end
50
-
51
- STANDARD
52
- end
53
- end
54
- end
55
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Metanorma
4
- module Release
5
- class DocumentVersion
6
- attr_reader :edition, :stage
7
-
8
- def self.from(edition, stage)
9
- ed = edition.to_s.strip
10
- ed = '0' if ed.empty?
11
- new(edition: ed, stage: stage)
12
- end
13
-
14
- def self.published(edition:)
15
- new(edition: edition.to_s.strip, stage: DocumentStage.published)
16
- end
17
-
18
- def initialize(edition:, stage:)
19
- @edition = edition
20
- @stage = stage
21
- freeze
22
- end
23
-
24
- def tag_component
25
- base = "ed#{edition}"
26
- return base if stage.published?
27
-
28
- suffix = stage.tag_suffix
29
- suffix.empty? ? base : "#{base}-#{suffix}"
30
- end
31
-
32
- def pre_release?
33
- stage.draft?
34
- end
35
-
36
- def file_name(doc_id)
37
- base = "#{doc_id}-#{tag_component}"
38
- "#{base}.zip"
39
- end
40
-
41
- def eql?(other)
42
- other.is_a?(self.class) && edition == other.edition && stage.eql?(other.stage)
43
- end
44
-
45
- def hash
46
- [edition, stage].hash
47
- end
48
- end
49
- end
50
- end
@@ -1,158 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Metanorma
4
- module Release
5
- module NamingStrategy
6
- def compute_tag(id, version)
7
- raise NotImplementedError, "#{self.class} must implement #compute_tag"
8
- end
9
-
10
- def compute_asset_name(id, version)
11
- raise NotImplementedError, "#{self.class} must implement #compute_asset_name"
12
- end
13
-
14
- def compute_canonical_base(id, version)
15
- raise NotImplementedError, "#{self.class} must implement #compute_canonical_base"
16
- end
17
- end
18
-
19
- class EditionNaming
20
- include NamingStrategy
21
-
22
- def compute_tag(id, version)
23
- tag = "#{id}/#{version.tag_component}"
24
- ReleaseTag.create(tag, pre_release: version.pre_release?)
25
- end
26
-
27
- def compute_asset_name(id, version)
28
- "#{id}-#{version.tag_component}.zip"
29
- end
30
-
31
- def compute_canonical_base(id, version)
32
- "#{id}-#{version.tag_component}"
33
- end
34
- end
35
-
36
- class VersionNaming
37
- include NamingStrategy
38
-
39
- def compute_tag(id, version)
40
- tag = "#{id}/v#{version.edition}"
41
- ReleaseTag.create(tag, pre_release: version.pre_release?)
42
- end
43
-
44
- def compute_asset_name(id, version)
45
- "#{id}-v#{version.edition}.zip"
46
- end
47
-
48
- def compute_canonical_base(id, version)
49
- "#{id}-v#{version.edition}"
50
- end
51
- end
52
-
53
- class InternetDraftNaming
54
- include NamingStrategy
55
-
56
- DRAFT_PATTERN = /\Adraft-ietf-([a-z0-9-]+?)-(\d+)\z/i
57
-
58
- def compute_tag(id, version)
59
- match = id.match(DRAFT_PATTERN)
60
- return fallback_tag(id, version) unless match
61
-
62
- name = match[1]
63
- num = match[2]
64
- ReleaseTag.create("id-#{name}/#{num}", pre_release: true)
65
- end
66
-
67
- def compute_asset_name(id, _version)
68
- "#{id}.zip"
69
- end
70
-
71
- def compute_canonical_base(id, _version)
72
- id.to_s
73
- end
74
-
75
- private
76
-
77
- def fallback_tag(id, _version)
78
- tag = "#{id}/draft"
79
- ReleaseTag.create(tag, pre_release: true)
80
- end
81
- end
82
-
83
- class RfcNaming
84
- include NamingStrategy
85
-
86
- def compute_tag(id, version)
87
- tag = "#{id}/ed#{version.edition}"
88
- ReleaseTag.create(tag, pre_release: version.pre_release?)
89
- end
90
-
91
- def compute_asset_name(id, _version)
92
- "#{id}.zip"
93
- end
94
-
95
- def compute_canonical_base(id, version)
96
- "#{id}-ed#{version.edition}"
97
- end
98
- end
99
-
100
- class DraftSuffixNaming
101
- include NamingStrategy
102
-
103
- DRAFT_SUFFIX = /-d(\d+)\z/
104
-
105
- def compute_tag(id, version)
106
- match = id.to_s.match(DRAFT_SUFFIX)
107
- return @fallback.compute_tag(id, version) unless match
108
-
109
- base = id.to_s.sub(DRAFT_SUFFIX, '')
110
- num = match[1]
111
- ReleaseTag.create("#{base}/#{num}", pre_release: true)
112
- end
113
-
114
- def compute_asset_name(id, version)
115
- match = id.to_s.match(DRAFT_SUFFIX)
116
- return @fallback.compute_asset_name(id, version) unless match
117
-
118
- "#{id}.zip"
119
- end
120
-
121
- def compute_canonical_base(id, version)
122
- match = id.to_s.match(DRAFT_SUFFIX)
123
- return @fallback.compute_canonical_base(id, version) unless match
124
-
125
- id.to_s
126
- end
127
-
128
- def initialize
129
- @fallback = EditionNaming.new
130
- end
131
- end
132
-
133
- class NamingRegistry
134
- def initialize(default: EditionNaming.new)
135
- @default = default
136
- @strategies = {}
137
- end
138
-
139
- def register(document_type, strategy)
140
- @strategies[document_type] = strategy
141
- end
142
-
143
- def resolve(document_type)
144
- @strategies.fetch(document_type, @default)
145
- end
146
-
147
- def self.default_registry
148
- registry = new
149
- registry.register(DocumentType::IETF_DRAFT, InternetDraftNaming.new)
150
- registry.register(DocumentType::IETF_RFC, RfcNaming.new)
151
- registry.register(DocumentType::IEEE, DraftSuffixNaming.new)
152
- registry.register(DocumentType::IHO, VersionNaming.new)
153
- registry.register(DocumentType::OGC, VersionNaming.new)
154
- registry
155
- end
156
- end
157
- end
158
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'yaml'
4
-
5
- module Metanorma
6
- module Release
7
- module Platform
8
- module GitHub
9
- class ConfigFetcher
10
- include Metanorma::Release::ConfigFetcher
11
-
12
- def initialize(client:)
13
- @client = client
14
- end
15
-
16
- def fetch(source)
17
- repo, path = parse_source(source)
18
- content = @client.contents(repo, path: path)
19
- return nil unless content
20
-
21
- ChannelConfig.from_yaml(content['content'].unpack1('m0'))
22
- rescue StandardError
23
- nil
24
- end
25
-
26
- private
27
-
28
- def parse_source(source)
29
- if source.include?('#')
30
- parts = source.split('#', 2)
31
- [parts[0], parts[1]]
32
- else
33
- [source, 'channels.yml']
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Metanorma
4
- module Release
5
- module Platform
6
- module Local
7
- class ConfigFetcher
8
- include Metanorma::Release::ConfigFetcher
9
-
10
- def fetch(source)
11
- path = source.sub(/\Alocal:/, '')
12
- return nil unless File.exist?(path)
13
-
14
- ChannelConfig.from_file(path)
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rake'
4
- require 'ostruct'
5
-
6
- module Metanorma
7
- module Release
8
- class RakeTasks
9
- include Rake::DSL
10
-
11
- def self.install(&block)
12
- new(&block).install
13
- end
14
-
15
- def initialize(&block)
16
- @config = OpenStruct.new(
17
- output_dir: '_site',
18
- manifest: 'metanorma.release.yml',
19
- platform: 'github',
20
- concurrency: 4,
21
- dest: 'dist',
22
- source: 'github',
23
- organizations: [],
24
- topic: 'metanorma-release'
25
- )
26
- block&.call(@config)
27
- end
28
-
29
- def install
30
- install_package_task
31
- install_publish_task
32
- install_aggregate_task
33
- end
34
-
35
- private
36
-
37
- def install_package_task
38
- desc 'Package compiled documents'
39
- task :"mn:package" do
40
- argv = ['--output-dir', @config.output_dir,
41
- '--dest', @config.dest,
42
- '--manifest', @config.manifest]
43
- CLI.run_package(argv)
44
- end
45
- end
46
-
47
- def install_publish_task
48
- desc 'Package and publish documents'
49
- task :"mn:publish" do
50
- argv = ['--platform', @config.platform,
51
- '--output-dir', @config.output_dir,
52
- '--manifest', @config.manifest,
53
- '--concurrency', @config.concurrency.to_s]
54
- CLI.run_publish(argv)
55
- end
56
- end
57
-
58
- def install_aggregate_task
59
- desc 'Aggregate released documents'
60
- task :"mn:aggregate" do
61
- argv = ['--source', @config.source,
62
- '--output-dir', @config.output_dir,
63
- '--concurrency', @config.concurrency.to_s]
64
- argv += ['--organizations', @config.organizations.join(',')] if @config.organizations.any?
65
- argv += ['--topic', @config.topic] if @config.topic
66
- CLI.run_aggregate(argv)
67
- end
68
- end
69
- end
70
- end
71
- end
@@ -1,138 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'relaton/bib'
4
- require 'json'
5
- require 'yaml'
6
- require 'fileutils'
7
-
8
- module Metanorma
9
- module Release
10
- class RelatonEnricher
11
- EnrichResult = Struct.new(
12
- :item_count, :output_dir, :documents,
13
- keyword_init: true
14
- )
15
-
16
- @flavor_registry = {}
17
-
18
- class << self
19
- def register_flavor(name, &loader)
20
- @flavor_registry[name.to_s] = loader
21
- end
22
-
23
- attr_reader :flavor_registry
24
- end
25
-
26
- register_flavor('calconnect') do
27
- require 'relaton/calconnect'
28
- Relaton::Calconnect::Item
29
- end
30
- register_flavor('cc') do
31
- require 'relaton/calconnect'
32
- Relaton::Calconnect::Item
33
- end
34
- register_flavor('iso') do
35
- require 'relaton/iso'
36
- Relaton::Iso::Item
37
- end
38
- register_flavor('iec') do
39
- require 'relaton/iec'
40
- Relaton::Iec::BibliographicItem
41
- end
42
- register_flavor('ogc') do
43
- require 'relaton/ogc'
44
- Relaton::Ogc::BibliographicItem
45
- end
46
- register_flavor('ietf') do
47
- require 'relaton/ietf'
48
- Relaton::Ietf::BibliographicItem
49
- end
50
- register_flavor('bipm') do
51
- require 'relaton/bipm'
52
- Relaton::Bipm::BibliographicItem
53
- end
54
- register_flavor('itu') do
55
- require 'relaton/itu'
56
- Relaton::Itu::BibliographicItem
57
- end
58
- register_flavor('nist') do
59
- require 'relaton/nist'
60
- Relaton::Nist::BibliographicItem
61
- end
62
- register_flavor('un') do
63
- require 'relaton/un'
64
- Relaton::Un::BibliographicItem
65
- end
66
- register_flavor('bsi') do
67
- require 'relaton/bsi'
68
- Relaton::Bsi::BibliographicItem
69
- end
70
- register_flavor('ribose') do
71
- require 'relaton/ribose'
72
- Relaton::Ribose::Item
73
- end
74
-
75
- def initialize(flavor: nil, registry_name: 'Document Registry')
76
- @flavor = flavor
77
- @registry_name = registry_name
78
- end
79
-
80
- def enrich(document_index, output_dir, bib_dir: 'relaton')
81
- return nil if document_index.empty?
82
-
83
- flavor = resolve_flavor(document_index)
84
- klass = resolve_class(flavor)
85
- documents = enrich_documents(document_index, output_dir, klass)
86
- return nil if documents.empty?
87
-
88
- dest = File.join(output_dir, bib_dir)
89
- write_index(documents, dest)
90
-
91
- EnrichResult.new(item_count: documents.length, output_dir: dest,
92
- documents: documents)
93
- rescue LoadError
94
- warn ' (relaton gem not available — bibliography skipped)'
95
- nil
96
- end
97
-
98
- private
99
-
100
- def resolve_flavor(document_index)
101
- @flavor || document_index.documents.first&.flavor
102
- end
103
-
104
- def resolve_class(flavor)
105
- loader = self.class.flavor_registry[flavor.to_s]
106
- return loader.call if loader
107
-
108
- Relaton::Bib::Item
109
- rescue LoadError
110
- warn " (relaton-#{flavor} gem not available — using base Relaton::Bib::Item)"
111
- Relaton::Bib::Item
112
- end
113
-
114
- def enrich_documents(document_index, output_dir, klass)
115
- document_index.documents.map do |doc|
116
- rxl = doc.files.find { |f| f.extension == 'rxl' }
117
- path = rxl && File.join(output_dir, rxl.path)
118
-
119
- bib = (klass.from_xml(File.read(path)) if path && File.exist?(path))
120
-
121
- enriched = doc.to_h
122
- enriched['bibliographic'] = bib.to_h if bib
123
- enriched
124
- rescue StandardError => e
125
- warn " Skip #{File.basename(path)}: #{e.message}"
126
- doc.to_h
127
- end
128
- end
129
-
130
- def write_index(documents, dest)
131
- FileUtils.mkdir_p(dest)
132
- index = { 'root' => { 'title' => @registry_name, 'items' => documents } }
133
- File.write(File.join(dest, 'index.json'), JSON.pretty_generate(index))
134
- File.write(File.join(dest, 'index.yaml'), YAML.dump(index))
135
- end
136
- end
137
- end
138
- end
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
-
5
- module Metanorma
6
- module Release
7
- class ReleaseMetadata
8
- SCHEMA_VERSION = 1
9
-
10
- def self.from_document(metadata, channels:)
11
- data = {
12
- 'version' => SCHEMA_VERSION,
13
- 'id' => metadata.id.to_s,
14
- 'title' => metadata.title,
15
- 'edition' => metadata.version.edition,
16
- 'stage' => metadata.version.stage.to_s,
17
- 'doctype' => metadata.doctype.to_s,
18
- 'revdate' => metadata.revdate,
19
- 'formats' => metadata.formats,
20
- 'channels' => channels.map(&:to_s),
21
- 'flavor' => metadata.flavor,
22
- 'sourcePath' => metadata.source_path
23
- }
24
- new(data)
25
- end
26
-
27
- def self.from_json(json_string)
28
- data = JSON.parse(json_string)
29
- raise ArgumentError, 'Missing required field: id' unless data['id']
30
- raise ArgumentError, 'Missing required field: title' unless data['title']
31
-
32
- new(data)
33
- end
34
-
35
- def self.from_release_body(body)
36
- return nil if body.nil? || body.empty?
37
-
38
- match = body.match(/<!--\s*mn-release-metadata\s*\n(.*?)\n-->/m)
39
- return nil unless match
40
-
41
- json_str = match[1]
42
- begin
43
- from_json(json_str)
44
- rescue JSON::ParserError
45
- nil
46
- end
47
- end
48
-
49
- def initialize(data)
50
- @data = data
51
- freeze
52
- end
53
-
54
- def to_json(*_args)
55
- JSON.generate(@data)
56
- end
57
-
58
- def to_release_body
59
- json_str = JSON.generate(@data)
60
- "<!-- mn-release-metadata\n#{json_str}\n-->"
61
- end
62
-
63
- def to_h
64
- @data.dup
65
- end
66
-
67
- def id = @data['id']
68
- def title = @data['title']
69
- def edition = @data['edition']
70
- def stage = @data['stage']
71
- def doctype = @data['doctype']
72
- def revdate = @data['revdate']
73
- def formats = @data['formats'] || []
74
- def channels = @data['channels'] || []
75
- def flavor = @data['flavor']
76
- def source_path = @data['sourcePath']
77
- end
78
- end
79
- end