From 8e9748af400cc7456dd9436869116850d6a83cdd Mon Sep 17 00:00:00 2001 From: Gonzalo Peci Date: Wed, 15 Jan 2025 10:47:43 +0100 Subject: [PATCH 1/7] Allow input of files --- src/main.ts | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/main.ts b/src/main.ts index 8320287..5f0757c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,9 @@ -import * as fs from 'fs' import * as core from '@actions/core' +import * as fs from 'fs' import * as github from '@actions/github' -import {GetResponseDataTypeFromEndpointMethod} from '@octokit/types' -import {PushEvent, PullRequestEvent} from '@octokit/webhooks-types' +import * as jsyaml from 'js-yaml' +import { GetResponseDataTypeFromEndpointMethod } from '@octokit/types' +import { PushEvent, PullRequestEvent } from '@octokit/webhooks-types' import { isPredicateQuantifier, @@ -12,28 +13,29 @@ import { PredicateQuantifier, SUPPORTED_PREDICATE_QUANTIFIERS } from './filter' -import {File, ChangeStatus} from './file' +import { File, ChangeStatus } from './file' import * as git from './git' -import {backslashEscape, shellEscape} from './list-format/shell-escape' -import {csvEscape} from './list-format/csv-escape' +import { backslashEscape, shellEscape } from './list-format/shell-escape' +import { csvEscape } from './list-format/csv-escape' type ExportFormat = 'none' | 'csv' | 'json' | 'shell' | 'escape' async function run(): Promise { try { - const workingDirectory = core.getInput('working-directory', {required: false}) + const workingDirectory = core.getInput('working-directory', { required: false }) if (workingDirectory) { 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 token = core.getInput('token', { required: false }) + const ref = core.getInput('ref', { required: false }) + const base = core.getInput('base', { required: false }) + const filesInput = core.getInput('files', { required: false }) + const filtersInput = core.getInput('filters', { required: true }) const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput - const listFiles = core.getInput('list-files', {required: false}).toLowerCase() || 'none' - const initialFetchDepth = parseInt(core.getInput('initial-fetch-depth', {required: false})) || 10 - const predicateQuantifier = core.getInput('predicate-quantifier', {required: false}) || PredicateQuantifier.SOME + const listFiles = core.getInput('list-files', { required: false }).toLowerCase() || 'none' + const initialFetchDepth = parseInt(core.getInput('initial-fetch-depth', { required: false })) || 10 + const predicateQuantifier = core.getInput('predicate-quantifier', { required: false }) || PredicateQuantifier.SOME if (!isExportFormat(listFiles)) { core.setFailed(`Input parameter 'list-files' is set to invalid value '${listFiles}'`) @@ -46,10 +48,10 @@ async function run(): Promise { `'${predicateQuantifier}'. Valid values: ${SUPPORTED_PREDICATE_QUANTIFIERS.join(', ')}` throw new Error(predicateQuantifierInvalidErrorMsg) } - const filterConfig: FilterConfig = {predicateQuantifier} + const filterConfig: FilterConfig = { predicateQuantifier } const filter = new Filter(filtersYaml, filterConfig) - const files = await getChangedFiles(token, base, ref, initialFetchDepth) + const files = await getChangedFiles(filesInput, token, base, ref, initialFetchDepth) core.info(`Detected ${files.length} changed files`) const results = filter.match(files) exportResults(results, listFiles) @@ -71,10 +73,21 @@ function getConfigFileContent(configPath: string): string { throw new Error(`'${configPath}' is not a file.`) } - return fs.readFileSync(configPath, {encoding: 'utf8'}) + return fs.readFileSync(configPath, { encoding: 'utf8' }) } -async function getChangedFiles(token: string, base: string, ref: string, initialFetchDepth: number): Promise { +async function getChangedFiles( + files: string, + token: string, + base: string, + ref: string, + initialFetchDepth: number +): Promise { + if (files) { + const doc = jsyaml.load(files) as string[] + return doc.map(filename => ({ filename, status: ChangeStatus.Modified })) + } + // 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) { From f804c5006dabde697617941f88d986203438f432 Mon Sep 17 00:00:00 2001 From: Gonzalo Peci Date: Wed, 15 Jan 2025 10:49:25 +0100 Subject: [PATCH 2/7] Add to action def --- action.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/action.yml b/action.yml index e7d24f5..6b984fe 100644 --- a/action.yml +++ b/action.yml @@ -1,13 +1,13 @@ -name: 'Paths Changes Filter' -description: 'Execute your workflow steps only if relevant files are modified.' -author: 'Michal Dorner ' +name: "Paths Changes Filter" +description: "Execute your workflow steps only if relevant files are modified." +author: "Michal Dorner " inputs: token: - description: 'GitHub Access Token' + description: "GitHub Access Token" required: false default: ${{ github.token }} working-directory: - description: 'Relative path under $GITHUB_WORKSPACE where the repository was checked out.' + description: "Relative path under $GITHUB_WORKSPACE where the repository was checked out." required: false ref: description: | @@ -20,8 +20,11 @@ inputs: If it references same branch it was pushed to, changes are detected against the most recent commit before the push. This option is ignored if action is triggered by pull_request event. required: false + files: + description: "Manual list of files to filter" + required: false filters: - description: 'Path to the configuration file or YAML string with filters definition' + description: "Path to the configuration file or YAML string with filters definition" required: true list-files: description: | @@ -43,13 +46,13 @@ inputs: until the merge-base is found or there are no more commits in the history. This option takes effect only when changes are detected using git against different base branch. required: false - default: '100' + default: "100" outputs: changes: description: JSON array with names of all filters matching any of changed files runs: - using: 'node20' - main: 'dist/index.js' + using: "node20" + main: "dist/index.js" branding: color: blue icon: filter From 5a3321d2f37a12683f2aa8d4ff13f5a55f66ddd8 Mon Sep 17 00:00:00 2001 From: Gonzalo Peci Date: Wed, 15 Jan 2025 10:56:21 +0100 Subject: [PATCH 3/7] Notify on manual list --- src/main.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.ts b/src/main.ts index 5f0757c..e43301b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -84,6 +84,7 @@ async function getChangedFiles( initialFetchDepth: number ): Promise { if (files) { + core.info('Using list of files provided as input') const doc = jsyaml.load(files) as string[] return doc.map(filename => ({ filename, status: ChangeStatus.Modified })) } From 1791a2a502b8f9fef41d563cd40bd2432c35b88f Mon Sep 17 00:00:00 2001 From: Gonzalo Peci Date: Wed, 15 Jan 2025 11:00:48 +0100 Subject: [PATCH 4/7] Verbose --- src/main.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.ts b/src/main.ts index e43301b..ed64245 100644 --- a/src/main.ts +++ b/src/main.ts @@ -51,6 +51,7 @@ async function run(): Promise { const filterConfig: FilterConfig = { predicateQuantifier } const filter = new Filter(filtersYaml, filterConfig) + core.info(`Detected ${filesInput} files`) const files = await getChangedFiles(filesInput, token, base, ref, initialFetchDepth) core.info(`Detected ${files.length} changed files`) const results = filter.match(files) From c41a842fa7df5897896789f61f6945d1bb06da6d Mon Sep 17 00:00:00 2001 From: Gonzalo Peci Date: Wed, 15 Jan 2025 11:05:23 +0100 Subject: [PATCH 5/7] Compile --- dist/index.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dist/index.js b/dist/index.js index cc7d7d4..f7ccea5 100644 --- a/dist/index.js +++ b/dist/index.js @@ -553,9 +553,10 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -const fs = __importStar(__nccwpck_require__(7147)); const core = __importStar(__nccwpck_require__(2186)); +const fs = __importStar(__nccwpck_require__(7147)); const github = __importStar(__nccwpck_require__(5438)); +const jsyaml = __importStar(__nccwpck_require__(1917)); const filter_1 = __nccwpck_require__(3707); const file_1 = __nccwpck_require__(4014); const git = __importStar(__nccwpck_require__(3374)); @@ -570,6 +571,7 @@ async function run() { const token = core.getInput('token', { required: false }); const ref = core.getInput('ref', { required: false }); const base = core.getInput('base', { required: false }); + const filesInput = core.getInput('files', { required: false }); const filtersInput = core.getInput('filters', { required: true }); const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput; const listFiles = core.getInput('list-files', { required: false }).toLowerCase() || 'none'; @@ -586,7 +588,8 @@ async function run() { } const filterConfig = { predicateQuantifier }; const filter = new filter_1.Filter(filtersYaml, filterConfig); - const files = await getChangedFiles(token, base, ref, initialFetchDepth); + core.info(`Detected ${filesInput} files`); + const files = await getChangedFiles(filesInput, token, base, ref, initialFetchDepth); core.info(`Detected ${files.length} changed files`); const results = filter.match(files); exportResults(results, listFiles); @@ -607,8 +610,13 @@ function getConfigFileContent(configPath) { } return fs.readFileSync(configPath, { encoding: 'utf8' }); } -async function getChangedFiles(token, base, ref, initialFetchDepth) { +async function getChangedFiles(files, token, base, ref, initialFetchDepth) { var _a, _b; + if (files) { + core.info('Using list of files provided as input'); + const doc = jsyaml.load(files); + return doc.map(filename => ({ filename, status: file_1.ChangeStatus.Modified })); + } // 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) { From 5c998f8d708cc452fc83f987b268843830b707b9 Mon Sep 17 00:00:00 2001 From: Gonzalo Peci Date: Wed, 15 Jan 2025 11:06:16 +0100 Subject: [PATCH 6/7] Format --- src/main.ts | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main.ts b/src/main.ts index ed64245..ae33428 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,8 +2,8 @@ import * as core from '@actions/core' import * as fs from 'fs' import * as github from '@actions/github' import * as jsyaml from 'js-yaml' -import { GetResponseDataTypeFromEndpointMethod } from '@octokit/types' -import { PushEvent, PullRequestEvent } from '@octokit/webhooks-types' +import {GetResponseDataTypeFromEndpointMethod} from '@octokit/types' +import {PushEvent, PullRequestEvent} from '@octokit/webhooks-types' import { isPredicateQuantifier, @@ -13,29 +13,29 @@ import { PredicateQuantifier, SUPPORTED_PREDICATE_QUANTIFIERS } from './filter' -import { File, ChangeStatus } from './file' +import {File, ChangeStatus} from './file' import * as git from './git' -import { backslashEscape, shellEscape } from './list-format/shell-escape' -import { csvEscape } from './list-format/csv-escape' +import {backslashEscape, shellEscape} from './list-format/shell-escape' +import {csvEscape} from './list-format/csv-escape' type ExportFormat = 'none' | 'csv' | 'json' | 'shell' | 'escape' async function run(): Promise { try { - const workingDirectory = core.getInput('working-directory', { required: false }) + const workingDirectory = core.getInput('working-directory', {required: false}) if (workingDirectory) { 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 filesInput = core.getInput('files', { required: false }) - const filtersInput = core.getInput('filters', { required: true }) + const token = core.getInput('token', {required: false}) + const ref = core.getInput('ref', {required: false}) + const base = core.getInput('base', {required: false}) + const filesInput = core.getInput('files', {required: false}) + const filtersInput = core.getInput('filters', {required: true}) const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput - const listFiles = core.getInput('list-files', { required: false }).toLowerCase() || 'none' - const initialFetchDepth = parseInt(core.getInput('initial-fetch-depth', { required: false })) || 10 - const predicateQuantifier = core.getInput('predicate-quantifier', { required: false }) || PredicateQuantifier.SOME + const listFiles = core.getInput('list-files', {required: false}).toLowerCase() || 'none' + const initialFetchDepth = parseInt(core.getInput('initial-fetch-depth', {required: false})) || 10 + const predicateQuantifier = core.getInput('predicate-quantifier', {required: false}) || PredicateQuantifier.SOME if (!isExportFormat(listFiles)) { core.setFailed(`Input parameter 'list-files' is set to invalid value '${listFiles}'`) @@ -48,7 +48,7 @@ async function run(): Promise { `'${predicateQuantifier}'. Valid values: ${SUPPORTED_PREDICATE_QUANTIFIERS.join(', ')}` throw new Error(predicateQuantifierInvalidErrorMsg) } - const filterConfig: FilterConfig = { predicateQuantifier } + const filterConfig: FilterConfig = {predicateQuantifier} const filter = new Filter(filtersYaml, filterConfig) core.info(`Detected ${filesInput} files`) @@ -74,7 +74,7 @@ function getConfigFileContent(configPath: string): string { throw new Error(`'${configPath}' is not a file.`) } - return fs.readFileSync(configPath, { encoding: 'utf8' }) + return fs.readFileSync(configPath, {encoding: 'utf8'}) } async function getChangedFiles( @@ -87,7 +87,7 @@ async function getChangedFiles( if (files) { core.info('Using list of files provided as input') const doc = jsyaml.load(files) as string[] - return doc.map(filename => ({ filename, status: ChangeStatus.Modified })) + return doc.map(filename => ({filename, status: ChangeStatus.Modified})) } // if base is 'HEAD' only local uncommitted changes will be detected From c4d782da08894ae289f4bdbcb22f8dac65d7f22a Mon Sep 17 00:00:00 2001 From: Gonzalo Peci Date: Fri, 17 Jan 2025 10:10:10 +0100 Subject: [PATCH 7/7] Format --- src/main.ts | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/main.ts b/src/main.ts index ae33428..e43301b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,8 +2,8 @@ import * as core from '@actions/core' import * as fs from 'fs' import * as github from '@actions/github' import * as jsyaml from 'js-yaml' -import {GetResponseDataTypeFromEndpointMethod} from '@octokit/types' -import {PushEvent, PullRequestEvent} from '@octokit/webhooks-types' +import { GetResponseDataTypeFromEndpointMethod } from '@octokit/types' +import { PushEvent, PullRequestEvent } from '@octokit/webhooks-types' import { isPredicateQuantifier, @@ -13,29 +13,29 @@ import { PredicateQuantifier, SUPPORTED_PREDICATE_QUANTIFIERS } from './filter' -import {File, ChangeStatus} from './file' +import { File, ChangeStatus } from './file' import * as git from './git' -import {backslashEscape, shellEscape} from './list-format/shell-escape' -import {csvEscape} from './list-format/csv-escape' +import { backslashEscape, shellEscape } from './list-format/shell-escape' +import { csvEscape } from './list-format/csv-escape' type ExportFormat = 'none' | 'csv' | 'json' | 'shell' | 'escape' async function run(): Promise { try { - const workingDirectory = core.getInput('working-directory', {required: false}) + const workingDirectory = core.getInput('working-directory', { required: false }) if (workingDirectory) { 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 filesInput = core.getInput('files', {required: false}) - const filtersInput = core.getInput('filters', {required: true}) + const token = core.getInput('token', { required: false }) + const ref = core.getInput('ref', { required: false }) + const base = core.getInput('base', { required: false }) + const filesInput = core.getInput('files', { required: false }) + const filtersInput = core.getInput('filters', { required: true }) const filtersYaml = isPathInput(filtersInput) ? getConfigFileContent(filtersInput) : filtersInput - const listFiles = core.getInput('list-files', {required: false}).toLowerCase() || 'none' - const initialFetchDepth = parseInt(core.getInput('initial-fetch-depth', {required: false})) || 10 - const predicateQuantifier = core.getInput('predicate-quantifier', {required: false}) || PredicateQuantifier.SOME + const listFiles = core.getInput('list-files', { required: false }).toLowerCase() || 'none' + const initialFetchDepth = parseInt(core.getInput('initial-fetch-depth', { required: false })) || 10 + const predicateQuantifier = core.getInput('predicate-quantifier', { required: false }) || PredicateQuantifier.SOME if (!isExportFormat(listFiles)) { core.setFailed(`Input parameter 'list-files' is set to invalid value '${listFiles}'`) @@ -48,10 +48,9 @@ async function run(): Promise { `'${predicateQuantifier}'. Valid values: ${SUPPORTED_PREDICATE_QUANTIFIERS.join(', ')}` throw new Error(predicateQuantifierInvalidErrorMsg) } - const filterConfig: FilterConfig = {predicateQuantifier} + const filterConfig: FilterConfig = { predicateQuantifier } const filter = new Filter(filtersYaml, filterConfig) - core.info(`Detected ${filesInput} files`) const files = await getChangedFiles(filesInput, token, base, ref, initialFetchDepth) core.info(`Detected ${files.length} changed files`) const results = filter.match(files) @@ -74,7 +73,7 @@ function getConfigFileContent(configPath: string): string { throw new Error(`'${configPath}' is not a file.`) } - return fs.readFileSync(configPath, {encoding: 'utf8'}) + return fs.readFileSync(configPath, { encoding: 'utf8' }) } async function getChangedFiles( @@ -87,7 +86,7 @@ async function getChangedFiles( if (files) { core.info('Using list of files provided as input') const doc = jsyaml.load(files) as string[] - return doc.map(filename => ({filename, status: ChangeStatus.Modified})) + return doc.map(filename => ({ filename, status: ChangeStatus.Modified })) } // if base is 'HEAD' only local uncommitted changes will be detected