From 914052aadcc37764030c56b9139482a115146cb4 Mon Sep 17 00:00:00 2001 From: BM Cho Date: Fri, 17 Jul 2026 17:07:36 +0800 Subject: [PATCH] fix: support comments in .nvmrc files --- __tests__/main.test.ts | 29 +++++++++++++++++++++++++++++ dist/cache-save/index.js | 15 +++++++++++++-- dist/setup/index.js | 15 +++++++++++++-- src/util.ts | 20 ++++++++++++++++++-- 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 382d8b196..4a96d2863 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -216,6 +216,35 @@ describe('main tests', () => { expect(util.getNodeVersionFromFile('file')).toBe(expected); }); + + each` + name | contents | expected + ${'ignores blank lines and comments'} | ${'# use the version below\n\n 20.16.0 # maintenance release\n'} | ${'20.16.0'} + ${'strips an inline comment'} | ${'v20.16.0 # maintenance release'} | ${'20.16.0'} + ${'preserves an alias before a comment'} | ${'lts/* # use the latest LTS'} | ${'lts/*'} + ${'rejects a comment-only file'} | ${'# comment only'} | ${null} + ${'rejects comments and whitespace only'} | ${'#\r\n # another comment\r\n'} | ${null} + `.it('$name', ({contents, expected}: any) => { + const existsSpy = jest.spyOn(fs, 'existsSync'); + existsSpy.mockImplementation(() => true); + + const readFileSpy = jest.spyOn(fs, 'readFileSync'); + readFileSpy.mockImplementation(() => contents); + + expect(util.getNodeVersionFromFile('.nvmrc')).toBe(expected); + }); + + it('preserves .tool-versions parsing', () => { + const existsSpy = jest.spyOn(fs, 'existsSync'); + existsSpy.mockImplementation(() => true); + + const readFileSpy = jest.spyOn(fs, 'readFileSync'); + readFileSpy.mockImplementation( + () => 'ruby 3.3.0\nnodejs 20.16.0\npython 3.12.0' + ); + + expect(util.getNodeVersionFromFile('.tool-versions')).toBe('20.16.0'); + }); }); describe('printEnvDetailsAndSetOutput', () => { diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js index 49820c5df..8852f9d1b 100644 --- a/dist/cache-save/index.js +++ b/dist/cache-save/index.js @@ -92709,8 +92709,19 @@ function getNodeVersionFromFile(versionFilePath) { catch { core.info('Node version file is not JSON file'); } - const found = contents.match(/^(?:node(js)?\s+)?v?(?[^\s]+)$/m); - return found?.groups?.version ?? contents.trim(); + let versionFileContents = contents; + if (path.basename(versionFilePath) === '.nvmrc') { + versionFileContents = contents + .split(/\r?\n/) + .map(line => line.replace(/#.*/, '').trim()) + .filter(Boolean) + .join('\n'); + if (!versionFileContents) { + return null; + } + } + const found = versionFileContents.match(/^(?:node(js)?\s+)?v?(?[^\s]+)$/m); + return found?.groups?.version ?? versionFileContents.trim(); } async function printEnvDetailsAndSetOutput() { core.startGroup('Environment details'); diff --git a/dist/setup/index.js b/dist/setup/index.js index 105c3a9cf..8eec56b67 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -98103,8 +98103,19 @@ function getNodeVersionFromFile(versionFilePath) { catch { core_info('Node version file is not JSON file'); } - const found = contents.match(/^(?:node(js)?\s+)?v?(?[^\s]+)$/m); - return found?.groups?.version ?? contents.trim(); + let versionFileContents = contents; + if (external_path_default().basename(versionFilePath) === '.nvmrc') { + versionFileContents = contents + .split(/\r?\n/) + .map(line => line.replace(/#.*/, '').trim()) + .filter(Boolean) + .join('\n'); + if (!versionFileContents) { + return null; + } + } + const found = versionFileContents.match(/^(?:node(js)?\s+)?v?(?[^\s]+)$/m); + return found?.groups?.version ?? versionFileContents.trim(); } async function printEnvDetailsAndSetOutput() { startGroup('Environment details'); diff --git a/src/util.ts b/src/util.ts index 1663a4064..8186d1fb1 100644 --- a/src/util.ts +++ b/src/util.ts @@ -68,8 +68,24 @@ export function getNodeVersionFromFile(versionFilePath: string): string | null { core.info('Node version file is not JSON file'); } - const found = contents.match(/^(?:node(js)?\s+)?v?(?[^\s]+)$/m); - return found?.groups?.version ?? contents.trim(); + let versionFileContents = contents; + + if (path.basename(versionFilePath) === '.nvmrc') { + versionFileContents = contents + .split(/\r?\n/) + .map(line => line.replace(/#.*/, '').trim()) + .filter(Boolean) + .join('\n'); + + if (!versionFileContents) { + return null; + } + } + + const found = versionFileContents.match( + /^(?:node(js)?\s+)?v?(?[^\s]+)$/m + ); + return found?.groups?.version ?? versionFileContents.trim(); } export async function printEnvDetailsAndSetOutput() {