Skip to content

Conversation

@google-labs-jules
Copy link
Contributor

Implement consistency check for switch -c command. Checks if all local branches match before creating/switching. If not, prompts user with a list of current branches.


PR created automatically by Jules for task 8979327570226183598 started by @keiji

Add a check to ensure all repositories are on the same branch when creating a new branch with `switch -c`.
If inconsistent, prompt the user with the current status of each repository.

Changes:
- internal/app/switch.go: Add consistency check logic and status display.
- internal/ui/ui.go: Use sys.Stdout for prompts to support testing.
- internal/app/switch_test.go: Add unit test for consistency check.
- manual_tests/manual_test_switch_check.py: Add manual test script.
- docs/internal/app/switch.md: Update design doc.
- docs/manual_tests/manual_test_switch_check.md: Add manual test doc.
- manual_tests/manual_test_full.sh: Include new manual test.
@google-labs-jules
Copy link
Contributor Author

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@github-actions
Copy link

Test Coverage Report

Total Coverage: 64.1%

Detailed Report
File Function Coverage
mistletoe/cmd/mstl-gh/main.go:15: main 0.0%
mistletoe/cmd/mstl/main.go:15: main 0.0%
mistletoe/internal/app/config_search.go:14: SearchParentConfig 77.3%
mistletoe/internal/app/config_search.go:67: validateParentConfig 64.0%
mistletoe/internal/app/dependency.go:24: LoadDependencies 100.0%
mistletoe/internal/app/dependency.go:34: ParseDependencies 100.0%
mistletoe/internal/app/dependency.go:132: extractID 100.0%
mistletoe/internal/app/dependency.go:140: addDependency 100.0%
mistletoe/internal/app/fire.go:16: handleFire 0.0%
mistletoe/internal/app/fire.go:40: resolveConfigForFire 0.0%
mistletoe/internal/app/fire.go:47: fireCommand 96.2%
mistletoe/internal/app/fire.go:100: processFireRepo 73.7%
mistletoe/internal/app/fire.go:140: runGitFire 100.0%
mistletoe/internal/app/fire.go:150: getSafeUsername 41.7%
mistletoe/internal/app/fire.go:172: sanitizeName 83.3%
mistletoe/internal/app/fire.go:184: getShortUUID 80.0%
mistletoe/internal/app/flags.go:14: ParseFlagsFlexible 93.1%
mistletoe/internal/app/flags.go:71: CheckFlagDuplicates 100.0%
mistletoe/internal/app/flags.go:95: isBoolFlag 100.0%
mistletoe/internal/app/help.go:7: handleHelp 100.0%
mistletoe/internal/app/init.go:25: ensureBranchExistsLocally 27.3%
mistletoe/internal/app/init.go:58: isDirEmpty 80.0%
mistletoe/internal/app/init.go:76: checkRootDirectorySafety 93.8%
mistletoe/internal/app/init.go:134: validateEnvironment 63.5%
mistletoe/internal/app/init.go:229: PerformInit 75.0%
mistletoe/internal/app/init.go:307: validateAndPrepareInitDest 77.3%
mistletoe/internal/app/init.go:349: handleInit 100.0%
mistletoe/internal/app/init.go:353: initCommand 85.3%
mistletoe/internal/app/pr.go:9: HandlePr 0.0%
mistletoe/internal/app/pr_body_logic.go:25: GenerateMistletoeBody 97.5%
mistletoe/internal/app/pr_body_logic.go:231: GeneratePlaceholderMistletoeBody 0.0%
mistletoe/internal/app/pr_body_logic.go:261: EmbedMistletoeBody 96.2%
mistletoe/internal/app/pr_body_logic.go:325: ParseMistletoeBlock 87.2%
mistletoe/internal/app/pr_checkout.go:18: handlePrCheckout 0.0%
mistletoe/internal/app/pr_checkout.go:24: prCheckoutCommand 23.6%
mistletoe/internal/app/pr_checkout.go:324: writeDependencyFile 100.0%
mistletoe/internal/app/pr_common.go:58: CollectPrStatus 45.7%
mistletoe/internal/app/pr_common.go:267: getPrDisplayState 42.9%
mistletoe/internal/app/pr_common.go:284: SortPrs 92.9%
mistletoe/internal/app/pr_common.go:316: RenderPrStatusTable 78.9%
mistletoe/internal/app/pr_common.go:353: executePush 0.0%
mistletoe/internal/app/pr_common.go:406: updatePrDescriptions 0.0%
mistletoe/internal/app/pr_common.go:548: parsePrURL 81.8%
mistletoe/internal/app/pr_common.go:566: getRepoName 66.7%
mistletoe/internal/app/pr_common.go:576: resolveRemoteBranchHash 69.2%
mistletoe/internal/app/pr_common.go:607: checkGhAvailability 100.0%
mistletoe/internal/app/pr_common.go:622: verifyGithubRequirements 61.2%
mistletoe/internal/app/pr_common.go:750: LoadDependencyGraph 92.3%
mistletoe/internal/app/pr_common_helper.go:10: GetGhUser 0.0%
mistletoe/internal/app/pr_common_helper.go:20: ValidatePrPermissionAndOverwrite 0.0%
mistletoe/internal/app/pr_common_helper.go:51: isPrFromConfiguredRepo 100.0%
mistletoe/internal/app/pr_create.go:21: handlePrCreate 0.0%
mistletoe/internal/app/pr_create.go:28: prCreateCommand 16.0%
mistletoe/internal/app/pr_create.go:526: executePrCreationOnly 57.8%
mistletoe/internal/app/pr_input_logic.go:19: ParsePrTitleBody 93.3%
mistletoe/internal/app/pr_status.go:16: handlePrStatus 0.0%
mistletoe/internal/app/pr_status.go:22: prStatusCommand 50.0%
mistletoe/internal/app/pr_update.go:18: handlePrUpdate 0.0%
mistletoe/internal/app/pr_update.go:24: prUpdateCommand 27.1%
mistletoe/internal/app/pr_update.go:247: categorizePrUpdate 100.0%
mistletoe/internal/app/pr_verify.go:13: VerifyRevisionsUnchanged 87.5%
mistletoe/internal/app/push.go:15: handlePush 83.3%
mistletoe/internal/app/reset.go:25: resolveResetTarget 100.0%
mistletoe/internal/app/reset.go:45: verifyResetTargetWithResolution 85.7%
mistletoe/internal/app/reset.go:82: handleReset 75.2%
mistletoe/internal/app/run.go:31: parseArgs 80.0%
mistletoe/internal/app/run.go:44: getGitPath 66.7%
mistletoe/internal/app/run.go:51: getGhPath 0.0%
mistletoe/internal/app/run.go:58: validateGit 100.0%
mistletoe/internal/app/run.go:63: validateGh 100.0%
mistletoe/internal/app/run.go:68: validateGhAuth 100.0%
mistletoe/internal/app/run.go:74: Run 0.0%
mistletoe/internal/app/run.go:82: RunApp 53.7%
mistletoe/internal/app/snapshot.go:20: handleSnapshot 83.5%
mistletoe/internal/app/snapshot.go:245: GenerateSnapshot 0.0%
mistletoe/internal/app/snapshot.go:258: GenerateSnapshotVerbose 76.9%
mistletoe/internal/app/snapshot.go:345: GenerateSnapshotFromStatus 89.5%
mistletoe/internal/app/snapshot.go:428: CalculateSnapshotIdentifier 76.9%
mistletoe/internal/app/status.go:14: handleStatus 91.5%
mistletoe/internal/app/status_logic.go:40: ValidateRepositoriesIntegrity 88.9%
mistletoe/internal/app/status_logic.go:80: CollectStatus 100.0%
mistletoe/internal/app/status_logic.go:110: getRepoStatus 88.2%
mistletoe/internal/app/status_logic.go:299: RenderStatusTable 95.0%
mistletoe/internal/app/status_logic.go:357: ValidateStatusForAction 100.0%
mistletoe/internal/app/switch.go:18: branchExists 100.0%
mistletoe/internal/app/switch.go:23: configureUpstreamIfSafe 76.2%
mistletoe/internal/app/switch.go:67: handleSwitch 84.4%
mistletoe/internal/app/sync.go:16: handleSync 80.7%
mistletoe/internal/app/utils.go:24: formatDuration 100.0%
mistletoe/internal/app/utils.go:34: RunGit 100.0%
mistletoe/internal/app/utils.go:66: RunGitInteractive 100.0%
mistletoe/internal/app/utils.go:97: RunGh 73.3%
mistletoe/internal/app/utils.go:128: RunEditor 76.0%
mistletoe/internal/app/utils.go:176: ResolveCommonValues 92.1%
mistletoe/internal/app/utils.go:266: DetermineJobs 100.0%
mistletoe/internal/app/version_common.go:11: printCommonVersionInfo 0.0%
mistletoe/internal/app/version_gh.go:11: handleVersionGh 0.0%
mistletoe/internal/app/version_mstl.go:4: handleVersionMstl 0.0%
mistletoe/internal/config/config.go:64: ParseConfig 100.0%
mistletoe/internal/config/config.go:84: validateConfig 95.0%
mistletoe/internal/config/config.go:163: isValidGitRef 100.0%
mistletoe/internal/config/config.go:173: GetRepoDirName 100.0%
mistletoe/internal/config/config.go:188: GetRepoPath 100.0%
mistletoe/internal/config/config.go:193: LoadConfigData 100.0%
mistletoe/internal/config/config.go:207: LoadConfigFile 78.6%
mistletoe/internal/ui/ui.go:16: AskForConfirmation 0.0%
mistletoe/internal/ui/ui.go:37: AskForConfirmationRequired 0.0%
mistletoe/internal/ui/ui.go:69: NewSpinner 0.0%
mistletoe/internal/ui/ui.go:78: Start 0.0%
mistletoe/internal/ui/ui.go:102: Stop 0.0%

