Skip to content

Commit 367e984

Browse files
committed
feat(cli): make release packaging explicit
1 parent 67c6b27 commit 367e984

12 files changed

Lines changed: 78 additions & 27 deletions

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ native checks before handing off larger refactors.
172172
--identifier "com.example.proton-release-smoke" -y --no-git
173173
proton_cli -C "$tmp_dir/release-smoke" cef setup
174174
proton_cli -C "$tmp_dir/release-smoke" build
175-
proton_cli -C "$tmp_dir/release-smoke" package --target app --dry-run
176-
proton_cli -C "$tmp_dir/release-smoke" package --target app
175+
proton_cli -C "$tmp_dir/release-smoke" package --release --target app --dry-run
176+
proton_cli -C "$tmp_dir/release-smoke" package --release --target app
177177
```
178178

179179
- The release is not complete until the independent scaffold passes

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -431,18 +431,21 @@ Inspect the resolved bundle plan before creating artifacts:
431431
```sh
432432
proton_cli package --dry-run
433433
proton_cli package
434+
proton_cli package --release
434435
```
435436

436-
The package command performs a release build unless `--no-build` is supplied.
437-
Package output is written to `target/proton-dist` by default. Icons, resources,
438-
output targets, signing, notarization, custom URL schemes, and macOS document
439-
types are configured through `moon.proton` and package command options.
437+
The package command performs a debug build by default. Pass `--release` to use
438+
MoonBit's release build mode, or `--no-build` to reuse an existing build from
439+
the selected mode. Package output is written to `target/proton-dist` by default.
440+
Icons, resources, output targets, signing, notarization, custom URL schemes, and
441+
macOS document types are configured through `moon.proton` and package command
442+
options.
440443

441444
The `dmg` target is available on macOS. It creates a compressed disk image
442445
containing the app and an `/Applications` shortcut for drag-to-install:
443446

444447
```sh
445-
proton_cli package --target app --target dmg
448+
proton_cli package --release --target app --target dmg
446449
```
447450

448451
With `--notarize`, Proton submits the DMG when that target is enabled, then
@@ -473,7 +476,7 @@ revision as well as the reproducible publication time. The revision is embedded
473476
in the signed app and emitted into the signed manifest fragment:
474477

475478
```sh
476-
proton_cli package --target zip \
479+
proton_cli package --release --target zip \
477480
--updater-base-url https://example.com/releases \
478481
--updater-published-at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
479482
--updater-revision 42

