|
45 | 45 | # after COMPILE (there are no server-side progress phases to poll, so RENDER is |
46 | 46 | # fast-forwarded and COMPILE shows the live spinner while the server works). |
47 | 47 | COMPILE_OPERATION_PHASES = ["RENDER", "COMPILE"] |
48 | | -OperationMode = Literal["deploy", "plan", "compile", "purge"] |
| 48 | +OperationMode = Literal["deploy", "plan", "compile", "purge", "test", "refresh"] |
49 | 49 |
|
50 | 50 | # Server-side phase list per operation mode. UPLOAD is first for operations |
51 | | -# that sync local files; purge runs entirely on the server (no local upload), |
52 | | -# so it has no UPLOAD phase. Every operation uses the same |
53 | | -# RENDER → COMPILE → PLAN → DEPLOY/PURGE vocabulary. |
| 51 | +# that sync local files; purge/test/refresh run entirely on the server against |
| 52 | +# already-deployed objects (no local upload), so they have no UPLOAD phase. |
| 53 | +# Deploy-family operations share the RENDER → COMPILE → PLAN → DEPLOY/PURGE |
| 54 | +# vocabulary; test/refresh are single-phase since they neither render nor plan. |
54 | 55 | _PHASES_BY_OPERATION: dict[OperationMode, list[str]] = { |
55 | 56 | "deploy": [UPLOAD_PHASE, *BACKEND_PHASES], |
56 | 57 | "plan": [UPLOAD_PHASE, *PLAN_OPERATION_PHASES], |
57 | 58 | "compile": [UPLOAD_PHASE, *COMPILE_OPERATION_PHASES], |
58 | 59 | "purge": [*BACKEND_PHASES], |
| 60 | + "test": ["TEST"], |
| 61 | + "refresh": ["REFRESH"], |
59 | 62 | } |
60 | 63 |
|
61 | 64 | # Only PLAN and DEPLOY emit a meaningful 0-100 progress value. |
@@ -273,6 +276,11 @@ def advance_upload(self, count: int = 1) -> None: |
273 | 276 | self._refresh_display() |
274 | 277 |
|
275 | 278 | def complete_upload(self) -> None: |
| 279 | + # Operations that don't sync local files (purge/test/refresh) have no |
| 280 | + # UPLOAD phase; nothing to complete. ``run_loader_phase`` calls this |
| 281 | + # unconditionally, so the guard keeps single-phase modes working. |
| 282 | + if not self._has_upload_phase(): |
| 283 | + return |
276 | 284 | if self._upload_file_total > 0: |
277 | 285 | self._get_phase(UPLOAD_PHASE).observe_running(100, datetime.now()) |
278 | 286 | self._get_phase(UPLOAD_PHASE).observe_done(datetime.now()) |
@@ -457,14 +465,14 @@ def _append_progress_bar(self, out: Text, progress: int) -> None: |
457 | 465 | in_progress = 0 < filled < _BAR_WIDTH |
458 | 466 |
|
459 | 467 | if in_progress: |
460 | | - out.append(_BAR_CELL * filled + _BAR_LEADING_EDGE, style="blue") |
| 468 | + out.append(_BAR_CELL * filled + _BAR_LEADING_EDGE, style=styles.BLUE) |
461 | 469 | out.append(_BAR_CELL * (_BAR_WIDTH - filled - 1), style="dim") |
462 | 470 | elif filled == 0: |
463 | 471 | out.append(_BAR_CELL * _BAR_WIDTH, style="dim") |
464 | 472 | else: |
465 | | - out.append(_BAR_CELL * _BAR_WIDTH, style="blue") |
| 473 | + out.append(_BAR_CELL * _BAR_WIDTH, style=styles.BLUE) |
466 | 474 |
|
467 | | - out.append(f" {progress:>3}%", style="blue") |
| 475 | + out.append(f" {progress:>3}%", style=styles.BLUE) |
468 | 476 |
|
469 | 477 | def _append_upload_details(self, out: Text) -> None: |
470 | 478 | """Render the stage-creation message and folder counters indented |
@@ -509,7 +517,7 @@ def _render_phase_line(self, out: Text, phase: _Phase) -> None: |
509 | 517 | # Blue matches the active-indicator color used by the |
510 | 518 | # pip-style progress bar so all "this phase is in flight" |
511 | 519 | # signals share the same hue. |
512 | | - out.append(_spinner_glyph(), style="blue") |
| 520 | + out.append(_spinner_glyph(), style=styles.BLUE) |
513 | 521 | out.append(duration_str + "\n", style="dim") |
514 | 522 | else: # PENDING |
515 | 523 | out.append(name_col + "·\n", style="dim") |
|
0 commit comments