Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix change detection when base is a tag #78

Merged
merged 5 commits into from Mar 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -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
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
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
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