Skip to content

Handle get_default_branch failure with fallback to HEAD - #35

Closed
blooop wants to merge 3 commits into
mainfrom
fix-default-branch-fallback
Closed

blooop wants to merge 3 commits into
mainfrom
fix-default-branch-fallback

Conversation

@blooop

@blooop blooop commented Mar 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • Wrap get_default_branch() in try/except in ensure_branch() so workspace creation remains robust when the default branch cannot be resolved (network issues, misconfigured repos)
  • Fall back to "HEAD" on error or empty/falsy return value
  • Tighten test_branch_custom_start_point to assert no remote push occurs when create_remote=False

Addresses review feedback from #31:

Test plan

  • Added test for get_default_branch raising an exception → falls back to "HEAD"
  • Added test for get_default_branch returning empty string → falls back to "HEAD"
  • Added mock_push.assert_not_called() to test_branch_custom_start_point
  • All 70 affected tests pass

🤖 Generated with Claude Code

Summary by Sourcery

Handle failures when resolving a repository’s default branch during workspace branch setup and tighten test coverage around branch creation behavior.

Bug Fixes:

  • Ensure workspace branch creation falls back to using HEAD when resolving the default branch fails or returns an empty value, preventing errors during ensure_branch.

Tests:

  • Add tests verifying ensure_branch falls back to HEAD when get_default_branch raises or returns an empty string.
  • Strengthen branch manager tests to assert no remote push occurs when create_remote is False for custom start points.

Wrap get_default_branch in try/except so workspace creation remains
robust when the default branch cannot be resolved (network issues,
misconfigured repos). Falls back to "HEAD" on error or empty return.
Also tighten test_branch_custom_start_point to assert no remote push
occurs when create_remote=False.
@sourcery-ai

sourcery-ai Bot commented Mar 12, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds robust handling around default-branch resolution in workspace cloning by falling back to HEAD when the default branch cannot be determined, and strengthens branch manager tests to verify no remote push occurs when create_remote is False.

Sequence diagram for ensure_branch default_branch fallback handling

sequenceDiagram
    participant WorkspaceClone
    participant RepoManager
    participant WorktreeBranchManager

    WorkspaceClone->>RepoManager: get_default_branch(owner, repo)
    alt get_default_branch succeeds with non_empty_branch
        RepoManager-->>WorkspaceClone: default_branch
        WorkspaceClone->>WorktreeBranchManager: ensure_branch_exists(bare_path, branch, create_remote=False, start_point=default_branch, use_local_refs=True)
    else get_default_branch raises_exception
        RepoManager--xWorkspaceClone: Exception
        WorkspaceClone->>WorkspaceClone: log warning Failed to resolve default branch
        WorkspaceClone->>WorktreeBranchManager: ensure_branch_exists(bare_path, branch, create_remote=False, start_point="HEAD", use_local_refs=True)
    else get_default_branch returns_empty_or_falsy
        RepoManager-->>WorkspaceClone: ""
        WorkspaceClone->>WorktreeBranchManager: ensure_branch_exists(bare_path, branch, create_remote=False, start_point="HEAD", use_local_refs=True)
    end
Loading

Class diagram for WorkspaceClone ensure_branch collaborators

classDiagram
    class WorkspaceClone {
        repo_manager
        branch_manager
        ensure_branch(owner, repo, branch) void
    }

    class RepoManager {
        get_default_branch(owner, repo) str
    }

    class WorktreeBranchManager {
        ensure_branch_exists(bare_path, branch, create_remote, start_point, use_local_refs) void
    }

    WorkspaceClone --> RepoManager : uses
    WorkspaceClone --> WorktreeBranchManager : uses
Loading

File-Level Changes

Change Details Files
Harden ensure_branch default-branch resolution to tolerate failures and empty responses, falling back to HEAD.
  • Wrap get_default_branch invocation in try/except and log a warning when resolution fails.
  • Allow default_branch to be None on error and pass default_branch or 'HEAD' as the start_point to branch creation.
  • Preserve existing fetch-before-ensure behavior and local-refs usage while making start point selection more robust.
devlaunch/worktree/workspace_clone.py
Add regression tests for default-branch failure/empty handling and for ensuring no remote push when create_remote is False with a custom start point.
  • Add tests that verify ensure_branch falls back to 'HEAD' when get_default_branch raises or returns an empty string.
  • Extend test_branch_custom_start_point to mock push_branch_to_remote and assert it is not called when create_remote is False.
  • Keep existing expectations on branch creation calls to ensure behavior remains consistent aside from the new guarantees.
test/test_workspace_clone.py
test/test_worktree_branch_manager.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In ensure_branch, consider narrowing the except Exception around get_default_branch to the specific error types you expect (or at least repository-related ones) so that unexpected failures don’t get silently masked with a fallback to HEAD.
  • When logging Failed to resolve default branch, it may be useful to include owner/repo in the log message to make troubleshooting easier when multiple repositories are being managed.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `ensure_branch`, consider narrowing the `except Exception` around `get_default_branch` to the specific error types you expect (or at least repository-related ones) so that unexpected failures don’t get silently masked with a fallback to `HEAD`.
- When logging `Failed to resolve default branch`, it may be useful to include `owner`/`repo` in the log message to make troubleshooting easier when multiple repositories are being managed.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov

codecov Bot commented Mar 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.09%. Comparing base (54ce575) to head (85aa2eb).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #35      +/-   ##
==========================================
+ Coverage   83.04%   83.09%   +0.05%     
==========================================
  Files           9        9              
  Lines        1197     1201       +4     
==========================================
+ Hits          994      998       +4     
  Misses        203      203              
Files with missing lines Coverage Δ
devlaunch/worktree/workspace_clone.py 89.38% <100.00%> (+0.38%) ⬆️

Impacted file tree graph

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

blooop added 2 commits March 12, 2026 22:30
- Catch (OSError, subprocess.SubprocessError) instead of bare Exception
  so programming bugs propagate instead of being silently swallowed
- Include owner/repo in the warning log message for easier debugging
- Add tests for None return and unexpected exception propagation
@blooop

blooop commented Aug 14, 2026

Copy link
Copy Markdown
Owner Author

Closing as superseded — the fallback landed, in a better place.

This PR wraps the call site so a raising get_default_branch degrades to start_point="HEAD". On current main that try/except would be dead code: get_default_branch (devlaunch/worktree/repo_manager.py:320-350) no longer raises for those exceptions. It catches (OSError, SubprocessError, TimeoutExpired) itself and ends with an unconditional return "main", so every caller gets a branch name or nothing at all.

Different design from the one proposed, and strictly better: one fallback inside the function rather than one per caller, so a new caller cannot forget it.

Mechanically it also cannot merge — 209 commits behind main, conflicting, and its CI predates the gate job that is now a required check, so the required check never appears at all.

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.

1 participant