electron-cli 0.3.0-alpha.0 → 0.3.0-alpha.10
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.
- package/Cargo.lock +1227 -67
- package/Cargo.toml +11 -2
- package/README.md +64 -10
- package/bin/electron-cli.js +6 -3
- package/package.json +8 -5
- package/scripts/install.js +101 -0
- package/src/cli.rs +260 -1
- package/src/commands/init.rs +814 -0
- package/src/commands/make.rs +1710 -0
- package/src/commands/mod.rs +5 -0
- package/src/commands/package.rs +1626 -0
- package/src/commands/plan.rs +64 -5
- package/src/commands/publish.rs +432 -0
- package/src/commands/start.rs +287 -0
- package/src/main.rs +5 -0
- package/src/project.rs +6 -0
- package/templates/minimal/gitignore +5 -0
- package/templates/minimal/src/index.html +82 -0
- package/templates/minimal/src/main.js +33 -0
- package/templates/minimal/src/preload.js +6 -0
- package/templates/minimal/src/renderer.js +5 -0
package/src/commands/plan.rs
CHANGED
|
@@ -83,7 +83,9 @@ fn build_report(snapshot: &project::ProjectSnapshot) -> PlanReport {
|
|
|
83
83
|
let mut risks = Vec::new();
|
|
84
84
|
let mut notes = Vec::new();
|
|
85
85
|
|
|
86
|
-
if
|
|
86
|
+
if matches!(project_type, ProjectType::Electron) && snapshot.main.is_some() {
|
|
87
|
+
recommended_commands.insert("dev".to_string(), "electron-cli start".to_string());
|
|
88
|
+
} else if let Some(script) = first_script(snapshot, &["start", "dev"]) {
|
|
87
89
|
recommended_commands.insert("dev".to_string(), run_script(snapshot, script));
|
|
88
90
|
} else if snapshot.electron_dependency.is_some() && snapshot.main.is_some() {
|
|
89
91
|
recommended_commands.insert("dev".to_string(), package_exec(snapshot, "electron ."));
|
|
@@ -94,7 +96,9 @@ fn build_report(snapshot: &project::ProjectSnapshot) -> PlanReport {
|
|
|
94
96
|
missing.push("No start or dev script was found.".to_string());
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
if
|
|
99
|
+
if matches!(project_type, ProjectType::Electron) && snapshot.main.is_some() {
|
|
100
|
+
recommended_commands.insert("package".to_string(), "electron-cli package".to_string());
|
|
101
|
+
} else if let Some(script) = first_script(snapshot, &["package", "pack"]) {
|
|
98
102
|
recommended_commands.insert("package".to_string(), run_script(snapshot, script));
|
|
99
103
|
} else if matches!(project_type, ProjectType::ElectronForge) {
|
|
100
104
|
missing.push(
|
|
@@ -102,10 +106,18 @@ fn build_report(snapshot: &project::ProjectSnapshot) -> PlanReport {
|
|
|
102
106
|
);
|
|
103
107
|
}
|
|
104
108
|
|
|
105
|
-
if
|
|
109
|
+
if matches!(project_type, ProjectType::Electron) && snapshot.main.is_some() {
|
|
110
|
+
recommended_commands.insert("make".to_string(), "electron-cli make".to_string());
|
|
111
|
+
} else if let Some(script) = first_script(snapshot, &["make", "dist"]) {
|
|
106
112
|
recommended_commands.insert("make".to_string(), run_script(snapshot, script));
|
|
107
113
|
}
|
|
108
114
|
|
|
115
|
+
if matches!(project_type, ProjectType::Electron) && snapshot.main.is_some() {
|
|
116
|
+
recommended_commands.insert("publish".to_string(), "electron-cli publish".to_string());
|
|
117
|
+
} else if let Some(script) = first_script(snapshot, &["publish", "release"]) {
|
|
118
|
+
recommended_commands.insert("publish".to_string(), run_script(snapshot, script));
|
|
119
|
+
}
|
|
120
|
+
|
|
109
121
|
recommended_commands.insert(
|
|
110
122
|
"diagnostics".to_string(),
|
|
111
123
|
"electron-cli doctor --json".to_string(),
|
|
@@ -134,9 +146,9 @@ fn build_report(snapshot: &project::ProjectSnapshot) -> PlanReport {
|
|
|
134
146
|
}
|
|
135
147
|
|
|
136
148
|
if matches!(project_type, ProjectType::ElectronForge) {
|
|
137
|
-
notes.push("Electron Forge was detected;
|
|
149
|
+
notes.push("Electron Forge was detected; its scripts remain the safest path for Forge-managed apps today.".to_string());
|
|
138
150
|
} else if snapshot.electron_dependency.is_some() {
|
|
139
|
-
notes.push("Electron was detected without Forge;
|
|
151
|
+
notes.push("Electron was detected without Forge; electron-cli can start, package, make, and publish local artifacts directly.".to_string());
|
|
140
152
|
} else {
|
|
141
153
|
notes.push("This does not currently look like an Electron app.".to_string());
|
|
142
154
|
}
|
|
@@ -232,4 +244,51 @@ mod tests {
|
|
|
232
244
|
);
|
|
233
245
|
assert!(report.risks.is_empty());
|
|
234
246
|
}
|
|
247
|
+
|
|
248
|
+
#[test]
|
|
249
|
+
fn plans_native_electron_cli_flow_for_plain_electron_app() {
|
|
250
|
+
let snapshot = project::ProjectSnapshot {
|
|
251
|
+
root: camino::Utf8PathBuf::from("/tmp/native-app"),
|
|
252
|
+
package_json: Some(camino::Utf8PathBuf::from("/tmp/native-app/package.json")),
|
|
253
|
+
name: Some("native-app".to_string()),
|
|
254
|
+
version: Some("0.1.0".to_string()),
|
|
255
|
+
license: None,
|
|
256
|
+
main: Some("src/main.js".to_string()),
|
|
257
|
+
package_manager: Some("npm".to_string()),
|
|
258
|
+
scripts: BTreeMap::new(),
|
|
259
|
+
dependencies: BTreeMap::new(),
|
|
260
|
+
dev_dependencies: BTreeMap::from([("electron".to_string(), "30.0.0".to_string())]),
|
|
261
|
+
optional_dependencies: BTreeMap::new(),
|
|
262
|
+
peer_dependencies: BTreeMap::new(),
|
|
263
|
+
electron_dependency: Some("30.0.0".to_string()),
|
|
264
|
+
forge_dependencies: BTreeMap::new(),
|
|
265
|
+
signals: vec!["electron dependency declared".to_string()],
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
let report = build_report(&snapshot);
|
|
269
|
+
|
|
270
|
+
assert!(matches!(report.project_type, ProjectType::Electron));
|
|
271
|
+
assert_eq!(
|
|
272
|
+
report.recommended_commands.get("dev").map(String::as_str),
|
|
273
|
+
Some("electron-cli start")
|
|
274
|
+
);
|
|
275
|
+
assert_eq!(
|
|
276
|
+
report
|
|
277
|
+
.recommended_commands
|
|
278
|
+
.get("package")
|
|
279
|
+
.map(String::as_str),
|
|
280
|
+
Some("electron-cli package")
|
|
281
|
+
);
|
|
282
|
+
assert_eq!(
|
|
283
|
+
report.recommended_commands.get("make").map(String::as_str),
|
|
284
|
+
Some("electron-cli make")
|
|
285
|
+
);
|
|
286
|
+
assert_eq!(
|
|
287
|
+
report
|
|
288
|
+
.recommended_commands
|
|
289
|
+
.get("publish")
|
|
290
|
+
.map(String::as_str),
|
|
291
|
+
Some("electron-cli publish")
|
|
292
|
+
);
|
|
293
|
+
}
|
|
235
294
|
}
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
use std::{
|
|
2
|
+
fs,
|
|
3
|
+
path::{Path, PathBuf},
|
|
4
|
+
time::{SystemTime, UNIX_EPOCH},
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
use anyhow::{bail, Context, Result};
|
|
8
|
+
use camino::Utf8PathBuf;
|
|
9
|
+
use serde::Serialize;
|
|
10
|
+
|
|
11
|
+
use crate::{
|
|
12
|
+
cli::{MakeArgs, PublishArgs},
|
|
13
|
+
commands::make::{self, MakeReport},
|
|
14
|
+
output,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
#[derive(Debug, Serialize)]
|
|
18
|
+
struct PublishReport {
|
|
19
|
+
make: MakeReport,
|
|
20
|
+
publisher: String,
|
|
21
|
+
channel: String,
|
|
22
|
+
destination_dir: Utf8PathBuf,
|
|
23
|
+
destination_artifact: Utf8PathBuf,
|
|
24
|
+
manifest: Utf8PathBuf,
|
|
25
|
+
skip_make: bool,
|
|
26
|
+
dry_run: bool,
|
|
27
|
+
status: PublishStatus,
|
|
28
|
+
published_at_unix_seconds: Option<u64>,
|
|
29
|
+
warnings: Vec<String>,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#[derive(Debug, Serialize)]
|
|
33
|
+
#[serde(rename_all = "kebab-case")]
|
|
34
|
+
enum PublishStatus {
|
|
35
|
+
Planned,
|
|
36
|
+
Published,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
#[derive(Debug, Serialize)]
|
|
40
|
+
struct PublishManifest {
|
|
41
|
+
schema_version: u8,
|
|
42
|
+
publisher: String,
|
|
43
|
+
channel: String,
|
|
44
|
+
app_name: String,
|
|
45
|
+
package_name: Option<String>,
|
|
46
|
+
package_version: Option<String>,
|
|
47
|
+
platform: String,
|
|
48
|
+
arch: String,
|
|
49
|
+
target: String,
|
|
50
|
+
published_at_unix_seconds: u64,
|
|
51
|
+
artifacts: Vec<PublishedArtifact>,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#[derive(Debug, Serialize)]
|
|
55
|
+
struct PublishedArtifact {
|
|
56
|
+
file: String,
|
|
57
|
+
path: Utf8PathBuf,
|
|
58
|
+
size: u64,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pub fn run(args: PublishArgs) -> Result<()> {
|
|
62
|
+
let mut report = build_report(&args)?;
|
|
63
|
+
|
|
64
|
+
if args.dry_run {
|
|
65
|
+
return print_report(&report, args.json);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
execute_publish(&mut report, &args)?;
|
|
69
|
+
report.status = PublishStatus::Published;
|
|
70
|
+
|
|
71
|
+
print_report(&report, args.json)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn build_report(args: &PublishArgs) -> Result<PublishReport> {
|
|
75
|
+
let make_args = MakeArgs {
|
|
76
|
+
cwd: args.cwd.clone(),
|
|
77
|
+
out_dir: args.out_dir.clone(),
|
|
78
|
+
name: args.name.clone(),
|
|
79
|
+
platform: args.platform.clone(),
|
|
80
|
+
arch: args.arch.clone(),
|
|
81
|
+
target: args.target,
|
|
82
|
+
skip_package: false,
|
|
83
|
+
force: args.force,
|
|
84
|
+
dry_run: false,
|
|
85
|
+
json: false,
|
|
86
|
+
};
|
|
87
|
+
let make = make::build_report(&make_args)?;
|
|
88
|
+
let root = Path::new(make.package().project().root.as_str());
|
|
89
|
+
let publish_root = resolve_destination(root, &args.to);
|
|
90
|
+
let destination_dir = publish_root
|
|
91
|
+
.join(&args.channel)
|
|
92
|
+
.join(make.package().platform())
|
|
93
|
+
.join(make.package().arch());
|
|
94
|
+
let artifact_name = make
|
|
95
|
+
.artifact()
|
|
96
|
+
.file_name()
|
|
97
|
+
.context("Make artifact path has no file name")?;
|
|
98
|
+
let destination_artifact = destination_dir.join(artifact_name);
|
|
99
|
+
let manifest = destination_dir.join("manifest.json");
|
|
100
|
+
|
|
101
|
+
let mut warnings = make.warnings().to_vec();
|
|
102
|
+
if args.skip_make && !Path::new(make.artifact().as_str()).exists() {
|
|
103
|
+
warnings.push(format!(
|
|
104
|
+
"Make artifact does not exist: {}.",
|
|
105
|
+
make.artifact()
|
|
106
|
+
));
|
|
107
|
+
}
|
|
108
|
+
if destination_artifact.exists() && !args.force {
|
|
109
|
+
warnings.push(format!(
|
|
110
|
+
"Publish artifact already exists: {}. Use --force to overwrite it.",
|
|
111
|
+
destination_artifact.display()
|
|
112
|
+
));
|
|
113
|
+
}
|
|
114
|
+
if manifest.exists() && !args.force {
|
|
115
|
+
warnings.push(format!(
|
|
116
|
+
"Publish manifest already exists: {}. Use --force to overwrite it.",
|
|
117
|
+
manifest.display()
|
|
118
|
+
));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
Ok(PublishReport {
|
|
122
|
+
make,
|
|
123
|
+
publisher: args.publisher.as_str().to_string(),
|
|
124
|
+
channel: args.channel.clone(),
|
|
125
|
+
destination_dir: utf8_path(destination_dir)?,
|
|
126
|
+
destination_artifact: utf8_path(destination_artifact)?,
|
|
127
|
+
manifest: utf8_path(manifest)?,
|
|
128
|
+
skip_make: args.skip_make,
|
|
129
|
+
dry_run: args.dry_run,
|
|
130
|
+
status: PublishStatus::Planned,
|
|
131
|
+
published_at_unix_seconds: None,
|
|
132
|
+
warnings,
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
fn execute_publish(report: &mut PublishReport, args: &PublishArgs) -> Result<()> {
|
|
137
|
+
if !args.skip_make {
|
|
138
|
+
let make_args = MakeArgs {
|
|
139
|
+
cwd: args.cwd.clone(),
|
|
140
|
+
out_dir: args.out_dir.clone(),
|
|
141
|
+
name: args.name.clone(),
|
|
142
|
+
platform: args.platform.clone(),
|
|
143
|
+
arch: args.arch.clone(),
|
|
144
|
+
target: args.target,
|
|
145
|
+
skip_package: false,
|
|
146
|
+
force: args.force,
|
|
147
|
+
dry_run: false,
|
|
148
|
+
json: false,
|
|
149
|
+
};
|
|
150
|
+
make::execute_make(&mut report.make, &make_args)?;
|
|
151
|
+
report.make.mark_made()?;
|
|
152
|
+
} else if !Path::new(report.make.artifact().as_str()).exists() {
|
|
153
|
+
bail!(
|
|
154
|
+
"Make artifact does not exist: {}. Run without --skip-make or run electron-cli make first.",
|
|
155
|
+
report.make.artifact()
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let destination_artifact = Path::new(report.destination_artifact.as_str());
|
|
160
|
+
let manifest = Path::new(report.manifest.as_str());
|
|
161
|
+
|
|
162
|
+
for path in [destination_artifact, manifest] {
|
|
163
|
+
if path.exists() {
|
|
164
|
+
if args.force {
|
|
165
|
+
fs::remove_file(path)
|
|
166
|
+
.with_context(|| format!("Could not remove {}", path.display()))?;
|
|
167
|
+
} else {
|
|
168
|
+
bail!(
|
|
169
|
+
"Publish output already exists: {}. Use --force to overwrite it.",
|
|
170
|
+
path.display()
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
fs::create_dir_all(report.destination_dir.as_str())
|
|
177
|
+
.with_context(|| format!("Could not create {}", report.destination_dir))?;
|
|
178
|
+
fs::copy(report.make.artifact().as_str(), destination_artifact).with_context(|| {
|
|
179
|
+
format!(
|
|
180
|
+
"Could not publish {} to {}",
|
|
181
|
+
report.make.artifact(),
|
|
182
|
+
destination_artifact.display()
|
|
183
|
+
)
|
|
184
|
+
})?;
|
|
185
|
+
|
|
186
|
+
let published_at_unix_seconds = now_unix_seconds()?;
|
|
187
|
+
report.published_at_unix_seconds = Some(published_at_unix_seconds);
|
|
188
|
+
let manifest_json =
|
|
189
|
+
serde_json::to_string_pretty(&build_manifest(report, published_at_unix_seconds)?)?;
|
|
190
|
+
fs::write(manifest, format!("{manifest_json}\n"))
|
|
191
|
+
.with_context(|| format!("Could not write {}", manifest.display()))?;
|
|
192
|
+
|
|
193
|
+
Ok(())
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
fn build_manifest(
|
|
197
|
+
report: &PublishReport,
|
|
198
|
+
published_at_unix_seconds: u64,
|
|
199
|
+
) -> Result<PublishManifest> {
|
|
200
|
+
let destination_artifact = Path::new(report.destination_artifact.as_str());
|
|
201
|
+
let artifact_size = fs::metadata(destination_artifact)
|
|
202
|
+
.with_context(|| format!("Could not stat {}", destination_artifact.display()))?
|
|
203
|
+
.len();
|
|
204
|
+
let artifact_file = destination_artifact
|
|
205
|
+
.file_name()
|
|
206
|
+
.and_then(|name| name.to_str())
|
|
207
|
+
.context("Published artifact path has no UTF-8 file name")?
|
|
208
|
+
.to_string();
|
|
209
|
+
|
|
210
|
+
Ok(PublishManifest {
|
|
211
|
+
schema_version: 1,
|
|
212
|
+
publisher: report.publisher.clone(),
|
|
213
|
+
channel: report.channel.clone(),
|
|
214
|
+
app_name: report.make.package().app_name().to_string(),
|
|
215
|
+
package_name: report.make.package().project().name.clone(),
|
|
216
|
+
package_version: report.make.package().project().version.clone(),
|
|
217
|
+
platform: report.make.package().platform().to_string(),
|
|
218
|
+
arch: report.make.package().arch().to_string(),
|
|
219
|
+
target: report.make.target().to_string(),
|
|
220
|
+
published_at_unix_seconds,
|
|
221
|
+
artifacts: vec![PublishedArtifact {
|
|
222
|
+
file: artifact_file,
|
|
223
|
+
path: report.destination_artifact.clone(),
|
|
224
|
+
size: artifact_size,
|
|
225
|
+
}],
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
fn print_report(report: &PublishReport, json: bool) -> Result<()> {
|
|
230
|
+
if json {
|
|
231
|
+
return output::json(report);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
println!("electron-cli publish");
|
|
235
|
+
println!();
|
|
236
|
+
println!("Project");
|
|
237
|
+
println!(" root: {}", report.make.package().project().root);
|
|
238
|
+
match report.make.package().project().package_label() {
|
|
239
|
+
Some(label) => println!(" package: {label}"),
|
|
240
|
+
None => println!(" package: not found"),
|
|
241
|
+
}
|
|
242
|
+
println!(" app name: {}", report.make.package().app_name());
|
|
243
|
+
println!(
|
|
244
|
+
" target: {} {} {}",
|
|
245
|
+
report.make.target(),
|
|
246
|
+
report.make.package().platform(),
|
|
247
|
+
report.make.package().arch()
|
|
248
|
+
);
|
|
249
|
+
println!(" publisher: {}", report.publisher);
|
|
250
|
+
println!(" channel: {}", report.channel);
|
|
251
|
+
println!(" status: {}", report.status.as_str());
|
|
252
|
+
|
|
253
|
+
println!();
|
|
254
|
+
println!("Publish");
|
|
255
|
+
println!(" artifact: {}", report.destination_artifact);
|
|
256
|
+
println!(" manifest: {}", report.manifest);
|
|
257
|
+
|
|
258
|
+
if !report.warnings.is_empty() {
|
|
259
|
+
println!();
|
|
260
|
+
println!("Warnings");
|
|
261
|
+
for warning in &report.warnings {
|
|
262
|
+
println!(" {warning}");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
Ok(())
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
fn resolve_destination(root: &Path, destination: &Path) -> PathBuf {
|
|
270
|
+
if destination.is_absolute() {
|
|
271
|
+
destination.to_path_buf()
|
|
272
|
+
} else {
|
|
273
|
+
root.join(destination)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
fn now_unix_seconds() -> Result<u64> {
|
|
278
|
+
Ok(SystemTime::now()
|
|
279
|
+
.duration_since(UNIX_EPOCH)
|
|
280
|
+
.context("System clock is before the Unix epoch")?
|
|
281
|
+
.as_secs())
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
fn utf8_path(path: PathBuf) -> Result<Utf8PathBuf> {
|
|
285
|
+
Utf8PathBuf::from_path_buf(path).map_err(|path| {
|
|
286
|
+
anyhow::anyhow!(
|
|
287
|
+
"Path contains invalid UTF-8 and cannot be represented in JSON: {}",
|
|
288
|
+
path.display()
|
|
289
|
+
)
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
impl PublishStatus {
|
|
294
|
+
fn as_str(&self) -> &'static str {
|
|
295
|
+
match self {
|
|
296
|
+
PublishStatus::Planned => "planned",
|
|
297
|
+
PublishStatus::Published => "published",
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
#[cfg(test)]
|
|
303
|
+
mod tests {
|
|
304
|
+
use super::*;
|
|
305
|
+
|
|
306
|
+
#[test]
|
|
307
|
+
fn builds_local_publish_report() {
|
|
308
|
+
let root = unique_temp_dir("plan");
|
|
309
|
+
write_package_json(&root);
|
|
310
|
+
write_app_file(&root);
|
|
311
|
+
write_fake_electron_dist(&root);
|
|
312
|
+
|
|
313
|
+
let args = publish_args(root.clone(), true);
|
|
314
|
+
let report = build_report(&args).expect("report should build");
|
|
315
|
+
|
|
316
|
+
assert_eq!(report.publisher, "local");
|
|
317
|
+
assert_eq!(report.channel, "default");
|
|
318
|
+
assert!(Path::new(report.destination_artifact.as_str()).ends_with(
|
|
319
|
+
PathBuf::from("out")
|
|
320
|
+
.join("publish")
|
|
321
|
+
.join("local")
|
|
322
|
+
.join("default")
|
|
323
|
+
.join(report.make.package().platform())
|
|
324
|
+
.join(report.make.package().arch())
|
|
325
|
+
.join(format!(
|
|
326
|
+
"starter-app-{}-{}.zip",
|
|
327
|
+
report.make.package().platform(),
|
|
328
|
+
report.make.package().arch()
|
|
329
|
+
))
|
|
330
|
+
));
|
|
331
|
+
|
|
332
|
+
let _ = fs::remove_dir_all(root);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
#[test]
|
|
336
|
+
fn publishes_make_artifact_to_local_directory() {
|
|
337
|
+
let root = unique_temp_dir("execute");
|
|
338
|
+
write_package_json(&root);
|
|
339
|
+
write_app_file(&root);
|
|
340
|
+
write_fake_electron_dist(&root);
|
|
341
|
+
|
|
342
|
+
let args = publish_args(root.clone(), false);
|
|
343
|
+
let mut report = build_report(&args).expect("report should build");
|
|
344
|
+
|
|
345
|
+
execute_publish(&mut report, &args).expect("publish should succeed");
|
|
346
|
+
|
|
347
|
+
assert!(Path::new(report.destination_artifact.as_str()).exists());
|
|
348
|
+
assert!(Path::new(report.manifest.as_str()).exists());
|
|
349
|
+
let manifest =
|
|
350
|
+
fs::read_to_string(report.manifest.as_str()).expect("manifest should be readable");
|
|
351
|
+
assert!(manifest.contains("\"publisher\": \"local\""));
|
|
352
|
+
assert!(manifest.contains("\"app_name\": \"starter-app\""));
|
|
353
|
+
|
|
354
|
+
let _ = fs::remove_dir_all(root);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
#[test]
|
|
358
|
+
fn skip_make_requires_existing_artifact() {
|
|
359
|
+
let root = unique_temp_dir("skip-make");
|
|
360
|
+
write_package_json(&root);
|
|
361
|
+
write_app_file(&root);
|
|
362
|
+
write_fake_electron_dist(&root);
|
|
363
|
+
|
|
364
|
+
let mut args = publish_args(root.clone(), false);
|
|
365
|
+
args.skip_make = true;
|
|
366
|
+
let mut report = build_report(&args).expect("report should build");
|
|
367
|
+
|
|
368
|
+
assert!(execute_publish(&mut report, &args).is_err());
|
|
369
|
+
|
|
370
|
+
let _ = fs::remove_dir_all(root);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
fn publish_args(root: PathBuf, dry_run: bool) -> PublishArgs {
|
|
374
|
+
PublishArgs {
|
|
375
|
+
cwd: root,
|
|
376
|
+
out_dir: PathBuf::from("out"),
|
|
377
|
+
name: None,
|
|
378
|
+
platform: None,
|
|
379
|
+
arch: None,
|
|
380
|
+
target: crate::cli::MakeTarget::Zip,
|
|
381
|
+
publisher: crate::cli::PublishTarget::Local,
|
|
382
|
+
to: PathBuf::from("out/publish/local"),
|
|
383
|
+
channel: "default".to_string(),
|
|
384
|
+
skip_make: false,
|
|
385
|
+
force: false,
|
|
386
|
+
dry_run,
|
|
387
|
+
json: true,
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
fn write_package_json(root: &Path) {
|
|
392
|
+
fs::write(
|
|
393
|
+
root.join("package.json"),
|
|
394
|
+
r#"{"name":"starter-app","version":"0.1.0","main":"src/main.js","devDependencies":{"electron":"30.0.0"}}"#,
|
|
395
|
+
)
|
|
396
|
+
.expect("package.json should be written");
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
fn write_app_file(root: &Path) {
|
|
400
|
+
fs::create_dir_all(root.join("src")).expect("src should be created");
|
|
401
|
+
fs::write(root.join("src/main.js"), "console.log('hello');")
|
|
402
|
+
.expect("main file should be written");
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
fn write_fake_electron_dist(root: &Path) {
|
|
406
|
+
let dist = root.join("node_modules/electron/dist");
|
|
407
|
+
if cfg!(target_os = "macos") {
|
|
408
|
+
let app = dist.join("Electron.app/Contents/MacOS");
|
|
409
|
+
fs::create_dir_all(&app).expect("fake macOS electron app should be created");
|
|
410
|
+
fs::write(app.join("Electron"), "").expect("fake macOS binary should be written");
|
|
411
|
+
} else if cfg!(target_os = "windows") {
|
|
412
|
+
fs::create_dir_all(&dist).expect("fake electron dist should be created");
|
|
413
|
+
fs::write(dist.join("electron.exe"), "").expect("fake exe should be written");
|
|
414
|
+
} else {
|
|
415
|
+
fs::create_dir_all(&dist).expect("fake electron dist should be created");
|
|
416
|
+
fs::write(dist.join("electron"), "").expect("fake binary should be written");
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
fn unique_temp_dir(label: &str) -> PathBuf {
|
|
421
|
+
let nanos = std::time::SystemTime::now()
|
|
422
|
+
.duration_since(std::time::UNIX_EPOCH)
|
|
423
|
+
.expect("clock should be after epoch")
|
|
424
|
+
.as_nanos();
|
|
425
|
+
let path = std::env::temp_dir().join(format!(
|
|
426
|
+
"electron-cli-publish-{label}-{}-{nanos}",
|
|
427
|
+
std::process::id()
|
|
428
|
+
));
|
|
429
|
+
fs::create_dir_all(&path).expect("temp dir should be created");
|
|
430
|
+
path
|
|
431
|
+
}
|
|
432
|
+
}
|