preserve local checkpoint policy ahead state · Entire

Preserve Local Checkpoint Policy Ahead State

9e881cb → main · pfleidi · 3w ago · 2 files · +38 added / -5 removed

Teach checkpoint policy sync to treat a local policy ref ahead of the remote as local state instead of divergence.

Add regression coverage for the linear unpushed policy case.

Sessions

e35d103fb746 View transcript

Changes

2

92 unmodified lines

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

92 unmodified lines

return baseline, nil
    }

baselineAncestor, err := isAncestorOf(ctx, repo, baseline.Hash, local.Hash)
    if err != nil {
        return State{}, err
    }
    if baselineAncestor {
        local.RemoteHash = baseline.RemoteHash
        return local, nil
    }

local.Source = SourceLocalDiverged
    local.RemoteHash = baseline.RemoteHash
    return local, nil
}

Mcmd/entire/cli/checkpointpolicy/remote.go +9

54 unmodified lines

55
56
57
58
58
59
60
61
24 unmodified lines

86
87
88
89
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
4 unmodified lines

121
122
123
100
124
125
126
127
88 unmodified lines

216
217
218
195
219
220
197
221
222
223

54 unmodified lines

require.Equal(t, checkpointpolicy.SourceRemote, got.Source)
    require.Equal(t, localHash, got.Hash)
    require.Equal(t, localHash, got.RemoteHash)
    requireNoRef(t, repo, "refs/entire/policies/checkpoint-fetch")
    requireNoPolicyFetchRef(t, repo)
}

func TestSyncRemotePolicyKeepsDivergedLocalRef(t *testing.T) {
24 unmodified lines

localState, err := checkpointpolicy.ReadLocal(t.Context(), localRepo)
    require.NoError(t, err)
    require.Equal(t, localHash, localState.Hash)
    requireNoRef(t, localRepo, "refs/entire/policies/checkpoint-fetch")
    requireNoPolicyFetchRef(t, localRepo)
}

func TestSyncRemotePolicyKeepsLocalRefAheadOfRemote(t *testing.T) {
    remoteDir, remoteRepo, bareDir := initPolicyRemoteFixture(t)
    baseHash, err := checkpointpolicy.WriteLocal(t.Context(), remoteRepo, plumbing.ZeroHash, checkpointpolicy.DefaultPolicy())
    require.NoError(t, err)
    pushPolicyRefWithGit(t, remoteDir, bareDir)

localDir, localRepo := initPolicyRepoWithDir(t)
    _, err = checkpointpolicy.Sync(t.Context(), localRepo, checkpointpolicy.Target{Remote: bareDir, Dir: localDir})
    require.NoError(t, err)
    localHash, err := checkpointpolicy.WriteLocal(t.Context(), localRepo, baseHash, checkpointpolicy.DefaultPolicy())
    require.NoError(t, err)

got, err := checkpointpolicy.Sync(t.Context(), localRepo, checkpointpolicy.Target{Remote: bareDir, Dir: localDir})
    require.NoError(t, err)
    require.Equal(t, checkpointpolicy.SourceLocal, got.Source)
    require.Equal(t, localHash, got.Hash)
    require.Equal(t, baseHash, got.RemoteHash)

localState, err := checkpointpolicy.ReadLocal(t.Context(), localRepo)
    require.NoError(t, err)
    require.Equal(t, localHash, localState.Hash)
    requireNoPolicyFetchRef(t, localRepo)
}

func TestSyncRemotePolicyRemovesTempRefWhenFetchedPolicyCannotBeRead(t *testing.T) {
4 unmodified lines

localDir, localRepo := initPolicyRepoWithDir(t)
    _, err := checkpointpolicy.Sync(t.Context(), localRepo, checkpointpolicy.Target{Remote: bareDir, Dir: localDir})
    require.ErrorContains(t, err, "parse policy.json")
    requireNoRef(t, localRepo, "refs/entire/policies/checkpoint-fetch")
    requireNoPolicyFetchRef(t, localRepo)
}

func TestPushPolicyRejectsNonFastForward(t *testing.T) {
88 unmodified lines

require.NoError(t, err, string(output))
}

func requireNoRef(t *testing.T, repo *git.Repository, refName plumbing.ReferenceName) {
func requireNoPolicyFetchRef(t *testing.T, repo *git.Repository) {
    t.Helper()
    _, err := repo.Reference(refName, true)
    _, err := repo.Reference("refs/entire/policies/checkpoint-fetch", true)
    require.ErrorIs(t, err, plumbing.ErrReferenceNotFound)
}