doctor migrate-checkpoints: don't report an empty queue as "push disabled" · Entire

doctor migrate-checkpoints: don't report an empty queue as "push disabled"

40abd51→main·

Soph·1w ago·3 files·+55 added/-18 removed

PushQueuedCheckpointRefs returned (0, nil) both when push_sessions is disabled and when the queue is empty, so the doctor command reported "Checkpoint pushing is disabled in settings" even when pushing was enabled and the refs had simply already been pushed — e.g. a concurrent git push flushed the just-migrated refs while the confirm prompt blocked.

Return an explicit pushDisabled flag alongside the pushed count so the two cases are distinguishable. The command now prints the disabled message only when pushing is actually disabled, and a distinct "no queued refs to push" message otherwise. Adds a push-disabled test and updates the existing entry-point tests for the new signature.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

Sessions

01KWY7XFF3PTNHZTXKW66FGRF1View transcript

Changes

3


91 unmodified lines

return nil
}

pushed, err := strategy.PushQueuedCheckpointRefs(ctx, repo, remote)
pushed, pushDisabled, err := strategy.PushQueuedCheckpointRefs(ctx, repo, remote)
if err != nil {
    if errors.Is(err, context.Canceled) {
        return NewSilentError(err)
    }
    return fmt.Errorf("push migrated refs: %w", err)
}
if pushed == 0 {
    // Confirmed, but nothing went to the remote — checkpoint pushing
    // is disabled in settings. The refs stay queued locally.
    switch {
    case pushDisabled:
        // Confirmed, but checkpoint pushing is disabled in settings, so
        // nothing went to the remote. The refs stay queued locally.
        fmt.Fprintln(out, "Checkpoint pushing is disabled in settings; refs stay queued for the next push.")
        return nil
    case pushed == 0:
        // Enabled, but the queue was already empty — e.g. a concurrent
        // git push flushed the just-migrated refs while we prompted.
        fmt.Fprintln(out, "No queued refs to push (they may have already been pushed).")
    default:
        fmt.Fprintf(out, "Pushed %d checkpoint ref(s).
", pushed)
}
printf(out, "Pushed %d checkpoint ref(s).
", pushed)
return nil
},
}

Mcmd/entire/cli/doctor_migrate.go+11/-6


172 unmodified lines

// PushQueuedCheckpointRefs pushes any queued checkpoint refs to the configured
// checkpoint remote, surfacing errors (unlike the fail-soft pre-push path); the
// caller owns the repo. Returns the number of refs pushed — a no-op (0, nil)
// when pushing is disabled or the queue is empty. Like the pre-push paths, a
// checkpoint policy that blocks pushing errors with the refs left queued.
// Currently used by the checkpoint migration command's opt-in "push now".
func PushQueuedCheckpointRefs(ctx context.Context, repo *git.Repository, remote string) (int, error) {
    // caller owns the repo. It returns the number of refs pushed and whether
    // pushing is disabled in settings — a distinct signal from pushed==0 with
    // pushing enabled (an empty queue), so callers can report the two accurately.
    // Like the pre-push paths, a checkpoint policy that blocks pushing errors with
    // the refs left queued. Currently used by the checkpoint migration command's
    // opt-in "push now".
    func PushQueuedCheckpointRefs(ctx context.Context, repo *git.Repository, remote string) (pushed int, pushDisabled bool, err error) {
        ps := resolvePushSettings(ctx, remote)
        if ps.pushDisabled {
            return 0, nil
            return 0, true, nil
        }
        syncCheckpointPolicyForPrePush(ctx, repo, ps)
        if !checkpointPolicyAllowsGitHook(ctx, repo) {
            return 0, errors.New("checkpoint policy does not allow pushing checkpoint refs; refs stay queued")
            return 0, false, errors.New("checkpoint policy does not allow pushing checkpoint refs; refs stay queued")
        }
        pushed, err := flushCheckpointRefsQueue(ctx, repo, ps.pushTarget())
pushed, err = flushCheckpointRefsQueue(ctx, repo, ps.pushTarget())
        // Clean up even on a partial/failed flush: a diverged batch can push some
        // refs and still return an error, and the shadow branches for the refs that
        // *did* land must still be cleaned up — parity with the pre-push path, which
        // always runs cleanup after flush regardless of its error.
        cleanupPushedShadowBranches(ctx)
        return pushed, err
        return pushed, false, err
    }

// flushCheckpointRefsQueue drains the push-discovery queue and batch-pushes the

Mcmd/entire/cli/strategy/manual_commit_push.go+11/-9


1 unmodified line

import (
    "context"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
)

215 unmodified lines

require.NoError(t, err)
queue := enqueueRefs(t, repo, refs)

pushed, err := PushQueuedCheckpointRefs(context.Background(), repo, bareDir)
pushed, pushDisabled, err := PushQueuedCheckpointRefs(context.Background(), repo, bareDir)
require.NoError(t, err)
assert.False(t, pushDisabled)
assert.Equal(t, len(refs), pushed)

for _, ref := range refs {
    assert.Empty(t, remaining, "pushed refs are removed from the queue")
}

func TestPushQueuedCheckpointRefs_PushDisabled(t *testing.T) {
    workDir, bareDir, refs := setupRepoWithCheckpointRefs(t)
    t.Chdir(workDir)
    paths.ClearWorktreeRootCache()

// push_sessions disabled: the push is a no-op, and the caller must be able
    // to tell that apart from an empty queue (pushed==0 with pushing enabled).
    require.NoError(t, os.MkdirAll(filepath.Join(workDir, ".entire"), 0o755))
    require.NoError(t, os.WriteFile(
        filepath.Join(workDir, ".entire", "settings.json"),
        []byte(`{"enabled": true, "strategy_options": {"push_sessions": false}}`),
        0o600,
    ))

repo, err := git.PlainOpen(workDir)
    require.NoError(t, err)
    queue := enqueueRefs(t, repo, refs)

pushed, pushDisabled, err := PushQueuedCheckpointRefs(context.Background(), repo, bareDir)
    require.NoError(t, err)
    assert.True(t, pushDisabled, "push_sessions=false must be reported as disabled")
    assert.Equal(t, 0, pushed)

remaining, err := queue.Drain()
    require.NoError(t, err)
    assert.ElementsMatch(t, refs, remaining, "disabled push leaves refs queued")
}

func TestPushQueuedCheckpointRefs_PolicyBlocked(t *testing.T) {
    workDir, bareDir, refs := setupRepoWithCheckpointRefs(t)
    t.Chdir(workDir)

writeUnsupportedCheckpointPolicy(t, repo)
    queue := enqueueRefs(t, repo, refs)

pushed, err := PushQueuedCheckpointRefs(context.Background(), repo, bareDir)
pushed, _, err := PushQueuedCheckpointRefs(context.Background(), repo, bareDir)
    require.ErrorContains(t, err, "checkpoint policy")
    assert.Equal(t, 0, pushed)