native-packages 0.3.1 → 0.4.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af0462ecd5b50ab3aeb8415ff1c95c7d910b858ef1f3804b18526cfd41ada930
4
- data.tar.gz: 48c6d9f15ad4b8ed60617416780fa5a03f294bc4f629949a5e31af7e041c84fd
3
+ metadata.gz: db11bd5b39c572e4983697e34112948cf182169145c1504a5c2223bd6c01bad0
4
+ data.tar.gz: 379244306eeb13a7e501cd3808dbe3fd81337079e70b129ca446e243a311daaa
5
5
  SHA512:
6
- metadata.gz: ed735938724f514a10b46a50b21ac3131abc1d07981544b0f6f89d5010137b9e7674e041aeed97828de39d1fc2ff243241047f051a7ae78ac75beda8a446e30b
7
- data.tar.gz: 5bb0021eeab1b651c10170de7a57c1e38036714477e15a9e8d698ad68fe836d136de70107b8f180734225b502cd161ada0b01df234a382c9b582e9789a79bc54
6
+ metadata.gz: 4169d1495a88f410c99a59ff1de20b9d6162468e5ddd4a3082a89e843ded13f84d74401cd91f4fde3b6e4457dfa91aa9ea78e19c7c0560c7fd89c3bd18785ec8
7
+ data.tar.gz: 2e89f5a56a85d642e8139c1c6725c3f90db7d664580c33ac64c6a432cac1998f5fa1e7cb220e415597532a83802b068c72f3be47c36a301ce51c795e89494244
data/README.md CHANGED
@@ -84,6 +84,14 @@ Release mode verifies the declared binary assets against the release checksum fi
84
84
 
85
85
  Outputs include packages, prepared recipes, checksums and `build.json`. Publication verifies their hashes, configuration identity and complete target set. Partial builds can be combined with `aggregate DIR... --output DIRECTORY`. Native filenames come from nFPM.
86
86
 