cli/new/templates.generated.mbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,7 @@ fn generated_template_specs() -> Array[TemplateSpec] {
844844
#|
845845
#|```sh
846846
#|proton_cli package --dry-run
847-
#|proton_cli package
847+
#|proton_cli package --release
848848
#|```
849849
#|
850850
#|## Layout

cli/new/templates/todo/files/README.md.mtpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Inspect the resolved package plan, then create the application and zip archive:
5858

5959
```sh
6060
proton_cli package --dry-run
61-
proton_cli package
61+
proton_cli package --release
6262
```
6363

6464
## Layout

cli/package/error.mbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ pub fn PackagePlanError::message(self : PackagePlanError) -> String {
110110
"unsupported bundle.resources glob: " + path
111111
MissingInput(path~) => "package input is missing: " + path
112112
MissingExecutable(path~) =>
113-
"package release executable not found under " +
113+
"package executable not found under " +
114114
path +
115115
"; run proton package without --no-build first"
116116
InputOutsideProject(path~) =>

cli/package/package.mbt

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct RawPackageOptions {
1111
targets : Array[String]
1212
output : String?
1313
build : Bool
14+
release : Bool
1415
dry_run : Bool
1516
sign : Bool
1617
notarize : Bool
@@ -32,6 +33,7 @@ struct PackagePlan {
3233
targets : Array[String]
3334
output : String
3435
build : Bool
36+
release : Bool
3537
base_dir : String
3638
frontend_dist : String?
3739
entry_paths : Array[String]
@@ -72,7 +74,8 @@ pub fn command() -> @argparse.Command {
7274
"package",
7375
about="Package a Proton application",
7476
flags=[
75-
FlagArg("no-build", about="Reuse an existing release build"),
77+
FlagArg("no-build", about="Reuse an existing package build"),
78+
FlagArg("release", about="Build and package the release output"),
7679
FlagArg("dry-run", about="Print the resolved package plan"),
7780
FlagArg("sign", about="Sign the packaged application"),
7881
FlagArg(
@@ -201,6 +204,8 @@ fn package_options_from_matches(
201204
| (None with notarize = false),
202205
"no-build"? : Some(no_build)
203206
| (None with no_build = false),
207+
"release"? : Some(release)
208+
| (None with release = false),
204209
"dry-run"? : Some(dry_run)
205210
| (None with dry_run = false),
206211
"sign"? : Some(sign)
@@ -216,6 +221,7 @@ fn package_options_from_matches(
216221
targets,
217222
output: output.get(0),
218223
build: !no_build,
224+
release,
219225
dry_run,
220226
sign: sign || notarize,
221227
notarize,
@@ -386,6 +392,7 @@ async fn build_package_plan(
386392
targets,
387393
output,
388394
build: raw.build,
395+
release: raw.release,
389396
base_dir,
390397
frontend_dist,
391398
entry_paths,
@@ -618,6 +625,8 @@ fn print_package_plan(plan : PackagePlan, dry_run : Bool) -> Unit {
618625
println(" sign binaries: " + sign_binaries)
619626
let build = if plan.build { "yes" } else { "no" }
620627
println(" build: " + build)
628+
let build_mode = if plan.release { "release" } else { "debug" }
629+
println(" build mode: " + build_mode)
621630
println(" sign: " + bool_text(plan.sign))
622631
println(" notarize: " + bool_text(plan.notarize))
623632
}
@@ -634,12 +643,12 @@ fn bool_text(value : Bool) -> String {
634643
///|
635644
async fn execute_package_plan(plan : PackagePlan) -> Unit {
636645
// Resolve the active runtime before any build work so a missing
637-
// `proton_cli cef setup` fails fast instead of after a full release build.
646+
// `proton_cli cef setup` fails fast instead of after a full application build.
638647
let runtime = read_active_runtime(plan.workspace_root)
639648
if plan.build {
640-
run_release_build(plan)
649+
run_package_build(plan)
641650
}
642-
let executable = match find_release_executable(plan) {
651+
let executable = match find_package_executable(plan) {
643652
Some(path) => path
644653
None =>
645654
raise PackagePlanError::MissingExecutable(path=plan.build_target_dir)
@@ -657,8 +666,15 @@ async fn is_macos_host() -> Bool {
657666
}
658667

659668
///|
660-
async fn run_release_build(plan : PackagePlan) -> Unit {
661-
let moon_args = ["--release", "--target-dir", plan.build_target_dir]
669+
async fn run_package_build(plan : PackagePlan) -> Unit {
670+
// Keep local packaging fast by default. Distribution builds opt into the
671+
// Moon release mode explicitly through `proton_cli package --release`.
672+
let moon_args : Array[String] = []
673+
if plan.release {
674+
moon_args.push("--release")
675+
}
676+
moon_args.push("--target-dir")
677+
moon_args.push(plan.build_target_dir)
662678
let old_rpath = @env.get_env_var("PROTON_PACKAGE_RPATH")
663679
// Mach-O only. The link config reads this on darwin; the Linux branch
664680
// ignores it and keeps the absolute runtime rpath, which is what a
@@ -683,8 +699,13 @@ fn restore_package_env(name : String, value : String?) -> Unit {
683699
}
684700

685701
///|
686-
async fn find_release_executable(plan : PackagePlan) -> String? {
687-
let root = @fsutil.resolve_path(plan.build_target_dir, "native/release/build")
702+
async fn find_package_executable(plan : PackagePlan) -> String? {
703+
// `--no-build` must reuse the same build mode selected for this command.
704+
let build_mode = if plan.release { "release" } else { "debug" }
705+
let root = @fsutil.resolve_path(
706+
plan.build_target_dir,
707+
"native/" + build_mode + "/build",
708+
)
688709
let package_name = path_basename(plan.app_package)
689710
find_named_file(root, package_name + ".exe")
690711
}

cli/package/package_macos_dmg_wbtest.mbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ fn macos_dmg_test_plan(root : String) -> PackagePlan {
1616
targets: ["app", "dmg"],
1717
output: root,
1818
build: false,
19+
release: false,
1920
base_dir: root,
2021
frontend_dist: None,
2122
entry_paths: [],

cli/package/package_wbtest.mbt

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,17 @@ test "parse package args accepts repeated targets and overrides" {
1818
@debug.assert_eq(raw.targets, ["app", "zip", "dmg"])
1919
@debug.assert_eq(raw.output, Some("dist"))
2020
assert_false(raw.build)
21+
assert_false(raw.release)
2122
assert_true(raw.dry_run)
2223
}
2324

25+
///|
26+
test "parse package args enables release builds explicitly" {
27+
let raw = parse_package_args(["--release"])
28+
assert_true(raw.build)
29+
assert_true(raw.release)
30+
}
31+
2432
///|
2533
test "parse package args rejects unsupported target" {
2634
try parse_package_args(["--target", "msi"]) catch {
@@ -153,11 +161,19 @@ async test "package plan uses the host defaults" {
153161
@debug.assert_eq(plan.targets, expected_targets)
154162
assert_eq(plan.identifier, "dev.proton.demo")
155163
assert_eq(plan.version, "1.0.0")
164+
assert_false(plan.release)
156165
assert_true(
157166
normalize_slashes(plan.build_target_dir).has_suffix(
158167
"/target/proton-package-build/dev-proton-demo",
159168
),
160169
)
170+
let release_plan = build_package_plan(
171+
parse_package_args(["--release"]),
172+
"moon.proton",
173+
project,
174+
0UL,
175+
)
176+
assert_true(release_plan.release)
161177
}
162178

163179
///|
@@ -587,6 +603,7 @@ async test "macOS icon selection stages icns and rejects a missing source" {
587603
targets: ["app"],
588604
output: root,
589605
build: false,
606+
release: false,
590607
base_dir: root,
591608
frontend_dist: None,
592609
entry_paths: [],
@@ -634,6 +651,7 @@ test "macOS plist contains bundle identity and executable" {
634651
targets: ["app"],
635652
output: "target",
636653
build: false,
654+
release: false,
637655
base_dir: ".",
638656
frontend_dist: None,
639657
entry_paths: [],
@@ -687,6 +705,7 @@ async test "package manifest records launch metadata" {
687705
targets: ["app"],
688706
output: "target",
689707
build: false,
708+
release: false,
690709
base_dir: ".",
691710
frontend_dist: None,
692711
entry_paths: [],
@@ -750,6 +769,7 @@ test "macOS helper plist matches its bundle identity" {
750769
targets: ["app"],
751770
output: "target",
752771
build: false,
772+
release: false,
753773
base_dir: ".",
754774
frontend_dist: None,
755775
entry_paths: [],
@@ -797,6 +817,7 @@ async test "macOS ZIP uses the final app name without metadata entries" {
797817
targets: ["app", "zip"],
798818
output: root,
799819
build: false,
820+
release: false,
800821
base_dir: root,
801822
frontend_dist: None,
802823
sign_binaries: [],
@@ -970,6 +991,7 @@ async test "macOS notarization validates success and cleans failed upload" {
970991
targets: ["app"],
971992
output: root,
972993
build: false,
994+
release: false,
973995
base_dir: root,
974996
frontend_dist: None,
975997
entry_paths: [],
@@ -1028,7 +1050,7 @@ async test "macOS notarization validates success and cleans failed upload" {
10281050
}
10291051

10301052
///|
1031-
async test "release executable lookup stays inside package target dir" {
1053+
async test "debug executable lookup stays inside package target dir" {
10321054
let root = "target/proton-package-executable-lookup"
10331055
remove_tree(root)
10341056
let package_target = @fsutil.resolve_path(root, "package-target")
@@ -1052,6 +1074,7 @@ async test "release executable lookup stays inside package target dir" {
10521074
targets: ["app"],
10531075
output: @fsutil.resolve_path(root, "output"),
10541076
build: false,
1077+
release: false,
10551078
base_dir: root,
10561079
frontend_dist: None,
10571080
entry_paths: [],
@@ -1064,16 +1087,16 @@ async test "release executable lookup stays inside package target dir" {
10641087
sign: false,
10651088
notarize: false,
10661089
}
1067-
@debug.assert_eq(find_release_executable(plan), None)
1090+
@debug.assert_eq(find_package_executable(plan), None)
10681091
let expected = @fsutil.resolve_path(
1069-
package_target, "native/release/build/vendor/app/app.exe",
1092+
package_target, "native/debug/build/vendor/app/app.exe",
10701093
)
10711094
ensure_dir(@fsutil.path_parent(expected))
10721095
write_text(expected, "right")
1073-
match find_release_executable(plan) {
1096+
match find_package_executable(plan) {
10741097
Some(actual) =>
10751098
assert_eq(normalize_slashes(actual), normalize_slashes(expected))
1076-
None => abort("expected release executable")
1099+
None => abort("expected debug executable")
10771100
}
10781101
}
10791102

@@ -1133,6 +1156,7 @@ async test "Windows portable staging flattens runtime bin beside app executable"
11331156
targets: ["app"],
11341157
output,
11351158
build: false,
1159+
release: false,
11361160
base_dir: root,
11371161
frontend_dist: None,
11381162
entry_paths: [],

cli/package/package_windows_wbtest.mbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ fn windows_test_plan(
1919
targets,
2020
output: @fsutil.resolve_path(root, "output with spaces"),
2121
build: false,
22+
release: false,
2223
base_dir: root,
2324
frontend_dist: Some(@fsutil.resolve_path(root, "frontend/dist")),
2425
entry_paths: [@fsutil.resolve_path(root, "frontend/dist/index.html")],

scripts/e2e_scaffold_source_smoke.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ async function main() {
735735
{ cwd: projectDir, env: runtimeEnv() },
736736
);
737737
setFrontendPackageRevision("first");
738-
localCli(["-C", projectDir, "package", "--target", "app", "--sign"], {
738+
localCli(["-C", projectDir, "package", "--release", "--target", "app", "--sign"], {
739739
env: runtimeEnv({
740740
PROTON_MACOS_ALLOW_ADHOC: "1",
741741
PROTON_MACOS_SIGNING_IDENTITY: "-",
@@ -745,7 +745,7 @@ async function main() {
745745
let packaged = verifyPackagedApp();
746746
await runPackagedAppSmoke(packaged.executable, "first");
747747
setFrontendPackageRevision("second");
748-
localCli(["-C", projectDir, "package", "--target", "app", "--sign"], {
748+
localCli(["-C", projectDir, "package", "--release", "--target", "app", "--sign"], {
749749
env: runtimeEnv({
750750
PROTON_MACOS_ALLOW_ADHOC: "1",
751751
PROTON_MACOS_SIGNING_IDENTITY: "-",

0 commit comments

Comments
 (0)