From b2c90faffd1a0ca5bea44194288a67bc6cf8edd1 Mon Sep 17 00:00:00 2001 From: Ruben Das Date: Wed, 6 Aug 2025 13:46:01 +0200 Subject: [PATCH] feat: allow configuring config path Currently this action assumes that the Redocly configuration lives in the root of wherever it is being run. That might not always be the case, thus I'm adding this option to be able to set where the config lives. --- action.yml | 3 ++ src/__tests__/helpers.test.ts | 60 +++++++++++++++++++++++++++++++---- src/helpers.ts | 12 +++++-- src/main.ts | 2 +- src/types.ts | 1 + 5 files changed, 68 insertions(+), 10 deletions(-) diff --git a/action.yml b/action.yml index c6739b2..2bdfbf8 100644 --- a/action.yml +++ b/action.yml @@ -27,6 +27,9 @@ inputs: description: 'Max execution time in seconds' required: false default: '1200' + configPath: + description: 'Path to Redocly config file' + required: false githubToken: description: 'Token to authenticate with' required: true diff --git a/src/__tests__/helpers.test.ts b/src/__tests__/helpers.test.ts index 838fe06..480be4c 100644 --- a/src/__tests__/helpers.test.ts +++ b/src/__tests__/helpers.test.ts @@ -1,7 +1,11 @@ import * as core from '@actions/core'; +import { Context } from '@actions/github/lib/context'; import { parseInputData, parseEventData, getRedoclyConfig } from '../helpers'; import { loadConfig } from '@redocly/openapi-core'; -import { Context } from '@actions/github/lib/context'; + +jest.mock('@redocly/openapi-core', () => ({ + loadConfig: jest.fn(), +})); let getInputMock: jest.SpiedFunction; @@ -64,7 +68,7 @@ describe('helpers', () => { }); describe('parseInputData', () => { - it('should return parsed input data', () => { + it('should return parsed input data without config', () => { getInputMock.mockImplementation( getGetInputMock({ organization: 'test-org-slug', @@ -77,7 +81,7 @@ describe('helpers', () => { ); const parsedInputData = parseInputData(); - expect(getInputMock).toHaveBeenCalledTimes(6); + expect(getInputMock).toHaveBeenCalledTimes(7); expect(parsedInputData).toEqual({ redoclyOrgSlug: 'test-org-slug', redoclyProjectSlug: 'test-project-slug', @@ -88,6 +92,36 @@ describe('helpers', () => { ], mountPath: 'test/mount/path', maxExecutionTime: 100, + configPath: undefined, + }); + }); + + it('should return parsed input data with custom config', () => { + getInputMock.mockImplementation( + getGetInputMock({ + organization: 'test-org-slug', + project: 'test-project-slug', + domain: 'redocly-domain.com', + files: 'testFolder testOpenApiFile.yaml', + mountPath: 'test/mount/path', + maxExecutionTime: '100', + configPath: 'custom/path/redocly.yaml', + }), + ); + const parsedInputData = parseInputData(); + + expect(getInputMock).toHaveBeenCalledTimes(7); + expect(parsedInputData).toEqual({ + redoclyOrgSlug: 'test-org-slug', + redoclyProjectSlug: 'test-project-slug', + redoclyDomain: 'redocly-domain.com', + files: [ + '/home/runner/work/reunite-push-action/testFolder', + '/home/runner/work/reunite-push-action/testOpenApiFile.yaml', + ], + mountPath: 'test/mount/path', + maxExecutionTime: 100, + configPath: 'custom/path/redocly.yaml', }); }); }); @@ -114,9 +148,23 @@ describe('helpers', () => { }); describe('getRedoclyConfig', () => { - it('should return redocly config', async () => { - const redoclyConfig = await getRedoclyConfig(); - expect(typeof redoclyConfig).toBe(typeof loadConfig({})); + const mockLoadConfig = loadConfig as jest.MockedFunction; + + beforeEach(() => { + mockLoadConfig.mockResolvedValue({} as ReturnType); + }); + + it('should return redocly config with default path', async () => { + await getRedoclyConfig(); + expect(mockLoadConfig).toHaveBeenCalledWith(undefined); + }); + + it('should return redocly config with custom path', async () => { + const customConfigPath = 'custom/path/redocly.yaml'; + await getRedoclyConfig(customConfigPath); + expect(mockLoadConfig).toHaveBeenCalledWith({ + configPath: customConfigPath, + }); }); }); }); diff --git a/src/helpers.ts b/src/helpers.ts index 33d60e8..7545448 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -13,6 +13,7 @@ export function parseInputData(): ParsedInputData { const redoclyDomain = core.getInput('domain') || 'https://app.cloud.redocly.com'; const maxExecutionTime = Number(core.getInput('maxExecutionTime')) || 1200; + const configPath = core.getInput('configPath') || undefined; const absoluteFilePaths = files.map(_path => path.join(process.env.GITHUB_WORKSPACE || '', _path), @@ -25,6 +26,7 @@ export function parseInputData(): ParsedInputData { files: absoluteFilePaths, redoclyDomain, maxExecutionTime, + configPath, }; } @@ -124,9 +126,13 @@ function getCommitSha(): string | undefined { } } -// Returns parsed config from the root or default config if not found -export async function getRedoclyConfig(): ReturnType { - const redoclyConfig = await loadConfig(); +// Returns parsed config from the specified path or default config if not found +export async function getRedoclyConfig( + configPath?: string, +): ReturnType { + const redoclyConfig = await loadConfig( + configPath ? { configPath } : undefined, + ); return redoclyConfig; } diff --git a/src/main.ts b/src/main.ts index c73bdff..5eeb129 100644 --- a/src/main.ts +++ b/src/main.ts @@ -18,7 +18,7 @@ export async function run(): Promise { console.debug('Parsed input data', inputData); console.debug('Parsed GitHub event', ghEvent); - const config = await getRedoclyConfig(); + const config = await getRedoclyConfig(inputData.configPath); const pushData = await handlePush({ argv: { diff --git a/src/types.ts b/src/types.ts index 66a065e..e022803 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5,6 +5,7 @@ export interface ParsedInputData { files: string[]; mountPath: string; maxExecutionTime: number; + configPath?: string; } export interface ParsedEventData {