electron-cli 0.3.0-alpha.12 → 0.3.0-alpha.14

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.
@@ -15,6 +15,7 @@ use fscommon::BufStream;
15
15
  use msi::{Column, Insert, Language, Package, PackageType, Value};
16
16
  use rpm::{BuildConfig, CompressionType, FileOptions, PackageBuilder};
17
17
  use serde::Serialize;
18
+ use serde_json::Value as JsonValue;
18
19
  use tar::{Builder as TarBuilder, Header as TarHeader};
19
20
  use uuid::Uuid;
20
21
  use zip::{write::SimpleFileOptions, CompressionMethod, ZipWriter};
@@ -23,12 +24,15 @@ use crate::{
23
24
  cli::{MakeArgs, MakeTarget, PackageArgs},
24
25
  commands::package::{self, PackageReport},
25
26
  output,
27
+ project::ProjectSnapshot,
26
28
  };
27
29
 
28
- #[derive(Debug, Serialize)]
30
+ #[derive(Clone, Debug, Serialize)]
29
31
  pub(crate) struct MakeReport {
30
32
  package: PackageReport,
31
33
  target: String,
34
+ #[serde(skip)]
35
+ target_kind: MakeTarget,
32
36
  skip_package: bool,
33
37
  dry_run: bool,
34
38
  make_dir: Utf8PathBuf,
@@ -38,27 +42,54 @@ pub(crate) struct MakeReport {
38
42
  warnings: Vec<String>,
39
43
  }
40
44
 
41
- #[derive(Debug, Serialize)]
45
+ #[derive(Clone, Copy, Debug, Serialize)]
42
46
  #[serde(rename_all = "kebab-case")]
43
47
  enum MakeStatus {
44
48
  Planned,
45
49
  Made,
46
50
  }
47
51
 
52
+ struct ResolvedMakeTargets {
53
+ targets: Vec<MakeTarget>,
54
+ warnings: Vec<String>,
55
+ }
56
+
57
+ #[derive(Debug, Serialize)]
58
+ struct MakeRunReport<'a> {
59
+ targets: &'a [MakeReport],
60
+ dry_run: bool,
61
+ status: MakeStatus,
62
+ warnings: Vec<String>,
63
+ }
64
+
48
65
  pub fn run(args: MakeArgs) -> Result<()> {
49
- let mut report = build_report(&args)?;
66
+ let mut reports = build_reports(&args)?;
50
67
 
51
68
  if args.dry_run {
52
- return print_report(&report, args.json);
69
+ return print_reports(&reports, args.json, MakeStatus::Planned);
53
70
  }
54
71
 
55
- execute_make(&mut report, &args)?;
56
- report.mark_made()?;
72
+ execute_make_reports(&mut reports, &args)?;
57
73
 
58
- print_report(&report, args.json)
74
+ print_reports(&reports, args.json, MakeStatus::Made)
59
75
  }
60
76
 