@keiji
Copy link
Owner

keiji commented Jan 24, 2026

Branch names do not match. Current status: のメッセージの前に、statusを実行したときと同じすべてのリポジトリの状態表示を追加してください。

@google-labs-jules
Copy link
Contributor Author

Branch names do not match. Current status: のメッセージの前に、statusを実行したときと同じすべてのリポジトリの状態表示を追加してください。

ステータス表示を status コマンド相当のテーブル表示に変更しました。CollectStatusRenderStatusTable を再利用して実装しています。

Update the switch consistency check to display the full status table (reusing status command logic) instead of a simple list when branches do not match.

Changes:
- internal/app/switch.go: Use `CollectStatus` and `RenderStatusTable`.
- internal/app/switch_test.go: Verify table output format.
- manual_tests/manual_test_switch_check.py: Check for table headers in output.
@github-actions
Copy link

Test Coverage Report

Total Coverage: 64.1%

Detailed Report
File Function Coverage
mistletoe/cmd/mstl-gh/main.go:15: main 0.0%
mistletoe/cmd/mstl/main.go:15: main 0.0%
mistletoe/internal/app/config_search.go:14: SearchParentConfig 77.3%
mistletoe/internal/app/config_search.go:67: validateParentConfig 64.0%
mistletoe/internal/app/dependency.go:24: LoadDependencies 100.0%
mistletoe/internal/app/dependency.go:34: ParseDependencies 100.0%
mistletoe/internal/app/dependency.go:132: extractID 100.0%
mistletoe/internal/app/dependency.go:140: addDependency 100.0%
mistletoe/internal/app/fire.go:16: handleFire 0.0%
mistletoe/internal/app/fire.go:40: resolveConfigForFire 0.0%
mistletoe/internal/app/fire.go:47: fireCommand 96.2%
mistletoe/internal/app/fire.go:100: processFireRepo 73.7%
mistletoe/internal/app/fire.go:140: runGitFire 100.0%
mistletoe/internal/app/fire.go:150: getSafeUsername 41.7%
mistletoe/internal/app/fire.go:172: sanitizeName 83.3%
mistletoe/internal/app/fire.go:184: getShortUUID 80.0%
mistletoe/internal/app/flags.go:14: ParseFlagsFlexible 93.1%
mistletoe/internal/app/flags.go:71: CheckFlagDuplicates 100.0%
mistletoe/internal/app/flags.go:95: isBoolFlag 100.0%
mistletoe/internal/app/help.go:7: handleHelp 100.0%
mistletoe/internal/app/init.go:25: ensureBranchExistsLocally 27.3%
mistletoe/internal/app/init.go:58: isDirEmpty 80.0%
mistletoe/internal/app/init.go:76: checkRootDirectorySafety 93.8%
mistletoe/internal/app/init.go:134: validateEnvironment 63.5%
mistletoe/internal/app/init.go:229: PerformInit 75.0%
mistletoe/internal/app/init.go:307: validateAndPrepareInitDest 77.3%
mistletoe/internal/app/init.go:349: handleInit 100.0%
mistletoe/internal/app/init.go:353: initCommand 85.3%
mistletoe/internal/app/pr.go:9: HandlePr 0.0%
mistletoe/internal/app/pr_body_logic.go:25: GenerateMistletoeBody 98.3%
mistletoe/internal/app/pr_body_logic.go:231: GeneratePlaceholderMistletoeBody 0.0%
mistletoe/internal/app/pr_body_logic.go:261: EmbedMistletoeBody 96.2%
mistletoe/internal/app/pr_body_logic.go:325: ParseMistletoeBlock 87.2%
mistletoe/internal/app/pr_checkout.go:18: handlePrCheckout 0.0%
mistletoe/internal/app/pr_checkout.go:24: prCheckoutCommand 23.6%
mistletoe/internal/app/pr_checkout.go:324: writeDependencyFile 100.0%
mistletoe/internal/app/pr_common.go:58: CollectPrStatus 45.7%
mistletoe/internal/app/pr_common.go:267: getPrDisplayState 42.9%
mistletoe/internal/app/pr_common.go:284: SortPrs 92.9%
mistletoe/internal/app/pr_common.go:316: RenderPrStatusTable 78.9%
mistletoe/internal/app/pr_common.go:353: executePush 0.0%
mistletoe/internal/app/pr_common.go:406: updatePrDescriptions 0.0%
mistletoe/internal/app/pr_common.go:548: parsePrURL 81.8%
mistletoe/internal/app/pr_common.go:566: getRepoName 66.7%
mistletoe/internal/app/pr_common.go:576: resolveRemoteBranchHash 69.2%
mistletoe/internal/app/pr_common.go:607: checkGhAvailability 100.0%
mistletoe/internal/app/pr_common.go:622: verifyGithubRequirements 61.2%
mistletoe/internal/app/pr_common.go:750: LoadDependencyGraph 92.3%
mistletoe/internal/app/pr_common_helper.go:10: GetGhUser 0.0%
mistletoe/internal/app/pr_common_helper.go:20: ValidatePrPermissionAndOverwrite 0.0%
mistletoe/internal/app/pr_common_helper.go:51: isPrFromConfiguredRepo 100.0%
mistletoe/internal/app/pr_create.go:21: handlePrCreate 0.0%
mistletoe/internal/app/pr_create.go:28: prCreateCommand 16.0%
mistletoe/internal/app/pr_create.go:526: executePrCreationOnly 57.8%
mistletoe/internal/app/pr_input_logic.go:19: ParsePrTitleBody 93.3%
mistletoe/internal/app/pr_status.go:16: handlePrStatus 0.0%
mistletoe/internal/app/pr_status.go:22: prStatusCommand 50.0%
mistletoe/internal/app/pr_update.go:18: handlePrUpdate 0.0%
mistletoe/internal/app/pr_update.go:24: prUpdateCommand 27.1%
mistletoe/internal/app/pr_update.go:247: categorizePrUpdate 100.0%
mistletoe/internal/app/pr_verify.go:13: VerifyRevisionsUnchanged 87.5%
mistletoe/internal/app/push.go:15: handlePush 83.3%
mistletoe/internal/app/reset.go:25: resolveResetTarget 100.0%
mistletoe/internal/app/reset.go:45: verifyResetTargetWithResolution 85.7%
mistletoe/internal/app/reset.go:82: handleReset 75.2%
mistletoe/internal/app/run.go:31: parseArgs 80.0%
mistletoe/internal/app/run.go:44: getGitPath 66.7%
mistletoe/internal/app/run.go:51: getGhPath 0.0%
mistletoe/internal/app/run.go:58: validateGit 100.0%
mistletoe/internal/app/run.go:63: validateGh 100.0%
mistletoe/internal/app/run.go:68: validateGhAuth 100.0%
mistletoe/internal/app/run.go:74: Run 0.0%
mistletoe/internal/app/run.go:82: RunApp 53.7%
mistletoe/internal/app/snapshot.go:20: handleSnapshot 83.5%
mistletoe/internal/app/snapshot.go:245: GenerateSnapshot 0.0%
mistletoe/internal/app/snapshot.go:258: GenerateSnapshotVerbose 76.9%
mistletoe/internal/app/snapshot.go:345: GenerateSnapshotFromStatus 89.5%
mistletoe/internal/app/snapshot.go:428: CalculateSnapshotIdentifier 76.9%
mistletoe/internal/app/status.go:14: handleStatus 91.5%
mistletoe/internal/app/status_logic.go:40: ValidateRepositoriesIntegrity 88.9%
mistletoe/internal/app/status_logic.go:80: CollectStatus 100.0%
mistletoe/internal/app/status_logic.go:110: getRepoStatus 88.2%
mistletoe/internal/app/status_logic.go:299: RenderStatusTable 95.0%
mistletoe/internal/app/status_logic.go:357: ValidateStatusForAction 100.0%
mistletoe/internal/app/switch.go:18: branchExists 100.0%
mistletoe/internal/app/switch.go:23: configureUpstreamIfSafe 76.2%
mistletoe/internal/app/switch.go:67: handleSwitch 84.5%
mistletoe/internal/app/sync.go:16: handleSync 80.7%
mistletoe/internal/app/utils.go:24: formatDuration 100.0%
mistletoe/internal/app/utils.go:34: RunGit 100.0%
mistletoe/internal/app/utils.go:66: RunGitInteractive 100.0%
mistletoe/internal/app/utils.go:97: RunGh 73.3%
mistletoe/internal/app/utils.go:128: RunEditor 76.0%
mistletoe/internal/app/utils.go:176: ResolveCommonValues 92.1%
mistletoe/internal/app/utils.go:266: DetermineJobs 100.0%
mistletoe/internal/app/version_common.go:11: printCommonVersionInfo 0.0%
mistletoe/internal/app/version_gh.go:11: handleVersionGh 0.0%
mistletoe/internal/app/version_mstl.go:4: handleVersionMstl 0.0%
mistletoe/internal/config/config.go:64: ParseConfig 100.0%
mistletoe/internal/config/config.go:84: validateConfig 95.0%
mistletoe/internal/config/config.go:163: isValidGitRef 100.0%
mistletoe/internal/config/config.go:173: GetRepoDirName 100.0%
mistletoe/internal/config/config.go:188: GetRepoPath 100.0%
mistletoe/internal/config/config.go:193: LoadConfigData 100.0%
mistletoe/internal/config/config.go:207: LoadConfigFile 78.6%
mistletoe/internal/ui/ui.go:16: AskForConfirmation 0.0%
mistletoe/internal/ui/ui.go:37: AskForConfirmationRequired 0.0%
mistletoe/internal/ui/ui.go:69: NewSpinner 0.0%
mistletoe/internal/ui/ui.go:78: Start 0.0%
mistletoe/internal/ui/ui.go:102: Stop 0.0%

