Skip to content

Commit 07d6abd

Browse files
authored
Merge pull request dorny#82 from dorny/issue-79-add-head-ref-input
Add ref input parameter
2 parents 208adf4 + e8f370c commit 07d6abd

File tree

6 files changed

+73
-42
lines changed

6 files changed

+73
-42
lines changed

.github/workflows/pull-request-verification.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
paths-ignore: [ '*.md' ]
55
branches:
66
- master
7-
- develop
7+
- '**'
88

99
jobs:
1010
build:

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,11 @@ For more scenarios see [examples](#examples) section.
6666

6767

6868
# What's New
69+
- Add `ref` input parameter
6970
- Add `list-files: csv` format
7071
- Configure matrix job to run for each folder with changes using `changes` output
7172
- Improved listing of matching files with `list-files: shell` and `list-files: escape` options
72-
- Support local changes
73-
- Fixed retrieval of all changes via Github API when there are 100+ changes
7473
- Paths expressions are now evaluated using [picomatch](https://github.com/micromatch/picomatch) library
75-
- Support workflows triggered by any event
7674

7775
For more information see [CHANGELOG](https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md)
7876

@@ -111,6 +109,13 @@ For more information see [CHANGELOG](https://github.com/dorny/paths-filter/blob/
111109
# Default: repository default branch (e.g. master)
112110
base: ''
113111
112+
# Git reference (e.g. branch name) from which the changes will be detected.
113+
# Useful when workflow can be triggered only on default branch (e.g. repository_dispatch event)
114+
# but you want to get changes on different branch.
115+
# This option is ignored if action is triggered by pull_request event.
116+
# default: ${{ github.ref }}
117+
ref:
118+
114119
# How many commits are initially fetched from base branch.
115120
# If needed, each subsequent fetch doubles the
116121
# previously requested number of commits until the merge-base

action.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ inputs:
99
working-directory:
1010
description: 'Relative path under $GITHUB_WORKSPACE where the repository was checked out.'
1111
required: false
12+
ref:
13+
description: |
14+
Git reference (e.g. branch name) from which the changes will be detected.
15+
This option is ignored if action is triggered by pull_request event.
16+
default: ${{ github.ref }}
17+
required: false
1218
base:
1319
description: |
1420
Git reference (e.g. branch name) against which the changes will be detected. Defaults to repository default branch (e.g. master).

dist/index.js

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3865,34 +3865,44 @@ async function getChangesOnHead() {
38653865
return parseGitDiffOutput(output);
38663866
}
38673867
exports.getChangesOnHead = getChangesOnHead;
3868-
async function getChangesSinceMergeBase(base, ref, initialFetchDepth) {
3868+
async function getChangesSinceMergeBase(base, head, initialFetchDepth) {
38693869
let baseRef;
3870+
let headRef;
38703871
async function hasMergeBase() {
3871-
return (baseRef !== undefined && (await exec_1.default('git', ['merge-base', baseRef, ref], { ignoreReturnCode: true })).code === 0);
3872+
if (baseRef === undefined || headRef === undefined) {
3873+
return false;
3874+
}
3875+
return (await exec_1.default('git', ['merge-base', baseRef, headRef], { ignoreReturnCode: true })).code === 0;
38723876
}
38733877
let noMergeBase = false;
3874-
core.startGroup(`Searching for merge-base ${base}...${ref}`);
3878+
core.startGroup(`Searching for merge-base ${base}...${head}`);
38753879
try {
38763880
baseRef = await getFullRef(base);
3881+
headRef = await getFullRef(head);
38773882
if (!(await hasMergeBase())) {
3878-
await exec_1.default('git', ['fetch', '--no-tags', `--depth=${initialFetchDepth}`, 'origin', base, ref]);
3879-
if (baseRef === undefined) {
3880-
baseRef = await getFullRef(base);
3881-
if (baseRef === undefined) {
3882-
await exec_1.default('git', ['fetch', '--tags', '--depth=1', 'origin', base, ref], {
3883+
await exec_1.default('git', ['fetch', '--no-tags', `--depth=${initialFetchDepth}`, 'origin', base, head]);
3884+
if (baseRef === undefined || headRef === undefined) {
3885+
baseRef = baseRef !== null && baseRef !== void 0 ? baseRef : (await getFullRef(base));
3886+
headRef = headRef !== null && headRef !== void 0 ? headRef : (await getFullRef(head));
3887+
if (baseRef === undefined || headRef === undefined) {
3888+
await exec_1.default('git', ['fetch', '--tags', '--depth=1', 'origin', base, head], {
38833889
ignoreReturnCode: true // returns exit code 1 if tags on remote were updated - we can safely ignore it
38843890
});
3885-
baseRef = await getFullRef(base);
3891+
baseRef = baseRef !== null && baseRef !== void 0 ? baseRef : (await getFullRef(base));
3892+
headRef = headRef !== null && headRef !== void 0 ? headRef : (await getFullRef(head));
38863893
if (baseRef === undefined) {
38873894
throw new Error(`Could not determine what is ${base} - fetch works but it's not a branch or tag`);
38883895
}
3896+
if (headRef === undefined) {
3897+
throw new Error(`Could not determine what is ${head} - fetch works but it's not a branch or tag`);
3898+
}
38893899
}
38903900
}
38913901
let depth = initialFetchDepth;
38923902
let lastCommitCount = await getCommitCount();
38933903
while (!(await hasMergeBase())) {
38943904
depth = Math.min(depth * 2, Number.MAX_SAFE_INTEGER);
3895-
await exec_1.default('git', ['fetch', `--deepen=${depth}`, 'origin', base, ref]);
3905+
await exec_1.default('git', ['fetch', `--deepen=${depth}`, 'origin', base, head]);
38963906
const commitCount = await getCommitCount();
38973907
if (commitCount === lastCommitCount) {
38983908
core.info('No more commits were fetched');
@@ -3910,16 +3920,16 @@ async function getChangesSinceMergeBase(base, ref, initialFetchDepth) {
39103920
finally {
39113921
core.endGroup();
39123922
}
3913-
let diffArg = `${baseRef}...${ref}`;
3923+
// Three dots '...' change detection - finds merge-base and compares against it
3924+
let diffArg = `${baseRef}...${headRef}`;
39143925
if (noMergeBase) {
39153926
core.warning('No merge base found - change detection will use direct <commit>..<commit> comparison');
3916-
diffArg = `${baseRef}..${ref}`;
3927+
diffArg = `${baseRef}..${headRef}`;
39173928
}
39183929
// Get changes introduced on ref compared to base
39193930
core.startGroup(`Change detection ${diffArg}`);
39203931
let output = '';
39213932
try {
3922-
// Three dots '...' change detection - finds merge-base and compares against it
39233933
output = (await exec_1.default('git', ['diff', '--no-renames', '--name-status', '-z', diffArg])).stdout;
39243934
}
39253935
finally {
@@ -4690,6 +4700,7 @@ async function run() {
46904700
process.chdir(workingDirectory);
46914701
}
46924702
const token = core.getInput('token', { required: false });
4703+
const ref = core.getInput('ref', { required: false });
46934704
const base = core.getInput('base', { required: false });
46944705
const filtersInput = core.getInput('filters', { required: true });
46954706
const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput;
@@ -4700,7 +4711,7 @@ async function run() {
47004711
return;
47014712
}
47024713
const filter = new filter_1.Filter(filtersYaml);
4703-
const files = await getChangedFiles(token, base, initialFetchDepth);
4714+
const files = await getChangedFiles(token, base, ref, initialFetchDepth);
47044715
const results = filter.match(files);
47054716
exportResults(results, listFiles);
47064717
}
@@ -4720,7 +4731,7 @@ function getConfigFileContent(configPath) {
47204731
}
47214732
return fs.readFileSync(configPath, { encoding: 'utf8' });
47224733
}
4723-
async function getChangedFiles(token, base, initialFetchDepth) {
4734+
async function getChangedFiles(token, base, ref, initialFetchDepth) {
47244735
// if base is 'HEAD' only local uncommitted changes will be detected
47254736
// This is the simplest case as we don't need to fetch more commits or evaluate current/before refs
47264737
if (base === git.HEAD) {
@@ -4735,14 +4746,14 @@ async function getChangedFiles(token, base, initialFetchDepth) {
47354746
return await git.getChangesInLastCommit();
47364747
}
47374748
else {
4738-
return getChangedFilesFromGit(base, initialFetchDepth);
4749+
return getChangedFilesFromGit(base, ref, initialFetchDepth);
47394750
}
47404751
}
4741-
async function getChangedFilesFromGit(base, initialFetchDepth) {
4752+
async function getChangedFilesFromGit(base, head, initialFetchDepth) {
47424753
var _a;
47434754
const defaultRef = (_a = github.context.payload.repository) === null || _a === void 0 ? void 0 : _a.default_branch;
47444755
const beforeSha = github.context.eventName === 'push' ? github.context.payload.before : null;
4745-
const ref = git.getShortName(github.context.ref) ||
4756+
const ref = git.getShortName(head || github.context.ref) ||
47464757
(core.warning(`'ref' field is missing in event payload - using current branch, tag or commit SHA`),
47474758
await git.getCurrentRef());
47484759
const baseRef = git.getShortName(base) || defaultRef;

src/git.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,38 +54,46 @@ export async function getChangesOnHead(): Promise<File[]> {
5454
return parseGitDiffOutput(output)
5555
}
5656

57-
export async function getChangesSinceMergeBase(base: string, ref: string, initialFetchDepth: number): Promise<File[]> {
57+
export async function getChangesSinceMergeBase(base: string, head: string, initialFetchDepth: number): Promise<File[]> {
5858
let baseRef: string | undefined
59+
let headRef: string | undefined
5960
async function hasMergeBase(): Promise<boolean> {
60-
return (
61-
baseRef !== undefined && (await exec('git', ['merge-base', baseRef, ref], {ignoreReturnCode: true})).code === 0
62-
)
61+
if (baseRef === undefined || headRef === undefined) {
62+
return false
63+
}
64+
return (await exec('git', ['merge-base', baseRef, headRef], {ignoreReturnCode: true})).code === 0
6365
}
6466

6567
let noMergeBase = false
66-
core.startGroup(`Searching for merge-base ${base}...${ref}`)
68+
core.startGroup(`Searching for merge-base ${base}...${head}`)
6769
try {
6870
baseRef = await getFullRef(base)
71+
headRef = await getFullRef(head)
6972
if (!(await hasMergeBase())) {
70-
await exec('git', ['fetch', '--no-tags', `--depth=${initialFetchDepth}`, 'origin', base, ref])
71-
if (baseRef === undefined) {
72-
baseRef = await getFullRef(base)
73-
if (baseRef === undefined) {
74-
await exec('git', ['fetch', '--tags', '--depth=1', 'origin', base, ref], {
73+
await exec('git', ['fetch', '--no-tags', `--depth=${initialFetchDepth}`, 'origin', base, head])
74+
if (baseRef === undefined || headRef === undefined) {
75+
baseRef = baseRef ?? (await getFullRef(base))
76+
headRef = headRef ?? (await getFullRef(head))
77+
if (baseRef === undefined || headRef === undefined) {
78+
await exec('git', ['fetch', '--tags', '--depth=1', 'origin', base, head], {
7579
ignoreReturnCode: true // returns exit code 1 if tags on remote were updated - we can safely ignore it
7680
})
77-
baseRef = await getFullRef(base)
81+
baseRef = baseRef ?? (await getFullRef(base))
82+
headRef = headRef ?? (await getFullRef(head))
7883
if (baseRef === undefined) {
7984
throw new Error(`Could not determine what is ${base} - fetch works but it's not a branch or tag`)
8085
}
86+
if (headRef === undefined) {
87+
throw new Error(`Could not determine what is ${head} - fetch works but it's not a branch or tag`)
88+
}
8189
}
8290
}
8391

8492
let depth = initialFetchDepth
8593
let lastCommitCount = await getCommitCount()
8694
while (!(await hasMergeBase())) {
8795
depth = Math.min(depth * 2, Number.MAX_SAFE_INTEGER)
88-
await exec('git', ['fetch', `--deepen=${depth}`, 'origin', base, ref])
96+
await exec('git', ['fetch', `--deepen=${depth}`, 'origin', base, head])
8997
const commitCount = await getCommitCount()
9098
if (commitCount === lastCommitCount) {
9199
core.info('No more commits were fetched')
@@ -103,17 +111,17 @@ export async function getChangesSinceMergeBase(base: string, ref: string, initia
103111
core.endGroup()
104112
}
105113

106-
let diffArg = `${baseRef}...${ref}`
114+
// Three dots '...' change detection - finds merge-base and compares against it
115+
let diffArg = `${baseRef}...${headRef}`
107116
if (noMergeBase) {
108117
core.warning('No merge base found - change detection will use direct <commit>..<commit> comparison')
109-
diffArg = `${baseRef}..${ref}`
118+
diffArg = `${baseRef}..${headRef}`
110119
}
111120

112121
// Get changes introduced on ref compared to base
113122
core.startGroup(`Change detection ${diffArg}`)
114123
let output = ''
115124
try {
116-
// Three dots '...' change detection - finds merge-base and compares against it
117125
output = (await exec('git', ['diff', '--no-renames', '--name-status', '-z', diffArg])).stdout
118126
} finally {
119127
fixStdOutNullTermination()

src/main.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ async function run(): Promise<void> {
1919
}
2020

2121
const token = core.getInput('token', {required: false})
22+
const ref = core.getInput('ref', {required: false})
2223
const base = core.getInput('base', {required: false})
2324
const filtersInput = core.getInput('filters', {required: true})
2425
const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput
@@ -31,7 +32,7 @@ async function run(): Promise<void> {
3132
}
3233

3334
const filter = new Filter(filtersYaml)
34-
const files = await getChangedFiles(token, base, initialFetchDepth)
35+
const files = await getChangedFiles(token, base, ref, initialFetchDepth)
3536
const results = filter.match(files)
3637
exportResults(results, listFiles)
3738
} catch (error) {
@@ -55,7 +56,7 @@ function getConfigFileContent(configPath: string): string {
5556
return fs.readFileSync(configPath, {encoding: 'utf8'})
5657
}
5758

58-
async function getChangedFiles(token: string, base: string, initialFetchDepth: number): Promise<File[]> {
59+
async function getChangedFiles(token: string, base: string, ref: string, initialFetchDepth: number): Promise<File[]> {
5960
// if base is 'HEAD' only local uncommitted changes will be detected
6061
// This is the simplest case as we don't need to fetch more commits or evaluate current/before refs
6162
if (base === git.HEAD) {
@@ -70,18 +71,18 @@ async function getChangedFiles(token: string, base: string, initialFetchDepth: n
7071
core.info('Github token is not available - changes will be detected from PRs merge commit')
7172
return await git.getChangesInLastCommit()
7273
} else {
73-
return getChangedFilesFromGit(base, initialFetchDepth)
74+
return getChangedFilesFromGit(base, ref, initialFetchDepth)
7475
}
7576
}
7677

77-
async function getChangedFilesFromGit(base: string, initialFetchDepth: number): Promise<File[]> {
78+
async function getChangedFilesFromGit(base: string, head: string, initialFetchDepth: number): Promise<File[]> {
7879
const defaultRef = github.context.payload.repository?.default_branch
7980

8081
const beforeSha =
8182
github.context.eventName === 'push' ? (github.context.payload as Webhooks.WebhookPayloadPush).before : null
8283

8384
const ref =
84-
git.getShortName(github.context.ref) ||
85+
git.getShortName(head || github.context.ref) ||
8586
(core.warning(`'ref' field is missing in event payload - using current branch, tag or commit SHA`),
8687
await git.getCurrentRef())
8788

0 commit comments

Comments
 (0)