diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e4f55976..b7f7c22d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -12,3 +12,15 @@ jobs:
- run: |
npm install
npm run all
+
+ self-test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: ./
+ id: filter
+ with:
+ filters: '.github/filters.yml'
+ - name: filter-test
+ if: steps.filter.outputs.any != 'true' || steps.filter.outputs.error == 'true'
+ run: exit 1
diff --git a/LICENSE b/LICENSE
index a426ef25..d81689a8 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,7 @@
The MIT License (MIT)
-Copyright (c) 2018 GitHub, Inc. and contributors
+Copyright (c) 2020 Michal Dorner and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 2acef130..b44c8b25 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,22 @@
-
+
-> **CAUTION**: This action can only be used in a workflow triggered by `pull_request` event.
+# Paths filter
-# Pull request changed files filter
+With this [Github Action](https://github.com/features/actions) you can execute your workflow steps only if relevant files are modified.
-This [Github Action](https://github.com/features/actions) enables conditional execution of workflow job steps considering which files are modified by a pull request.
-
-It saves time and resources especially in monorepo setups, where you can run slow tasks (e.g. integration tests) only for changed components.
-Github workflows built-in
-[path filters](https://help.github.com/en/actions/referenceworkflow-syntax-for-github-actions#onpushpull_requestpaths)
+It saves time and resources especially in monorepo setups, where you can run slow tasks (e.g. integration tests or deployments) only for changed components.
+Github workflows built-in [path filters](https://help.github.com/en/actions/referenceworkflow-syntax-for-github-actions#onpushpull_requestpaths)
doesn't allow this because they doesn't work on a level of individual jobs or steps.
+Action supports workflows triggered by:
+- Pull request: changes are detected against the base branch
+- Push: changes are detected against the most recent commit on the same branch before the push
+
## Usage
-The action accepts filter rules in the YAML format.
+Filter rules are defined using YAML format.
Each filter rule is a list of [glob expressions](https://github.com/isaacs/minimatch).
Corresponding output variable will be created to indicate if there's a changed file matching any of the rule glob expressions.
Output variables can be later used in the `if` clause to conditionally run specific steps.
@@ -29,16 +30,16 @@ Output variables can be later used in the `if` clause to conditionally run speci
- `'true'` - if **any** of changed files matches any of rule patterns
- `'false'` - if **none** of changed files matches any of rule patterns
-
### Notes
- minimatch [dot](https://www.npmjs.com/package/minimatch#dot) option is set to true - therefore
globbing will match also paths where file or folder name starts with a dot.
-### Sample workflow
+### Example
```yaml
-name: Build verification
-
on:
+ push:
+ branches:
+ - master
pull_request:
types:
- opened
@@ -50,7 +51,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- - uses: dorny/pr-changed-files-filter@v1.1.0
+ - uses: dorny/paths-filter@v2.0.0
id: filter
with:
# inline YAML or path to separate file (e.g.: .github/filters.yaml)
@@ -78,18 +79,19 @@ jobs:
## How it works
-1. Required inputs are checked (`filters`)
-2. If token was provided, it's used to fetch list of changed files from Github API.
-3. If token was not provided, base branch is fetched and changed files are detected using `git diff-index` command.
-4. For each filter rule it checks if there is any matching file
-5. Output variables are set
+1. If action was triggered by pull request:
+ - If access token was provided it's used to fetch list of changed files from Github API.
+ - If access token was not provided, top of the base branch is fetched and changed files are detected using `git diff-index` command.
+2. If action was triggered by push event
+ - Last commit before the push is fetched and changed files are detected using `git diff-index` command.
+3. For each filter rule it checks if there is any matching file
+4. Output variables are set
-## Difference from related projects:
+## Difference from similar projects:
- [Has Changed Path](https://github.com/MarceloPrado/has-changed-path)
- detects changes from previous commit
- you have to configure `checkout` action to fetch some number of previous commits
- - `git diff` is used for change detection
- outputs only single `true` / `false` value if any of provided paths contains changes
- [Changed Files Exporter](https://github.com/futuratrepadeira/changed-files)
- outputs lists with paths of created, updated and deleted files
diff --git a/action.yml b/action.yml
index 1b8ca9cd..8865f335 100644
--- a/action.yml
+++ b/action.yml
@@ -1,5 +1,5 @@
-name: 'Pull request changed files filter'
-description: 'Enables conditional execution of workflow job steps considering which files are modified by a pull request.'
+name: 'Paths filter'
+description: 'Execute your workflow steps only if relevant files are modified.'
author: 'Michal Dorner '
inputs:
token:
diff --git a/dist/index.js b/dist/index.js
index 09f38c0c..c5cb95e8 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -3798,27 +3798,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", { value: true });
-exports.getChangedFiles = exports.fetchBranch = void 0;
+exports.getChangedFiles = exports.fetchCommit = void 0;
const exec_1 = __webpack_require__(986);
-function fetchBranch(base) {
+function fetchCommit(sha) {
return __awaiter(this, void 0, void 0, function* () {
- const exitCode = yield exec_1.exec('git', ['fetch', '--depth=1', 'origin', base]);
+ const exitCode = yield exec_1.exec('git', ['fetch', '--depth=1', 'origin', sha]);
if (exitCode !== 0) {
- throw new Error(`Fetching branch ${base} failed, exiting`);
+ throw new Error(`Fetching commit ${sha} failed`);
}
});
}
-exports.fetchBranch = fetchBranch;
-function getChangedFiles(base) {
+exports.fetchCommit = fetchCommit;
+function getChangedFiles(sha) {
return __awaiter(this, void 0, void 0, function* () {
let output = '';
- const exitCode = yield exec_1.exec('git', ['diff-index', '--name-only', base], {
+ const exitCode = yield exec_1.exec('git', ['diff-index', '--name-only', sha], {
listeners: {
stdout: (data) => (output += data.toString())
}
});
if (exitCode !== 0) {
- throw new Error(`Couldn't determine changed files, exiting`);
+ throw new Error(`Couldn't determine changed files`);
}
return output
.split('\n')
@@ -4485,13 +4485,8 @@ function run() {
const token = core.getInput('token', { required: false });
const filtersInput = core.getInput('filters', { required: true });
const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput;
- if (github.context.eventName !== 'pull_request') {
- core.setFailed('This action can be triggered only by pull_request event');
- return;
- }
- const pr = github.context.payload.pull_request;
const filter = new filter_1.default(filtersYaml);
- const files = token ? yield getChangedFilesFromApi(token, pr) : yield getChangedFilesFromGit(pr);
+ const files = yield getChangedFiles(token);
const result = filter.match(files);
for (const key in result) {
core.setOutput(key, String(result[key]));
@@ -4514,13 +4509,27 @@ function getConfigFileContent(configPath) {
}
return fs.readFileSync(configPath, { encoding: 'utf8' });
}
+function getChangedFiles(token) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (github.context.eventName === 'pull_request') {
+ const pr = github.context.payload.pull_request;
+ return token ? yield getChangedFilesFromApi(token, pr) : yield getChangedFilesFromGit(pr.base.sha);
+ }
+ else if (github.context.eventName === 'push') {
+ const push = github.context.payload;
+ return yield getChangedFilesFromGit(push.before);
+ }
+ else {
+ throw new Error('This action can be triggered only by pull_request or push event');
+ }
+ });
+}
// Fetch base branch and use `git diff` to determine changed files
-function getChangedFilesFromGit(pullRequest) {
+function getChangedFilesFromGit(sha) {
return __awaiter(this, void 0, void 0, function* () {
core.debug('Fetching base branch and using `git diff-index` to determine changed files');
- const baseRef = pullRequest.base.ref;
- yield git.fetchBranch(baseRef);
- return yield git.getChangedFiles(pullRequest.base.sha);
+ yield git.fetchCommit(sha);
+ return yield git.getChangedFiles(sha);
});
}
// Uses github REST api to get list of files changed in PR
diff --git a/package.json b/package.json
index 5bb4e2fa..8aeba1a9 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
{
- "name": "pr-changed-files-filter",
+ "name": "paths-filter",
"version": "1.0.0",
"private": true,
- "description": "Enables conditional execution of workflow job steps considering which files are modified by a pull request.",
+ "description": "Execute your workflow steps only if relevant files are modified.",
"main": "lib/main.js",
"scripts": {
"build": "tsc",
diff --git a/src/git.ts b/src/git.ts
index 242a1c3d..4cfc5db3 100644
--- a/src/git.ts
+++ b/src/git.ts
@@ -1,22 +1,22 @@
import {exec} from '@actions/exec'
-export async function fetchBranch(base: string): Promise {
- const exitCode = await exec('git', ['fetch', '--depth=1', 'origin', base])
+export async function fetchCommit(sha: string): Promise {
+ const exitCode = await exec('git', ['fetch', '--depth=1', 'origin', sha])
if (exitCode !== 0) {
- throw new Error(`Fetching branch ${base} failed, exiting`)
+ throw new Error(`Fetching commit ${sha} failed`)
}
}
-export async function getChangedFiles(base: string): Promise {
+export async function getChangedFiles(sha: string): Promise {
let output = ''
- const exitCode = await exec('git', ['diff-index', '--name-only', base], {
+ const exitCode = await exec('git', ['diff-index', '--name-only', sha], {
listeners: {
stdout: (data: Buffer) => (output += data.toString())
}
})
if (exitCode !== 0) {
- throw new Error(`Couldn't determine changed files, exiting`)
+ throw new Error(`Couldn't determine changed files`)
}
return output
diff --git a/src/main.ts b/src/main.ts
index f9121b5c..f67d7cb7 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -12,14 +12,8 @@ async function run(): Promise {
const filtersInput = core.getInput('filters', {required: true})
const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput
- if (github.context.eventName !== 'pull_request') {
- core.setFailed('This action can be triggered only by pull_request event')
- return
- }
-
- const pr = github.context.payload.pull_request as Webhooks.WebhookPayloadPullRequestPullRequest
const filter = new Filter(filtersYaml)
- const files = token ? await getChangedFilesFromApi(token, pr) : await getChangedFilesFromGit(pr)
+ const files = await getChangedFiles(token)
const result = filter.match(files)
for (const key in result) {
@@ -46,12 +40,23 @@ function getConfigFileContent(configPath: string): string {
return fs.readFileSync(configPath, {encoding: 'utf8'})
}
+async function getChangedFiles(token: string): Promise {
+ if (github.context.eventName === 'pull_request') {
+ const pr = github.context.payload.pull_request as Webhooks.WebhookPayloadPullRequestPullRequest
+ return token ? await getChangedFilesFromApi(token, pr) : await getChangedFilesFromGit(pr.base.sha)
+ } else if (github.context.eventName === 'push') {
+ const push = github.context.payload as Webhooks.WebhookPayloadPush
+ return await getChangedFilesFromGit(push.before)
+ } else {
+ throw new Error('This action can be triggered only by pull_request or push event')
+ }
+}
+
// Fetch base branch and use `git diff` to determine changed files
-async function getChangedFilesFromGit(pullRequest: Webhooks.WebhookPayloadPullRequestPullRequest): Promise {
+async function getChangedFilesFromGit(sha: string): Promise {
core.debug('Fetching base branch and using `git diff-index` to determine changed files')
- const baseRef = pullRequest.base.ref
- await git.fetchBranch(baseRef)
- return await git.getChangedFiles(pullRequest.base.sha)
+ await git.fetchCommit(sha)
+ return await git.getChangedFiles(sha)
}
// Uses github REST api to get list of files changed in PR