turborepo-template-upgrade
Version:
Upgrade projects based on a Turborepo template using selective git diffs, with support for ignore paths and skipped packages.
27 lines (23 loc) • 7.58 kB
JavaScript
;var a=require("child_process"),u=require("fs"),L=require("path");var E=require("git-json-resolver"),x=require("git-json-resolver/utils"),j=()=>{let e=process.cwd();for(;e!=="/"&&!((0,u.existsSync)((0,L.resolve)(e,"pnpm-lock.yaml"))&&(0,u.existsSync)((0,L.resolve)(e,"pnpm-workspace.yaml")));)e=(0,L.resolve)(e,"..");return process.chdir(e),e},B="159692443c7a196d86c2612f752ae1d0786b004b",U=".turborepo-template.lst",O=()=>{var c;if((0,u.existsSync)(U))return(c=(0,u.readFileSync)(U,"utf8"))==null?void 0:c.trim();let e=(0,a.execSync)("git log --reverse --format=%ai | head -n 1",{encoding:"utf8"}).trim(),t=new Date(e),s=(0,a.execSync)("git log --format=%H::%ai template/main",{encoding:"utf8"}).trim().split(`
`).map(n=>{let[g,p]=n.split("::");return{hash:g,date:new Date(p==null?void 0:p.trim())}}).reverse().find(n=>n.date>=t);return s?(console.info("Applying changes from ",s.hash," dated ",s.date),s.hash):B},P=async e=>{let t=(0,u.existsSync)("scripts/rebrand.js"),r=(0,u.existsSync)("typedoc.config.js"),s=(0,u.existsSync)("scripts/templates");await(0,E.resolveConflicts)({include:["package.json"],defaultStrategy:["merge","ours"],rules:{"devDependencies.*":["ignore-removed","theirs"],"dependencies.*":["ignore-removed","theirs"]},customStrategies:{"ignore-removed":({theirs:c,path:n})=>!t&&/enquirer$/.test(n)||!r&&/typedoc/.test(n)||!s&&/plop/.test(n)?{status:x.StrategyStatus_OK,value:x.DROP}:{status:x.StrategyStatus_OK,value:c}},debug:e}),await(0,E.resolveConflicts)({include:["**/package.json"],exclude:["package.json","**/dist/**","**/.next/**"],defaultStrategy:["merge","ours"],rules:{"devDependencies.*":["semver-max"],"dependencies.*":["semver-max"]},loggerConfig:{logDir:".logs2",levels:{stdout:[]}},plugins:["git-json-resolver-semver"],pluginConfig:{"git-json-resolver-semver":{preferValid:!0}},includeNonConflicted:!0,debug:e})};var A=e=>{let t=(0,L.resolve)(e,".tt-upgrade.config.json");if(!(0,$.existsSync)(t))return{};try{let r=(0,$.readFileSync)(t,"utf8");return JSON.parse(r)}catch{return console.warn(`\u26A0\uFE0F Failed to parse config file: ${t}`),{}}},R=(e,t)=>({...e,...t,excludePaths:[...e.excludePaths||[],...t.excludePaths||[]]});var h=[],I=0,T=(e,t,r,s="template",c=3)=>{var p,k;if(I++>c){I=0,r(`Max patch recursion reached (${c}), stopping`);return}let n=`git diff ${e} ${s}/main -- ${t.join(" ")} .`;r(`Running: ${n}`);let g=(0,a.execSync)(n,{encoding:"utf8"});(0,u.writeFileSync)(".template.patch",g),r(`Patch written to .template.patch (${g.length} chars)`);try{r("Applying patch with 3-way merge"),(0,a.execSync)("git apply --3way --ignore-space-change --ignore-whitespace .template.patch",{encoding:"utf8"}),r("Patch applied successfully")}catch(C){let i=(k=(p=C.stderr)==null?void 0:p.split)==null?void 0:k.call(p,`
`).filter(y=>y.startsWith("error"));r(`Patch failed with ${i.length} errors`),i.forEach(y=>{var o;let b=(o=y.split(":")[1])==null?void 0:o.trim();b&&(t.push(`:!${b}`),r(`Added to exclusions: ${b}`))}),h.push("Applied patch with errors: "),h.push({errorLines:i,exclusions:t}),h.push("^^^---Applied patch with errors"),i.length&&T(e,t,r,s,c)}},F=async(e,t={})=>{let r=j(),s=A(r),c=R(s,t),{debug:n=!1,dryRun:g=!1,templateUrl:p="https://github.com/react18-tools/turborepo-template",excludePaths:k=[],skipInstall:C=!1,remoteName:i="template",maxPatchRetries:y=3,skipCleanCheck:b=!1}=c,o=m=>n&&console.log(`\u{1F50D} [DEBUG] ${m}`);if(o(`Working directory: ${r}`),Object.keys(s).length>0&&o("Loaded config from .tt-upgrade.config.json"),b)o("Skipping git clean check");else try{(0,a.execSync)("git diff --quiet"),(0,a.execSync)("git diff --cached --quiet"),o("Git tree is clean")}catch{console.error("\u274C Error: Please commit or stash your changes before upgrading.");return}g&&console.log("\u{1F50D} Dry run mode - no changes will be applied");try{(0,a.execSync)(`git remote add ${i} ${p}`),o(`Added ${i} remote: ${p}`)}catch{o(`${i} remote already exists`)}try{(0,a.execSync)(`rm -rf ${x.DEFAULT_BACKUP_DIR}`)}catch{}try{(0,a.execSync)(`git fetch ${i}`),o(`Fetched latest changes from ${i}`);let m=(e==null?void 0:e.trim())||O(),f=[...[".tkb","CHANGELOG.md","README.md","**/CHANGELOG.md","**/FUNDING.md","SECURITY.md","TODO.md","FEATURED.md","docs","lib","scripts/rebrand.config.json","pnpm-lock.yaml",".lst",".turborepo-template.lst",".vscode/settings.json"],...k].map(l=>`:!${l}`);if(o(`Base exclusions: ${f.length} items`),[".github/workflows/docs.yml","scripts/templates","examples/express","examples/nextjs/src/app/button.tsx","examples/nextjs/src/app/button.module.css","examples/remix","packages/logger","packages/jest-presets","scripts/rebrand.js","scripts/rebrander.js","plopfile.js","tsconfig.docs.json","typedoc.config.js"].forEach(l=>{(0,u.existsSync)((0,L.resolve)(r,l))||(f.push(`:!${l}`),o(`Added missing path to exclusions: ${l}`))}),[["scripts/templates",["component-generator.md"]],["docs",["scripts/add-frontmatter.mjs"]]].forEach(([l,v])=>{(0,u.existsSync)(l)||v.forEach(_=>f.push(`:!${_}`))}),o(`Generating patch from ${m} to template/main`),o(`Total exclusions: ${f.length}`),g){let l=`git diff ${m} ${i}/main -- ${f.join(" ")} .`,v=(0,a.execSync)(l,{encoding:"utf8"});console.log("\u{1F4CB} Patch preview:"),console.log(v||"No changes to apply");return}T(m,f,o,i,y);let G=(0,a.execSync)(`git rev-parse ${i}/main`,{encoding:"utf8"}).trim();(0,u.writeFileSync)(".turborepo-template.lst",G),await P(n),console.log("\u2705 Upgrade applied successfully."),!g&&!C?(console.log("Reinstalling dependencies..."),(0,a.execSync)("pnpm i",{stdio:n?"inherit":"pipe"}),o("Dependencies reinstalled")):C&&o("Skipping dependency installation");try{(0,a.execSync)("sed -i '/\\.turborepo-template\\.lst/u' .github/workflows/upgrade.yml"),(0,a.execSync)("sed -i '/\\.turborepo-template\\.lst/u' .github/workflows/docs.yml")}catch{}}catch(m){console.error("\u274C Upgrade failed:",m)}h.length>0&&((0,u.writeFileSync)(".error.log",JSON.stringify(h,null,2)),o(`Error log written with ${h.length} entries`))};var H=e=>{var r;let t={};for(let s=0;s<e.length;s++)switch(e[s]){case"--debug":case"-u":t.debug=!0;break;case"--dry-run":t.dryRun=!0;break;case"--template-url":t.templateUrl=e[++s];break;case"--exclude":t.excludePaths=((r=e[++s])==null?void 0:r.split(","))||[];break;case"--skip-install":t.skipInstall=!0;break;case"--remote-name":t.remoteName=e[++s];break;case"--max-retries":t.maxPatchRetries=parseInt(e[++s])||3;break;case"--skip-clean-check":t.skipCleanCheck=!0;break;case"--help":case"-h":t.help=!0;break}return t},J=()=>{console.log(`
Usage: turborepo-template-upgrade [options]
Options:
-u, --debug Enable debug logging
--dry-run Show what would be changed without applying
--template-url <url> Custom template repository URL
--exclude <paths> Comma-separated paths to exclude from upgrade
--skip-install Skip dependency reinstallation after upgrade
--remote-name <name> Custom remote name for template (default: template)
--max-retries <num> Maximum patch retry attempts (default: 3)
--skip-clean-check Skip git tree clean check
-h, --help Show this help message
Configuration:
Create .tt-upgrade.config.json in your repo root for persistent settings.
Examples:
turborepo-template-upgrade --debug
turborepo-template-upgrade --dry-run
turborepo-template-upgrade --exclude "docs,examples" --skip-install
turborepo-template-upgrade --template-url https://github.com/custom/template
`)},M=H(process.argv.slice(2));M.help&&(J(),process.exit(0));var{help:te,...q}=M;F(void 0,q);