The GitHub Actions job "Required Checks" on texera.git/main has failed. Run started by GitHub user github-merge-queue[bot] (triggered by github-merge-queue[bot]).
Head commit for run: ee06e4ba05f937f43041f7dc7faaca11d6759f9b / Ryan Zhang <[email protected]> feat(notebook-migration): remove a workflow's notebook file from the Jupyter pod on delete (#7741) ### What changes were proposed in this PR? Removes a workflow's notebook file from the Jupyter pod when the notebook is deleted, so the pod's `work/` directory no longer accumulates notebooks for workflows the user has removed. Before #7671 this was self limiting: every workflow uploaded to the same `work/notebook.ipynb`, so there was only ever one file and it was overwritten on reuse. Now that each workflow uploads to `work/notebook_<wid>.ipynb`, the file survives both a notebook delete and a workflow delete, because those paths only touched the database. The database is authoritative for whether a notebook exists. The pod file is a per user artifact only the frontend can reach, since the notebook migration service targets one Jupyter per process under the per user pod model. So the file cleanup is best effort from the frontend after the authoritative database delete, and a failure is logged rather than surfaced. **`NotebookMigrationResource` (new `delete-notebook` endpoint)** - Adds `POST /notebook-migration/delete-notebook`, the counterpart to `set-notebook`: it takes a `notebookName`, validates it with the same `[A-Za-z0-9._-]+\.ipynb` pattern (blocking path traversal before any network call), and issues `DELETE /api/contents/work/<name>` against the Jupyter Contents API, bounded by a 2s connect and read timeout so a stalled pod cannot wedge the request thread. - A 204 or 200 reports `deleted: 1`. A 404 is treated as a no op with `deleted: 0`, so a workflow whose notebook was never uploaded still deletes cleanly, consistent with how the database delete reports `deleted: 0` when nothing was stored. Any other status is a 500. - Extracts the shared `jupyterUnavailableResponse` so the four endpoints that need a reachable Jupyter cannot drift in status or body. **`NotebookMigrationService` (frontend)** - Adds `deleteNotebookForWorkflow(wid)`, the single seam both delete paths call. It derives the filename from the wid, so the `notebook_<wid>.ipynb` convention lives only in the service that owns it, posts it to the new endpoint, and returns nothing: pod cleanup is best effort, so a failure is logged, not surfaced, and no caller acts on the outcome. The parameter is a concrete wid so it can never fall back to the shared default filename. **`JupyterPanelService` (panel delete button)** - `deleteJupyterNotebook()` captures the current wid up front (so a mid flight workflow switch cannot retarget the delete), then calls `deleteNotebookForWorkflow(wid)` after the database delete succeeds. The unsaved workflow path (wid undefined or the default 0) still resets local state only, since no file was ever uploaded for it. **`UserWorkflowComponent` (dashboard delete)** - Adds a private `cleanupNotebookFiles(wids)` that calls `deleteNotebookForWorkflow(wid)` per wid, and calls it from the success handler of both single delete (`deleteWorkflow`) and bulk delete (`handleConfirmDeleteSelectedWorkflows`). It runs only after the backend delete succeeds, so a failed delete leaves the pod file in place. A deleted workflow with no notebook produces a harmless 404. ### Any related issues, documentation, discussions? Closes #7737 Parent issue #4301 ### How was this PR tested? - `NotebookMigrationResourceSpec.scala`: `delete-notebook` issues a DELETE against the `work/<name>` contents path (verb and path pinned), reports `deleted=1` on 204 and on 200, treats 404 as `deleted=0`, returns 500 when Jupyter rejects the delete or is unreachable, and returns 400 on an invalid name, a missing or non string name, or a malformed body. - `notebook-migration.service.spec.ts`: `deleteNotebookForWorkflow` posts the wid-derived name to `delete-notebook`, swallows a transport failure without notifying, and makes no HTTP call when the feature flag is off. - `jupyter-panel.service.spec.ts`: the panel delete calls `deleteNotebookForWorkflow` with the current wid, does not touch the pod when the database delete fails or for the unsaved default wid, and no ops when the flag is off. - `user-workflow.component.spec.ts`: single delete cleans up wid 5, bulk delete cleans up each checked wid in order, and neither the no wid path nor a backend delete error touches the pod. ### Was this PR authored or co-authored using generative AI tooling? Generated-by: Claude Code (Claude Opus 4.8) Report URL: https://github.com/apache/texera/actions/runs/32312008500 With regards, GitHub Actions via GitBox
