From e0cb5ec013bfee51ca0df69da966719f264e81b1 Mon Sep 17 00:00:00 2001 From: Kim Jaehyun <231584193+kimdzhekhon@users.noreply.github.com> Date: Fri, 17 Jul 2026 22:59:58 +0900 Subject: [PATCH 1/2] fix: open only the produced output folder, not the whole build/ root Flutter's preferred output root collapsed to build/ whenever any one output pattern matched, dragging in unrelated plugin build caches (mobile_scanner, shared_preferences_android, ...). Now prefixes are only merged when more than one output type actually produced an artifact this build. Co-Authored-By: Claude Sonnet 5 --- scripts/ubs.py | 23 +++++++++++++++-------- tests/test_python_core.py | 15 +++++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/scripts/ubs.py b/scripts/ubs.py index 267d48b..43560b9 100755 --- a/scripts/ubs.py +++ b/scripts/ubs.py @@ -1238,19 +1238,26 @@ def pattern_static_prefix(pattern: str) -> Optional[str]: return "/".join(segments) if segments else None -def preferred_output_roots(project: Project) -> List[Path]: +def preferred_output_roots(project: Project, artifacts: Sequence[Path]) -> List[Path]: """Derive common output roots per project type straight from ARTIFACT_PATTERNS. - Prefixes sharing the same top-level path segment are collapsed to their - common ancestor (e.g. flutter's four patterns all live under "build" and - become one root), while prefixes under different top-level segments stay - separate (e.g. tauri's "src-tauri/..." and "signing/build"). + Only prefixes that actually produced an artifact this build are considered, + so a single-output build (e.g. just an .aab) opens its own specific folder + instead of the noisy shared "build" root. Prefixes sharing the same + top-level path segment are collapsed to their common ancestor only when + more than one of them has real output (e.g. flutter producing both an + .aab and build/web), while prefixes under different top-level segments + stay separate (e.g. tauri's "src-tauri/..." and "signing/build"). """ groups: Dict[str, List[str]] = {} for pattern in ARTIFACT_PATTERNS.get(project.type, []): prefix = pattern_static_prefix(pattern) - if prefix: - groups.setdefault(prefix.split("/", 1)[0], []).append(prefix) + if not prefix: + continue + resolved = (project.path / prefix).resolve() + if not any(artifact == resolved or resolved in artifact.parents for artifact in artifacts): + continue + groups.setdefault(prefix.split("/", 1)[0], []).append(prefix) return [project.path / os.path.commonpath(prefixes) for prefixes in groups.values()] @@ -1263,7 +1270,7 @@ def artifact_output_directories(project: Project) -> List[Path]: selected: Set[Path] = set() covered: Set[Path] = set() - for root in preferred_output_roots(project): + for root in preferred_output_roots(project, artifacts): resolved_root = root.resolve() matches = { artifact for artifact in artifacts diff --git a/tests/test_python_core.py b/tests/test_python_core.py index d4a9d9a..1746a06 100644 --- a/tests/test_python_core.py +++ b/tests/test_python_core.py @@ -46,6 +46,21 @@ def test_flutter_artifacts_open_the_common_build_root(self) -> None: [root / "build"], ) + def test_flutter_single_output_opens_its_own_folder_not_whole_build(self) -> None: + with tempfile.TemporaryDirectory() as temporary: + root = Path(temporary).resolve() + output = root / "build/app/outputs/bundle/release" + output.mkdir(parents=True) + (output / "app-release.aab").write_bytes(b"bundle") + # Unrelated plugin build caches that Flutter always leaves under + # build/ regardless of which output was actually produced — these + # must not cause the whole build/ root to be opened. + (root / "build/mobile_scanner").mkdir(parents=True) + self.assertEqual( + ubs.artifact_output_directories(ubs.Project("flutter", root)), + [output], + ) + def test_output_directories_cover_tauri_gradle_and_xcode(self) -> None: with tempfile.TemporaryDirectory() as temporary: root = Path(temporary).resolve() From 7f0d4b90cf5cadfa96eb274f9408b66f2fb07883 Mon Sep 17 00:00:00 2001 From: Kim Jaehyun <231584193+kimdzhekhon@users.noreply.github.com> Date: Fri, 17 Jul 2026 23:01:33 +0900 Subject: [PATCH 2/2] chore: regenerate update-manifest.txt for ubs.py checksum Co-Authored-By: Claude Sonnet 5 --- scripts/update-manifest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update-manifest.txt b/scripts/update-manifest.txt index ddedecf..20f1814 100644 --- a/scripts/update-manifest.txt +++ b/scripts/update-manifest.txt @@ -3,7 +3,7 @@ version 3.7.0 file 84746b20a3a72f6ff85a629706e50507c1bd200907456b76dd808a2a5ca0efba VERSION file 62d7189d00ccadbdeae9647a37b80db6ed9e179bfcf5b2f1d4d1c487dbc815bf build.sh file d9672f7bb74551de59fb3d27e1cdf2a5c7c96d41f40135372552c2798a04d7c5 install.sh -file 76e4cfe7cd7301018a5cae450a6b6dcfbf18bc029759b1bc5da2eea046603b00 scripts/ubs.py +file 1c4d89ae31cf4ec50c4a908d8ef913525a3410a1017644ff91949d43713e50d7 scripts/ubs.py file df0231e3cc0e584be7ae3ade3f1c0a7f92afb2124ec8a15bdb51c76737bbe1e0 scripts/ubs_mcp.py file 0a3b9d28fbe62bc55c073f5337954ae92ffca7482fca5d1f681dc99333363416 scripts/bootstrap-update.sh file 7b9a21a0854e0ca0476ae6ee38f2b7fc552446c97448ee655995f91e5c6f23d5 scripts/build-rust-helper.sh