77
+ #[cfg(test)]
61
78
  pub(crate) fn build_report(args: &MakeArgs) -> Result<MakeReport> {
79
+ let reports = build_reports(args)?;
80
+ if reports.len() != 1 {
81
+ bail!(
82
+ "Expected one make target, but resolved {}. Pass --target to select one target.",
83
+ reports.len()
84
+ );
85
+ }
86
+ Ok(reports
87
+ .into_iter()
88
+ .next()
89
+ .expect("length was checked above"))
90
+ }
91
+
92
+ pub(crate) fn build_reports(args: &MakeArgs) -> Result<Vec<MakeReport>> {
62
93
  let package_args = PackageArgs {
63
94
  cwd: args.cwd.clone(),
64
95
  out_dir: args.out_dir.clone(),
@@ -70,29 +101,47 @@ pub(crate) fn build_report(args: &MakeArgs) -> Result<MakeReport> {
70
101
  json: false,
71
102
  };
72
103
  let snapshot = crate::project::inspect(&package_args.cwd)?;
73
- let package = package::build_report(snapshot, &package_args)?;
104
+ let resolved = resolve_make_targets(&snapshot, args)?;
105
+ let config_warnings = resolved.warnings;
106
+ resolved
107
+ .targets
108
+ .into_iter()
109
+ .map(|target| {
110
+ let package = package::build_report(snapshot.clone(), &package_args)?;
111
+ build_report_for_target(package, target, args, &config_warnings)
112
+ })
113
+ .collect()
114
+ }
115
+
116
+ fn build_report_for_target(
117
+ package: PackageReport,
118
+ target: MakeTarget,
119
+ args: &MakeArgs,
120
+ config_warnings: &[String],
121
+ ) -> Result<MakeReport> {
74
122
  let make_dir = Path::new(package.output_dir().as_str())
75
123
  .join("make")
76
- .join(args.target.as_str())
124
+ .join(target.as_str())
77
125
  .join(package.platform())
78
126
  .join(package.arch());
79
- let artifact = make_artifact_path(&make_dir, &package, args.target);
127
+ let artifact = make_artifact_path(&make_dir, &package, target);
80
128
 
81
129
  let mut warnings = package.warnings().to_vec();
82
- if matches!(args.target, MakeTarget::Deb | MakeTarget::Rpm) && package.platform() != "linux" {
130
+ warnings.extend(config_warnings.iter().cloned());
131
+ if matches!(target, MakeTarget::Deb | MakeTarget::Rpm) && package.platform() != "linux" {
83
132
  warnings.push(format!(
84
133
  "{} maker only supports linux packages; target platform is {}.",
85
- args.target.as_str(),
134
+ target.as_str(),
86
135
  package.platform()
87
136
  ));
88
137
  }
89
- if args.target == MakeTarget::Dmg && package.platform() != "darwin" {
138
+ if target == MakeTarget::Dmg && package.platform() != "darwin" {
90
139
  warnings.push(format!(
91
140
  "dmg maker only supports macOS packages; target platform is {}.",
92
141
  package.platform()
93
142
  ));
94
143
  }
95
- if args.target == MakeTarget::Msi && package.platform() != "win32" {
144
+ if target == MakeTarget::Msi && package.platform() != "win32" {
96
145
  warnings.push(format!(
97
146
  "msi maker only supports Windows packages; target platform is {}.",
98
147
  package.platform()
@@ -114,7 +163,8 @@ pub(crate) fn build_report(args: &MakeArgs) -> Result<MakeReport> {
114
163
 
115
164
  Ok(MakeReport {
116
165
  package,
117
- target: args.target.as_str().to_string(),
166
+ target: target.as_str().to_string(),
167
+ target_kind: target,
118
168
  skip_package: args.skip_package,
119
169
  dry_run: args.dry_run,
120
170
  make_dir: utf8_path(make_dir)?,
@@ -125,17 +175,216 @@ pub(crate) fn build_report(args: &MakeArgs) -> Result<MakeReport> {
125
175
  })
126
176
  }
127
177
 
178
+ struct ConfiguredMaker {
179
+ label: String,
180
+ target: Option<MakeTarget>,
181
+ platforms: Vec<String>,
182
+ }
183
+
184
+ fn resolve_make_targets(
185
+ snapshot: &ProjectSnapshot,
186
+ args: &MakeArgs,
187
+ ) -> Result<ResolvedMakeTargets> {
188
+ if let Some(target) = args.target {
189
+ return Ok(ResolvedMakeTargets {
190
+ targets: vec![target],
191
+ warnings: Vec::new(),
192
+ });
193
+ }
194
+
195
+ let platform = args.platform.clone().unwrap_or_else(current_platform_label);
196
+ let makers = configured_makers(snapshot)?;
197
+ let mut warnings = Vec::new();
198
+ let mut targets = Vec::new();
199
+
200
+ for maker in &makers {
201
+ let Some(target) = maker.target else {
202
+ warnings.push(format!(
203
+ "Configured maker is not implemented yet and will be skipped: {}.",
204
+ maker.label
205
+ ));
206
+ continue;
207
+ };
208
+ if !maker_applies_to_platform(maker, &platform) {
209
+ continue;
210
+ }
211
+ if !targets.contains(&target) {
212
+ targets.push(target);
213
+ }
214
+ }
215
+
216
+ if targets.is_empty() {
217
+ if makers.is_empty() {
218
+ targets.push(MakeTarget::Zip);
219
+ } else {
220
+ warnings.push(format!(
221
+ "No supported configured makers apply to {platform}; defaulting to zip. Pass --target to override."
222
+ ));
223
+ targets.push(MakeTarget::Zip);
224
+ }
225
+ }
226
+
227
+ Ok(ResolvedMakeTargets { targets, warnings })
228
+ }
229
+
230
+ fn configured_makers(snapshot: &ProjectSnapshot) -> Result<Vec<ConfiguredMaker>> {
231
+ let Some(package_json_path) = &snapshot.package_json else {
232
+ return Ok(Vec::new());
233
+ };
234
+ let package_json_path = Path::new(package_json_path.as_str());
235
+ let raw = fs::read_to_string(package_json_path)
236
+ .with_context(|| format!("Could not read {}", package_json_path.display()))?;
237
+ let package = serde_json::from_str::<JsonValue>(&raw)
238
+ .with_context(|| format!("Could not parse {}", package_json_path.display()))?;
239
+
240
+ let mut makers = Vec::new();
241
+ for value in [
242
+ package
243
+ .get("config")
244
+ .and_then(|config| config.get("forge"))
245
+ .and_then(|forge| forge.get("makers")),
246
+ package
247
+ .get("electronCli")
248
+ .or_else(|| package.get("electron-cli"))
249
+ .and_then(|config| config.get("makers")),
250
+ ]
251
+ .into_iter()
252
+ .flatten()
253
+ {
254
+ makers.extend(parse_maker_list(value));
255
+ }
256
+
257
+ Ok(makers)
258
+ }
259
+
260
+ fn parse_maker_list(value: &JsonValue) -> Vec<ConfiguredMaker> {
261
+ match value {
262
+ JsonValue::Array(values) => values.iter().filter_map(parse_maker).collect(),
263
+ _ => Vec::new(),
264
+ }
265
+ }
266
+
267
+ fn parse_maker(value: &JsonValue) -> Option<ConfiguredMaker> {
268
+ match value {
269
+ JsonValue::String(label) => Some(ConfiguredMaker {
270
+ label: label.clone(),
271
+ target: maker_target(label),
272
+ platforms: Vec::new(),
273
+ }),
274
+ JsonValue::Object(object) => {
275
+ let label = object
276
+ .get("name")
277
+ .or_else(|| object.get("target"))
278
+ .or_else(|| object.get("maker"))
279
+ .and_then(JsonValue::as_str)?
280
+ .to_string();
281
+ Some(ConfiguredMaker {
282
+ target: maker_target(&label),
283
+ platforms: string_values(object.get("platforms")),
284
+ label,
285
+ })
286
+ }
287
+ _ => None,
288
+ }
289
+ }
290
+
291
+ fn maker_target(label: &str) -> Option<MakeTarget> {
292
+ let label = label.trim().to_ascii_lowercase();
293
+ let compact = label
294
+ .trim_start_matches("@electron-forge/")
295
+ .trim_start_matches("electron-forge-")
296
+ .trim_start_matches("maker-");
297
+
298
+ if matches!(compact, "zip" | "@electron-forge/maker-zip")
299
+ || label.ends_with("/maker-zip")
300
+ || label.ends_with("maker-zip")
301
+ {
302
+ Some(MakeTarget::Zip)
303
+ } else if compact == "dmg" || label.ends_with("/maker-dmg") || label.ends_with("maker-dmg") {
304
+ Some(MakeTarget::Dmg)
305
+ } else if compact == "deb" || label.ends_with("/maker-deb") || label.ends_with("maker-deb") {
306
+ Some(MakeTarget::Deb)
307
+ } else if compact == "rpm" || label.ends_with("/maker-rpm") || label.ends_with("maker-rpm") {
308
+ Some(MakeTarget::Rpm)
309
+ } else if matches!(compact, "msi" | "wix")
310
+ || label.ends_with("/maker-wix")
311
+ || label.ends_with("maker-wix")
312
+ {
313
+ Some(MakeTarget::Msi)
314
+ } else {
315
+ None
316
+ }
317
+ }
318
+
319
+ fn maker_applies_to_platform(maker: &ConfiguredMaker, platform: &str) -> bool {
320
+ maker.platforms.is_empty()
321
+ || maker
322
+ .platforms
323
+ .iter()
324
+ .any(|configured| configured == platform || configured == "*")
325
+ }
326
+
327
+ fn string_values(value: Option<&JsonValue>) -> Vec<String> {
328
+ match value {
329
+ Some(JsonValue::String(value)) => vec![value.clone()],
330
+ Some(JsonValue::Array(values)) => values
331
+ .iter()
332
+ .filter_map(JsonValue::as_str)
333
+ .map(ToOwned::to_owned)
334
+ .collect(),
335
+ _ => Vec::new(),
336
+ }
337
+ }
338
+
339
+ fn current_platform_label() -> String {
340
+ if cfg!(target_os = "macos") {
341
+ "darwin".to_string()
342
+ } else if cfg!(target_os = "windows") {
343
+ "win32".to_string()
344
+ } else {
345
+ "linux".to_string()
346
+ }
347
+ }
348
+
349
+ #[cfg(test)]
128
350
  pub(crate) fn execute_make(report: &mut MakeReport, args: &MakeArgs) -> Result<()> {
351
+ ensure_package_ready(std::slice::from_mut(report), args)?;
352
+ execute_make_artifact(report, args)?;
353
+ Ok(())
354
+ }
355
+
356
+ pub(crate) fn execute_make_reports(reports: &mut [MakeReport], args: &MakeArgs) -> Result<()> {
357
+ if reports.is_empty() {
358
+ bail!("No make targets were resolved.");
359
+ }
360
+ ensure_package_ready(reports, args)?;
361
+ for report in reports {
362
+ execute_make_artifact(report, args)?;
363
+ report.mark_made()?;
364
+ }
365
+ Ok(())
366
+ }
367
+
368
+ fn ensure_package_ready(reports: &mut [MakeReport], args: &MakeArgs) -> Result<()> {
369
+ let first = reports
370
+ .first_mut()
371
+ .context("No make targets were resolved.")?;
129
372
  if !args.skip_package {
130
- package::execute_package(&report.package, args.force)?;
131
- report.package.mark_packaged();
132
- } else if !Path::new(report.package.bundle_dir().as_str()).exists() {
373
+ package::execute_package(&first.package, args.force)?;
374
+ for report in reports {
375
+ report.package.mark_packaged();
376
+ }
377
+ } else if !Path::new(first.package.bundle_dir().as_str()).exists() {
133
378
  bail!(
134
379
  "Package output does not exist: {}. Run without --skip-package or run electron-cli package first.",
135
- report.package.bundle_dir()
380
+ first.package.bundle_dir()
136
381
  );
137
382
  }
138
383
 
384
+ Ok(())
385
+ }
386
+
387
+ fn execute_make_artifact(report: &mut MakeReport, args: &MakeArgs) -> Result<()> {
139
388
  let artifact = Path::new(report.artifact.as_str());
140
389
  if artifact.exists() {
141
390
  if args.force {
@@ -151,7 +400,7 @@ pub(crate) fn execute_make(report: &mut MakeReport, args: &MakeArgs) -> Result<(
151
400
 
152
401
  fs::create_dir_all(report.make_dir.as_str())
153
402
  .with_context(|| format!("Could not create {}", report.make_dir))?;
154
- match args.target {
403
+ match report.target_kind {
155
404
  MakeTarget::Zip => {
156
405
  write_zip_archive(Path::new(report.package.bundle_dir().as_str()), artifact)?
157
406
  }
@@ -204,6 +453,69 @@ fn print_report(report: &MakeReport, json: bool) -> Result<()> {
204
453
  Ok(())
205
454
  }
206
455
 
456
+ fn print_reports(reports: &[MakeReport], json: bool, status: MakeStatus) -> Result<()> {
457
+ if reports.len() == 1 {
458
+ return print_report(&reports[0], json);
459
+ }
460
+
461
+ let warnings = combined_warnings(reports);
462
+ if json {
463
+ return output::json(&MakeRunReport {
464
+ targets: reports,
465
+ dry_run: reports.iter().any(|report| report.dry_run),
466
+ status,
467
+ warnings,
468
+ });
469
+ }
470
+
471
+ println!("electron-cli make");
472
+ println!();
473
+ if let Some(first) = reports.first() {
474
+ println!("Project");
475
+ println!(" root: {}", first.package.project().root);
476
+ match first.package.project().package_label() {
477
+ Some(label) => println!(" package: {label}"),
478
+ None => println!(" package: not found"),
479
+ }
480
+ println!(" app name: {}", first.package.app_name());
481
+ println!(
482
+ " target platform: {} {}",
483
+ first.package.platform(),
484
+ first.package.arch()
485
+ );
486
+ println!(" status: {}", status.as_str());
487
+ }
488
+
489
+ println!();
490
+ println!("Artifacts");
491
+ for report in reports {
492
+ println!(" {}: {}", report.target, report.artifact);
493
+ if let Some(size) = report.artifact_size {
494
+ println!(" size: {size} bytes");
495
+ }
496
+ }
497
+
498
+ if !warnings.is_empty() {
499
+ println!();
500
+ println!("Warnings");
501
+ for warning in warnings {
502
+ println!(" {warning}");
503
+ }
504
+ }
505
+
506
+ Ok(())
507
+ }
508
+
509
+ fn combined_warnings(reports: &[MakeReport]) -> Vec<String> {
510
+ let mut warnings = Vec::new();
511
+ for warning in reports.iter().flat_map(|report| report.warnings()) {
512
+ if !warnings.contains(warning) {
513
+ warnings.push(warning.clone());
514
+ }
515
+ }
516
+ warnings
517
+ }
518
+
207
519
  fn make_artifact_path(make_dir: &Path, package: &PackageReport, target: MakeTarget) -> PathBuf {
208
520
  match target {
209
521
  MakeTarget::Zip => make_dir.join(format!(
@@ -1909,7 +2221,7 @@ mod tests {
1909
2221
  name: None,
1910
2222
  platform: None,
1911
2223
  arch: None,
1912
- target: crate::cli::MakeTarget::Zip,
2224
+ target: Some(crate::cli::MakeTarget::Zip),
1913
2225
  skip_package: false,
1914
2226
  force: false,
1915
2227
  dry_run: true,
@@ -1946,7 +2258,7 @@ mod tests {
1946
2258
  name: None,
1947
2259
  platform: Some("linux".to_string()),
1948
2260
  arch: Some("x64".to_string()),
1949
- target: crate::cli::MakeTarget::Deb,
2261
+ target: Some(crate::cli::MakeTarget::Deb),
1950
2262
  skip_package: false,
1951
2263
  force: false,
1952
2264
  dry_run: true,
@@ -1980,7 +2292,7 @@ mod tests {
1980
2292
  name: None,
1981
2293
  platform: Some("darwin".to_string()),
1982
2294
  arch: Some("arm64".to_string()),
1983
- target: crate::cli::MakeTarget::Dmg,
2295
+ target: Some(crate::cli::MakeTarget::Dmg),
1984
2296
  skip_package: false,
1985
2297
  force: false,
1986
2298
  dry_run: true,
@@ -2014,7 +2326,7 @@ mod tests {
2014
2326
  name: None,
2015
2327
  platform: Some("linux".to_string()),
2016
2328
  arch: Some("x64".to_string()),
2017
- target: crate::cli::MakeTarget::Rpm,
2329
+ target: Some(crate::cli::MakeTarget::Rpm),
2018
2330
  skip_package: false,
2019
2331
  force: false,
2020
2332
  dry_run: true,
@@ -2048,7 +2360,7 @@ mod tests {
2048
2360
  name: None,
2049
2361
  platform: Some("win32".to_string()),
2050
2362
  arch: Some("x64".to_string()),
2051
- target: crate::cli::MakeTarget::Msi,
2363
+ target: Some(crate::cli::MakeTarget::Msi),
2052
2364
  skip_package: false,
2053
2365
  force: false,
2054
2366
  dry_run: true,
@@ -2069,6 +2381,79 @@ mod tests {
2069
2381
  let _ = fs::remove_dir_all(root);
2070
2382
  }
2071
2383
 
2384
+ #[test]
2385
+ fn builds_make_reports_from_configured_forge_makers() {
2386
+ let root = unique_temp_dir("configured-makers");
2387
+ write_package_json_with_makers(
2388
+ &root,
2389
+ r#"[
2390
+ {"name":"@electron-forge/maker-zip"},
2391
+ {"name":"@electron-forge/maker-deb","platforms":["linux"]},
2392
+ {"name":"@electron-forge/maker-rpm","platforms":["darwin"]},
2393
+ {"name":"@electron-forge/maker-squirrel","platforms":["linux"]}
2394
+ ]"#,
2395
+ );
2396
+ write_app_file(&root);
2397
+ write_fake_electron_dist(&root);
2398
+
2399
+ let args = MakeArgs {
2400
+ cwd: root.clone(),
2401
+ out_dir: PathBuf::from("out"),
2402
+ name: None,
2403
+ platform: Some("linux".to_string()),
2404
+ arch: Some("x64".to_string()),
2405
+ target: None,
2406
+ skip_package: false,
2407
+ force: false,
2408
+ dry_run: true,
2409
+ json: true,
2410
+ };
2411
+ let reports = build_reports(&args).expect("reports should build");
2412
+
2413
+ assert_eq!(reports.len(), 2);
2414
+ assert_eq!(reports[0].target(), "zip");
2415
+ assert_eq!(reports[1].target(), "deb");
2416
+ assert!(reports[0]
2417
+ .warnings()
2418
+ .iter()
2419
+ .any(|warning| warning.contains("@electron-forge/maker-squirrel")));
2420
+
2421
+ let _ = fs::remove_dir_all(root);
2422
+ }
2423
+
2424
+ #[test]
2425
+ fn explicit_make_target_overrides_configured_makers() {
2426
+ let root = unique_temp_dir("target-override");
2427
+ write_package_json_with_makers(
2428
+ &root,
2429
+ r#"[{"name":"@electron-forge/maker-zip"},{"name":"@electron-forge/maker-deb"}]"#,
2430
+ );
2431
+ write_app_file(&root);
2432
+ write_fake_electron_dist(&root);
2433
+
2434
+ let args = MakeArgs {
2435
+ cwd: root.clone(),
2436
+ out_dir: PathBuf::from("out"),
2437
+ name: None,
2438
+ platform: Some("win32".to_string()),
2439
+ arch: Some("x64".to_string()),
2440
+ target: Some(crate::cli::MakeTarget::Msi),
2441
+ skip_package: false,
2442
+ force: false,
2443
+ dry_run: true,
2444
+ json: true,
2445
+ };
2446
+ let report = build_report(&args).expect("report should build");
2447
+
2448
+ assert_eq!(report.target(), "msi");
2449
+ assert!(report
2450
+ .warnings()
2451
+ .iter()
2452
+ .all(|warning| !warning.contains("maker-deb")));
2453
+
2454
+ let _ = fs::remove_dir_all(root);
2455
+ }
2456
+
2072
2457
  #[test]
2073
2458
  fn makes_zip_artifact_after_packaging() {
2074
2459
  let root = unique_temp_dir("execute");
@@ -2082,7 +2467,7 @@ mod tests {
2082
2467
  name: None,
2083
2468
  platform: None,
2084
2469
  arch: None,
2085
- target: crate::cli::MakeTarget::Zip,
2470
+ target: Some(crate::cli::MakeTarget::Zip),
2086
2471
  skip_package: false,
2087
2472
  force: false,
2088
2473
  dry_run: false,
@@ -2111,6 +2496,44 @@ mod tests {
2111
2496
  let _ = fs::remove_dir_all(root);
2112
2497
  }
2113
2498
 
2499
+ #[test]
2500
+ fn makes_multiple_configured_artifacts_from_existing_package() {
2501
+ let root = unique_temp_dir("configured-execute");
2502
+ write_package_json_with_makers(
2503
+ &root,
2504
+ r#"[
2505
+ {"name":"@electron-forge/maker-zip","platforms":["win32"]},
2506
+ {"name":"@electron-forge/maker-wix","platforms":["win32"]}
2507
+ ]"#,
2508
+ );
2509
+ write_app_file(&root);
2510
+ write_fake_windows_bundle(&root.join("out/starter-app-win32-x64"), "starter-app.exe");
2511
+
2512
+ let args = MakeArgs {
2513
+ cwd: root.clone(),
2514
+ out_dir: PathBuf::from("out"),
2515
+ name: None,
2516
+ platform: Some("win32".to_string()),
2517
+ arch: Some("x64".to_string()),
2518
+ target: None,
2519
+ skip_package: true,
2520
+ force: false,
2521
+ dry_run: false,
2522
+ json: true,
2523
+ };
2524
+ let mut reports = build_reports(&args).expect("reports should build");
2525
+
2526
+ execute_make_reports(&mut reports, &args).expect("configured makers should execute");
2527
+
2528
+ assert_eq!(reports.len(), 2);
2529
+ assert_eq!(reports[0].target(), "zip");
2530
+ assert_eq!(reports[1].target(), "msi");
2531
+ assert!(Path::new(reports[0].artifact.as_str()).exists());
2532
+ assert!(Path::new(reports[1].artifact.as_str()).exists());
2533
+
2534
+ let _ = fs::remove_dir_all(root);
2535
+ }
2536
+
2114
2537
  #[test]
2115
2538
  fn writes_deb_archive_with_control_and_data_members() {
2116
2539
  let root = unique_temp_dir("deb-archive");
@@ -2124,7 +2547,7 @@ mod tests {
2124
2547
  name: None,
2125
2548
  platform: Some("linux".to_string()),
2126
2549
  arch: Some("x64".to_string()),
2127
- target: crate::cli::MakeTarget::Deb,
2550
+ target: Some(crate::cli::MakeTarget::Deb),
2128
2551
  skip_package: false,
2129
2552
  force: false,
2130
2553
  dry_run: true,
@@ -2183,7 +2606,7 @@ mod tests {
2183
2606
  name: None,
2184
2607
  platform: Some("darwin".to_string()),
2185
2608
  arch: Some("arm64".to_string()),
2186
- target: crate::cli::MakeTarget::Dmg,
2609
+ target: Some(crate::cli::MakeTarget::Dmg),
2187
2610
  skip_package: false,
2188
2611
  force: false,
2189
2612
  dry_run: true,
@@ -2251,7 +2674,7 @@ mod tests {
2251
2674
  name: None,
2252
2675
  platform: Some("linux".to_string()),
2253
2676
  arch: Some("x64".to_string()),
2254
- target: crate::cli::MakeTarget::Rpm,
2677
+ target: Some(crate::cli::MakeTarget::Rpm),
2255
2678
  skip_package: false,
2256
2679
  force: false,
2257
2680
  dry_run: true,
@@ -2310,7 +2733,7 @@ mod tests {
2310
2733
  name: None,
2311
2734
  platform: Some("win32".to_string()),
2312
2735
  arch: Some("x64".to_string()),
2313
- target: crate::cli::MakeTarget::Msi,
2736
+ target: Some(crate::cli::MakeTarget::Msi),
2314
2737
  skip_package: false,
2315
2738
  force: false,
2316
2739
  dry_run: true,
@@ -2384,7 +2807,7 @@ mod tests {
2384
2807
  name: None,
2385
2808
  platform: None,
2386
2809
  arch: None,
2387
- target: crate::cli::MakeTarget::Deb,
2810
+ target: Some(crate::cli::MakeTarget::Deb),
2388
2811
  skip_package: false,
2389
2812
  force: false,
2390
2813
  dry_run: false,
@@ -2416,7 +2839,7 @@ mod tests {
2416
2839
  name: None,
2417
2840
  platform: None,
2418
2841
  arch: None,
2419
- target: crate::cli::MakeTarget::Dmg,
2842
+ target: Some(crate::cli::MakeTarget::Dmg),
2420
2843
  skip_package: false,
2421
2844
  force: false,
2422
2845
  dry_run: false,
@@ -2448,7 +2871,7 @@ mod tests {
2448
2871
  name: None,
2449
2872
  platform: None,
2450
2873
  arch: None,
2451
- target: crate::cli::MakeTarget::Rpm,
2874
+ target: Some(crate::cli::MakeTarget::Rpm),
2452
2875
  skip_package: false,
2453
2876
  force: false,
2454
2877
  dry_run: false,
@@ -2471,6 +2894,23 @@ mod tests {
2471
2894
  .expect("package.json should be written");
2472
2895
  }
2473
2896
 
2897
+ fn write_package_json_with_makers(root: &Path, makers: &str) {
2898
+ fs::write(
2899
+ root.join("package.json"),
2900
+ format!(
2901
+ r#"{{
2902
+ "name":"starter-app",
2903
+ "version":"0.1.0",
2904
+ "license":"MIT",
2905
+ "main":"src/main.js",
2906
+ "devDependencies":{{"electron":"30.0.0"}},
2907
+ "config":{{"forge":{{"makers":{makers}}}}}
2908
+ }}"#
2909
+ ),
2910
+ )
2911
+ .expect("package.json with makers should be written");
2912
+ }
2913
+
2474
2914
  fn write_app_file(root: &Path) {
2475
2915
  fs::create_dir_all(root.join("src")).expect("src should be created");
2476
2916
  fs::write(root.join("src/main.js"), "console.log('hello');")