Skip to content

Commit

Permalink
Merge pull request #78 from dorny/issue-77-tag-as-base-broken
Browse files Browse the repository at this point in the history
Fix change detection when base is a tag
  • Loading branch information
dorny authored Mar 25, 2021
2 parents ca8fa40 + 5d414b8 commit ad1ae68
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## v2.9.3
- [Fix change detection when base is a tag](https://github.com/dorny/paths-filter/pull/78)

## v2.9.2
- [Fix fetching git history](https://github.com/dorny/paths-filter/pull/75)

Expand Down
50 changes: 40 additions & 10 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3866,15 +3866,26 @@ async function getChangesOnHead() {
}
exports.getChangesOnHead = getChangesOnHead;
async function getChangesSinceMergeBase(base, ref, initialFetchDepth) {
const baseRef = `remotes/origin/${base}`;
let baseRef;
async function hasMergeBase() {
return (await exec_1.default('git', ['merge-base', baseRef, ref], { ignoreReturnCode: true })).code === 0;
return (baseRef !== undefined && (await exec_1.default('git', ['merge-base', baseRef, ref], { ignoreReturnCode: true })).code === 0);
}
let noMergeBase = false;
core.startGroup(`Searching for merge-base ${baseRef}...${ref}`);
core.startGroup(`Searching for merge-base ${base}...${ref}`);
try {
baseRef = await getFullRef(base);
if (!(await hasMergeBase())) {
await exec_1.default('git', ['fetch', `--depth=${initialFetchDepth}`, 'origin', base, ref]);
await exec_1.default('git', ['fetch', '--no-tags', `--depth=${initialFetchDepth}`, 'origin', base, ref]);
if (baseRef === undefined) {
baseRef = await getFullRef(base);
if (baseRef === undefined) {
await exec_1.default('git', ['fetch', '--tags', `--depth=1`, 'origin', base, ref]);
baseRef = await getFullRef(base);
if (baseRef === undefined) {
throw new Error(`Could not determine what is ${base} - fetch works but it's not a branch or tag`);
}
}
}
let depth = initialFetchDepth;
let lastCommitCount = await getCommitCount();
while (!(await hasMergeBase())) {
Expand All @@ -3897,16 +3908,17 @@ async function getChangesSinceMergeBase(base, ref, initialFetchDepth) {
finally {
core.endGroup();
}
let diffArg = `${baseRef}...${ref}`;
if (noMergeBase) {
core.warning('No merge base found - all files will be listed as added');
return await listAllFilesAsAdded();
core.warning('No merge base found - change detection will use direct <commit>..<commit> comparison');
diffArg = `${baseRef}..${ref}`;
}
// Get changes introduced on HEAD compared to ref
core.startGroup(`Change detection ${baseRef}...${ref}`);
// Get changes introduced on ref compared to base
core.startGroup(`Change detection ${diffArg}`);
let output = '';
try {
// Three dots '...' change detection - finds merge-base and compares against it
output = (await exec_1.default('git', ['diff', '--no-renames', '--name-status', '-z', `${baseRef}...${ref}`])).stdout;
output = (await exec_1.default('git', ['diff', '--no-renames', '--name-status', '-z', diffArg])).stdout;
}
finally {
fixStdOutNullTermination();
Expand Down Expand Up @@ -3994,6 +4006,24 @@ async function getCommitCount() {
const count = parseInt(output);
return isNaN(count) ? 0 : count;
}
async function getFullRef(shortName) {
if (isGitSha(shortName)) {
return shortName;
}
const output = (await exec_1.default('git', ['show-ref', shortName], { ignoreReturnCode: true })).stdout;
const refs = output
.split(/\r?\n/g)
.map(l => { var _a, _b; return (_b = (_a = l.match(/refs\/.*$/)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : ''; })
.filter(l => l !== '');
if (refs.length === 0) {
return undefined;
}
const remoteRef = refs.find(ref => ref.startsWith('refs/remotes/origin/'));
if (remoteRef) {
return remoteRef;
}
return refs[0];
}
function fixStdOutNullTermination() {
// Previous command uses NULL as delimiters and output is printed to stdout.
// We have to make sure next thing written to stdout will start on new line.
Expand Down Expand Up @@ -4743,7 +4773,7 @@ async function getChangedFilesFromGit(base, initialFetchDepth) {
return await git.getChanges(baseSha);
}
// Changes introduced by current branch against the base branch
core.info(`Changes will be detected against the branch ${baseRef}`);
core.info(`Changes will be detected against ${baseRef}`);
return await git.getChangesSinceMergeBase(baseRef, ref, initialFetchDepth);
}
// Uses github REST api to get list of files changed in PR
Expand Down
57 changes: 47 additions & 10 deletions src/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,30 @@ export async function getChangesOnHead(): Promise<File[]> {
}

export async function getChangesSinceMergeBase(base: string, ref: string, initialFetchDepth: number): Promise<File[]> {
const baseRef = `remotes/origin/${base}`

let baseRef: string | undefined
async function hasMergeBase(): Promise<boolean> {
return (await exec('git', ['merge-base', baseRef, ref], {ignoreReturnCode: true})).code === 0
return (
baseRef !== undefined && (await exec('git', ['merge-base', baseRef, ref], {ignoreReturnCode: true})).code === 0
)
}

let noMergeBase = false
core.startGroup(`Searching for merge-base ${baseRef}...${ref}`)
core.startGroup(`Searching for merge-base ${base}...${ref}`)
try {
baseRef = await getFullRef(base)
if (!(await hasMergeBase())) {
await exec('git', ['fetch', `--depth=${initialFetchDepth}`, 'origin', base, ref])
await exec('git', ['fetch', '--no-tags', `--depth=${initialFetchDepth}`, 'origin', base, ref])
if (baseRef === undefined) {
baseRef = await getFullRef(base)
if (baseRef === undefined) {
await exec('git', ['fetch', '--tags', `--depth=1`, 'origin', base, ref])
baseRef = await getFullRef(base)
if (baseRef === undefined) {
throw new Error(`Could not determine what is ${base} - fetch works but it's not a branch or tag`)
}
}
}

let depth = initialFetchDepth
let lastCommitCount = await getCommitCount()
while (!(await hasMergeBase())) {
Expand All @@ -88,17 +101,18 @@ export async function getChangesSinceMergeBase(base: string, ref: string, initia
core.endGroup()
}

let diffArg = `${baseRef}...${ref}`
if (noMergeBase) {
core.warning('No merge base found - all files will be listed as added')
return await listAllFilesAsAdded()
core.warning('No merge base found - change detection will use direct <commit>..<commit> comparison')
diffArg = `${baseRef}..${ref}`
}

// Get changes introduced on HEAD compared to ref
core.startGroup(`Change detection ${baseRef}...${ref}`)
// Get changes introduced on ref compared to base
core.startGroup(`Change detection ${diffArg}`)
let output = ''
try {
// Three dots '...' change detection - finds merge-base and compares against it
output = (await exec('git', ['diff', '--no-renames', '--name-status', '-z', `${baseRef}...${ref}`])).stdout
output = (await exec('git', ['diff', '--no-renames', '--name-status', '-z', diffArg])).stdout
} finally {
fixStdOutNullTermination()
core.endGroup()
Expand Down Expand Up @@ -188,6 +202,29 @@ async function getCommitCount(): Promise<number> {
return isNaN(count) ? 0 : count
}

async function getFullRef(shortName: string): Promise<string | undefined> {
if (isGitSha(shortName)) {
return shortName
}

const output = (await exec('git', ['show-ref', shortName], {ignoreReturnCode: true})).stdout
const refs = output
.split(/\r?\n/g)
.map(l => l.match(/refs\/.*$/)?.[0] ?? '')
.filter(l => l !== '')

if (refs.length === 0) {
return undefined
}

const remoteRef = refs.find(ref => ref.startsWith('refs/remotes/origin/'))
if (remoteRef) {
return remoteRef
}

return refs[0]
}

function fixStdOutNullTermination(): void {
// Previous command uses NULL as delimiters and output is printed to stdout.
// We have to make sure next thing written to stdout will start on new line.
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ async function getChangedFilesFromGit(base: string, initialFetchDepth: number):
}

// Changes introduced by current branch against the base branch
core.info(`Changes will be detected against the branch ${baseRef}`)
core.info(`Changes will be detected against ${baseRef}`)
return await git.getChangesSinceMergeBase(baseRef, ref, initialFetchDepth)
}

Expand Down

0 comments on commit ad1ae68

Please sign in to comment.