@keiji
Copy link
Owner

keiji commented Jan 24, 2026

============================================================
Config Search Verification
============================================================
[Expected Result]
This test automatically verifies:
1. Standard 'mstl status' behavior from root.
2. Parent configuration search (automatic switch verification).
3. Parent configuration validation failure handling (should not switch).

Do you want to execute the process? [Y/n] (Auto-Yes): yes

[Execution]
Setting up local test environment...
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 220 bytes | 220.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To /app/manual_test_workspace_search/remotes/repo-a.git
 * [new branch]      master -> master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 222 bytes | 222.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To /app/manual_test_workspace_search/remotes/repo-b.git
 * [new branch]      master -> master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 221 bytes | 221.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To /app/manual_test_workspace_search/remotes/repo-c.git
 * [new branch]      master -> master
1. Verifying standard behavior (running from root)...
Standard status passed.
2. Testing Parent Search from sub-directory: /app/manual_test_workspace_search/repo-a
Automatic switch notification appeared.
3. Testing Validation Failure...
Error during execution: Unexpected error message: exit status 1

Traceback (most recent call last):
  File "/app/manual_tests/interactive_runner.py", line 94, in execute_scenario
    logic_func()
  File "/app/manual_tests/manual_test_config_search.py", line 152, in run_test_logic
    raise Exception(f"Unexpected error message: {stderr}")
