Last active
January 26, 2023 10:55
-
-
Save pyronaur/60e7ab68e09fdfa4e8b1ea7f22d76beb to your computer and use it in GitHub Desktop.
Auto-fix all changed files in the Jetpack Monorepo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env zx | |
// Pass --verbose to see the full output | |
$.verbose = argv.verbose; | |
function isPHP(filename) { | |
return filename.match(/\.php$/); | |
} | |
function isJS(filename) { | |
return filename.match(/\.(js|jsx|cjs|mjs|ts|tsx|svelte|json|json5)$/); | |
} | |
async function getFilesToFix(target, rootPath, scope = 'any') { | |
target = path.resolve(target); | |
if (!fs.existsSync(target)) { | |
console.error(chalk.red.bold(`"${target}" doesn't exist`)); | |
process.exit(); | |
} | |
const isFixableFile = (file) => isPHP(file) || isJS(file); | |
const isDirectory = fs.statSync(target).isDirectory(); | |
const files = []; | |
if (isDirectory) { | |
const changedFileList = await $`git diff --name-only --diff-filter=ACMRTUXB HEAD;`; | |
const changedFiles = | |
changedFileList.toString().split('\n') | |
.map(f => path.resolve(rootPath, f)) | |
.filter(isFixableFile) | |
.filter(file => file.startsWith(target)) | |
files.push(...changedFiles); | |
} else { | |
files.push(target); | |
} | |
return { | |
js: scope == 'any' || scope === 'js' ? files.filter(isJS) : [], | |
php: scope == 'any' || scope === 'php' ? files.filter(isPHP) : [], | |
} | |
} | |
function logResult(file, result) { | |
if (result.stderr && !result.stdout.toString().includes("No fixable errors were found")) { | |
console.log(chalk.bold.red(`Error reported fixing "${file.replace(`${cwd}/`, '')}"`)); | |
console.log(result.stdout); | |
console.log(chalk.dim("--------------------------------")); | |
console.log(chalk.bold.red(`exitCode "${result.exitCode}" received:\n`)); | |
console.error(result.stderr); | |
console.log(chalk.dim("--------------------------------")); | |
} else { | |
console.log(`${chalk.green.bold("Fixed")} ${file.replace(`${cwd}/`, '')}`); | |
} | |
} | |
async function fixJS(file) { | |
const result = await $`pnpm run -w lint-file ${file} --fix && ${gitDirectory}/tools/js-tools/node_modules/.bin/prettier --ignore-path .eslintignore --write ${file}`; | |
logResult(file, result); | |
} | |
async function fixPHP(file) { | |
const result = await nothrow($`pnpm run -w php:autofix ${file}`); | |
// php:autofix outputs the fixes to stderr for some reason. | |
// Hide it unless --verbose is passed | |
if (argv.verbose !== true) { | |
logResult(file, { | |
stderr: null, | |
...result | |
}); | |
} else { | |
logResult(file, result); | |
} | |
} | |
async function confirm(q, defaultAnswer = "n") { | |
let yes_no = `(y/N)`; | |
if (defaultAnswer === "y") { | |
yes_no = `(Y/n)`; | |
} | |
let answer = await question(`${q} ${yes_no} `); | |
if (!answer) { | |
answer = defaultAnswer; | |
} | |
return "y" === answer; | |
} | |
async function selection(options, selectionQuestion) { | |
let result; | |
options.forEach((opt, index) => { | |
console.log(`> ${chalk.bold(index + 1)}: ${opt} `) | |
}) | |
const selected = await question(selectionQuestion + " (default: 1): \n") || 1; | |
result = options[selected - 1]; | |
return result; | |
} | |
async function reformatEverything(gitDirectory, target) { | |
const options = [ | |
`Fix all files in "${target}"`, | |
'Fix all files in the repo', | |
] | |
const selected = await selection(options, 'What do you want to do?'); | |
// This is going to be slow. | |
// Show the verbose output otherwise it feels like the command is stuck | |
$.verbose = true; | |
// Fix all files in the repo | |
if (selected === options[0]) { | |
console.log(chalk.bold.green("Fixing all files in the repo...")); | |
cd(gitDirectory); | |
await $`pnpm run -w php:autofix`; | |
await $`pnpm run -w reformat-files`; | |
} | |
// Fix all files in the current directory | |
if (selected === options[1]) { | |
console.log(chalk.bold.green("Fixing all files in the current directory...")); | |
let eslintIgnorePath = path.resolve(target, '.eslintignore'); | |
if (!fs.existsSync(eslintIgnorePath)) { | |
eslintIgnorePath = path.resolve(gitDirectory, '.eslintignore'); | |
} | |
await $`pnpm run -w php:autofix ${target}`; | |
await $`${gitDirectory}/tools/js-tools/node_modules/.bin/prettier --ignore-path ${eslintIgnorePath} --write ${target}`; | |
} | |
if (!selected) { | |
console.log(chalk.dim(`Couldn't find an option matching what you specified.`)); | |
console.log(chalk.bold.red("Nothing to do.")); | |
process.exit(); | |
} | |
} | |
/** | |
* | |
* Run | |
* | |
*/ | |
/** | |
* --all | |
* look for all changed files in the repo | |
*/ | |
const gitDirectory = (await $`git rev-parse --show-toplevel`).toString().trim(); | |
if (argv.all) { | |
await cd(gitDirectory); | |
} | |
const cwd = (await $`pwd`).toString().trim(); | |
/** | |
* --js | --php | |
* only fix specific file types | |
*/ | |
let scope = 'any'; | |
if (argv.js) { | |
scope = 'js'; | |
} | |
if (argv.php) { | |
scope = 'php'; | |
} | |
const target = argv._[0] || cwd; | |
const files = await getFilesToFix(target, gitDirectory, scope); | |
const count = Object.values(files).flat().length; | |
if (count > 0) { | |
if (argv.all) { | |
console.log(`Fixing ${count} files in "${chalk.dim(gitDirectory)}"...\n`); | |
} else if (count > 1) { | |
console.log(`Fixing ${count} files in "${target}"...\n`); | |
} else { | |
const file = Object.values(files).flat().pop(); | |
console.log(`Fixing "${chalk.dim(file)}"...\n`) | |
} | |
const tasks = [ | |
...files.php.map(fixPHP), | |
...files.js.map(fixJS) | |
] | |
await Promise.all(tasks); | |
} else { | |
console.log(chalk.green.bold("Nothing to fix")); | |
if (await confirm("Do you want to reformat all files?")) { | |
await reformatEverything(gitDirectory, target); | |
} | |
} | |
console.log(chalk.bold.green("Done!")); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment