mirror of
https://gitea.com/actions/dorny-paths-filter.git
synced 2025-12-25 16:38:20 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87375a4a68 | ||
|
|
24a74833cc | ||
|
|
d0507d9a8a | ||
|
|
f093f3520b | ||
|
|
8d029eb508 | ||
|
|
07d6abdb9c | ||
|
|
e8f370c197 | ||
|
|
58ed00ec48 | ||
|
|
02eeef4973 | ||
|
|
37a6d38b2d | ||
|
|
208adf42c8 | ||
|
|
ad1ae68cd0 | ||
|
|
5d414b88ab | ||
|
|
a6989ad592 | ||
|
|
6d8169070c | ||
|
|
3d4a25053b | ||
|
|
e59197f91b |
@@ -4,7 +4,7 @@ on:
|
||||
paths-ignore: [ '*.md' ]
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- '**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## v2.10.0
|
||||
- [Add ref input parameter](https://github.com/dorny/paths-filter/pull/82)
|
||||
- [Fix change detection in PR when pullRequest.changed_files is incorrect](https://github.com/dorny/paths-filter/pull/83)
|
||||
|
||||
## 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)
|
||||
|
||||
|
||||
11
README.md
11
README.md
@@ -66,13 +66,11 @@ For more scenarios see [examples](#examples) section.
|
||||
|
||||
|
||||
# What's New
|
||||
- Add `ref` input parameter
|
||||
- Add `list-files: csv` format
|
||||
- Configure matrix job to run for each folder with changes using `changes` output
|
||||
- Improved listing of matching files with `list-files: shell` and `list-files: escape` options
|
||||
- Support local changes
|
||||
- Fixed retrieval of all changes via Github API when there are 100+ changes
|
||||
- Paths expressions are now evaluated using [picomatch](https://github.com/micromatch/picomatch) library
|
||||
- Support workflows triggered by any event
|
||||
|
||||
For more information see [CHANGELOG](https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md)
|
||||
|
||||
@@ -111,6 +109,13 @@ For more information see [CHANGELOG](https://github.com/dorny/paths-filter/blob/
|
||||
# Default: repository default branch (e.g. master)
|
||||
base: ''
|
||||
|
||||
# Git reference (e.g. branch name) from which the changes will be detected.
|
||||
# Useful when workflow can be triggered only on default branch (e.g. repository_dispatch event)
|
||||
# but you want to get changes on different branch.
|
||||
# This option is ignored if action is triggered by pull_request event.
|
||||
# default: ${{ github.ref }}
|
||||
ref:
|
||||
|
||||
# How many commits are initially fetched from base branch.
|
||||
# If needed, each subsequent fetch doubles the
|
||||
# previously requested number of commits until the merge-base
|
||||
|
||||
@@ -9,6 +9,12 @@ inputs:
|
||||
working-directory:
|
||||
description: 'Relative path under $GITHUB_WORKSPACE where the repository was checked out.'
|
||||
required: false
|
||||
ref:
|
||||
description: |
|
||||
Git reference (e.g. branch name) from which the changes will be detected.
|
||||
This option is ignored if action is triggered by pull_request event.
|
||||
default: ${{ github.ref }}
|
||||
required: false
|
||||
base:
|
||||
description: |
|
||||
Git reference (e.g. branch name) against which the changes will be detected. Defaults to repository default branch (e.g. master).
|
||||
|
||||
165
dist/index.js
vendored
165
dist/index.js
vendored
@@ -3865,21 +3865,44 @@ async function getChangesOnHead() {
|
||||
return parseGitDiffOutput(output);
|
||||
}
|
||||
exports.getChangesOnHead = getChangesOnHead;
|
||||
async function getChangesSinceMergeBase(base, ref, initialFetchDepth) {
|
||||
const baseRef = `remotes/origin/${base}`;
|
||||
async function getChangesSinceMergeBase(base, head, initialFetchDepth) {
|
||||
let baseRef;
|
||||
let headRef;
|
||||
async function hasMergeBase() {
|
||||
return (await exec_1.default('git', ['merge-base', baseRef, ref], { ignoreReturnCode: true })).code === 0;
|
||||
if (baseRef === undefined || headRef === undefined) {
|
||||
return false;
|
||||
}
|
||||
return (await exec_1.default('git', ['merge-base', baseRef, headRef], { ignoreReturnCode: true })).code === 0;
|
||||
}
|
||||
let noMergeBase = false;
|
||||
core.startGroup(`Searching for merge-base ${baseRef}...${ref}`);
|
||||
core.startGroup(`Searching for merge-base ${base}...${head}`);
|
||||
try {
|
||||
baseRef = await getFullRef(base);
|
||||
headRef = await getFullRef(head);
|
||||
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, head]);
|
||||
if (baseRef === undefined || headRef === undefined) {
|
||||
baseRef = baseRef !== null && baseRef !== void 0 ? baseRef : (await getFullRef(base));
|
||||
headRef = headRef !== null && headRef !== void 0 ? headRef : (await getFullRef(head));
|
||||
if (baseRef === undefined || headRef === undefined) {
|
||||
await exec_1.default('git', ['fetch', '--tags', '--depth=1', 'origin', base, head], {
|
||||
ignoreReturnCode: true // returns exit code 1 if tags on remote were updated - we can safely ignore it
|
||||
});
|
||||
baseRef = baseRef !== null && baseRef !== void 0 ? baseRef : (await getFullRef(base));
|
||||
headRef = headRef !== null && headRef !== void 0 ? headRef : (await getFullRef(head));
|
||||
if (baseRef === undefined) {
|
||||
throw new Error(`Could not determine what is ${base} - fetch works but it's not a branch or tag`);
|
||||
}
|
||||
if (headRef === undefined) {
|
||||
throw new Error(`Could not determine what is ${head} - fetch works but it's not a branch or tag`);
|
||||
}
|
||||
}
|
||||
}
|
||||
let depth = initialFetchDepth;
|
||||
let lastCommitCount = await getCommitCount();
|
||||
while (!(await hasMergeBase())) {
|
||||
depth = Math.min(depth * 2, Number.MAX_SAFE_INTEGER);
|
||||
await exec_1.default('git', ['fetch', `--deepen=${depth}`, 'origin', base, ref]);
|
||||
await exec_1.default('git', ['fetch', `--deepen=${depth}`, 'origin', base, head]);
|
||||
const commitCount = await getCommitCount();
|
||||
if (commitCount === lastCommitCount) {
|
||||
core.info('No more commits were fetched');
|
||||
@@ -3897,16 +3920,17 @@ async function getChangesSinceMergeBase(base, ref, initialFetchDepth) {
|
||||
finally {
|
||||
core.endGroup();
|
||||
}
|
||||
// Three dots '...' change detection - finds merge-base and compares against it
|
||||
let diffArg = `${baseRef}...${headRef}`;
|
||||
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}..${headRef}`;
|
||||
}
|
||||
// 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();
|
||||
@@ -3994,6 +4018,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.
|
||||
@@ -4658,6 +4700,7 @@ async function run() {
|
||||
process.chdir(workingDirectory);
|
||||
}
|
||||
const token = core.getInput('token', { required: false });
|
||||
const ref = core.getInput('ref', { required: false });
|
||||
const base = core.getInput('base', { required: false });
|
||||
const filtersInput = core.getInput('filters', { required: true });
|
||||
const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput;
|
||||
@@ -4668,7 +4711,8 @@ async function run() {
|
||||
return;
|
||||
}
|
||||
const filter = new filter_1.Filter(filtersYaml);
|
||||
const files = await getChangedFiles(token, base, initialFetchDepth);
|
||||
const files = await getChangedFiles(token, base, ref, initialFetchDepth);
|
||||
core.info(`Detected ${files.length} changed files`);
|
||||
const results = filter.match(files);
|
||||
exportResults(results, listFiles);
|
||||
}
|
||||
@@ -4688,7 +4732,7 @@ function getConfigFileContent(configPath) {
|
||||
}
|
||||
return fs.readFileSync(configPath, { encoding: 'utf8' });
|
||||
}
|
||||
async function getChangedFiles(token, base, initialFetchDepth) {
|
||||
async function getChangedFiles(token, base, ref, initialFetchDepth) {
|
||||
// if base is 'HEAD' only local uncommitted changes will be detected
|
||||
// This is the simplest case as we don't need to fetch more commits or evaluate current/before refs
|
||||
if (base === git.HEAD) {
|
||||
@@ -4703,14 +4747,14 @@ async function getChangedFiles(token, base, initialFetchDepth) {
|
||||
return await git.getChangesInLastCommit();
|
||||
}
|
||||
else {
|
||||
return getChangedFilesFromGit(base, initialFetchDepth);
|
||||
return getChangedFilesFromGit(base, ref, initialFetchDepth);
|
||||
}
|
||||
}
|
||||
async function getChangedFilesFromGit(base, initialFetchDepth) {
|
||||
async function getChangedFilesFromGit(base, head, initialFetchDepth) {
|
||||
var _a;
|
||||
const defaultRef = (_a = github.context.payload.repository) === null || _a === void 0 ? void 0 : _a.default_branch;
|
||||
const beforeSha = github.context.eventName === 'push' ? github.context.payload.before : null;
|
||||
const ref = git.getShortName(github.context.ref) ||
|
||||
const ref = git.getShortName(head || github.context.ref) ||
|
||||
(core.warning(`'ref' field is missing in event payload - using current branch, tag or commit SHA`),
|
||||
await git.getCurrentRef());
|
||||
const baseRef = git.getShortName(base) || defaultRef;
|
||||
@@ -4743,53 +4787,64 @@ 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
|
||||
async function getChangedFilesFromApi(token, pullRequest) {
|
||||
core.startGroup(`Fetching list of changed files for PR#${pullRequest.number} from Github API`);
|
||||
core.info(`Number of changed_files is ${pullRequest.changed_files}`);
|
||||
const client = new github.GitHub(token);
|
||||
const pageSize = 100;
|
||||
const files = [];
|
||||
for (let page = 1; (page - 1) * pageSize < pullRequest.changed_files; page++) {
|
||||
core.info(`Invoking listFiles(pull_number: ${pullRequest.number}, page: ${page}, per_page: ${pageSize})`);
|
||||
const response = await client.pulls.listFiles({
|
||||
owner: github.context.repo.owner,
|
||||
repo: github.context.repo.repo,
|
||||
pull_number: pullRequest.number,
|
||||
page,
|
||||
per_page: pageSize
|
||||
});
|
||||
for (const row of response.data) {
|
||||
core.info(`[${row.status}] ${row.filename}`);
|
||||
// There's no obvious use-case for detection of renames
|
||||
// Therefore we treat it as if rename detection in git diff was turned off.
|
||||
// Rename is replaced by delete of original filename and add of new filename
|
||||
if (row.status === file_1.ChangeStatus.Renamed) {
|
||||
files.push({
|
||||
filename: row.filename,
|
||||
status: file_1.ChangeStatus.Added
|
||||
});
|
||||
files.push({
|
||||
// 'previous_filename' for some unknown reason isn't in the type definition or documentation
|
||||
filename: row.previous_filename,
|
||||
status: file_1.ChangeStatus.Deleted
|
||||
});
|
||||
try {
|
||||
const client = new github.GitHub(token);
|
||||
const per_page = 100;
|
||||
const files = [];
|
||||
for (let page = 1;; page++) {
|
||||
core.info(`Invoking listFiles(pull_number: ${pullRequest.number}, page: ${page}, per_page: ${per_page})`);
|
||||
const response = await client.pulls.listFiles({
|
||||
owner: github.context.repo.owner,
|
||||
repo: github.context.repo.repo,
|
||||
pull_number: pullRequest.number,
|
||||
per_page,
|
||||
page
|
||||
});
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`Fetching list of changed files from GitHub API failed with error code ${response.status}`);
|
||||
}
|
||||
else {
|
||||
// Github status and git status variants are same except for deleted files
|
||||
const status = row.status === 'removed' ? file_1.ChangeStatus.Deleted : row.status;
|
||||
files.push({
|
||||
filename: row.filename,
|
||||
status
|
||||
});
|
||||
core.info(`Received ${response.data.length} items`);
|
||||
if (response.data.length === 0) {
|
||||
core.info('All changed files has been fetched from GitHub API');
|
||||
break;
|
||||
}
|
||||
for (const row of response.data) {
|
||||
core.info(`[${row.status}] ${row.filename}`);
|
||||
// There's no obvious use-case for detection of renames
|
||||
// Therefore we treat it as if rename detection in git diff was turned off.
|
||||
// Rename is replaced by delete of original filename and add of new filename
|
||||
if (row.status === file_1.ChangeStatus.Renamed) {
|
||||
files.push({
|
||||
filename: row.filename,
|
||||
status: file_1.ChangeStatus.Added
|
||||
});
|
||||
files.push({
|
||||
// 'previous_filename' for some unknown reason isn't in the type definition or documentation
|
||||
filename: row.previous_filename,
|
||||
status: file_1.ChangeStatus.Deleted
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Github status and git status variants are same except for deleted files
|
||||
const status = row.status === 'removed' ? file_1.ChangeStatus.Deleted : row.status;
|
||||
files.push({
|
||||
filename: row.filename,
|
||||
status
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
finally {
|
||||
core.endGroup();
|
||||
}
|
||||
core.endGroup();
|
||||
return files;
|
||||
}
|
||||
function exportResults(results, format) {
|
||||
core.info('Results:');
|
||||
|
||||
73
src/git.ts
73
src/git.ts
@@ -54,23 +54,46 @@ export async function getChangesOnHead(): Promise<File[]> {
|
||||
return parseGitDiffOutput(output)
|
||||
}
|
||||
|
||||
export async function getChangesSinceMergeBase(base: string, ref: string, initialFetchDepth: number): Promise<File[]> {
|
||||
const baseRef = `remotes/origin/${base}`
|
||||
|
||||
export async function getChangesSinceMergeBase(base: string, head: string, initialFetchDepth: number): Promise<File[]> {
|
||||
let baseRef: string | undefined
|
||||
let headRef: string | undefined
|
||||
async function hasMergeBase(): Promise<boolean> {
|
||||
return (await exec('git', ['merge-base', baseRef, ref], {ignoreReturnCode: true})).code === 0
|
||||
if (baseRef === undefined || headRef === undefined) {
|
||||
return false
|
||||
}
|
||||
return (await exec('git', ['merge-base', baseRef, headRef], {ignoreReturnCode: true})).code === 0
|
||||
}
|
||||
|
||||
let noMergeBase = false
|
||||
core.startGroup(`Searching for merge-base ${baseRef}...${ref}`)
|
||||
core.startGroup(`Searching for merge-base ${base}...${head}`)
|
||||
try {
|
||||
baseRef = await getFullRef(base)
|
||||
headRef = await getFullRef(head)
|
||||
if (!(await hasMergeBase())) {
|
||||
await exec('git', ['fetch', `--depth=${initialFetchDepth}`, 'origin', base, ref])
|
||||
await exec('git', ['fetch', '--no-tags', `--depth=${initialFetchDepth}`, 'origin', base, head])
|
||||
if (baseRef === undefined || headRef === undefined) {
|
||||
baseRef = baseRef ?? (await getFullRef(base))
|
||||
headRef = headRef ?? (await getFullRef(head))
|
||||
if (baseRef === undefined || headRef === undefined) {
|
||||
await exec('git', ['fetch', '--tags', '--depth=1', 'origin', base, head], {
|
||||
ignoreReturnCode: true // returns exit code 1 if tags on remote were updated - we can safely ignore it
|
||||
})
|
||||
baseRef = baseRef ?? (await getFullRef(base))
|
||||
headRef = headRef ?? (await getFullRef(head))
|
||||
if (baseRef === undefined) {
|
||||
throw new Error(`Could not determine what is ${base} - fetch works but it's not a branch or tag`)
|
||||
}
|
||||
if (headRef === undefined) {
|
||||
throw new Error(`Could not determine what is ${head} - fetch works but it's not a branch or tag`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let depth = initialFetchDepth
|
||||
let lastCommitCount = await getCommitCount()
|
||||
while (!(await hasMergeBase())) {
|
||||
depth = Math.min(depth * 2, Number.MAX_SAFE_INTEGER)
|
||||
await exec('git', ['fetch', `--deepen=${depth}`, 'origin', base, ref])
|
||||
await exec('git', ['fetch', `--deepen=${depth}`, 'origin', base, head])
|
||||
const commitCount = await getCommitCount()
|
||||
if (commitCount === lastCommitCount) {
|
||||
core.info('No more commits were fetched')
|
||||
@@ -88,17 +111,18 @@ export async function getChangesSinceMergeBase(base: string, ref: string, initia
|
||||
core.endGroup()
|
||||
}
|
||||
|
||||
// Three dots '...' change detection - finds merge-base and compares against it
|
||||
let diffArg = `${baseRef}...${headRef}`
|
||||
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}..${headRef}`
|
||||
}
|
||||
|
||||
// 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()
|
||||
@@ -188,6 +212,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.
|
||||
|
||||
104
src/main.ts
104
src/main.ts
@@ -19,6 +19,7 @@ async function run(): Promise<void> {
|
||||
}
|
||||
|
||||
const token = core.getInput('token', {required: false})
|
||||
const ref = core.getInput('ref', {required: false})
|
||||
const base = core.getInput('base', {required: false})
|
||||
const filtersInput = core.getInput('filters', {required: true})
|
||||
const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput
|
||||
@@ -31,7 +32,8 @@ async function run(): Promise<void> {
|
||||
}
|
||||
|
||||
const filter = new Filter(filtersYaml)
|
||||
const files = await getChangedFiles(token, base, initialFetchDepth)
|
||||
const files = await getChangedFiles(token, base, ref, initialFetchDepth)
|
||||
core.info(`Detected ${files.length} changed files`)
|
||||
const results = filter.match(files)
|
||||
exportResults(results, listFiles)
|
||||
} catch (error) {
|
||||
@@ -55,7 +57,7 @@ function getConfigFileContent(configPath: string): string {
|
||||
return fs.readFileSync(configPath, {encoding: 'utf8'})
|
||||
}
|
||||
|
||||
async function getChangedFiles(token: string, base: string, initialFetchDepth: number): Promise<File[]> {
|
||||
async function getChangedFiles(token: string, base: string, ref: string, initialFetchDepth: number): Promise<File[]> {
|
||||
// if base is 'HEAD' only local uncommitted changes will be detected
|
||||
// This is the simplest case as we don't need to fetch more commits or evaluate current/before refs
|
||||
if (base === git.HEAD) {
|
||||
@@ -70,18 +72,18 @@ async function getChangedFiles(token: string, base: string, initialFetchDepth: n
|
||||
core.info('Github token is not available - changes will be detected from PRs merge commit')
|
||||
return await git.getChangesInLastCommit()
|
||||
} else {
|
||||
return getChangedFilesFromGit(base, initialFetchDepth)
|
||||
return getChangedFilesFromGit(base, ref, initialFetchDepth)
|
||||
}
|
||||
}
|
||||
|
||||
async function getChangedFilesFromGit(base: string, initialFetchDepth: number): Promise<File[]> {
|
||||
async function getChangedFilesFromGit(base: string, head: string, initialFetchDepth: number): Promise<File[]> {
|
||||
const defaultRef = github.context.payload.repository?.default_branch
|
||||
|
||||
const beforeSha =
|
||||
github.context.eventName === 'push' ? (github.context.payload as Webhooks.WebhookPayloadPush).before : null
|
||||
|
||||
const ref =
|
||||
git.getShortName(github.context.ref) ||
|
||||
git.getShortName(head || github.context.ref) ||
|
||||
(core.warning(`'ref' field is missing in event payload - using current branch, tag or commit SHA`),
|
||||
await git.getCurrentRef())
|
||||
|
||||
@@ -121,7 +123,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)
|
||||
}
|
||||
|
||||
@@ -131,47 +133,61 @@ async function getChangedFilesFromApi(
|
||||
pullRequest: Webhooks.WebhookPayloadPullRequestPullRequest
|
||||
): Promise<File[]> {
|
||||
core.startGroup(`Fetching list of changed files for PR#${pullRequest.number} from Github API`)
|
||||
core.info(`Number of changed_files is ${pullRequest.changed_files}`)
|
||||
const client = new github.GitHub(token)
|
||||
const pageSize = 100
|
||||
const files: File[] = []
|
||||
for (let page = 1; (page - 1) * pageSize < pullRequest.changed_files; page++) {
|
||||
core.info(`Invoking listFiles(pull_number: ${pullRequest.number}, page: ${page}, per_page: ${pageSize})`)
|
||||
const response = await client.pulls.listFiles({
|
||||
owner: github.context.repo.owner,
|
||||
repo: github.context.repo.repo,
|
||||
pull_number: pullRequest.number,
|
||||
page,
|
||||
per_page: pageSize
|
||||
})
|
||||
for (const row of response.data) {
|
||||
core.info(`[${row.status}] ${row.filename}`)
|
||||
// There's no obvious use-case for detection of renames
|
||||
// Therefore we treat it as if rename detection in git diff was turned off.
|
||||
// Rename is replaced by delete of original filename and add of new filename
|
||||
if (row.status === ChangeStatus.Renamed) {
|
||||
files.push({
|
||||
filename: row.filename,
|
||||
status: ChangeStatus.Added
|
||||
})
|
||||
files.push({
|
||||
// 'previous_filename' for some unknown reason isn't in the type definition or documentation
|
||||
filename: (<any>row).previous_filename as string,
|
||||
status: ChangeStatus.Deleted
|
||||
})
|
||||
} else {
|
||||
// Github status and git status variants are same except for deleted files
|
||||
const status = row.status === 'removed' ? ChangeStatus.Deleted : (row.status as ChangeStatus)
|
||||
files.push({
|
||||
filename: row.filename,
|
||||
status
|
||||
})
|
||||
try {
|
||||
const client = new github.GitHub(token)
|
||||
const per_page = 100
|
||||
const files: File[] = []
|
||||
|
||||
for (let page = 1; ; page++) {
|
||||
core.info(`Invoking listFiles(pull_number: ${pullRequest.number}, page: ${page}, per_page: ${per_page})`)
|
||||
const response = await client.pulls.listFiles({
|
||||
owner: github.context.repo.owner,
|
||||
repo: github.context.repo.repo,
|
||||
pull_number: pullRequest.number,
|
||||
per_page,
|
||||
page
|
||||
})
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`Fetching list of changed files from GitHub API failed with error code ${response.status}`)
|
||||
}
|
||||
|
||||
core.info(`Received ${response.data.length} items`)
|
||||
if (response.data.length === 0) {
|
||||
core.info('All changed files has been fetched from GitHub API')
|
||||
break
|
||||
}
|
||||
|
||||
for (const row of response.data) {
|
||||
core.info(`[${row.status}] ${row.filename}`)
|
||||
// There's no obvious use-case for detection of renames
|
||||
// Therefore we treat it as if rename detection in git diff was turned off.
|
||||
// Rename is replaced by delete of original filename and add of new filename
|
||||
if (row.status === ChangeStatus.Renamed) {
|
||||
files.push({
|
||||
filename: row.filename,
|
||||
status: ChangeStatus.Added
|
||||
})
|
||||
files.push({
|
||||
// 'previous_filename' for some unknown reason isn't in the type definition or documentation
|
||||
filename: (<any>row).previous_filename as string,
|
||||
status: ChangeStatus.Deleted
|
||||
})
|
||||
} else {
|
||||
// Github status and git status variants are same except for deleted files
|
||||
const status = row.status === 'removed' ? ChangeStatus.Deleted : (row.status as ChangeStatus)
|
||||
files.push({
|
||||
filename: row.filename,
|
||||
status
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
core.endGroup()
|
||||
return files
|
||||
return files
|
||||
} finally {
|
||||
core.endGroup()
|
||||
}
|
||||
}
|
||||
|
||||
function exportResults(results: FilterResults, format: ExportFormat): void {
|
||||
|
||||
Reference in New Issue
Block a user