Exception: Unexpected error message: exit status 1

[2026-01-24 08:41:03] Test 'Config Search Verification' FAILED (Exception) - FAILED
Running manual_test_parent_config_switch.py...
============================================================
Switch Remote Fallback Verification
============================================================
[Expected Result]
This test verifies that 'mstl switch <branch>' works when the branch
does not exist locally but exists on the remote.

Do you want to execute the process? [Y/n] (Auto-Yes): yes

[Execution]
Setting up local test environment...
Author identity unknown

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'root@bb50cfbe6934.(none)')
Error during execution: Command '['git', 'commit', '-m', 'Initial commit']' returned non-zero exit status 128.
Traceback (most recent call last):
  File "/app/manual_tests/interactive_runner.py", line 94, in execute_scenario
    logic_func()
  File "/app/manual_tests/manual_test_switch_remote.py", line 39, in run_test_logic
    subprocess.run(["git", "commit", "-m", "Initial commit"], cwd=origin_setup_dir, check=True, stdout=subprocess.DEVNULL)
  File "/usr/lib/python3.12/subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['git', 'commit', '-m', 'Initial commit']' returned non-zero exit status 128.
[2026-01-24 08:41:05] Test 'Switch Remote Fallback Verification' FAILED (Exception) - FAILED
Running manual_test_switch_check.py...
[TEST] Setting up in /tmp/mstl_switch_check_757r3x16
Traceback (most recent call last):
  File "/app/manual_tests/manual_test_switch_check.py", line 133, in <module>
    main()
  File "/app/manual_tests/manual_test_switch_check.py", line 130, in main
    test.run()
  File "/app/manual_tests/manual_test_switch_check.py", line 76, in run
    self.setup()
  File "/app/manual_tests/manual_test_switch_check.py", line 58, in setup
    self.run_git(self.repo1_dir, "checkout", "-b", "main")
  File "/app/manual_tests/manual_test_switch_check.py", line 47, in run_git
    subprocess.run(["git"] + list(args), cwd=cwd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=env)
  File "/usr/lib/python3.12/subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['git', 'checkout', '-b', 'main']' returned non-zero exit status 128.
