Skip to content

Commit

Permalink
fix: correctly handle git stash when using MSYS2 (#1178)
Browse files Browse the repository at this point in the history
  • Loading branch information
Piotr Bosak committed Jun 24, 2022
1 parent 1a5a66a commit 0d627a5
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 1 deletion.
12 changes: 11 additions & 1 deletion lib/gitWorkflow.js
Expand Up @@ -43,7 +43,7 @@ const processRenames = (files, includeRenameFrom = true) =>
return flattened
}, [])

const STASH = 'lint-staged automatic backup'
export const STASH = 'lint-staged automatic backup'

const PATCH_UNSTAGED = 'lint-staged_unstaged.patch'

Expand Down Expand Up @@ -103,6 +103,16 @@ export class GitWorkflow {
ctx.errors.add(GetBackupStashError)
throw new Error('lint-staged automatic backup is missing!')
}

/**
* https://github.com/okonet/lint-staged/issues/1121
* Detect MSYS in login shell mode and escape braces
* to prevent interpolation
*/
if (!!process.env.MSYSTEM && !!process.env.LOGINSHELL) {
return `refs/stash@\\{${index}\\}`
}

return `refs/stash@{${index}}`
}

Expand Down
93 changes: 93 additions & 0 deletions test/unit/getBackupStash.spec.js
@@ -0,0 +1,93 @@
import { execGit } from '../../lib/execGit.js'
import { GitWorkflow, STASH } from '../../lib/gitWorkflow.js'
import { getInitialState } from '../../lib/state.js'
import { GetBackupStashError } from '../../lib/symbols'

jest.mock('../../lib/execGit.js', () => ({
execGit: jest.fn(async () => ''),
}))

describe('gitWorkflow', () => {
const options = { gitConfigDir: '.' }

describe('getBackupStash', () => {
it('should throw when stash not found', async () => {
const gitWorkflow = new GitWorkflow(options)
const ctx = getInitialState()

await expect(gitWorkflow.getBackupStash(ctx)).rejects.toThrowError(
'lint-staged automatic backup is missing!'
)

expect(ctx.errors.has(GetBackupStashError)).toEqual(true)
})

it('should throw when stash not found even when other stashes are', async () => {
const gitWorkflow = new GitWorkflow(options)
const ctx = getInitialState()

execGit.mockResolvedValueOnce('stash@{0}: some random stuff')

await expect(gitWorkflow.getBackupStash(ctx)).rejects.toThrowError(
'lint-staged automatic backup is missing!'
)

expect(ctx.errors.has(GetBackupStashError)).toEqual(true)
})

it('should return ref to the backup stash', async () => {
const gitWorkflow = new GitWorkflow(options)
const ctx = getInitialState()

execGit.mockResolvedValueOnce(
[
'stash@{0}: some random stuff',
`stash@{1}: ${STASH}`,
'stash@{2}: other random stuff',
].join('\n')
)

await expect(gitWorkflow.getBackupStash(ctx)).resolves.toEqual('refs/stash@{1}')
})

it('should return unescaped ref to the backup stash when using MSYS2 without login shell', async () => {
const gitWorkflow = new GitWorkflow(options)
const ctx = getInitialState()

process.env.MSYSTEM = 'MSYS'

execGit.mockResolvedValueOnce(
[
'stash@{0}: some random stuff',
`stash@{1}: ${STASH}`,
'stash@{2}: other random stuff',
].join('\n')
)

await expect(gitWorkflow.getBackupStash(ctx)).resolves.toEqual('refs/stash@{1}')

delete process.env.MSYSTEM
})

it('should return escaped ref to the backup stash when using MSYS2 with login shell', async () => {
const gitWorkflow = new GitWorkflow(options)
const ctx = getInitialState()

process.env.MSYSTEM = 'MSYS'
process.env.LOGINSHELL = 'bash'

execGit.mockResolvedValueOnce(
[
'stash@{0}: some random stuff',
`stash@{1}: ${STASH}`,
'stash@{2}: other random stuff',
].join('\n')
)

await expect(gitWorkflow.getBackupStash(ctx)).resolves.toEqual('refs/stash@\\{1\\}')

delete process.env.MSYSTEM
delete process.env.LOGINSHELL
})
})
})

0 comments on commit 0d627a5

Please sign in to comment.