Last active
October 22, 2020 07:47
-
-
Save chalkygames123/d04e699975ac4f70d6438be85409973e to your computer and use it in GitHub Desktop.
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
/* eslint-disable no-console, no-continue */ | |
/* eslint 'import/no-extraneous-dependencies': ['error', { optionalDependencies: false }] */ | |
const { execSync } = require('child_process') | |
const { dirname } = require('path') | |
function convertFilesToTree(files) { | |
const tree = {} | |
const dirs = [...new Set(files.map((file) => dirname(file)))] | |
dirs.forEach((dir) => { | |
tree[dir] = files.filter((file) => dirname(file) === dir) | |
}) | |
return tree | |
} | |
function compareTrees(leftTree, rightTree) { | |
return Object.entries(leftTree).flatMap(([leftDir, leftFiles]) => { | |
if (leftDir === '.') { | |
return leftFiles | |
} | |
const rightBranch = Object.entries(rightTree).find( | |
([rightDir]) => rightDir === leftDir | |
) | |
if (!rightBranch) { | |
console.debug( | |
'DEBUG: 新規ディレクトリに子ファイルが追加された: %O', | |
leftDir | |
) | |
return `${leftDir}/*` | |
} | |
const [, rightFiles] = rightBranch | |
if (rightFiles.every((rightFile) => leftFiles.includes(rightFile))) { | |
console.debug( | |
'DEBUG: 既存ディレクトリの子ファイルが完全に変更された: %O', | |
leftDir | |
) | |
return `${leftDir}/*` | |
} | |
console.debug( | |
'DEBUG: 既存ディレクトリの子ファイルが部分的に変更された: %O', | |
leftDir | |
) | |
return leftFiles | |
}) | |
} | |
function dedupeChanges(originalChanges, repoTree) { | |
const changes = [] | |
for (let i = 0; i < originalChanges.length; i += 1) { | |
const originalChange = originalChanges[i] | |
if (!originalChange.endsWith('/*')) { | |
console.debug( | |
'DEBUG: 一部の子が変更された (i = %d): %O', | |
i, | |
originalChange | |
) | |
changes.push(originalChange) | |
continue | |
} | |
const descendantChanges = originalChanges | |
.filter((el) => el.startsWith(dirname(originalChange))) | |
.slice(1) | |
const descendantsRepoDirs = Object.keys(repoTree) | |
.filter((el) => el.startsWith(dirname(originalChange))) | |
.slice(1) | |
if ( | |
descendantChanges.every((el) => el.endsWith('/*')) && | |
descendantChanges.length === descendantsRepoDirs.length && | |
descendantChanges.every( | |
(el, i2) => dirname(el) === descendantsRepoDirs[i2] | |
) | |
) { | |
console.debug( | |
'DEBUG: 全ての子孫が変更された (i = %d): %O', | |
i, | |
originalChange | |
) | |
changes.push(originalChange) | |
i += descendantChanges.length | |
continue | |
} | |
const [, repoFiles] = Object.entries(repoTree).find( | |
([repoDir]) => repoDir === dirname(originalChange) | |
) | |
console.debug( | |
'DEBUG: 一部の子孫が変更された (i = %d): %O', | |
i, | |
originalChange | |
) | |
changes.push(...repoFiles) | |
} | |
return changes | |
} | |
try { | |
{ | |
const dirty = execSync('git status --short', { | |
encoding: 'utf8', | |
}) | |
if (dirty) { | |
throw new Error('The working tree is not clean') | |
} | |
} | |
{ | |
const currentBranch = execSync('git branch --show-current', { | |
encoding: 'utf8', | |
}).trim() | |
if (currentBranch !== 'develop') { | |
throw new Error('The current branch is not "develop"') | |
} | |
} | |
execSync('git checkout release', { | |
stdio: 'inherit', | |
}) | |
{ | |
const mergeResult = execSync('git merge --no-edit develop', { | |
encoding: 'utf8', | |
}).trim() | |
if (mergeResult === 'Already up to date.') { | |
throw new Error('Already up to date.') | |
} | |
console.log(mergeResult) | |
} | |
execSync('yarn', { | |
stdio: 'inherit', | |
}) | |
execSync('yarn build', { | |
stdio: 'inherit', | |
}) | |
execSync('git add dist/', { | |
stdio: 'inherit', | |
}) | |
const indexTree = convertFilesToTree( | |
execSync( | |
'git diff --staged --name-only --diff-filter=d --relative=dist/ -- dist/', | |
{ | |
encoding: 'utf8', | |
} | |
) | |
.trim() | |
.split('\n') | |
) | |
console.debug('DEBUG: indexTree: %O', indexTree) | |
if ( | |
Object.keys(indexTree).length === 1 && | |
Object.values(indexTree).length === 1 && | |
Object.values(indexTree)[0][0] === '' | |
) { | |
throw new Error('There are no changes to commit') | |
} | |
const repoTree = convertFilesToTree( | |
execSync('git ls-tree -r --name-only HEAD -- dist/', { | |
encoding: 'utf8', | |
}) | |
.trim() | |
.split('\n') | |
.map((file) => file.replace('dist/', '')) | |
) | |
console.debug('DEBUG: repoTree: %O', repoTree) | |
const changes = compareTrees(indexTree, repoTree) | |
console.debug('DEBUG: changes: %O', changes) | |
const dedupedChanges = dedupeChanges(changes, repoTree) | |
console.debug('DEBUG: dedupedChanges: %O', dedupedChanges) | |
{ | |
const commitTitle = 'Release by automation script' | |
const commitDescription = `Changes:\n${dedupedChanges.join('\n')}` | |
execSync( | |
`git commit --message="${commitTitle}" --message="${commitDescription}" --no-verify`, | |
{ | |
stdio: 'inherit', | |
} | |
) | |
} | |
execSync('git checkout -', { | |
stdio: 'inherit', | |
}) | |
} catch (error) { | |
console.error(error) | |
process.exitCode = 1 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment