This commit is contained in:
Kelorastus
2026-10-02 11:43:22 +02:00
parent 7843d48c8f
commit 9a3094bebc
8 changed files with 37 additions and 9 deletions
+2 -1
View File
@@ -28,8 +28,9 @@ pub async fn release_run(
password: String,
with_api: bool,
with_mcp: bool,
with_web: bool,
) -> CmdResult<()> {
launcher.release_run(password, with_api, with_mcp).await
launcher.release_run(password, with_api, with_mcp, with_web).await
}
#[tauri::command]
+2 -1
View File
@@ -2496,7 +2496,7 @@ impl Launcher {
/// Start a release. Returns once it has started, not when it is done: its output arrives
/// in the console panel, which reads `release_console` as it fills.
pub async fn release_run(&self, password: String, with_api: bool, with_mcp: bool) -> Result<(), String> {
pub async fn release_run(&self, password: String, with_api: bool, with_mcp: bool, with_web: bool) -> Result<(), String> {
// Two at once would interleave into one buffer and fight over the same build dirs.
if self.release_console.lock().is_ok_and(|c| c.is_running()) {
return Err("A release is already running: wait for it to finish.".to_string());
@@ -2533,6 +2533,7 @@ impl Launcher {
launcher_next.as_deref(),
with_api && plan.docker,
with_mcp && plan.docker,
with_web && plan.docker,
&password,
&self.release_console,
)
+14
View File
@@ -384,6 +384,7 @@ pub fn run_release(
launcher_version: Option<&str>,
with_api: bool,
with_mcp: bool,
with_web: bool,
sudo: &str,
console: &Shared,
) -> Result<PathBuf, String> {
@@ -430,6 +431,19 @@ pub fn run_release(
));
}
if with_web {
// From _WEB in the Engine checkout. Its Dockerfile runs npm inside the image, so this
// needs Docker and nothing else - no Node, no node_modules on this PC.
body.push_str(&format!(
"Write-Host '=== ODIAN WEB ===' -ForegroundColor Cyan
& '{}'
if ($LASTEXITCODE -eq 2) {{ Write-Host 'web: already serving this commit' -ForegroundColor Yellow }}
elseif ($LASTEXITCODE -ne 0) {{ throw 'the web step failed' }}
",
scripts.join("deploy_web.ps1").display()
));
}
if with_mcp {
// LAST, always. The MCP serves /download/* and proxies /dhp, so rolling it interrupts
// the very road the steps above publish over; anything still in flight would fail.
+10 -1
View File
@@ -16,9 +16,11 @@
// Off by default, deliberately: it serves /download/* and proxies /dhp, so it is the one
// step that interrupts the road everything else publishes over.
let withMcp = $state(false);
// The browser client at web.odian.fr. Built from _WEB in the Engine checkout, in Docker.
let withWeb = $state(false);
async function release() {
await launcher.releaseRun(password, withApi, withMcp);
await launcher.releaseRun(password, withApi, withMcp, withWeb);
password = ""; // held for the one run, never kept
}
@@ -194,6 +196,13 @@
<em>— every operator is logged out</em>
</span>
</label>
<label class="check">
<input type="checkbox" bind:checked={withWeb} disabled={!plan.docker || busy} />
<span>
Also deploy ODIAN WEB{plan.docker ? "" : " — needs Docker"}
<em>— web.odian.fr, from the Engine checkout</em>
</span>
</label>
<label class="check">
<input type="checkbox" bind:checked={withMcp} disabled={!plan.docker || busy} />
<span>
+2 -1
View File
@@ -73,7 +73,8 @@ function createTauriBackend(): Backend {
onStatus: (handler) => subscribe<Status>("status", handler),
onInstallProgress: (handler) => subscribe<InstallProgress>("install-progress", handler),
releasePlan: () => invoke<ReleasePlan>("release_plan"),
releaseRun: (password, withApi, withMcp) => invoke<void>("release_run", { password, withApi, withMcp }),
releaseRun: (password, withApi, withMcp, withWeb) =>
invoke<void>("release_run", { password, withApi, withMcp, withWeb }),
releaseConsole: (since) => invoke<ReleaseConsoleTail>("release_console", { since }),
refreshRun: (password, pgPassword, tileRoot) => invoke<void>("refresh_run", { password, pgPassword, tileRoot }),
onTileSyncProgress: (handler) => subscribe<TileSyncProgress>("tile-sync-progress", handler),
+2 -2
View File
@@ -420,9 +420,9 @@ class Launcher {
});
}
releaseRun(password: string, withApi: boolean, withMcp: boolean) {
releaseRun(password: string, withApi: boolean, withMcp: boolean, withWeb: boolean) {
return this.run("release", async () => {
await backend.releaseRun(password, withApi, withMcp);
await backend.releaseRun(password, withApi, withMcp, withWeb);
this.releaseOpen = false;
// Straight into the console: the release is running with nowhere else to show itself.
this.consoleLines = [];
+4 -2
View File
@@ -814,6 +814,8 @@ class MockBackend implements Backend {
dirty: false, note: "what is published does not say which commit it came from" },
{ key: "mcp", title: "MCP server", live: null, commit: "c7d8e9f", behind: null,
dirty: false, note: "the script asks the node whether it is already running this commit" },
{ key: "web", title: "ODIAN WEB", live: "0.1.7", commit: "a1b2c3d", behind: null,
dirty: false, note: "web.odian.fr; the script asks whether it already serves this commit" },
],
// The real numbers from pack 0.72.0, so the panel can be judged on what it will show.
data: {
@@ -831,7 +833,7 @@ class MockBackend implements Backend {
};
}
async releaseRun(password: string, withApi: boolean, withMcp: boolean): Promise<void> {
async releaseRun(password: string, withApi: boolean, withMcp: boolean, withWeb: boolean): Promise<void> {
await this.wait(400);
if (!password.trim()) throw "The node's sudo password is needed to cut a pack and to roll the API.";
// Nothing runs in the browser, so play a short script into the console instead: enough
@@ -842,7 +844,7 @@ class MockBackend implements Backend {
"engine at 1255873...",
"Nothing that ships has changed. No pack cut.",
"pack: nothing to release",
`=== Launcher 0.1.40 === (API ${withApi}, MCP ${withMcp})`,
`=== Launcher 0.1.40 === (API ${withApi}, MCP ${withMcp}, web ${withWeb})`,
"npx tauri build ...",
"Release finished.",
];
+1 -1
View File
@@ -412,7 +412,7 @@ export interface Backend {
/** Take the tiles the DHP baked while this PC was away. */
syncTiles(): Promise<void>;
releasePlan(): Promise<ReleasePlan>;
releaseRun(password: string, withApi: boolean, withMcp: boolean): Promise<void>;
releaseRun(password: string, withApi: boolean, withMcp: boolean, withWeb: boolean): Promise<void>;
releaseConsole(since: number): Promise<ReleaseConsoleTail>;
/** Rebuild the pack's data payload. Prepares inputs only; it publishes nothing. */
refreshRun(password: string, pgPassword: string, tileRoot: string): Promise<void>;