bb50cfbe6934:/app#

@google-labs-jules
Copy link
Contributor Author

============================================================
Config Search Verification
============================================================
[Expected Result]
This test automatically verifies:
1. Standard 'mstl status' behavior from root.
2. Parent configuration search (automatic switch verification).
3. Parent configuration validation failure handling (should not switch).

Do you want to execute the process? [Y/n] (Auto-Yes): yes

[Execution]
Setting up local test environment...
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 220 bytes | 220.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To /app/manual_test_workspace_search/remotes/repo-a.git
 * [new branch]      master -> master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 222 bytes | 222.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To /app/manual_test_workspace_search/remotes/repo-b.git
 * [new branch]      master -> master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 221 bytes | 221.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To /app/manual_test_workspace_search/remotes/repo-c.git
 * [new branch]      master -> master
1. Verifying standard behavior (running from root)...
Standard status passed.
2. Testing Parent Search from sub-directory: /app/manual_test_workspace_search/repo-a
Automatic switch notification appeared.
3. Testing Validation Failure...
Error during execution: Unexpected error message: exit status 1

Traceback (most recent call last):
  File "/app/manual_tests/interactive_runner.py", line 94, in execute_scenario
    logic_func()
  File "/app/manual_tests/manual_test_config_search.py", line 152, in run_test_logic
    raise Exception(f"Unexpected error message: {stderr}")
