one-way-git-sync 6.0.2 → 6.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{hideBin as e}from"yargs/helpers";import t from"yargs/yargs";import{createLogger as o,transports as r,format as i}from"winston";import a from"node:child_process";import s from"node:fs/promises";import n from"node:path";import{copy as c}from"fs-extra";import m from"micromatch";import{simpleGit as l}from"simple-git";const d=o({transports:[new r.Console({format:i.cli({colors:{error:"red"}})})]});const h=n.join("node_modules",".temp","sync-git-repo");const p={dest:{type:"string",alias:"d",describe:"A URL of a destination git repository.",demand:!0},prefix:{type:"string",alias:"p",describe:"A prefix of a commit hash used to generate a commit title, e.g. 'sync <prefix>/<hash>'.\n A typical value is like 'https://github.com/WillBooster/one-way-git-sync/commits'"},branch:{type:"string",alias:"b",describe:"Specify branch of destination repo."},tag:{type:"string",alias:"t",describe:"Specify tag to be created in destination repo."},"tag-hash":{type:"boolean",describe:"Create version+hash tag (e.g. v1.31.5-2-gcdde507). It should be a unique tag."},"tag-version":{type:"boolean",describe:"Create version tag (e.g. v1.31.5). It could be a non-unique tag."},"ignore-patterns":{type:"string",alias:"i",describe:"Exclude the files whose path matches one of the given patterns.\n The patterns are processed by micromatch (https://github.com/micromatch/micromatch).\n You may specify the option multiple times. Default value is \"-i .git -i .github -i node_modules -i '.renovaterc.*'\"",default:[".git",".github","node_modules",".renovaterc.*"]},dry:{type:"boolean",describe:"Enable dry-run mode."},force:{type:"boolean",describe:"Force to overwrite the destination git repository."},verbose:{type:"boolean",alias:"v",describe:"Show details logs."}},g=await t(e(process.argv)).scriptName("one-way-git-sync").options(p).middleware((e=>{d.level=e.verbose?"verbose":"info"})).strict().help().argv;await async function(e){await s.mkdir(h,{recursive:!0});const t=await s.mkdtemp(n.join(h,"repo-")),o=await async function(e,t){const o={"--single-branch":null};t.force||(o["--depth"]=1);t.branch&&(o["--branch"]=t.branch);try{await l().clone(t.dest,e,o)}catch{delete o["--branch"],delete o["--single-branch"],await l().clone(t.dest,e,o),l(e).checkout(["-b",t.branch])}d.verbose(`Cloned destination repo on ${e}`);const r=l(e),i=await r.log(),[h,p]=function(e){if(0===e.all.length)return d.verbose("No commit history"),[];for(const t of e.all){const[e,...o]=t.message.replaceAll(/[()]/g,"").split(/[\s/]/);if("sync"===e&&o.length>0)return[t.message,o.at(-1)]}return d.verbose(`No sync commit: ${e.all[0].message}`),[]}(i);if(p)d.verbose(`Extracted a valid commit: ${p}`),d.verbose(`(${h})`);else if(!t.force)return d.error("No valid commit in destination repo"),!1;const g=l();let f;try{f=await g.log(p?{from:p,to:"HEAD","--first-parent":void 0}:void 0)}catch(e){return d.error(`Failed to get source commit history: ${e.stack}`),!1}const b=f.latest?.hash;if(!b)return d.info("No synchronizable commit"),!0;const[u,y]=await Promise.all([s.readdir(e),s.readdir(".")]);for(const o of m.not(u,t["ignore-patterns"]))await s.rm(n.join(e,o),{recursive:!0,force:!0});for(const o of m.not(y,t["ignore-patterns"]))await c(o,n.join(e,o));await r.add("-A");let v="";if(t["tag-hash"]||t["tag-version"]){const e="git describe --tags --always "+(t["tag-version"]?"--abbrev=0":"");v=a.execSync(e).toString().trim()}let w=t.prefix??await async function(e){const t=(await e.getRemotes(!0)).find((e=>"origin"===e.name)),o=t?.refs?.fetch??t?.refs?.push;if("string"==typeof o&&o.includes("github.com")){const e=o.split("/"),t=e.at(-2),r=e.at(-1)?.replace(/.git$/,"");if(t&&r)return`https://github.com/${t}/${r}/commits`}}(g)??"";w&&!w.endsWith("/")&&(w+="/");const $=`${w}${b}`,x=v?`sync ${v} (${$})`:`sync ${$}`,k=p?f.all.map((e=>`* ${e.message}`)).join("\n\n"):`Replace all the files with those of ${t.dest} due to missing sync commit.`;try{await r.commit(`${x}\n\n${k}`),d.verbose(`Created a commit: ${x}`),d.verbose(` with body: ${k}`)}catch(e){return d.error(`Failed to commit changes: ${e.stack}`),!1}const A=v||t.tag;if(A)try{await r.addTag(A),d.verbose(`Created a tag: ${A}`)}catch{d.warn(`Failed to create a tag: ${A}`)}if(t.dry)return d.verbose("Finished dry run"),!0;try{await(t.branch?r.push("origin",t.branch):r.push()),A&&await r.push({"--tags":null})}catch(e){return d.error(`Failed to push the commit: ${e.stack}`),!1}return d.verbose("Pushed the commit"),!0}(t,e);process.exit(o?0:1)}(g);
1
+ import{hideBin as e}from"yargs/helpers";import t from"yargs/yargs";import{pino as i}from"pino";import o from"node:child_process";import r from"node:fs/promises";import a from"node:path";import{copy as s}from"fs-extra";import n from"micromatch";import{simpleGit as c}from"simple-git";const d=i({transport:{target:"pino-pretty",options:{colorize:!0}}});const m=a.join("node_modules",".temp","sync-git-repo");const l={dest:{type:"string",alias:"d",describe:"A URL of a destination git repository.",demand:!0},prefix:{type:"string",alias:"p",describe:"A prefix of a commit hash used to generate a commit title, e.g. 'sync <prefix>/<hash>'.\n A typical value is like 'https://github.com/WillBooster/one-way-git-sync/commits'"},branch:{type:"string",alias:"b",describe:"Specify branch of destination repo."},tag:{type:"string",alias:"t",describe:"Specify tag to be created in destination repo."},"tag-hash":{type:"boolean",describe:"Create version+hash tag (e.g. v1.31.5-2-gcdde507). It should be a unique tag."},"tag-version":{type:"boolean",describe:"Create version tag (e.g. v1.31.5). It could be a non-unique tag."},"ignore-patterns":{type:"array",alias:"i",describe:"Exclude the files whose path matches one of the given patterns.\n The patterns are processed by micromatch (https://github.com/micromatch/micromatch).\n You may specify the option multiple times. Default value is \"-i .git -i .github -i node_modules -i '.renovaterc.*'\"",default:[".git",".github","node_modules",".renovaterc.*"]},dry:{type:"boolean",describe:"Enable dry-run mode."},force:{type:"boolean",describe:"Force to overwrite the destination git repository."},verbose:{type:"boolean",alias:"v",describe:"Show details logs."}},g=await t(e(process.argv)).scriptName("one-way-git-sync").options(l).middleware((e=>{d.level=e.verbose?"verbose":"info"})).strict().help().argv;await async function(e){await r.mkdir(m,{recursive:!0});const t=await r.mkdtemp(a.join(m,"repo-")),i=await async function(e,t,i=process.cwd()){const m={"--single-branch":null};t.force||(m["--depth"]=1);t.branch&&(m["--branch"]=t.branch);try{await c(i).clone(t.dest,e,m)}catch{delete m["--branch"],delete m["--single-branch"],await c(i).clone(t.dest,e,m),c(e).checkout(["-b",t.branch])}d.debug(`Cloned destination repo on ${e}`);const l=c(e),g=await l.log(),[p,h]=function(e){if(0===e.all.length)return d.debug("No commit history"),[];for(const t of e.all){const[e,...i]=t.message.replaceAll(/[()]/g,"").split(/[\s/]/);if("sync"===e&&i.length>0)return[t.message,i.at(-1)]}return d.debug(`No sync commit: ${e.all[0].message}`),[]}(g);if(h)d.debug(`Extracted a valid commit: ${h}`),d.debug(`(${p})`);else if(!t.force)return d.error("No valid commit in destination repo"),!1;const u=c(i);let f;try{f=await u.log(h?{from:h,to:"HEAD","--first-parent":void 0}:void 0)}catch(e){return d.error(`Failed to get source commit history: ${e.stack}`),!1}const b=f.latest?.hash;if(!b)return d.info("No synchronizable commit"),!0;const[y,w]=await Promise.all([r.readdir(e),r.readdir(i)]),v=[...new Set([...t["ignore-patterns"].map(String),".git"])];for(const t of n.not(y,v))await r.rm(a.join(e,t),{recursive:!0,force:!0});for(const t of n.not(w,v))await s(a.join(i,t),a.join(e,t));await l.add("-A");let $="";if(t["tag-hash"]||t["tag-version"]){const e="git describe --tags --always "+(t["tag-version"]?"--abbrev=0":"");$=o.execSync(e,{cwd:i}).toString().trim()}let x=t.prefix??await async function(e){const t=(await e.getRemotes(!0)).find((e=>"origin"===e.name)),i=t?.refs?.fetch??t?.refs?.push;if("string"==typeof i&&i.includes("github.com")){const e=i.split("/"),t=e.at(-2),o=e.at(-1)?.replace(/.git$/,"");if(t&&o)return`https://github.com/${t}/${o}/commits`}}(u)??"";x&&!x.endsWith("/")&&(x+="/");const k=`${x}${b}`,S=$?`sync ${$} (${k})`:`sync ${k}`,j=h?f.all.map((e=>`* ${e.message}`)).join("\n\n"):`Replace all the files with those of ${t.dest} due to missing sync commit.`;try{await l.commit(`${S}\n\n${j}`),d.debug(`Created a commit: ${S}`),d.debug(` with body: ${j}`)}catch(e){return d.error(`Failed to commit changes: ${e.stack}`),!1}const A=$||t.tag;if(A)try{await l.addTag(A),d.debug(`Created a tag: ${A}`)}catch{d.warn(`Failed to create a tag: ${A}`)}if(t.dry)return d.debug("Finished dry run"),!0;try{await(t.branch?l.push("origin",t.branch):l.push()),A&&await l.push({"--tags":null})}catch(e){return d.error(`Failed to push the commit: ${e.stack}`),!1}return d.debug("Pushed the commit"),!0}(t,e);process.exit(i?0:1)}(g);
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/logger.ts","../src/sync.ts","../src/yargsOptions.ts","../src/index.ts","../src/gitHub.ts"],"sourcesContent":["import { createLogger, format, transports } from 'winston';\n\nexport const logger = createLogger({\n transports: [\n new transports.Console({\n format: format.cli({ colors: { error: 'red' } }),\n }),\n ],\n});\n","import child_process from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { copy } from 'fs-extra';\nimport micromatch from 'micromatch';\nimport type { LogResult, TaskOptions, SimpleGit, Options } from 'simple-git';\nimport { simpleGit } from 'simple-git';\nimport type { InferredOptionTypes } from 'yargs';\n\nimport { getGitHubCommitsUrl } from './gitHub.js';\nimport { logger } from './logger.js';\nimport type { yargsOptions } from './yargsOptions.js';\n\nconst syncDirPath = path.join('node_modules', '.temp', 'sync-git-repo');\n\nexport async function sync(opts: InferredOptionTypes<typeof yargsOptions>): Promise<void> {\n await fs.mkdir(syncDirPath, { recursive: true });\n const dirPath = await fs.mkdtemp(path.join(syncDirPath, 'repo-'));\n const ret = await syncCore(dirPath, opts);\n // await fs.rm(dirPath, { recursive: true, force: true });\n process.exit(ret ? 0 : 1);\n}\n\nasync function syncCore(destRepoPath: string, opts: InferredOptionTypes<typeof yargsOptions>): Promise<boolean> {\n // eslint-disable-next-line unicorn/no-null\n const cloneOpts: Options = { '--single-branch': null };\n if (!opts.force) {\n cloneOpts['--depth'] = 1;\n }\n if (opts.branch) {\n cloneOpts['--branch'] = opts.branch;\n }\n try {\n await simpleGit().clone(opts.dest, destRepoPath, cloneOpts);\n } catch {\n delete cloneOpts['--branch'];\n delete cloneOpts['--single-branch'];\n await simpleGit().clone(opts.dest, destRepoPath, cloneOpts);\n simpleGit(destRepoPath).checkout(['-b', opts.branch] as TaskOptions);\n }\n logger.verbose(`Cloned destination repo on ${destRepoPath}`);\n\n const dstGit: SimpleGit = simpleGit(destRepoPath);\n const dstLog = await dstGit.log();\n\n const [head, from] = extractCommitHash(dstLog);\n if (from) {\n logger.verbose(`Extracted a valid commit: ${from}`);\n logger.verbose(`(${head})`);\n } else if (!opts.force) {\n logger.error('No valid commit in destination repo');\n return false;\n }\n\n const srcGit: SimpleGit = simpleGit();\n let srcLog: LogResult;\n try {\n // '--first-parent' hides children commits of merge commits\n srcLog = await srcGit.log(from ? { from, to: 'HEAD', '--first-parent': undefined } : undefined);\n } catch (error) {\n logger.error(`Failed to get source commit history: ${(error as Error).stack}`);\n return false;\n }\n\n const latestHash = srcLog.latest?.hash;\n if (!latestHash) {\n logger.info('No synchronizable commit');\n return true;\n }\n\n const [destFiles, srcFiles] = await Promise.all([fs.readdir(destRepoPath), fs.readdir('.')]);\n for (const destFile of micromatch.not(destFiles, opts['ignore-patterns'])) {\n await fs.rm(path.join(destRepoPath, destFile), { recursive: true, force: true });\n }\n for (const srcFile of micromatch.not(srcFiles, opts['ignore-patterns'])) {\n await copy(srcFile, path.join(destRepoPath, srcFile));\n }\n await dstGit.add('-A');\n\n let srcTag = '';\n if (opts['tag-hash'] || opts['tag-version']) {\n // e.g. `--abbrev=0` changes `v1.31.5-2-gcdde507` to `v1.31.5`\n const describeCommand = `git describe --tags --always ${opts['tag-version'] ? '--abbrev=0' : ''}`;\n srcTag = child_process.execSync(describeCommand).toString().trim();\n }\n let prefix = opts.prefix ?? (await getGitHubCommitsUrl(srcGit)) ?? '';\n if (prefix && !prefix.endsWith('/')) {\n prefix += '/';\n }\n const link = `${prefix}${latestHash}`;\n const title = srcTag ? `sync ${srcTag} (${link})` : `sync ${link}`;\n const body = from\n ? srcLog.all.map((l) => `* ${l.message}`).join('\\n\\n')\n : `Replace all the files with those of ${opts.dest} due to missing sync commit.`;\n try {\n await dstGit.commit(`${title}\\n\\n${body}`);\n logger.verbose(`Created a commit: ${title}`);\n logger.verbose(` with body: ${body}`);\n } catch (error) {\n logger.error(`Failed to commit changes: ${(error as Error).stack}`);\n return false;\n }\n\n const destTag = srcTag || opts.tag;\n if (destTag) {\n try {\n await dstGit.addTag(destTag);\n logger.verbose(`Created a tag: ${destTag}`);\n } catch {\n // Ignore the error since `--abbrev=0` may yield a tag that already exists\n logger.warn(`Failed to create a tag: ${destTag}`);\n }\n }\n\n if (opts.dry) {\n logger.verbose('Finished dry run');\n return true;\n }\n\n try {\n await (opts.branch ? dstGit.push('origin', opts.branch) : dstGit.push());\n if (destTag) {\n // eslint-disable-next-line unicorn/no-null\n await dstGit.push({ '--tags': null });\n }\n } catch (error) {\n logger.error(`Failed to push the commit: ${(error as Error).stack}`);\n return false;\n }\n\n logger.verbose('Pushed the commit');\n return true;\n}\n\nfunction extractCommitHash(logResult: LogResult): [string, string] | [] {\n if (logResult.all.length === 0) {\n logger.verbose('No commit history');\n return [];\n }\n\n for (const log of logResult.all) {\n const [head, ...words] = log.message.replaceAll(/[()]/g, '').split(/[\\s/]/);\n if (head === 'sync' && words.length > 0) {\n return [log.message, words.at(-1) as string];\n }\n }\n logger.verbose(`No sync commit: ${logResult.all[0].message}`);\n return [];\n}\n","export const yargsOptions = {\n dest: {\n type: 'string',\n alias: 'd',\n describe: 'A URL of a destination git repository.',\n demand: true,\n },\n prefix: {\n type: 'string',\n alias: 'p',\n describe: `A prefix of a commit hash used to generate a commit title, e.g. 'sync <prefix>/<hash>'.\n A typical value is like 'https://github.com/WillBooster/one-way-git-sync/commits'`,\n },\n branch: {\n type: 'string',\n alias: 'b',\n describe: 'Specify branch of destination repo.',\n },\n tag: {\n type: 'string',\n alias: 't',\n describe: 'Specify tag to be created in destination repo.',\n },\n 'tag-hash': {\n type: 'boolean',\n describe: 'Create version+hash tag (e.g. v1.31.5-2-gcdde507). It should be a unique tag.',\n },\n 'tag-version': {\n type: 'boolean',\n describe: 'Create version tag (e.g. v1.31.5). It could be a non-unique tag.',\n },\n 'ignore-patterns': {\n type: 'string',\n alias: 'i',\n describe: `Exclude the files whose path matches one of the given patterns.\n The patterns are processed by micromatch (https://github.com/micromatch/micromatch).\n You may specify the option multiple times. Default value is \"-i .git -i .github -i node_modules -i '.renovaterc.*'\"`,\n default: ['.git', '.github', 'node_modules', '.renovaterc.*'],\n },\n dry: {\n type: 'boolean',\n describe: 'Enable dry-run mode.',\n },\n force: {\n type: 'boolean',\n describe: 'Force to overwrite the destination git repository.',\n },\n verbose: {\n type: 'boolean',\n alias: 'v',\n describe: 'Show details logs.',\n },\n} as const;\n","import { hideBin } from 'yargs/helpers';\nimport yargs from 'yargs/yargs';\n\nimport { logger } from './logger.js';\nimport { sync } from './sync.js';\nimport { yargsOptions } from './yargsOptions.js';\n\nconst argv = await yargs(hideBin(process.argv))\n .scriptName('one-way-git-sync')\n .options(yargsOptions)\n .middleware((argv) => {\n logger.level = argv.verbose ? 'verbose' : 'info';\n })\n .strict()\n .help().argv;\nawait sync(argv);\n","import type { SimpleGit } from 'simple-git';\n\nexport async function getGitHubCommitsUrl(git: SimpleGit): Promise<string | undefined> {\n const remotes = await git.getRemotes(true);\n const origin = remotes.find((r) => r.name === 'origin');\n const remoteUrl = origin?.refs?.fetch ?? origin?.refs?.push;\n if (typeof remoteUrl === 'string' && remoteUrl.includes('github.com')) {\n const words = remoteUrl.split('/');\n const org = words.at(-2);\n const name = words.at(-1)?.replace(/.git$/, '');\n if (org && name) return `https://github.com/${org}/${name}/commits`;\n }\n}\n"],"names":["logger","createLogger","transports","Console","format","cli","colors","error","syncDirPath","path","join","yargsOptions","dest","type","alias","describe","demand","prefix","branch","tag","default","dry","force","verbose","argv","yargs","hideBin","process","scriptName","options","middleware","level","strict","help","async","opts","fs","mkdir","recursive","dirPath","mkdtemp","ret","destRepoPath","cloneOpts","simpleGit","clone","checkout","dstGit","dstLog","log","head","from","logResult","all","length","words","message","replaceAll","split","at","extractCommitHash","srcGit","srcLog","to","undefined","stack","latestHash","latest","hash","info","destFiles","srcFiles","Promise","readdir","destFile","micromatch","not","rm","srcFile","copy","add","srcTag","describeCommand","child_process","execSync","toString","trim","git","origin","getRemotes","find","r","name","remoteUrl","refs","fetch","push","includes","org","replace","getGitHubCommitsUrl","endsWith","link","title","body","map","l","commit","destTag","addTag","warn","syncCore","exit","sync"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/logger.ts","../src/sync.ts","../src/yargsOptions.ts","../src/index.ts","../src/gitHub.ts"],"sourcesContent":["import { pino } from 'pino';\n\nexport const logger = pino({\n transport: {\n target: 'pino-pretty',\n options: {\n colorize: true,\n },\n },\n});\n","import child_process from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { copy } from 'fs-extra';\nimport micromatch from 'micromatch';\nimport type { LogResult, Options, SimpleGit, TaskOptions } from 'simple-git';\nimport { simpleGit } from 'simple-git';\nimport type { InferredOptionTypes } from 'yargs';\n\nimport { getGitHubCommitsUrl } from './gitHub.js';\nimport { logger } from './logger.js';\nimport type { yargsOptions } from './yargsOptions.js';\n\nconst syncDirPath = path.join('node_modules', '.temp', 'sync-git-repo');\n\nexport type YargsOptions = InferredOptionTypes<typeof yargsOptions>;\n\nexport async function sync(opts: YargsOptions): Promise<void> {\n await fs.mkdir(syncDirPath, { recursive: true });\n const dirPath = await fs.mkdtemp(path.join(syncDirPath, 'repo-'));\n const ret = await syncCore(dirPath, opts);\n // await fs.rm(dirPath, { recursive: true, force: true });\n process.exit(ret ? 0 : 1);\n}\n\nexport async function syncCore(\n destRepoPath: string,\n opts: YargsOptions,\n srcRepoPath = process.cwd()\n): Promise<boolean> {\n // eslint-disable-next-line unicorn/no-null\n const cloneOpts: Options = { '--single-branch': null };\n if (!opts.force) {\n cloneOpts['--depth'] = 1;\n }\n if (opts.branch) {\n cloneOpts['--branch'] = opts.branch;\n }\n try {\n await simpleGit(srcRepoPath).clone(opts.dest, destRepoPath, cloneOpts);\n } catch {\n delete cloneOpts['--branch'];\n delete cloneOpts['--single-branch'];\n await simpleGit(srcRepoPath).clone(opts.dest, destRepoPath, cloneOpts);\n simpleGit(destRepoPath).checkout(['-b', opts.branch] as TaskOptions);\n }\n logger.debug(`Cloned destination repo on ${destRepoPath}`);\n\n const dstGit: SimpleGit = simpleGit(destRepoPath);\n const dstLog = await dstGit.log();\n\n const [head, from] = extractCommitHash(dstLog);\n if (from) {\n logger.debug(`Extracted a valid commit: ${from}`);\n logger.debug(`(${head})`);\n } else if (!opts.force) {\n logger.error('No valid commit in destination repo');\n return false;\n }\n\n const srcGit: SimpleGit = simpleGit(srcRepoPath);\n let srcLog: LogResult;\n try {\n // '--first-parent' hides children commits of merge commits\n srcLog = await srcGit.log(from ? { from, to: 'HEAD', '--first-parent': undefined } : undefined);\n } catch (error) {\n logger.error(`Failed to get source commit history: ${(error as Error).stack}`);\n return false;\n }\n\n const latestHash = srcLog.latest?.hash;\n if (!latestHash) {\n logger.info('No synchronizable commit');\n return true;\n }\n\n const [destFiles, srcFiles] = await Promise.all([fs.readdir(destRepoPath), fs.readdir(srcRepoPath)]);\n // Force to ignore .git directory\n const ignorePatterns = [...new Set([...opts['ignore-patterns'].map(String), '.git'])];\n for (const destFile of micromatch.not(destFiles, ignorePatterns)) {\n await fs.rm(path.join(destRepoPath, destFile), { recursive: true, force: true });\n }\n for (const srcFile of micromatch.not(srcFiles, ignorePatterns)) {\n await copy(path.join(srcRepoPath, srcFile), path.join(destRepoPath, srcFile));\n }\n await dstGit.add('-A');\n\n let srcTag = '';\n if (opts['tag-hash'] || opts['tag-version']) {\n // e.g. `--abbrev=0` changes `v1.31.5-2-gcdde507` to `v1.31.5`\n const describeCommand = `git describe --tags --always ${opts['tag-version'] ? '--abbrev=0' : ''}`;\n srcTag = child_process.execSync(describeCommand, { cwd: srcRepoPath }).toString().trim();\n }\n let prefix = opts.prefix ?? (await getGitHubCommitsUrl(srcGit)) ?? '';\n if (prefix && !prefix.endsWith('/')) {\n prefix += '/';\n }\n const link = `${prefix}${latestHash}`;\n const title = srcTag ? `sync ${srcTag} (${link})` : `sync ${link}`;\n const body = from\n ? srcLog.all.map((l) => `* ${l.message}`).join('\\n\\n')\n : `Replace all the files with those of ${opts.dest} due to missing sync commit.`;\n try {\n await dstGit.commit(`${title}\\n\\n${body}`);\n logger.debug(`Created a commit: ${title}`);\n logger.debug(` with body: ${body}`);\n } catch (error) {\n logger.error(`Failed to commit changes: ${(error as Error).stack}`);\n return false;\n }\n\n const destTag = srcTag || opts.tag;\n if (destTag) {\n try {\n await dstGit.addTag(destTag);\n logger.debug(`Created a tag: ${destTag}`);\n } catch {\n // Ignore the error since `--abbrev=0` may yield a tag that already exists\n logger.warn(`Failed to create a tag: ${destTag}`);\n }\n }\n\n if (opts.dry) {\n logger.debug('Finished dry run');\n return true;\n }\n\n try {\n await (opts.branch ? dstGit.push('origin', opts.branch) : dstGit.push());\n if (destTag) {\n // eslint-disable-next-line unicorn/no-null\n await dstGit.push({ '--tags': null });\n }\n } catch (error) {\n logger.error(`Failed to push the commit: ${(error as Error).stack}`);\n return false;\n }\n\n logger.debug('Pushed the commit');\n return true;\n}\n\nfunction extractCommitHash(logResult: LogResult): [string, string] | [] {\n if (logResult.all.length === 0) {\n logger.debug('No commit history');\n return [];\n }\n\n for (const log of logResult.all) {\n const [head, ...words] = log.message.replaceAll(/[()]/g, '').split(/[\\s/]/);\n if (head === 'sync' && words.length > 0) {\n return [log.message, words.at(-1) as string];\n }\n }\n logger.debug(`No sync commit: ${logResult.all[0].message}`);\n return [];\n}\n","export const yargsOptions = {\n dest: {\n type: 'string',\n alias: 'd',\n describe: 'A URL of a destination git repository.',\n demand: true,\n },\n prefix: {\n type: 'string',\n alias: 'p',\n describe: `A prefix of a commit hash used to generate a commit title, e.g. 'sync <prefix>/<hash>'.\n A typical value is like 'https://github.com/WillBooster/one-way-git-sync/commits'`,\n },\n branch: {\n type: 'string',\n alias: 'b',\n describe: 'Specify branch of destination repo.',\n },\n tag: {\n type: 'string',\n alias: 't',\n describe: 'Specify tag to be created in destination repo.',\n },\n 'tag-hash': {\n type: 'boolean',\n describe: 'Create version+hash tag (e.g. v1.31.5-2-gcdde507). It should be a unique tag.',\n },\n 'tag-version': {\n type: 'boolean',\n describe: 'Create version tag (e.g. v1.31.5). It could be a non-unique tag.',\n },\n 'ignore-patterns': {\n type: 'array',\n alias: 'i',\n describe: `Exclude the files whose path matches one of the given patterns.\n The patterns are processed by micromatch (https://github.com/micromatch/micromatch).\n You may specify the option multiple times. Default value is \"-i .git -i .github -i node_modules -i '.renovaterc.*'\"`,\n default: ['.git', '.github', 'node_modules', '.renovaterc.*'],\n },\n dry: {\n type: 'boolean',\n describe: 'Enable dry-run mode.',\n },\n force: {\n type: 'boolean',\n describe: 'Force to overwrite the destination git repository.',\n },\n verbose: {\n type: 'boolean',\n alias: 'v',\n describe: 'Show details logs.',\n },\n} as const;\n","import { hideBin } from 'yargs/helpers';\nimport yargs from 'yargs/yargs';\n\nimport { logger } from './logger.js';\nimport { sync } from './sync.js';\nimport { yargsOptions } from './yargsOptions.js';\n\nconst argv = await yargs(hideBin(process.argv))\n .scriptName('one-way-git-sync')\n .options(yargsOptions)\n .middleware((argv) => {\n logger.level = argv.verbose ? 'verbose' : 'info';\n })\n .strict()\n .help().argv;\nawait sync(argv);\n","import type { SimpleGit } from 'simple-git';\n\nexport async function getGitHubCommitsUrl(git: SimpleGit): Promise<string | undefined> {\n const remotes = await git.getRemotes(true);\n const origin = remotes.find((r) => r.name === 'origin');\n const remoteUrl = origin?.refs?.fetch ?? origin?.refs?.push;\n if (typeof remoteUrl === 'string' && remoteUrl.includes('github.com')) {\n const words = remoteUrl.split('/');\n const org = words.at(-2);\n const name = words.at(-1)?.replace(/.git$/, '');\n if (org && name) return `https://github.com/${org}/${name}/commits`;\n }\n}\n"],"names":["logger","pino","transport","target","options","colorize","syncDirPath","path","join","yargsOptions","dest","type","alias","describe","demand","prefix","branch","tag","default","dry","force","verbose","argv","yargs","hideBin","process","scriptName","middleware","level","strict","help","async","opts","fs","mkdir","recursive","dirPath","mkdtemp","ret","destRepoPath","srcRepoPath","cwd","cloneOpts","simpleGit","clone","checkout","debug","dstGit","dstLog","log","head","from","logResult","all","length","words","message","replaceAll","split","at","extractCommitHash","error","srcGit","srcLog","to","undefined","stack","latestHash","latest","hash","info","destFiles","srcFiles","Promise","readdir","ignorePatterns","Set","map","String","destFile","micromatch","not","rm","srcFile","copy","add","srcTag","describeCommand","child_process","execSync","toString","trim","git","origin","getRemotes","find","r","name","remoteUrl","refs","fetch","push","includes","org","replace","getGitHubCommitsUrl","endsWith","link","title","body","l","commit","destTag","addTag","warn","syncCore","exit","sync"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "one-way-git-sync",
3
- "version": "6.0.2",
3
+ "version": "6.0.3",
4
4
  "description": "A tool for synchronizing a destination git repository with a source git repository SAFELY.",
5
5
  "keywords": [
6
6
  "git",
@@ -28,27 +28,29 @@
28
28
  "release": "yarn build && semantic-release",
29
29
  "start": "build-ts run src/index.ts",
30
30
  "start-prod": "yarn build && yarn one-way-git-sync",
31
+ "test": "vitest --poolOptions.threads.singleThread",
31
32
  "typecheck": "tsc --noEmit --Pretty"
32
33
  },
33
34
  "prettier": "@willbooster/prettier-config",
34
35
  "dependencies": {
35
36
  "fs-extra": "11.2.0",
36
37
  "micromatch": "4.0.5",
37
- "simple-git": "3.22.0",
38
- "winston": "3.12.0",
38
+ "pino": "8.20.0",
39
+ "pino-pretty": "11.0.0",
40
+ "simple-git": "3.24.0",
39
41
  "yargs": "17.7.2"
40
42
  },
41
43
  "devDependencies": {
42
- "@types/eslint": "8.56.5",
44
+ "@types/eslint": "8.56.10",
43
45
  "@types/fs-extra": "11.0.4",
44
- "@types/micromatch": "4.0.6",
46
+ "@types/micromatch": "4.0.7",
45
47
  "@types/semantic-release": "20.0.6",
46
48
  "@types/yargs": "17.0.32",
47
- "@typescript-eslint/eslint-plugin": "7.1.1",
48
- "@typescript-eslint/parser": "7.1.1",
49
+ "@typescript-eslint/eslint-plugin": "7.7.0",
50
+ "@typescript-eslint/parser": "7.7.0",
49
51
  "@willbooster/eslint-config-ts": "10.5.1",
50
52
  "@willbooster/prettier-config": "9.1.2",
51
- "build-ts": "12.0.10",
53
+ "build-ts": "13.0.4",
52
54
  "conventional-changelog-conventionalcommits": "7.0.2",
53
55
  "eslint": "8.57.0",
54
56
  "eslint-config-prettier": "9.1.0",
@@ -56,14 +58,15 @@
56
58
  "eslint-plugin-import": "2.29.1",
57
59
  "eslint-plugin-sort-class-members": "1.20.0",
58
60
  "eslint-plugin-sort-destructure-keys": "1.5.0",
59
- "eslint-plugin-unicorn": "51.0.1",
61
+ "eslint-plugin-unicorn": "52.0.0",
60
62
  "husky": "9.0.11",
61
63
  "lint-staged": "15.2.2",
62
64
  "pinst": "3.0.0",
63
65
  "prettier": "3.2.5",
64
- "semantic-release": "23.0.2",
65
- "sort-package-json": "2.8.0",
66
- "typescript": "5.4.2"
66
+ "semantic-release": "23.0.8",
67
+ "sort-package-json": "2.10.0",
68
+ "typescript": "5.4.5",
69
+ "vitest": "1.5.0"
67
70
  },
68
71
  "packageManager": "yarn@4.1.1",
69
72
  "engines": {