feat(workout): unify release command surface
Route local dev, tests, production build, mobile release, mobile verification, and doctor through one Workout xtask surface, and update the canonical docs around that surface. req: examples/001 req: examples/006 req: test/004
This commit is contained in:
@@ -49,8 +49,8 @@ Keep it stable. Prefer pointers to canonical sources over copied structure, file
|
||||
- Prefer links or pointers to canonical sources over copied lists.
|
||||
- Avoid project trees, architecture maps, generated inventories, current file sizes, issue lists, TODO inventories, and other snapshots that will rot.
|
||||
- Stable commands: `cargo run -p hemx-xtask -- test`, `cargo check --workspace`, `redgate health --strict`. Use the xtask runner for full verification so jobs are capped from local CPU and memory. req: test/004
|
||||
- Run the workout product exemplar with `cargo run --bin hemx-workout-example` and open `http://127.0.0.1:3028`; set `HEMX_WORKOUT_ADDR=127.0.0.1:3030` if the default port is busy. Its durable visual direction and recovery expectations live in `examples/workout/DESIGN.md`. req: examples/001
|
||||
- Generate and verify the Workout mobile release kit with `HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout-mobile release` and `HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout-mobile verify`; Android/iOS SDKs and signing remain external blockers, not repo-owned secrets. req: examples/006
|
||||
- Run the workout product exemplar with `cargo run -p hemx-xtask -- workout dev` and open `http://127.0.0.1:3028`; set `HEMX_WORKOUT_ADDR=127.0.0.1:3030` if the default port is busy. Its durable visual direction and recovery expectations live in `examples/workout/DESIGN.md`. req: examples/001
|
||||
- Use the same Workout command surface for tests, production build, and mobile release: `cargo run -p hemx-xtask -- workout test`, `cargo run -p hemx-xtask -- workout build`, `HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout mobile-release`, and `HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout mobile-verify`; Android/iOS SDKs and signing remain external blockers, not repo-owned secrets. req: examples/006
|
||||
- hemx core stays small: effects, typed ids, registries, and wire schema only.
|
||||
- Routing, auth, sessions, transport, transitions, sync, and storage belong in integration/user crates.
|
||||
- Public examples and beginner APIs should use generated resources and `IntoEffect`, not raw ids or runtime opcodes.
|
||||
|
||||
@@ -134,10 +134,11 @@ See `docs/versioning.md`.
|
||||
`docs/recipes/sqlx-persistence.md` shows the provider boundary without moving
|
||||
SQL into core.
|
||||
- `examples/workout`: phone-first local-first product exemplar. Run with
|
||||
`cargo run --bin hemx-workout-example` and open `http://127.0.0.1:3028`.
|
||||
`cargo run -p hemx-xtask -- workout dev` and open `http://127.0.0.1:3028`.
|
||||
It keeps workout truth as commands/events/projections and routes export
|
||||
through the host capability boundary; `examples/workout/README.md` documents
|
||||
run, test, deploy, and failure-mode paths. req: examples/001 req: local/001 req: host/005
|
||||
the canonical dev, test, production build, mobile release, verification, and
|
||||
failure-mode paths. req: examples/001 req: examples/006 req: local/001 req: host/005
|
||||
- `examples/kanban`: advanced / north-star milestone boundary sketch. It may
|
||||
expose manual registry or render escape hatches while exploring product limits.
|
||||
- `examples/techdemo`: advanced integration demo with a leaf island and broader
|
||||
|
||||
+1
-1
@@ -810,7 +810,7 @@ what a valid business email is.
|
||||
005 Canonical examples must not contain user-authored browser JavaScript. They may load the shared hemx runtime (`/hemx.js`) and may use declarative `data-hemx-*` attributes; inline `<script>`, `on*=` event handlers, and `javascript:` URLs are forbidden outside opaque leaf-widget examples.
|
||||
|
||||
### req: examples/006
|
||||
006 The Workout exemplar must have one boring mobile release command that builds the production server binary and writes Android and iOS shell metadata, plus one verification command for that generated kit. The commands must make app identity, version, production origin, runtime asset policy, cache/offline state policy, environment/secrets boundary, rollback expectation, and external store-signing blockers explicit without adding a broad `hemx-mobile` framework.
|
||||
006 The Workout exemplar must have one boring command surface for local development, product tests, production server build, Android/iOS mobile release metadata, and mobile verification. The mobile commands must make app identity, version, production origin, runtime asset policy, cache/offline state policy, environment/secrets boundary, rollback expectation, and external store-signing blockers explicit without adding a broad `hemx-mobile` framework.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -8,13 +8,16 @@ vendor work. req: examples/006
|
||||
## Command surface
|
||||
|
||||
```sh
|
||||
cargo run -p hemx-xtask -- workout-mobile release
|
||||
cargo run -p hemx-xtask -- workout-mobile verify
|
||||
cargo run -p hemx-xtask -- workout-mobile doctor
|
||||
cargo run -p hemx-xtask -- workout dev
|
||||
cargo run -p hemx-xtask -- workout test
|
||||
cargo run -p hemx-xtask -- workout build
|
||||
cargo run -p hemx-xtask -- workout mobile-release
|
||||
cargo run -p hemx-xtask -- workout mobile-verify
|
||||
cargo run -p hemx-xtask -- workout doctor
|
||||
```
|
||||
|
||||
`release` builds `target/release/hemx-workout-example` and writes a release kit
|
||||
under `target/hemx-mobile/workout` by default:
|
||||
`workout mobile-release` builds `target/release/hemx-workout-example` and writes
|
||||
a release kit under `target/hemx-mobile/workout` by default:
|
||||
|
||||
```text
|
||||
target/hemx-mobile/workout/
|
||||
@@ -26,8 +29,8 @@ target/hemx-mobile/workout/
|
||||
ios/README.md
|
||||
```
|
||||
|
||||
Use `verify` to check the generated kit and release binary. Use `doctor` when
|
||||
you only want to see missing external inputs.
|
||||
Use `workout mobile-verify` to check the generated kit and release binary. Use
|
||||
`workout doctor` when you only want to see missing external inputs.
|
||||
|
||||
## Production configuration
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ req: examples/001 req: local/001 req: local/003 req: local/004
|
||||
## Run
|
||||
|
||||
```sh
|
||||
cargo run --bin hemx-workout-example
|
||||
cargo run -p hemx-xtask -- workout dev
|
||||
```
|
||||
|
||||
Open `http://127.0.0.1:3028`.
|
||||
@@ -18,7 +18,7 @@ Open `http://127.0.0.1:3028`.
|
||||
If the port is busy, pick another address:
|
||||
|
||||
```sh
|
||||
HEMX_WORKOUT_ADDR=127.0.0.1:3030 cargo run --bin hemx-workout-example
|
||||
HEMX_WORKOUT_ADDR=127.0.0.1:3030 cargo run -p hemx-xtask -- workout dev
|
||||
```
|
||||
|
||||
The server prints the URL it bound. A bind failure means another process owns
|
||||
@@ -27,7 +27,7 @@ the address; retry with `HEMX_WORKOUT_ADDR` instead of changing app code.
|
||||
## Test
|
||||
|
||||
```sh
|
||||
cargo test -p hemx-workout-example
|
||||
cargo run -p hemx-xtask -- workout test
|
||||
```
|
||||
|
||||
The E2E test starts the real HTTP binary, loads the page, checks the shared
|
||||
@@ -48,7 +48,7 @@ The deployable artifact is the Rust server binary plus the generated hemx
|
||||
resources embedded by the build script:
|
||||
|
||||
```sh
|
||||
cargo build --release --bin hemx-workout-example
|
||||
cargo run -p hemx-xtask -- workout build
|
||||
HEMX_WORKOUT_ADDR=0.0.0.0:8080 ./target/release/hemx-workout-example
|
||||
```
|
||||
|
||||
@@ -64,9 +64,9 @@ write Android/iOS shell metadata:
|
||||
|
||||
```sh
|
||||
HEMX_WORKOUT_ORIGIN=https://workout.example.com \
|
||||
cargo run -p hemx-xtask -- workout-mobile release
|
||||
cargo run -p hemx-xtask -- workout mobile-release
|
||||
HEMX_WORKOUT_ORIGIN=https://workout.example.com \
|
||||
cargo run -p hemx-xtask -- workout-mobile verify
|
||||
cargo run -p hemx-xtask -- workout mobile-verify
|
||||
```
|
||||
|
||||
The kit lands in `target/hemx-mobile/workout` unless
|
||||
|
||||
+48
-6
@@ -9,6 +9,7 @@ fn main() -> ExitCode {
|
||||
match args.next().as_deref() {
|
||||
Some("test") | None => run_test_plan(),
|
||||
Some("bench") => run_bench_plan(),
|
||||
Some("workout") => run_workout(args.next().as_deref()),
|
||||
Some("workout-mobile") => run_workout_mobile(args.next().as_deref()),
|
||||
Some("help") | Some("--help") | Some("-h") => {
|
||||
print_help();
|
||||
@@ -24,10 +25,45 @@ fn main() -> ExitCode {
|
||||
|
||||
fn print_help() {
|
||||
println!(
|
||||
"hemx-ci — resource-aware project checks\n\n cargo run -p hemx-xtask -- test\n cargo run -p hemx-xtask -- bench\n cargo run -p hemx-xtask -- workout-mobile release\n cargo run -p hemx-xtask -- workout-mobile verify\n cargo run -p hemx-xtask -- workout-mobile doctor\n\nEnvironment overrides:\n HEMX_CI_JOBS=N compile jobs, capped by detected resources\n HEMX_CI_TEST_THREADS=N Rust test threads, capped by detected resources\n HEMX_CI_SKIP_BROWSER=1 skip browser E2E\n HEMX_WORKOUT_ORIGIN=https://app.example.com\n HEMX_WORKOUT_MOBILE_OUT=target/hemx-mobile/workout"
|
||||
"hemx-ci — resource-aware project checks\n\n cargo run -p hemx-xtask -- test\n cargo run -p hemx-xtask -- bench\n cargo run -p hemx-xtask -- workout dev\n cargo run -p hemx-xtask -- workout test\n cargo run -p hemx-xtask -- workout build\n cargo run -p hemx-xtask -- workout mobile-release\n cargo run -p hemx-xtask -- workout mobile-verify\n cargo run -p hemx-xtask -- workout doctor\n\nEnvironment overrides:\n HEMX_CI_JOBS=N compile jobs, capped by detected resources\n HEMX_CI_TEST_THREADS=N Rust test threads, capped by detected resources\n HEMX_CI_SKIP_BROWSER=1 skip browser E2E\n HEMX_WORKOUT_ORIGIN=https://app.example.com\n HEMX_WORKOUT_MOBILE_OUT=target/hemx-mobile/workout"
|
||||
);
|
||||
}
|
||||
|
||||
fn run_workout(command: Option<&str>) -> ExitCode {
|
||||
// req: examples/001 req: examples/006
|
||||
match command.unwrap_or("dev") {
|
||||
"dev" | "run" => Step::new(
|
||||
"workout-dev-server",
|
||||
["run", "--bin", "hemx-workout-example"],
|
||||
)
|
||||
.run(&Budget::detect())
|
||||
.map(|()| ExitCode::SUCCESS)
|
||||
.unwrap_or_else(|code| code),
|
||||
"test" => Step::new("workout-test", ["test", "-p", "hemx-workout-example"])
|
||||
.run(&Budget::detect())
|
||||
.map(|()| ExitCode::SUCCESS)
|
||||
.unwrap_or_else(|code| code),
|
||||
"build" | "release-build" => run_workout_release_build("workout-release-build"),
|
||||
"mobile-release" => run_workout_mobile_release(),
|
||||
"mobile-verify" | "verify" => run_workout_mobile_verify(),
|
||||
"doctor" => {
|
||||
let config = WorkoutMobileConfig::from_env();
|
||||
let blockers = mobile_external_blockers(&config);
|
||||
print_mobile_doctor(&config, &blockers);
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
"help" | "--help" | "-h" => {
|
||||
print_help();
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
other => {
|
||||
eprintln!("unknown workout command `{other}`\n");
|
||||
print_help();
|
||||
ExitCode::from(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_workout_mobile(command: Option<&str>) -> ExitCode {
|
||||
match command.unwrap_or("release") {
|
||||
"release" => run_workout_mobile_release(),
|
||||
@@ -50,16 +86,22 @@ fn run_workout_mobile(command: Option<&str>) -> ExitCode {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_workout_mobile_release() -> ExitCode {
|
||||
// req: examples/001 req: examples/006 req: host/002 req: local/001
|
||||
fn run_workout_release_build(label: &'static str) -> ExitCode {
|
||||
let budget = Budget::detect();
|
||||
budget.report();
|
||||
if let Err(code) = Step::new(
|
||||
"workout-mobile-server-release",
|
||||
Step::new(
|
||||
label,
|
||||
["build", "--release", "--bin", "hemx-workout-example"],
|
||||
)
|
||||
.run(&budget)
|
||||
{
|
||||
.map(|()| ExitCode::SUCCESS)
|
||||
.unwrap_or_else(|code| code)
|
||||
}
|
||||
|
||||
fn run_workout_mobile_release() -> ExitCode {
|
||||
// req: examples/001 req: examples/006 req: host/002 req: local/001
|
||||
let code = run_workout_release_build("workout-mobile-server-release");
|
||||
if code != ExitCode::SUCCESS {
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user