Exception: Unexpected error message: exit status 1

[2026-01-24 08:41:03] Test 'Config Search Verification' FAILED (Exception) - FAILED
Running manual_test_parent_config_switch.py...
============================================================
Switch Remote Fallback Verification
============================================================
[Expected Result]
This test verifies that 'mstl switch <branch>' works when the branch
does not exist locally but exists on the remote.

Do you want to execute the process? [Y/n] (Auto-Yes): yes

[Execution]
Setting up local test environment...
Author identity unknown

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'root@bb50cfbe6934.(none)')
Error during execution: Command '['git', 'commit', '-m', 'Initial commit']' returned non-zero exit status 128.
Traceback (most recent call last):
  File "/app/manual_tests/interactive_runner.py", line 94, in execute_scenario
    logic_func()
  File "/app/manual_tests/manual_test_switch_remote.py", line 39, in run_test_logic
    subprocess.run(["git", "commit", "-m", "Initial commit"], cwd=origin_setup_dir, check=True, stdout=subprocess.DEVNULL)
  File "/usr/lib/python3.12/subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['git', 'commit', '-m', 'Initial commit']' returned non-zero exit status 128.
[2026-01-24 08:41:05] Test 'Switch Remote Fallback Verification' FAILED (Exception) - FAILED
Running manual_test_switch_check.py...
[TEST] Setting up in /tmp/mstl_switch_check_757r3x16
Traceback (most recent call last):
  File "/app/manual_tests/manual_test_switch_check.py", line 133, in <module>
    main()
  File "/app/manual_tests/manual_test_switch_check.py", line 130, in main
    test.run()
  File "/app/manual_tests/manual_test_switch_check.py", line 76, in run
    self.setup()
  File "/app/manual_tests/manual_test_switch_check.py", line 58, in setup
    self.run_git(self.repo1_dir, "checkout", "-b", "main")
  File "/app/manual_tests/manual_test_switch_check.py", line 47, in run_git
    subprocess.run(["git"] + list(args), cwd=cwd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=env)
  File "/usr/lib/python3.12/subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['git', 'checkout', '-b', 'main']' returned non-zero exit status 128.
bb50cfbe6934:/app#

Fixed manual tests failures. manual_test_switch_remote.py was missing git user config. manual_test_switch_check.py needed -B to handle existing branches. manual_test_config_search.py failed because fatal errors were printed to stdout instead of stderr; fixed mstl to print fatal errors to stderr.

Fix failures in manual tests reported in PR review.
- Fix manual_test_switch_remote.py to set git user config.
- Fix manual_test_switch_check.py to use `git checkout -B` for robustness.
- Fix internal/app/run.go to print fatal errors to Stderr instead of Stdout, fixing manual_test_config_search.py expectations and adhering to CLI standards.

Changes:
- internal/app/run.go: Print error to os.Stderr.
- manual_tests/manual_test_switch_remote.py: Configure git user.
- manual_tests/manual_test_switch_check.py: Use -B flag.
@github-actions
Copy link

Test Coverage Report

Total Coverage: 64.1%

