From ed69f3bbdd331f561e02e4ba566bb550e2ea906b Mon Sep 17 00:00:00 2001 From: Michael Wyraz Date: Thu, 5 Mar 2026 15:54:36 +0100 Subject: [PATCH] feat: override fetch-depth to 0 when reference-cache is active When reference-cache is enabled, shallow fetches (fetch-depth > 0) are counterproductive because objects are served from the local cache. Shallow negotiation only adds network latency without saving bandwidth. If fetch-depth was not explicitly set by the user, it is automatically overridden to 0. If explicitly set, a warning is emitted explaining the performance impact. Signed-off-by: Michael Wyraz --- __test__/git-auth-helper.test.ts | 1 + __test__/git-source-provider.test.ts | 88 ++++++++++++++++++++++++++++ dist/index.js | 26 +++++++- src/git-source-provider.ts | 31 ++++++++++ src/git-source-settings.ts | 5 ++ src/input-helper.ts | 4 +- 6 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 __test__/git-source-provider.test.ts diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts index 4f6133f..d3936e2 100644 --- a/__test__/git-auth-helper.test.ts +++ b/__test__/git-auth-helper.test.ts @@ -1159,6 +1159,7 @@ async function setup(testName: string): Promise { sparseCheckout: [], sparseCheckoutConeMode: true, fetchDepth: 1, + fetchDepthExplicit: false, fetchTags: false, showProgress: true, lfs: false, diff --git a/__test__/git-source-provider.test.ts b/__test__/git-source-provider.test.ts new file mode 100644 index 0000000..dd2d6f2 --- /dev/null +++ b/__test__/git-source-provider.test.ts @@ -0,0 +1,88 @@ +import * as core from '@actions/core' +import {adjustFetchDepthForCache} from '../src/git-source-provider' + +// Mock @actions/core +jest.mock('@actions/core') + +describe('adjustFetchDepthForCache', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + it('does nothing when referenceCache is not set', () => { + const settings = { + referenceCache: '', + fetchDepth: 1, + fetchDepthExplicit: false + } + adjustFetchDepthForCache(settings) + expect(settings.fetchDepth).toBe(1) + expect(core.warning).not.toHaveBeenCalled() + expect(core.info).not.toHaveBeenCalled() + }) + + it('overrides fetchDepth to 0 when referenceCache is set and fetchDepth is default', () => { + const settings = { + referenceCache: '/cache/git-reference-cache', + fetchDepth: 1, + fetchDepthExplicit: false + } + adjustFetchDepthForCache(settings) + expect(settings.fetchDepth).toBe(0) + expect(core.info).toHaveBeenCalledWith( + expect.stringContaining('Overriding fetch-depth from 1 to 0') + ) + expect(core.warning).not.toHaveBeenCalled() + }) + + it('warns but keeps fetchDepth when referenceCache is set and fetchDepth is explicit', () => { + const settings = { + referenceCache: '/cache/git-reference-cache', + fetchDepth: 1, + fetchDepthExplicit: true + } + adjustFetchDepthForCache(settings) + expect(settings.fetchDepth).toBe(1) + expect(core.warning).toHaveBeenCalledWith( + expect.stringContaining("'fetch-depth: 1' is set with reference-cache enabled") + ) + expect(core.info).not.toHaveBeenCalled() + }) + + it('does nothing when referenceCache is set and fetchDepth is already 0 (explicit)', () => { + const settings = { + referenceCache: '/cache/git-reference-cache', + fetchDepth: 0, + fetchDepthExplicit: true + } + adjustFetchDepthForCache(settings) + expect(settings.fetchDepth).toBe(0) + expect(core.warning).not.toHaveBeenCalled() + expect(core.info).not.toHaveBeenCalled() + }) + + it('does nothing when referenceCache is set and fetchDepth is already 0 (default)', () => { + const settings = { + referenceCache: '/cache/git-reference-cache', + fetchDepth: 0, + fetchDepthExplicit: false + } + adjustFetchDepthForCache(settings) + expect(settings.fetchDepth).toBe(0) + expect(core.warning).not.toHaveBeenCalled() + expect(core.info).not.toHaveBeenCalled() + }) + + it('warns with correct depth value when explicit fetchDepth is > 1', () => { + const settings = { + referenceCache: '/cache/git-reference-cache', + fetchDepth: 42, + fetchDepthExplicit: true + } + adjustFetchDepthForCache(settings) + expect(settings.fetchDepth).toBe(42) + expect(core.warning).toHaveBeenCalledWith( + expect.stringContaining("'fetch-depth: 42' is set with reference-cache enabled") + ) + }) +}) diff --git a/dist/index.js b/dist/index.js index 3659660..23666bf 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1581,6 +1581,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getSource = getSource; exports.cleanup = cleanup; +exports.adjustFetchDepthForCache = adjustFetchDepthForCache; const core = __importStar(__nccwpck_require__(2186)); const fsHelper = __importStar(__nccwpck_require__(7219)); const gitAuthHelper = __importStar(__nccwpck_require__(2565)); @@ -1841,6 +1842,9 @@ function getSource(settings) { if (settings.lfs) { yield git.lfsInstall(); } + // When using reference cache, fetch-depth > 0 is counterproductive: + // objects are served from the local cache, so shallow negotiation only adds latency. + adjustFetchDepthForCache(settings); // Fetch core.startGroup('Fetching the repository'); const fetchOptions = {}; @@ -2014,6 +2018,24 @@ function getGitCommandManager(settings) { } }); } +/** + * Adjusts fetchDepth when reference-cache is active. + * Shallow fetches are counterproductive with a local cache because + * objects are served from disk, making shallow negotiation pure overhead. + */ +function adjustFetchDepthForCache(settings) { + if (settings.referenceCache && settings.fetchDepth > 0) { + if (settings.fetchDepthExplicit) { + core.warning(`'fetch-depth: ${settings.fetchDepth}' is set with reference-cache enabled. ` + + `This may slow down checkout because shallow negotiation bypasses the local cache. ` + + `Consider using 'fetch-depth: 0' for best performance with reference-cache.`); + } + else { + core.info(`Overriding fetch-depth from ${settings.fetchDepth} to 0 because reference-cache is enabled`); + settings.fetchDepth = 0; + } + } +} /***/ }), @@ -2374,7 +2396,9 @@ function getInputs() { (core.getInput('sparse-checkout-cone-mode') || 'true').toUpperCase() === 'TRUE'; // Fetch depth - result.fetchDepth = Math.floor(Number(core.getInput('fetch-depth') || '1')); + const fetchDepthInput = core.getInput('fetch-depth'); + result.fetchDepthExplicit = fetchDepthInput !== ''; + result.fetchDepth = Math.floor(Number(fetchDepthInput || '1')); if (isNaN(result.fetchDepth) || result.fetchDepth < 0) { result.fetchDepth = 0; } diff --git a/src/git-source-provider.ts b/src/git-source-provider.ts index e04e351..ffe17e0 100644 --- a/src/git-source-provider.ts +++ b/src/git-source-provider.ts @@ -335,6 +335,10 @@ export async function getSource(settings: IGitSourceSettings): Promise { await git.lfsInstall() } + // When using reference cache, fetch-depth > 0 is counterproductive: + // objects are served from the local cache, so shallow negotiation only adds latency. + adjustFetchDepthForCache(settings) + // Fetch core.startGroup('Fetching the repository') const fetchOptions: { @@ -568,3 +572,30 @@ async function getGitCommandManager( return undefined } } + +/** + * Adjusts fetchDepth when reference-cache is active. + * Shallow fetches are counterproductive with a local cache because + * objects are served from disk, making shallow negotiation pure overhead. + */ +export function adjustFetchDepthForCache( + settings: Pick< + IGitSourceSettings, + 'referenceCache' | 'fetchDepth' | 'fetchDepthExplicit' + > +): void { + if (settings.referenceCache && settings.fetchDepth > 0) { + if (settings.fetchDepthExplicit) { + core.warning( + `'fetch-depth: ${settings.fetchDepth}' is set with reference-cache enabled. ` + + `This may slow down checkout because shallow negotiation bypasses the local cache. ` + + `Consider using 'fetch-depth: 0' for best performance with reference-cache.` + ) + } else { + core.info( + `Overriding fetch-depth from ${settings.fetchDepth} to 0 because reference-cache is enabled` + ) + settings.fetchDepth = 0 + } + } +} diff --git a/src/git-source-settings.ts b/src/git-source-settings.ts index 3e6e952..d79871d 100644 --- a/src/git-source-settings.ts +++ b/src/git-source-settings.ts @@ -49,6 +49,11 @@ export interface IGitSourceSettings { */ fetchDepth: number + /** + * Whether fetch-depth was explicitly set by the user + */ + fetchDepthExplicit: boolean + /** * Fetch tags, even if fetchDepth > 0 (default: false) */ diff --git a/src/input-helper.ts b/src/input-helper.ts index 7ce7303..70d47dc 100644 --- a/src/input-helper.ts +++ b/src/input-helper.ts @@ -102,7 +102,9 @@ export async function getInputs(): Promise { 'TRUE' // Fetch depth - result.fetchDepth = Math.floor(Number(core.getInput('fetch-depth') || '1')) + const fetchDepthInput = core.getInput('fetch-depth') + result.fetchDepthExplicit = fetchDepthInput !== '' + result.fetchDepth = Math.floor(Number(fetchDepthInput || '1')) if (isNaN(result.fetchDepth) || result.fetchDepth < 0) { result.fetchDepth = 0 }