Change detection via git + rename `githubToken` to `token` (#9)

This commit is contained in:
Michal Dorner 2020-05-26 17:16:09 +02:00 committed by GitHub
parent a2e5f9f7bb
commit 1cbb925a17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1318 additions and 31 deletions

2
.github/filters.yml vendored
View File

@ -1,2 +1,4 @@
error:
- not_existing_path/**/*
any:
- "**/*"

View File

@ -16,7 +16,23 @@ jobs:
npm install
npm run all
test:
test-inline:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./
id: filter
with:
filters: |
error:
- not_existing_path/**/*
any:
- "**/*"
- name: filter-test
if: steps.filter.outputs.any != 'true' || steps.filter.outputs.error == 'true'
run: exit 1
test-external:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@ -24,16 +40,19 @@ jobs:
id: filter
with:
filters: '.github/filters.yml'
- uses: ./
id: inlineFilter
with:
filters: |
src:
- src/**/*
tests:
- __tests__/**/*
any:
- "**/*"
- name: filter-test
if: steps.filter.outputs.any != 'true' || steps.inlineFilter.outputs.any != 'true'
if: steps.filter.outputs.any != 'true' || steps.filter.outputs.error == 'true'
run: exit 1
test-without-token:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ./
id: filter
with:
token: ''
filters: '.github/filters.yml'
- name: filter-test
if: steps.filter.outputs.any != 'true' || steps.filter.outputs.error == 'true'
run: exit 1

View File

@ -21,7 +21,7 @@ Corresponding output variable will be created to indicate if there's a changed f
Output variables can be later used in the `if` clause to conditionally run specific steps.
### Inputs
- **`githubToken`**: GitHub Access Token - defaults to `${{ github.token }}`
- **`token`**: GitHub Access Token - defaults to `${{ github.token }}`
- **`filters`**: Path to the configuration file or directly embedded string in YAML format. Filter configuration is a dictionary, where keys specifies rule names and values are lists of file path patterns.
### Outputs
@ -78,10 +78,11 @@ jobs:
## How it works
1. Required inputs are checked (`githubToken` & `filters`)
2. Provided access token is used to fetch list of changed files.
3. For each filter rule it checks if there is any matching file
4. Output variables are set
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
## Difference from related projects:

View File

@ -2,9 +2,9 @@ name: 'Pull request changed files filter'
description: 'Enables conditional execution of workflow job steps considering which files are modified by a pull request.'
author: 'Michal Dorner <dorner.michal@gmail.com>'
inputs:
githubToken:
token:
description: 'GitHub Access Token'
required: true
required: false
default: ${{ github.token }}
filters:
description: 'Path to the configuration file or YAML string with filters definition'

1226
dist/index.js vendored

File diff suppressed because it is too large Load Diff

13
package-lock.json generated
View File

@ -9,6 +9,14 @@
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.4.tgz",
"integrity": "sha512-YJCEq8BE3CdN8+7HPZ/4DxJjk/OkZV2FFIf+DlZTC/4iBlzYCD5yjRR6eiOS5llO11zbRltIRuKAjMKaWTE6cg=="
},
"@actions/exec": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.4.tgz",
"integrity": "sha512-4DPChWow9yc9W3WqEbUj8Nr86xkpyE29ZzWjXucHItclLbEW6jr80Zx4nqv18QL6KK65+cifiQZXvnqgTV6oHw==",
"requires": {
"@actions/io": "^1.0.1"
}
},
"@actions/github": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-2.2.0.tgz",
@ -27,6 +35,11 @@
"tunnel": "0.0.6"
}
},
"@actions/io": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz",
"integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg=="
},
"@babel/code-frame": {
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",

View File

@ -26,6 +26,7 @@
"license": "MIT",
"dependencies": {
"@actions/core": "^1.2.4",
"@actions/exec": "^1.0.4",
"@actions/github": "^2.2.0",
"@octokit/webhooks": "^7.6.2",
"minimatch": "^3.0.4"

26
src/git.ts Normal file
View File

@ -0,0 +1,26 @@
import {exec} from '@actions/exec'
export async function fetchBranch(base: string): Promise<void> {
const exitCode = await exec('git', ['fetch', '--depth=1', 'origin', base])
if (exitCode !== 0) {
throw new Error(`Fetching branch ${base} failed, exiting`)
}
}
export async function getChangedFiles(base: string): Promise<string[]> {
let output = ''
const exitCode = await exec('git', ['diff-index', '--name-only', base], {
listeners: {
stdout: (data: Buffer) => (output += data.toString())
}
})
if (exitCode !== 0) {
throw new Error(`Couldn't determine changed files, exiting`)
}
return output
.split('\n')
.map(s => s.trim())
.filter(s => s.length > 0)
}

View File

@ -4,16 +4,14 @@ import * as github from '@actions/github'
import {Webhooks} from '@octokit/webhooks'
import Filter from './filter'
import * as git from './git'
async function run(): Promise<void> {
try {
const token = core.getInput('githubToken', {required: true})
const token = core.getInput('token', {required: false})
const filtersInput = core.getInput('filters', {required: true})
const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput
const client = new github.GitHub(token)
if (github.context.eventName !== 'pull_request') {
core.setFailed('This action can be triggered only by pull_request event')
return
@ -21,7 +19,8 @@ async function run(): Promise<void> {
const pr = github.context.payload.pull_request as Webhooks.WebhookPayloadPullRequestPullRequest
const filter = new Filter(filtersYaml)
const files = await getChangedFiles(client, pr)
const files = token ? await getChangedFilesFromApi(token, pr) : await getChangedFilesFromGit(pr)
const result = filter.match(files)
for (const key in result) {
core.setOutput(key, String(result[key]))
@ -47,11 +46,21 @@ function getConfigFileContent(configPath: string): string {
return fs.readFileSync(configPath, {encoding: 'utf8'})
}
// Fetch base branch and use `git diff` to determine changed files
async function getChangedFilesFromGit(pullRequest: Webhooks.WebhookPayloadPullRequestPullRequest): 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)
}
// Uses github REST api to get list of files changed in PR
async function getChangedFiles(
client: github.GitHub,
async function getChangedFilesFromApi(
token: string,
pullRequest: Webhooks.WebhookPayloadPullRequestPullRequest
): Promise<string[]> {
core.debug('Fetching list of modified files from Github API')
const client = new github.GitHub(token)
const pageSize = 100
const files: string[] = []
for (let page = 0; page * pageSize < pullRequest.changed_files; page++) {