Detailed Report
File Function Coverage
mistletoe/cmd/mstl-gh/main.go:15: main 0.0%
mistletoe/cmd/mstl/main.go:15: main 0.0%
mistletoe/internal/app/config_search.go:14: SearchParentConfig 77.3%
mistletoe/internal/app/config_search.go:67: validateParentConfig 64.0%
mistletoe/internal/app/dependency.go:24: LoadDependencies 100.0%
mistletoe/internal/app/dependency.go:34: ParseDependencies 100.0%
mistletoe/internal/app/dependency.go:132: extractID 100.0%
mistletoe/internal/app/dependency.go:140: addDependency 100.0%
mistletoe/internal/app/fire.go:16: handleFire 0.0%
mistletoe/internal/app/fire.go:40: resolveConfigForFire 0.0%
mistletoe/internal/app/fire.go:47: fireCommand 96.2%
mistletoe/internal/app/fire.go:100: processFireRepo 73.7%
mistletoe/internal/app/fire.go:140: runGitFire 100.0%
mistletoe/internal/app/fire.go:150: getSafeUsername 41.7%
mistletoe/internal/app/fire.go:172: sanitizeName 83.3%
mistletoe/internal/app/fire.go:184: getShortUUID 80.0%
mistletoe/internal/app/flags.go:14: ParseFlagsFlexible 93.1%
mistletoe/internal/app/flags.go:71: CheckFlagDuplicates 100.0%
mistletoe/internal/app/flags.go:95: isBoolFlag 100.0%
mistletoe/internal/app/help.go:7: handleHelp 100.0%
mistletoe/internal/app/init.go:25: ensureBranchExistsLocally 27.3%
mistletoe/internal/app/init.go:58: isDirEmpty 80.0%
mistletoe/internal/app/init.go:76: checkRootDirectorySafety 93.8%
mistletoe/internal/app/init.go:134: validateEnvironment 63.5%
mistletoe/internal/app/init.go:229: PerformInit 75.0%
mistletoe/internal/app/init.go:307: validateAndPrepareInitDest 77.3%
mistletoe/internal/app/init.go:349: handleInit 100.0%
mistletoe/internal/app/init.go:353: initCommand 85.3%
mistletoe/internal/app/pr.go:9: HandlePr 0.0%
mistletoe/internal/app/pr_body_logic.go:25: GenerateMistletoeBody 98.3%
mistletoe/internal/app/pr_body_logic.go:231: GeneratePlaceholderMistletoeBody 0.0%
mistletoe/internal/app/pr_body_logic.go:261: EmbedMistletoeBody 96.2%
mistletoe/internal/app/pr_body_logic.go:325: ParseMistletoeBlock 87.2%
mistletoe/internal/app/pr_checkout.go:18: handlePrCheckout 0.0%
mistletoe/internal/app/pr_checkout.go:24: prCheckoutCommand 23.6%
mistletoe/internal/app/pr_checkout.go:324: writeDependencyFile 100.0%
mistletoe/internal/app/pr_common.go:58: CollectPrStatus 45.7%
mistletoe/internal/app/pr_common.go:267: getPrDisplayState 42.9%
mistletoe/internal/app/pr_common.go:284: SortPrs 92.9%
mistletoe/internal/app/pr_common.go:316: RenderPrStatusTable 78.9%
mistletoe/internal/app/pr_common.go:353: executePush 0.0%
mistletoe/internal/app/pr_common.go:406: updatePrDescriptions 0.0%
mistletoe/internal/app/pr_common.go:548: parsePrURL 81.8%
mistletoe/internal/app/pr_common.go:566: getRepoName 66.7%
mistletoe/internal/app/pr_common.go:576: resolveRemoteBranchHash 69.2%
mistletoe/internal/app/pr_common.go:607: checkGhAvailability 100.0%
mistletoe/internal/app/pr_common.go:622: verifyGithubRequirements 61.2%
mistletoe/internal/app/pr_common.go:750: LoadDependencyGraph 92.3%
mistletoe/internal/app/pr_common_helper.go:10: GetGhUser 0.0%
mistletoe/internal/app/pr_common_helper.go:20: ValidatePrPermissionAndOverwrite 0.0%
mistletoe/internal/app/pr_common_helper.go:51: isPrFromConfiguredRepo 100.0%
mistletoe/internal/app/pr_create.go:21: handlePrCreate 0.0%
mistletoe/internal/app/pr_create.go:28: prCreateCommand 16.0%
mistletoe/internal/app/pr_create.go:526: executePrCreationOnly 57.8%
mistletoe/internal/app/pr_input_logic.go:19: ParsePrTitleBody 93.3%
mistletoe/internal/app/pr_status.go:16: handlePrStatus 0.0%
mistletoe/internal/app/pr_status.go:22: prStatusCommand 50.0%
mistletoe/internal/app/pr_update.go:18: handlePrUpdate 0.0%
mistletoe/internal/app/pr_update.go:24: prUpdateCommand 27.1%
mistletoe/internal/app/pr_update.go:247: categorizePrUpdate 100.0%
mistletoe/internal/app/pr_verify.go:13: VerifyRevisionsUnchanged 87.5%
mistletoe/internal/app/push.go:15: handlePush 83.3%
mistletoe/internal/app/reset.go:25: resolveResetTarget 100.0%
mistletoe/internal/app/reset.go:45: verifyResetTargetWithResolution 85.7%
mistletoe/internal/app/reset.go:82: handleReset 75.2%
mistletoe/internal/app/run.go:31: parseArgs 80.0%
mistletoe/internal/app/run.go:44: getGitPath 66.7%
mistletoe/internal/app/run.go:51: getGhPath 0.0%
mistletoe/internal/app/run.go:58: validateGit 100.0%
mistletoe/internal/app/run.go:63: validateGh 100.0%
mistletoe/internal/app/run.go:68: validateGhAuth 100.0%
mistletoe/internal/app/run.go:74: Run 0.0%
mistletoe/internal/app/run.go:82: RunApp 53.7%
mistletoe/internal/app/snapshot.go:20: handleSnapshot 83.5%
mistletoe/internal/app/snapshot.go:245: GenerateSnapshot 0.0%
mistletoe/internal/app/snapshot.go:258: GenerateSnapshotVerbose 76.9%
mistletoe/internal/app/snapshot.go:345: GenerateSnapshotFromStatus 89.5%
mistletoe/internal/app/snapshot.go:428: CalculateSnapshotIdentifier 76.9%
mistletoe/internal/app/status.go:14: handleStatus 91.5%
mistletoe/internal/app/status_logic.go:40: ValidateRepositoriesIntegrity 88.9%
mistletoe/internal/app/status_logic.go:80: CollectStatus 100.0%
mistletoe/internal/app/status_logic.go:110: getRepoStatus 88.2%
mistletoe/internal/app/status_logic.go:299: RenderStatusTable 95.0%
mistletoe/internal/app/status_logic.go:357: ValidateStatusForAction 100.0%
mistletoe/internal/app/switch.go:18: branchExists 100.0%
mistletoe/internal/app/switch.go:23: configureUpstreamIfSafe 76.2%
mistletoe/internal/app/switch.go:67: handleSwitch 84.5%
mistletoe/internal/app/sync.go:16: handleSync 80.7%
mistletoe/internal/app/utils.go:24: formatDuration 100.0%
mistletoe/internal/app/utils.go:34: RunGit 100.0%
mistletoe/internal/app/utils.go:66: RunGitInteractive 100.0%
mistletoe/internal/app/utils.go:97: RunGh 73.3%
mistletoe/internal/app/utils.go:128: RunEditor 76.0%
mistletoe/internal/app/utils.go:176: ResolveCommonValues 92.1%
mistletoe/internal/app/utils.go:266: DetermineJobs 100.0%
mistletoe/internal/app/version_common.go:11: printCommonVersionInfo 0.0%
mistletoe/internal/app/version_gh.go:11: handleVersionGh 0.0%
mistletoe/internal/app/version_mstl.go:4: handleVersionMstl 0.0%
mistletoe/internal/config/config.go:64: ParseConfig 100.0%
mistletoe/internal/config/config.go:84: validateConfig 95.0%
mistletoe/internal/config/config.go:163: isValidGitRef 100.0%
mistletoe/internal/config/config.go:173: GetRepoDirName 100.0%
mistletoe/internal/config/config.go:188: GetRepoPath 100.0%
mistletoe/internal/config/config.go:193: LoadConfigData 100.0%
mistletoe/internal/config/config.go:207: LoadConfigFile 78.6%
mistletoe/internal/ui/ui.go:16: AskForConfirmation 0.0%
mistletoe/internal/ui/ui.go:37: AskForConfirmationRequired 0.0%
mistletoe/internal/ui/ui.go:69: NewSpinner 0.0%
mistletoe/internal/ui/ui.go:78: Start 0.0%
mistletoe/internal/ui/ui.go:102: Stop 0.0%

@keiji keiji marked this pull request as ready for review January 24, 2026 09:06
@keiji keiji merged commit c3db719 into main Jan 24, 2026
1 check passed
@keiji keiji deleted the switch-consistency-check-8979327570226183598 branch January 24, 2026 09:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants