Skip to content

Instantly share code, notes, and snippets.

@chalkygames123
Last active October 22, 2020 07:47
Show Gist options
  • Save chalkygames123/d04e699975ac4f70d6438be85409973e to your computer and use it in GitHub Desktop.
Save chalkygames123/d04e699975ac4f70d6438be85409973e to your computer and use it in GitHub Desktop.
/* 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