mirror of
https://github.com/dorny/paths-filter.git
synced 2024-12-20 00:49:04 +00:00
Support push event (#10)
* Support triggering from push event * Add self-test to build workflow * Update action metadata
This commit is contained in:
parent
910e8b1235
commit
affb29871a
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@ -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
|
||||
|
2
LICENSE
2
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
|
||||
|
44
README.md
44
README.md
@ -1,21 +1,22 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/dorny/pr-changed-files-filter/actions"><img alt="typescript-action status" src="https://github.com/dorny/pr-changed-files-filter/workflows/Build/badge.svg"></a>
|
||||
<a href="https://github.com/dorny/paths-filter/actions"><img alt="paths-filter status" src="https://github.com/dorny/paths-filter/workflows/Build/badge.svg"></a>
|
||||
</p>
|
||||
|
||||
> **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
|
||||
|
@ -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 <dorner.michal@gmail.com>'
|
||||
inputs:
|
||||
token:
|
||||
|
45
dist/index.js
vendored
45
dist/index.js
vendored
@ -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
|
||||
|
@ -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",
|
||||
|
12
src/git.ts
12
src/git.ts
@ -1,22 +1,22 @@
|
||||
import {exec} from '@actions/exec'
|
||||
|
||||
export async function fetchBranch(base: string): Promise<void> {
|
||||
const exitCode = await exec('git', ['fetch', '--depth=1', 'origin', base])
|
||||
export async function fetchCommit(sha: string): Promise<void> {
|
||||
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<string[]> {
|
||||
export async function getChangedFiles(sha: string): Promise<string[]> {
|
||||
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
|
||||
|
27
src/main.ts
27
src/main.ts
@ -12,14 +12,8 @@ async function run(): Promise<void> {
|
||||
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<string[]> {
|
||||
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<string[]> {
|
||||
async function getChangedFilesFromGit(sha: string): Promise<string[]> {
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user