Add manual resolutions to continueCherryPick

This commit is contained in:
tidy-dev 2021-02-23 10:18:42 -05:00
parent 29c23c029c
commit f65b5aff52
2 changed files with 52 additions and 5 deletions

View file

@ -17,6 +17,8 @@ import { ChildProcess } from 'child_process'
import { round } from '../../ui/lib/round'
import byline from 'byline'
import { ICherryPickSnapshot } from '../../models/cherry-pick'
import { ManualConflictResolution } from '../../models/manual-conflict-resolution'
import { stageManualConflictResolution } from './stage'
/** The app-specific results from attempting to cherry pick commits*/
export enum CherryPickResult {
@ -203,7 +205,7 @@ function parseCherryPickResult(result: IGitResult): CherryPickResult {
export async function getCherryPickSnapshot(
repository: Repository
): Promise<ICherryPickSnapshot | null> {
if (isCherryPickHeadFound(repository)) {
if (!isCherryPickHeadFound(repository)) {
// If there no cherry pick head, there is no cherry pick in progress.
return null
}
@ -302,13 +304,28 @@ export async function getCherryPickSnapshot(
export async function continueCherryPick(
repository: Repository,
files: ReadonlyArray<WorkingDirectoryFileChange>,
manualResolutions: ReadonlyMap<string, ManualConflictResolution> = new Map(),
progressCallback?: (progress: ICherryPickProgress) => void
): Promise<CherryPickResult> {
// only stage files related to cherry pick
const trackedFiles = files.filter(f => {
return f.status.kind !== AppFileStatusKind.Untracked
})
await stageFiles(repository, trackedFiles)
// apply conflict resolutions
for (const [path, resolution] of manualResolutions) {
const file = files.find(f => f.path === path)
if (file !== undefined) {
await stageManualConflictResolution(repository, file, resolution)
} else {
log.error(
`[continueCherryPick] couldn't find file ${path} even though there's a manual resolution for it`
)
}
}
const otherFiles = trackedFiles.filter(f => !manualResolutions.has(f.path))
await stageFiles(repository, otherFiles)
const status = await getStatus(repository)
if (status == null) {
@ -320,7 +337,7 @@ export async function continueCherryPick(
}
// make sure cherry pick is still in progress to continue
if (await isCherryPickHeadFound(repository)) {
if (await !isCherryPickHeadFound(repository)) {
return CherryPickResult.Aborted
}

View file

@ -15,7 +15,9 @@ import {
continueCherryPick,
getCherryPickSnapshot,
} from '../../../src/lib/git/cherry-pick'
import { isConflictedFile } from '../../../src/lib/status'
import { Branch } from '../../../src/models/branch'
import { ManualConflictResolution } from '../../../src/models/manual-conflict-resolution'
import { ICherryPickProgress } from '../../../src/models/progress'
import { Repository } from '../../../src/models/repository'
import { AppFileStatusKind } from '../../../src/models/status'
@ -279,7 +281,7 @@ describe('git/cherry-pick', () => {
expect(conflictedFiles).toHaveLength(1)
})
it('successfully continues cherry picking with conflicts after resolving them', async () => {
it('successfully continues cherry picking with conflicts after resolving them by overwriting', async () => {
result = await cherryPick(repository, featureBranch.tip.sha)
expect(result).toBe(CherryPickResult.ConflictsEncountered)
@ -312,6 +314,34 @@ describe('git/cherry-pick', () => {
expect(result).toBe(CherryPickResult.CompletedWithoutError)
})
it('successfully continues cherry picking with conflicts after resolving them manually', async () => {
result = await cherryPick(repository, featureBranch.tip.sha)
expect(result).toBe(CherryPickResult.ConflictsEncountered)
const statusAfterCherryPick = await getStatusOrThrow(repository)
const { files } = statusAfterCherryPick.workingDirectory
// git diff --check warns if conflict markers exist and will exit with
// non-zero status if conflicts found
const diffCheckBefore = await GitProcess.exec(
['diff', '--check'],
repository.path
)
expect(diffCheckBefore.exitCode).toBeGreaterThan(0)
const manualResolutions = new Map<string, ManualConflictResolution>()
for (const file of files) {
if (isConflictedFile(file.status)) {
manualResolutions.set(file.path, ManualConflictResolution.theirs)
}
}
result = await continueCherryPick(repository, files, manualResolutions)
expect(result).toBe(CherryPickResult.CompletedWithoutError)
})
it('successfully detects cherry picking with outstanding files not staged', async () => {
result = await cherryPick(repository, featureBranch.tip.sha)
expect(result).toBe(CherryPickResult.ConflictsEncountered)
@ -462,7 +492,7 @@ describe('git/cherry-pick', () => {
Path.join(repository.path, 'THING_THREE.md'),
'# Resolve conflicts!'
)
result = await continueCherryPick(repository, files, p =>
result = await continueCherryPick(repository, files, new Map(), p =>
progress.push(p)
)
expect(result).toBe(CherryPickResult.CompletedWithoutError)