nano-staged
Version:
Tiny tool to run commands for modified, staged, and committed git files.
158 lines (137 loc) • 3.94 kB
JavaScript
import { createGitWorkflow } from './git-workflow.js'
import { createCmdRunner } from './cmd-runner.js'
import { createReporter } from './reporter.js'
import { createRenderer } from './renderer.js'
import { NanoStagedError } from './errors.js'
export function createRunner({ allowEmpty, git_paths, config, stream, files, type, cwd }) {
const reporter = createReporter(stream)
const renderer = createRenderer(stream, { isTTY: !process.env.CI })
const runner = {
async run() {
const changes = [...files.changed, ...files.deleted]
const gitWorkflow = createGitWorkflow({
allowEmpty,
rootPath: git_paths.root,
dotPath: git_paths.dot,
})
const cmdRunner = createCmdRunner({
rootPath: git_paths.root,
files: files.working,
config,
type,
cwd,
})
const cmdTasks = await cmdRunner.generateCmdTasks()
if (!cmdTasks.some((task) => task.file_count > 0)) {
reporter.error(new NanoStagedError('noMatchingFiles'))
return
}
let enabled = false
let revert = false
let clear = true
let errors = []
let tasks = []
tasks.push({
title: `Preparing nano-staged`,
run: async () => {
try {
await gitWorkflow.backupOriginalState()
} catch (e) {
enabled = true
throw e
}
},
})
tasks.push({
title: `Backing up unstaged changes for staged files`,
run: async () => {
try {
await gitWorkflow.backupUnstagedFiles(changes)
} catch (e) {
revert = true
throw e
}
},
skipped: () => enabled || type === 'unstaged' || type === 'diff' || changes.length === 0,
})
tasks.push({
title: `Running tasks for ${type} files`,
run: async (task) => {
task.tasks = cmdTasks
try {
await cmdRunner.run(task)
} catch (e) {
revert = true
throw e
}
},
skipped: () => enabled || revert,
})
tasks.push({
title: `Applying modifications from tasks`,
run: async () => {
try {
await gitWorkflow.applyModifications(files.working)
} catch (e) {
revert = true
throw e
}
},
skipped: () => enabled || revert || type === 'unstaged' || type === 'diff',
})
tasks.push({
title: `Restoring unstaged changes for staged files`,
run: async () => {
try {
await gitWorkflow.restoreUnstagedFiles(changes)
} catch (e) {
throw e
}
},
skipped: () =>
enabled || revert || type === 'unstaged' || type === 'diff' || changes.length === 0,
})
tasks.push({
title: `Restoring to original state because of errors`,
run: async () => {
try {
await gitWorkflow.restoreOriginalState()
} catch (e) {
clear = false
throw e
}
},
skipped: () => enabled || !revert,
})
tasks.push({
title: `Cleaning up temporary to patch files`,
run: async () => {
try {
await gitWorkflow.cleanUp()
} catch (e) {
throw e
}
},
skipped: () => enabled || !clear,
})
for (const task of tasks) {
if (task.skipped ? !task.skipped() : true) {
renderer.start(task)
try {
task.state = 'run'
await task.run(task)
task.state = 'done'
} catch (e) {
task.state = 'fail'
errors.push(e)
}
}
}
renderer.stop()
if (errors.length) {
throw errors
}
},
}
return runner
}