From d74248fff01a1ae5b4d93a68dd561eba1f38d602 Mon Sep 17 00:00:00 2001 From: Stephen Way Date: Mon, 6 Oct 2025 08:38:06 -0700 Subject: [PATCH] feat: respect working_directory for files globs; add input and tests --- __tests__/util.test.ts | 19 +++++++++++++++++++ action.yml | 3 +++ src/main.ts | 4 ++-- src/util.ts | 32 ++++++++++++++++++++++++++------ 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/__tests__/util.test.ts b/__tests__/util.test.ts index 87e0ad3..fca856e 100644 --- a/__tests__/util.test.ts +++ b/__tests__/util.test.ts @@ -128,6 +128,7 @@ describe('util', () => { github_ref: '', github_repository: '', github_token: '', + input_working_directory: undefined, input_append_body: false, input_body: undefined, input_body_path: undefined, @@ -156,6 +157,7 @@ describe('util', () => { github_ref: '', github_repository: '', github_token: '', + input_working_directory: undefined, input_append_body: false, input_body: undefined, input_body_path: undefined, @@ -183,6 +185,7 @@ describe('util', () => { github_ref: '', github_repository: '', github_token: '', + input_working_directory: undefined, input_append_body: false, input_body: undefined, input_body_path: undefined, @@ -211,6 +214,7 @@ describe('util', () => { github_ref: '', github_repository: '', github_token: '', + input_working_directory: undefined, input_append_body: false, input_body: undefined, input_body_path: undefined, @@ -243,6 +247,7 @@ describe('util', () => { github_ref: '', github_repository: '', github_token: 'env-token', + input_working_directory: undefined, input_append_body: false, input_body: undefined, input_body_path: undefined, @@ -272,6 +277,7 @@ describe('util', () => { github_ref: '', github_repository: '', github_token: 'input-token', + input_working_directory: undefined, input_append_body: false, input_body: undefined, input_body_path: undefined, @@ -300,6 +306,7 @@ describe('util', () => { github_ref: '', github_repository: '', github_token: '', + input_working_directory: undefined, input_append_body: false, input_body: undefined, input_body_path: undefined, @@ -327,6 +334,7 @@ describe('util', () => { github_ref: '', github_repository: '', github_token: '', + input_working_directory: undefined, input_append_body: false, input_body: undefined, input_body_path: undefined, @@ -354,6 +362,7 @@ describe('util', () => { github_ref: '', github_repository: '', github_token: '', + input_working_directory: undefined, input_append_body: true, input_body: undefined, input_body_path: undefined, @@ -388,6 +397,10 @@ describe('util', () => { 'tests/data/foo/bar.txt', ]); }); + + it('resolves files relative to working_directory', async () => { + assert.deepStrictEqual(paths(['data/**/*'], 'tests'), ['tests/data/foo/bar.txt']); + }); }); describe('unmatchedPatterns', () => { @@ -397,6 +410,12 @@ describe('util', () => { ['tests/data/does/not/exist/*'], ); }); + + it('resolves unmatched relative to working_directory', async () => { + assert.deepStrictEqual(unmatchedPatterns(['data/does/not/exist/*'], 'tests'), [ + 'data/does/not/exist/*', + ]); + }); }); describe('replaceSpacesWithDots', () => { diff --git a/action.yml b/action.yml index e9319e6..cb49005 100644 --- a/action.yml +++ b/action.yml @@ -27,6 +27,9 @@ inputs: files: description: "Newline-delimited list of path globs for asset files to upload" required: false + working_directory: + description: "Base directory to resolve 'files' globs against (defaults to job working-directory)" + required: false overwrite_files: description: "Overwrite existing files with the same name. Defaults to true" required: false diff --git a/src/main.ts b/src/main.ts index b645a18..79bf326 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,7 +12,7 @@ async function run() { throw new Error(`⚠️ GitHub Releases requires a tag`); } if (config.input_files) { - const patterns = unmatchedPatterns(config.input_files); + const patterns = unmatchedPatterns(config.input_files, config.input_working_directory); patterns.forEach((pattern) => { if (config.input_fail_on_unmatched_files) { throw new Error(`⚠️ Pattern '${pattern}' does not match any files.`); @@ -50,7 +50,7 @@ async function run() { //); const rel = await release(config, new GitHubReleaser(gh)); if (config.input_files && config.input_files.length > 0) { - const files = paths(config.input_files); + const files = paths(config.input_files, config.input_working_directory); if (files.length == 0) { if (config.input_fail_on_unmatched_files) { throw new Error(`⚠️ ${config.input_files} does not include a valid file.`); diff --git a/src/util.ts b/src/util.ts index c6e2b4d..7a115d0 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,5 +1,6 @@ import * as glob from 'glob'; import { statSync, readFileSync } from 'fs'; +import * as pathLib from 'path'; export interface Config { github_token: string; @@ -12,6 +13,7 @@ export interface Config { input_body?: string; input_body_path?: string; input_files?: string[]; + input_working_directory?: string; input_overwrite_files?: boolean; input_draft?: boolean; input_preserve_order?: boolean; @@ -62,6 +64,7 @@ export const parseConfig = (env: Env): Config => { input_body: env.INPUT_BODY, input_body_path: env.INPUT_BODY_PATH, input_files: parseInputFiles(env.INPUT_FILES || ''), + input_working_directory: env.INPUT_WORKING_DIRECTORY || undefined, input_overwrite_files: env.INPUT_OVERWRITE_FILES ? env.INPUT_OVERWRITE_FILES == 'true' : undefined, @@ -84,17 +87,34 @@ const parseMakeLatest = (value: string | undefined): 'true' | 'false' | 'legacy' return undefined; }; -export const paths = (patterns: string[]): string[] => { +export const paths = (patterns: string[], cwd?: string): string[] => { return patterns.reduce((acc: string[], pattern: string): string[] => { - return acc.concat(glob.sync(pattern).filter((path) => statSync(path).isFile())); + const matches = glob.sync(pattern, { cwd, dot: true, absolute: false }); + const resolved = matches + .map((p) => (cwd ? pathLib.join(cwd, p) : p)) + .filter((p) => { + try { + return statSync(p).isFile(); + } catch { + return false; + } + }); + return acc.concat(resolved); }, []); }; -export const unmatchedPatterns = (patterns: string[]): string[] => { +export const unmatchedPatterns = (patterns: string[], cwd?: string): string[] => { return patterns.reduce((acc: string[], pattern: string): string[] => { - return acc.concat( - glob.sync(pattern).filter((path) => statSync(path).isFile()).length == 0 ? [pattern] : [], - ); + const matches = glob.sync(pattern, { cwd, dot: true, absolute: false }); + const files = matches.filter((p) => { + try { + const full = cwd ? pathLib.join(cwd, p) : p; + return statSync(full).isFile(); + } catch { + return false; + } + }); + return acc.concat(files.length == 0 ? [pattern] : []); }, []); };