87
+ Since 0.4.0, `build --defer-recipes` lets each platform package its
88
+ own inputs without acquiring global recipe assets or requiring AUR tools.
89
+ Then `aggregate --finalize-recipes` generates the downstream recipes once,
90
+ using hashes of the completed packages. This allows a Homebrew cask to reference
91
+ the DMG being built in the same release. Deferred builds cannot be published.
92
+ See [deferred recipe generation](docs/configuration.md#deferred-recipe-generation)
93
+ for the finalizer's inputs and checks.
94
+
87
95
  Optional `repositories` and `templates` sections replace the old separate registries. Existing `stage`, `diff`, `publish TARGET` and `status` commands support reviewed downstream updates. AUR uses PKGBUILD/`.SRCINFO`; Homebrew uses formulae/casks. Each destination has an independent ignored Git clone, with no application submodules or extra remotes. Native source repositories still apply their own validation and review.
88
96
 
89
97
  ## GitHub Actions
@@ -95,7 +103,7 @@ packaging:
95
103
  needs: release
96
104
  permissions:
97
105
  contents: write
98
- uses: crmne/native-packages/.github/workflows/package.yml@v0.3.1
106
+ uses: crmne/native-packages/.github/workflows/package.yml@v0.4.0
99
107
  with:
100
108
  version: ${{ github.ref_name }}
101
109
  publish: true
@@ -121,7 +129,7 @@ Migration combines `packaging/project.yml`, its nFPM definition and repository r
121
129
  bundle install
122
130
  bundle exec ruby -Ilib -e 'Dir["test/*_test.rb"].sort.each { |path| require_relative path }'
123
131
  gem build native-packages.gemspec
124
- ruby test/gem_install.rb native-packages-0.3.1.gem
132
+ ruby test/gem_install.rb native-packages-0.4.0.gem
125
133
  ```
126
134
 
127
135
  Tests build real packages, inspect their payloads and exercise repository publication against local Git fixtures. CI additionally runs disposable Linux install/upgrade/remove checks, SRPM rebuilds and Windows MSIX acceptance. Runtime build manifests report installation as `not-tested`: CI fixture coverage is not a substitute for testing each application's packages.
@@ -65,3 +65,62 @@ native-packages publish --from dist/complete --to github
65
65
  ```
66
66
 
67
67
  Each build must use the same configuration, release version and timestamp. Aggregate rejects duplicate target/format outputs, conflicting recipe files and incomplete sets. Publishing recipes can still use the existing reviewed sequence: `stage TARGET DIRECTORY/recipes`, `diff TARGET`, then `publish TARGET --body-file FILE` where required by a submission destination.
68
+
69
+
70
+ ## Deferred recipe generation
71
+
72
+ Since 0.4.0, use this opt-in sequence when downstream recipes depend
73
+ on packages built in separate jobs. The existing build and aggregate commands
74
+ keep generating and checking recipes as before when the new flags are absent.
75
+ There are no new configuration keys.
76
+
77
+ ```sh
78
+ # Run each target on its required host, with the same checkout and epoch.
79
+ native-packages doctor --target linux-amd64 --defer-recipes
80
+ native-packages build --version 1.2.3 --target linux-amd64 --defer-recipes --output dist/linux
81
+ native-packages build --version 1.2.3 --target macos-universal --defer-recipes --output dist/macos
82
+ native-packages build --version 1.2.3 --target windows-amd64 --defer-recipes --output dist/windows
83
+
84
+ # Download those build directories and remaining recipe assets onto Linux.
85
+ native-packages aggregate dist/linux dist/macos dist/windows --finalize-recipes --output dist/complete
86
+ # Run the application's package installation/upgrade/removal checks here.
87
+ native-packages publish --from dist/complete --to github,aur,homebrew
88
+ ```
89
+
90
+ A deferred build still validates configuration, selected inputs, architecture,
91
+ container contents and signing hooks. It does not acquire the global `assets`
92
+ or generate `templates`. `doctor --defer-recipes` likewise omits recipe tooling;
93
+ the selected package formats still need their own tools. Asset filenames and
94
+ URLs are available as tokens, but unknown `@KEY_SHA256@` values cannot be used
95
+ by a target's input, package definition or hooks. Such a target must use the
96
+ normal build path with its assets already available. Release-mode target inputs
97
+ still require their published checksums, even with `--defer-recipes`.
98
+
99
+ The finalizer first verifies every input manifest and the complete target set.
100
+ All inputs must defer recipes and agree on configuration, version, timestamp,
101
+ tool and recipe metadata, including Git version. Use the same Git history depth
102
+ and `SOURCE_DATE_EPOCH` on every host. Mixing ordinary and deferred builds fails.
103
+ Neither a partial target set nor a deferred build can be published. An ordinary
104
+ aggregate rejects deferred inputs unless `--finalize-recipes` is supplied.
105
+
106
+ For each global asset, finalization first looks for a verified package whose
107
+ release filename exactly matches the asset's rendered `file`. For example,
108
+ `assets.MACOS.file: app-v@VERSION@-macos-universal.dmg` resolves to a native target
109
+ with that output filename. Its hash includes the completed signing/notarization
110
+ hook. A stale `local` file cannot override that package. Duplicate package
111
+ filenames are rejected. The manifest records this asset by package filename
112
+ and digest, without a temporary staging path.
113
+
114
+ Other assets, such as portable or source archives, must be staged at their
115
+ configured `local` paths on the finalization host. Finalization reads local
116
+ inputs and does not download recipe assets from a release. This also applies
117
+ when the deferred target builds used `--release`. Recipe tools run only here:
118
+ AUR templates require makepkg or working Docker, and recipe archives require
119
+ tar and xz. The finalizer renders and validates recipes, writes the recipe
120
+ archive and complete manifest, and atomically creates a fresh output directory.
121
+ Failure leaves the original target directories intact and creates no completed
122
+ output. Existing destinations are never overwritten.
123
+
124
+ Deferral does not enable stable downstream recipes in a prerelease configuration.
125
+ The existing preview-format and stable-recipe restrictions still apply. Use a
126
+ preview configuration without downstream templates when building previews.
@@ -43,7 +43,13 @@ targets:
43
43
 
44
44
  Run each target on its own host using `build --version VERSION --target ID`.
45
45
  Use the normal `aggregate` command to combine complete target results later.
46
- Use the same configuration and `SOURCE_DATE_EPOCH` across jobs. No nFPM binary
46
+ Use the same configuration and `SOURCE_DATE_EPOCH` across jobs.
47
+ Since 0.4.0, configurations with AUR/Homebrew recipes can use
48
+ `build --defer-recipes` on each host, then `aggregate --finalize-recipes` on
49
+ Linux. This avoids requiring the finished DMG before its own build or running
50
+ AUR tools on macOS/Windows. The finalizer resolves recipe assets from the
51
+ completed package filenames and locally staged external assets. See
52
+ [deferred recipe generation](configuration.md#deferred-recipe-generation). No nFPM binary
47
53
  is required when only native targets are selected; its version remains part of
48
54
  the configuration for compatibility with mixed Linux/native builds.
49
55
 
data/docs/releasing.md CHANGED
@@ -23,7 +23,7 @@ Update the gemspec, `NativePackages::VERSION`, example/version references and ch
23
23
  Create a GitHub release for that commit:
24
24
 
25
25
  ```sh
26
- gh release create v0.3.1 --target main --title 'native-packages 0.3.1' --notes-file release-notes.md
26
+ gh release create v0.4.0 --target main --title 'native-packages 0.4.0' --notes-file release-notes.md
27
27
  ```
28
28
 
29
29
  Adding `--draft` permits review before publication and does not trigger the publisher. The tag must match the exact gem version and point to a commit on `main`. Set `--prerelease` only for a prerelease gem version.
@@ -1,7 +1,7 @@
1
1
  # Supply the listed build outputs before running this example.
2
2
  schema: 1
3
3
  tool:
4
- version: '0.3.1'
4
+ version: '0.4.0'
5
5
  nfpm: '2.47.0'
6
6
  nfpm:
7
7
  name: example-app
@@ -1,6 +1,6 @@
1
1
  schema: 1
2
2
  tool:
3
- version: '0.3.1'
3
+ version: '0.4.0'
4
4
  nfpm: '2.47.0'
5
5
  nfpm:
6
6
  name: example-app
@@ -27,7 +27,7 @@ module NativePackages
27
27
  version
28
28
  end
29
29
 
30
- def doctor(ids: [], formats: [], release: false)
30
+ def doctor(ids: [], formats: [], release: false, defer_recipes: false)
31
31
  configuration.validate
32
32
  selected = configuration.select(ids: ids, formats: formats)
33
33
  nfpm_version if selected.values.any? { |target| (target.fetch("formats") & Configuration::NATIVE_FORMATS).empty? }
@@ -40,13 +40,19 @@ module NativePackages
40
40
  required << "readelf" if selected.values.any? { |target| target["platform"] == "linux" && target.fetch("kind", "binary") == "binary" }
41
41
  required << "bsdtar" if selected.values.any? { |target| target.fetch("input").fetch("kind", "archive") == "archive" }
42
42
  required << "curl" if release
43
- required += %w[tar xz] unless configuration.data.fetch("templates").empty?
44
43
  missing = required.uniq.reject { |tool| available?(tool) }
45
44
  raise Error, "install required tools: #{missing.join(', ')}" unless missing.empty?
45
+ recipe_tools unless defer_recipes
46
+ selected
47
+ end
48
+
49
+ def recipe_tools
50
+ return if configuration.data.fetch("templates").empty?
51
+ missing = %w[tar xz].reject { |tool| available?(tool) }
52
+ raise Error, "install required recipe tools: #{missing.join(', ')}" unless missing.empty?
46
53
  if configuration.data.fetch("templates").keys.any? { |path| path.match?(%r{\Aarch/[^/]+/PKGBUILD\z}) }
47
54
  raise Error, "AUR metadata needs makepkg or accessible Docker" unless available?("makepkg") || available?("docker")
48
55
  end
49
- selected
50
56
  end
51
57
 
52
58
  def version(value, release)
@@ -73,7 +79,7 @@ module NativePackages
73
79
  configuration.tokens(version, epoch: epoch).merge("GIT_VERSION" => git_version)
74
80
  end
75
81
 
76
- def run_build(value: nil, release: nil, ids: [], formats: [], output: nil, dry_run: false)
82
+ def run_build(value: nil, release: nil, ids: [], formats: [], output: nil, dry_run: false, defer_recipes: false)
77
83
  configuration.validate
78
84
  selected = configuration.select(ids: ids, formats: formats)
79
85
  number = version(value, release)
@@ -84,15 +90,26 @@ module NativePackages
84
90
  output = Pathname.new(output || root / "dist/packages" / number).expand_path(root)
85
91
  if dry_run
86
92
  puts JSON.pretty_generate("version" => number, "mode" => release ? "release" : "local", "output" => output.to_s,
87
- "targets" => selected.transform_values { |target| target.slice("formats", "platform", "arch", "input", "before_build", "after_package", "native") })
93
+ "recipes" => defer_recipes ? "deferred" : "included", "targets" => selected.transform_values { |target| target.slice("formats", "platform", "arch", "input", "before_build", "after_package", "native") })
88
94
  return
89
95
  end
90
96
  raise Error, "output exists: #{output}; choose a fresh --output" if output.exist?
91
- doctor(ids: ids, formats: formats, release: !!release)
97
+ doctor(ids: ids, formats: formats, release: !!release, defer_recipes: defer_recipes)
92
98
  info = metadata(number, release: !!release)
93
99
  sources = []
94
100
  expected = release ? release_checksums(info) : nil
95
- acquire_assets(info, expected, sources)
101
+ if defer_recipes
102
+ # Asset hashes are unknown until finalization. Do not silently pass the
103
+ # validation placeholders into a target's input, hooks or package data.
104
+ configuration.data.fetch("assets").each_key { |key| info.delete("#{key}_SHA256") }
105
+ selected.each do |id, target|
106
+ tokens = configuration.target_tokens(info, id, target, "/payload").merge("PACKAGE" => "/output/package", "FORMAT" => target.fetch("formats").first)
107
+ render_tree(target, tokens)
108
+ render_tree(configuration.package(target), tokens)
109
+ end
110
+ else
111
+ acquire_assets(info, expected, sources)
112
+ end
96
113
  output.dirname.mkpath
97
114
  Dir.mktmpdir(".native-packages-", output.dirname) do |temporary|
98
115
  staging = Pathname.new(temporary) / "result"
@@ -161,17 +178,14 @@ module NativePackages
161
178
  end
162
179
  end
163
180
  end
164
- recipes = staging / "recipes"
165
- project.generate(recipes, info)
166
- project.check(recipes, prerelease: number.include?("-"))
167
- if !configuration.data.fetch("templates").empty?
168
- project.recipe_archive(recipes, staging, name: configuration.name, version: number, epoch: info.fetch("SOURCE_DATE_EPOCH"))
169
- (staging / "packaging-checksums.txt").delete
170
- end
181
+ write_recipes(staging, info) unless defer_recipes
171
182
  manifest = { "schema" => 1, "name" => configuration.name, "version" => number, "configuration" => configuration.digest,
172
183
  "tool" => configuration.data.fetch("tool"), "epoch" => info.fetch("SOURCE_DATE_EPOCH"), "inputs" => sources,
173
184
  "targets" => selected.transform_values { |target| target.fetch("formats") }, "packages" => records,
174
185
  "files" => files(staging).to_h { |file| [file.relative_path_from(staging).to_s, sha256(file)] } }
186
+ if defer_recipes
187
+ manifest["recipes"] = { "state" => "deferred", "metadata" => info.reject { |key, _| key == "ROOT" } }
188
+ end
175
189
  write(staging / "build.json", JSON.pretty_generate(manifest) + "\n")
176
190
  write(staging / "packaging-checksums.txt", files(staging).map { |file| "#{sha256(file)} #{file.relative_path_from(staging)}\n" }.join)
177
191
  staging.rename(output)
@@ -212,10 +226,12 @@ module NativePackages
212
226
  path
213
227
  end
214
228
 
215
- def acquire_assets(info, expected, sources)
229
+ def acquire_assets(info, expected, sources, packages: {})
216
230
  configuration.data.fetch("assets").each do |key, definition|
217
231
  asset = render_tree(definition, info)
218
- path = if expected
232
+ path = if packages.key?(asset.fetch("file"))
233
+ packages.fetch(asset.fetch("file"))
234
+ elsif expected
219
235
  release_input(asset.merge("release_asset" => asset.fetch("file")), info, expected, checksummed: asset.fetch("checksummed", true))
220
236
  else
221
237
  root / asset.fetch("local") { raise Error, "assets.#{key}: declare local input or use --release" }
@@ -224,7 +240,15 @@ module NativePackages
224
240
  info["#{key}_SHA256"] = digest
225
241
  info["#{key}_FILE"] = asset.fetch("file")
226
242
  info["#{key}_URL"] = asset.fetch("url", "#{info.fetch('UPSTREAM')}/releases/download/#{info.fetch('TAG')}/#{asset.fetch('file')}")
227
- sources << { "asset" => key, "path" => path.to_s, "sha256" => digest }
243
+ source = { "asset" => key, "sha256" => digest }
244
+ # An aggregated package survives under its release filename; the
245
+ # finalizer's temporary staging path does not survive the rename.
246
+ if packages.key?(asset.fetch("file"))
247
+ source["package"] = asset.fetch("file")
248
+ else
249
+ source["path"] = path.to_s
250
+ end
251
+ sources << source
228
252
  end
229
253
  end
230
254
 
@@ -248,6 +272,48 @@ module NativePackages
248
272
  end
249
273
  end
250
274
 
275
+ def write_recipes(output, info)
276
+ recipes = output / "recipes"
277
+ project.generate(recipes, info)
278
+ project.check(recipes, prerelease: info.fetch("VERSION").include?("-"))
279
+ unless configuration.data.fetch("templates").empty?
280
+ project.recipe_archive(recipes, output, name: configuration.name, version: info.fetch("VERSION"), epoch: info.fetch("SOURCE_DATE_EPOCH"))
281
+ (output / "packaging-checksums.txt").delete
282
+ end
283
+ end
284
+
285
+ def verify_recipes(output, manifest, complete:)
286
+ if manifest.key?("recipes")
287
+ phase = manifest.fetch("recipes")
288
+ unless phase.is_a?(Hash) && phase["state"] == "deferred" && phase["metadata"].is_a?(Hash)
289
+ raise Error, "invalid recipe phase"
290
+ end
291
+ info = phase.fetch("metadata")
292
+ unless info.values_at("NAME", "VERSION", "SOURCE_DATE_EPOCH") == manifest.values_at("name", "version", "epoch")
293
+ raise Error, "deferred recipe metadata disagrees with build"
294
+ end
295
+ package_paths = manifest.fetch("packages").map { |entry| entry.fetch("path") }
296
+ raise Error, "deferred build contains recipe files" unless (manifest.fetch("files").keys - package_paths).empty?
297
+ raise Error, "recipes are deferred; aggregate with --finalize-recipes before publishing" if complete
298
+ return
299
+ end
300
+ # Require the recipe files as well as hashes, so dropping the deferred
301
+ # marker cannot make an unfinished build appear publishable.
302
+ required = ["recipes/release.json"]
303
+ raise Error, "missing recipe metadata" unless manifest.fetch("files").key?(required.first)
304
+ info = JSON.parse((output / required.first).read)
305
+ configuration.data.fetch("templates").each_key do |path|
306
+ relative = render(path, info.merge("ROOT" => root.to_s))
307
+ required << "recipes/#{relative_path(relative)}"
308
+ required << "recipes/#{File.dirname(relative)}/.SRCINFO" if relative.match?(%r{\Aarch/[^/]+/PKGBUILD\z})
309
+ end
310
+ unless configuration.data.fetch("templates").empty?
311
+ required << "#{configuration.name}-#{manifest.fetch('version')}-packaging.tar.xz"
312
+ end
313
+ missing = required - manifest.fetch("files").keys
314
+ raise Error, "missing recipe outputs: #{missing.join(', ')}" unless missing.empty?
315
+ end
316
+
251
317
  def verify(output, complete: true)
252
318
  output = Pathname.new(output).expand_path(root)
253
319
  manifest = JSON.parse((output / "build.json").read)
@@ -271,6 +337,7 @@ module NativePackages
271
337
  manifest.fetch("packages").each do |entry|
272
338
  raise Error, "package hash does not match file manifest" unless entry.fetch("sha256") == manifest.fetch("files").fetch(entry.fetch("path"))
273
339
  end
340
+ verify_recipes(output, manifest, complete: complete)
274
341
  manifest
275
342
  end
276
343
 
@@ -304,7 +371,7 @@ module NativePackages
304
371
  end
305
372
  end
306
373
 
307
- def aggregate(inputs, output:)
374
+ def aggregate(inputs, output:, finalize_recipes: false)
308
375
  configuration.validate
309
376
  output = Pathname.new(output).expand_path(root)
310
377
  raise Error, "output exists: #{output}" if output.exist?
@@ -314,6 +381,14 @@ module NativePackages
314
381
  %w[version epoch tool].each do |key|
315
382
  raise Error, "builds disagree on #{key}" unless manifests.map { |entry| entry.fetch(key) }.uniq.length == 1
316
383
  end
384
+ phases = manifests.map { |entry| entry["recipes"] }
385
+ if phases.any?
386
+ raise Error, "do not mix deferred and completed recipe builds" if phases.any?(&:nil?)
387
+ raise Error, "deferred recipe metadata differs between builds" unless phases.uniq.length == 1
388
+ raise Error, "deferred builds require --finalize-recipes" unless finalize_recipes
389
+ elsif finalize_recipes
390
+ raise Error, "--finalize-recipes requires builds made with --defer-recipes"
391
+ end
317
392
  result = Marshal.load(Marshal.dump(manifests.first))
318
393
  result.merge!("targets" => {}, "packages" => [], "files" => {}, "inputs" => manifests.flat_map { |entry| entry.fetch("inputs") }.uniq)
319
394
  output.dirname.mkpath
@@ -338,6 +413,21 @@ module NativePackages
338
413
  configuration.targets.each do |id, target|
339
414
  result["targets"][id] = target.fetch("formats").select { |format| result["targets"].fetch(id, []).include?(format) }
340
415
  end
416
+ if finalize_recipes
417
+ expected = configuration.targets.transform_values { |target| target.fetch("formats") }
418
+ raise Error, "incomplete target set; aggregate all configured targets before finalizing recipes" unless result.fetch("targets") == expected
419
+ recipe_tools
420
+ info = result.fetch("recipes").fetch("metadata").merge("ROOT" => root.to_s)
421
+ packages = result.fetch("packages").each_with_object({}) do |entry, paths|
422
+ name = File.basename(entry.fetch("path"))
423
+ raise Error, "ambiguous recipe asset filename: #{name}" if paths.key?(name)
424
+ paths[name] = staging / entry.fetch("path")
425
+ end
426
+ acquire_assets(info, nil, result.fetch("inputs"), packages: packages)
427
+ write_recipes(staging, info)
428
+ result.delete("recipes")
429
+ result["files"] = files(staging).to_h { |file| [file.relative_path_from(staging).to_s, sha256(file)] }
430
+ end
341
431
  write(staging / "build.json", JSON.pretty_generate(result) + "\n")
342
432
  write(staging / "packaging-checksums.txt", files(staging).map { |file| "#{sha256(file)} #{file.relative_path_from(staging)}\n" }.join)
343
433
  verify(staging)
@@ -13,7 +13,9 @@ module NativePackages
13
13
  build [--version VERSION | --release TAG] Build all configured packages
14
14
  [--target ID] [--format FORMAT] Select targets/formats (repeatable)
15
15
  [--output DIRECTORY] [--dry-run] Choose output or inspect the plan
16
+ [--defer-recipes] Build targets without recipe assets/tools
16
17
  aggregate DIR... --output DIRECTORY Combine target builds before publishing
18
+ [--finalize-recipes] Generate recipes from deferred builds
17
19
  publish --from DIRECTORY --to github,aur Publish a complete, verified build
18
20
  migrate [--dry-run] Convert packaging/project.yml
19
21
  repositories List downstream destinations
@@ -50,11 +52,13 @@ module NativePackages
50
52
  flags.on("--target ID") { |value| options[:ids] << value }
51
53
  flags.on("--format FORMAT") { |value| options[:formats] << value }
52
54
  flags.on("--release TAG") { |value| options[:release] = value }
55
+ flags.on("--defer-recipes") { options[:defer_recipes] = true }
53
56
  end
54
57
  if command == "build"
55
58
  flags.on("--version VERSION") { |value| options[:value] = value }
56
59
  flags.on("--dry-run") { options[:dry_run] = true }
57
60
  end
61
+ flags.on("--finalize-recipes") { options[:finalize_recipes] = true } if command == "aggregate"
58
62
  if command == "init"
59
63
  flags.on("--interactive") { options[:interactive] = true }
60
64
  flags.on("--name NAME") { |value| options[:name] = value }
@@ -88,13 +92,13 @@ module NativePackages
88
92
  raise Error, "create native-packages.yaml with init, or convert existing packaging with migrate" unless configuration
89
93
  builder = Build.new(configuration)
90
94
  case command
91
- when "build" then return builder.run_build(**options.slice(:value, :release, :ids, :formats, :output, :dry_run))
95
+ when "build" then return builder.run_build(**options.slice(:value, :release, :ids, :formats, :output, :dry_run, :defer_recipes))
92
96
  when "doctor"
93
- builder.doctor(**options.slice(:ids, :formats, :release))
97
+ builder.doctor(**options.slice(:ids, :formats, :release, :defer_recipes))
94
98
  return puts "Configuration and packaging tools are ready. Build checks input files and package contents."
95
99
  when "aggregate"
96
100
  raise Error, "aggregate requires --output" unless options[:output]
97
- return builder.aggregate(arguments, output: options.fetch(:output))
101
+ return builder.aggregate(arguments, output: options.fetch(:output), finalize_recipes: options.fetch(:finalize_recipes, false))
98
102
  when "publish" then return builder.publish(options.fetch(:from), options.fetch(:destinations), body_file: options[:body_file])
99
103
  end
100
104
  end
@@ -12,7 +12,7 @@ require "tmpdir"
12
12
  require "yaml"
13
13
 
14
14
  module NativePackages
15
- VERSION = "0.3.1"
15
+ VERSION = "0.4.0"
16
16
  class Error < StandardError; end
17
17
 
18
18
  module Support
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: native-packages
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carmine Paolino