Skip to content

Commit

Permalink
Find merge base by progressively deepening history
Browse files Browse the repository at this point in the history
  • Loading branch information
lerebear committed Dec 29, 2023
1 parent 7037589 commit 46da167
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 54 deletions.
7 changes: 6 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ inputs:
token:
description: 'GitHub API token with read permissions for pull requests in this repository.'
required: true
fetch-depth:
description: |
Number of commits to fetch each time we need to deepen git history in order to find the
merge base between the head ref and the base ref of the pull request
default: 10
git-diff-args:
description: |
Optional custom arguments to forward to `git diff` when retrieving the diff of the pull request that triggered this workflow.
Custom arguments to forward to `git diff` when retrieving the diff of the pull request that triggered this workflow.
The result of that `git diff` command will be used for evaluation with sizeup.
default: '--ignore-space-change'
configuration-file-path:
Expand Down
2 changes: 1 addition & 1 deletion badges/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 37 additions & 25 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 44 additions & 27 deletions src/initializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,48 +35,65 @@ export function loadConfiguration(): Configuration {
*/
export async function fetchDiff(pull: PullRequest): Promise<string> {
const git = simpleGit('.', { trimmed: true })
const diffArgs = ['--merge-base', `origin/${pull.base.ref}`].concat(
core.getInput('git-diff-args').split(/\s+/)
)
const fetchDepth = parseInt(core.getInput('fetch-depth'))

core.info(`Retrieving diff with \`git diff ${diffArgs.join(' ')}\``)
core.debug(
`Fetching base ref "${pull.base.ref}" and head ref "${pull.head.ref}" with depth ${fetchDepth}`
)

// Fetch all commits for the head branch back to where it diverged from the base.
core.debug(`Fetching ${pull.commits + 1} commits for ${pull.head.ref}`)
await git.fetch([
'origin',
`+${pull.base.ref}:${pull.base.ref}`,
`+${pull.head.ref}:${pull.head.ref}`,
`--depth=${pull.commits + 1}`,
`--depth=${fetchDepth}`,
'--no-tags',
'--prune',
'--no-recurse-submodules'
])

core.debug(`Switching to branch ${pull.head.ref}`)
core.debug(`Switching to head ref "${pull.head.ref}"`)
await git.raw('switch', pull.head.ref)

// Fetch commits for the base branch that were made since the head diverged from it.
const divergedFrom = await git.raw('rev-list', '--max-parents=0', 'HEAD')
const divergedAt = await git.show([
'--quiet',
'--date=unix',
'--format=%cd',
divergedFrom
])
core.info(
`Searching for merge base between "${pull.base.ref}" and "${pull.head.ref}"`
)
let mergeBase = ''
let fetches = 0
while (mergeBase) {
try {
mergeBase = await git.raw('merge-base', pull.base.ref, pull.head.ref)
core.info(`Found merge base: ${mergeBase}`)
} catch (e) {
if (fetches === 0) {
core.debug(`git merge-base error: ${(e as Error).message}`)
core.info('Deepening git history in search of merge base')
} else if (fetches % 10 === 0) {
core.debug(`git merge-base error: ${(e as Error).message}`)
core.info(`Still searching for merge base after ${fetches} fetches`)
}
fetches++
await git.fetch([
'origin',
pull.base.ref,
pull.head.ref,
`--deepen=${fetchDepth}`,
'--no-tags',
'--prune',
'--no-recurse-modules'
])
}
}

core.debug(
`Retrieving history for origin/${pull.base.ref} since ${divergedFrom} which was committed at ${divergedAt}`
`Performed ${fetches} fetch${
fetches === 1 ? '' : 'es'
} to find the merge base`
)
await git.fetch([
'origin',
`+${pull.base.ref}:${pull.base.ref}`,
`--shallow-since=${divergedAt}`,
'--no-tags',
'--prune',
'--no-recurse-submodules'
])

// Now we have all relevant history from both base and head branches, so we
// can compute an accurate diff relative to the base branch.
const diffArgs = ['--merge-base', pull.base.ref].concat(
core.getInput('git-diff-args').split(/\s+/)
)
core.info(`Retrieving diff with \`git diff ${diffArgs.join(' ')}\``)
return git.diff(diffArgs)
}

Expand Down

0 comments on commit 46da167

Please sign in to comment.