From cd7d8d697e10461458bc61a30d094dc601a8b017 Mon Sep 17 00:00:00 2001 From: John Wesley Walker III <81404201+jww3@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:40:14 +0100 Subject: [PATCH] Check git version before attempting to disable `sparse-checkout` (#1656) * Check git version before attempting to disable `sparse-checkout` * Bump `MinimumGitSparseCheckoutVersion` to 2.28 due to #1386 * Initial prep for release 4.1.3 --- __test__/git-auth-helper.test.ts | 3 +- __test__/git-directory-helper.test.ts | 3 +- __test__/git-version.test.ts | 43 ++++++++++++++++++++++++++- dist/index.js | 35 ++++++++++++++-------- package-lock.json | 4 +-- package.json | 2 +- src/git-command-manager.ts | 26 +++++++++------- src/git-source-provider.ts | 11 +++++-- 8 files changed, 97 insertions(+), 30 deletions(-) diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts index a75b79d24..4081cb10e 100644 --- a/__test__/git-auth-helper.test.ts +++ b/__test__/git-auth-helper.test.ts @@ -796,7 +796,8 @@ async function setup(testName: string): Promise { ), tryDisableAutomaticGarbageCollection: jest.fn(), tryGetFetchUrl: jest.fn(), - tryReset: jest.fn() + tryReset: jest.fn(), + version: jest.fn() } settings = { diff --git a/__test__/git-directory-helper.test.ts b/__test__/git-directory-helper.test.ts index 79e0538a7..22e9ae6d4 100644 --- a/__test__/git-directory-helper.test.ts +++ b/__test__/git-directory-helper.test.ts @@ -501,6 +501,7 @@ async function setup(testName: string): Promise { }), tryReset: jest.fn(async () => { return true - }) + }), + version: jest.fn() } } diff --git a/__test__/git-version.test.ts b/__test__/git-version.test.ts index aa3ae4ba0..27f702e16 100644 --- a/__test__/git-version.test.ts +++ b/__test__/git-version.test.ts @@ -1,4 +1,5 @@ -import {GitVersion} from '../lib/git-version' +import {GitVersion} from '../src/git-version' +import {MinimumGitSparseCheckoutVersion} from '../src/git-command-manager' describe('git-version tests', () => { it('basics', async () => { @@ -42,4 +43,44 @@ describe('git-version tests', () => { expect(version.checkMinimum(new GitVersion('5.1'))).toBeFalsy() expect(version.checkMinimum(new GitVersion('5.1.2'))).toBeFalsy() }) + + it('sparse checkout', async () => { + const minSparseVer = MinimumGitSparseCheckoutVersion + expect(new GitVersion('1.0').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('1.99').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.0').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.24').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.24.0').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.24.9').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.25').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.25.0').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.25.1').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.25.9').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.26').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.26.0').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.26.1').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.26.9').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.27').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.27.0').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.27.1').checkMinimum(minSparseVer)).toBeFalsy() + expect(new GitVersion('2.27.9').checkMinimum(minSparseVer)).toBeFalsy() + // /--------------------------------------- + // ^^^ before / after vvv + // --------------------------/ + expect(new GitVersion('2.28').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('2.28.0').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('2.28.1').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('2.28.9').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('2.29').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('2.29.0').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('2.29.1').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('2.29.9').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('2.99').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('3.0').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('3.99').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('4.0').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('4.99').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('5.0').checkMinimum(minSparseVer)).toBeTruthy() + expect(new GitVersion('5.99').checkMinimum(minSparseVer)).toBeTruthy() + }) }) diff --git a/dist/index.js b/dist/index.js index 13896027d..35f6780de 100644 --- a/dist/index.js +++ b/dist/index.js @@ -467,7 +467,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.createCommandManager = exports.MinimumGitVersion = void 0; +exports.createCommandManager = exports.MinimumGitSparseCheckoutVersion = exports.MinimumGitVersion = void 0; const core = __importStar(__nccwpck_require__(2186)); const exec = __importStar(__nccwpck_require__(1514)); const fs = __importStar(__nccwpck_require__(7147)); @@ -480,7 +480,9 @@ const retryHelper = __importStar(__nccwpck_require__(2155)); const git_version_1 = __nccwpck_require__(3142); // Auth header not supported before 2.9 // Wire protocol v2 not supported before 2.18 +// sparse-checkout not [well-]supported before 2.28 (see https://github.com/actions/checkout/issues/1386) exports.MinimumGitVersion = new git_version_1.GitVersion('2.18'); +exports.MinimumGitSparseCheckoutVersion = new git_version_1.GitVersion('2.28'); function createCommandManager(workingDirectory, lfs, doSparseCheckout) { return __awaiter(this, void 0, void 0, function* () { return yield GitCommandManager.createCommandManager(workingDirectory, lfs, doSparseCheckout); @@ -498,6 +500,7 @@ class GitCommandManager { this.lfs = false; this.doSparseCheckout = false; this.workingDirectory = ''; + this.gitVersion = new git_version_1.GitVersion(); } branchDelete(remote, branch) { return __awaiter(this, void 0, void 0, function* () { @@ -850,6 +853,11 @@ class GitCommandManager { return output.exitCode === 0; }); } + version() { + return __awaiter(this, void 0, void 0, function* () { + return this.gitVersion; + }); + } static createCommandManager(workingDirectory, lfs, doSparseCheckout) { return __awaiter(this, void 0, void 0, function* () { const result = new GitCommandManager(); @@ -901,21 +909,21 @@ class GitCommandManager { this.gitPath = yield io.which('git', true); // Git version core.debug('Getting git version'); - let gitVersion = new git_version_1.GitVersion(); + this.gitVersion = new git_version_1.GitVersion(); let gitOutput = yield this.execGit(['version']); let stdout = gitOutput.stdout.trim(); if (!stdout.includes('\n')) { const match = stdout.match(/\d+\.\d+(\.\d+)?/); if (match) { - gitVersion = new git_version_1.GitVersion(match[0]); + this.gitVersion = new git_version_1.GitVersion(match[0]); } } - if (!gitVersion.isValid()) { + if (!this.gitVersion.isValid()) { throw new Error('Unable to determine git version'); } // Minimum git version - if (!gitVersion.checkMinimum(exports.MinimumGitVersion)) { - throw new Error(`Minimum required git version is ${exports.MinimumGitVersion}. Your git ('${this.gitPath}') is ${gitVersion}`); + if (!this.gitVersion.checkMinimum(exports.MinimumGitVersion)) { + throw new Error(`Minimum required git version is ${exports.MinimumGitVersion}. Your git ('${this.gitPath}') is ${this.gitVersion}`); } if (this.lfs) { // Git-lfs version @@ -943,14 +951,12 @@ class GitCommandManager { } this.doSparseCheckout = doSparseCheckout; if (this.doSparseCheckout) { - // The `git sparse-checkout` command was introduced in Git v2.25.0 - const minimumGitSparseCheckoutVersion = new git_version_1.GitVersion('2.25'); - if (!gitVersion.checkMinimum(minimumGitSparseCheckoutVersion)) { - throw new Error(`Minimum Git version required for sparse checkout is ${minimumGitSparseCheckoutVersion}. Your git ('${this.gitPath}') is ${gitVersion}`); + if (!this.gitVersion.checkMinimum(exports.MinimumGitSparseCheckoutVersion)) { + throw new Error(`Minimum Git version required for sparse checkout is ${exports.MinimumGitSparseCheckoutVersion}. Your git ('${this.gitPath}') is ${this.gitVersion}`); } } // Set the user agent - const gitHttpUserAgent = `git/${gitVersion} (github-actions-checkout)`; + const gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)`; core.debug(`Set git useragent to: ${gitHttpUserAgent}`); this.gitEnv['GIT_HTTP_USER_AGENT'] = gitHttpUserAgent; }); @@ -1155,6 +1161,7 @@ const path = __importStar(__nccwpck_require__(1017)); const refHelper = __importStar(__nccwpck_require__(8601)); const stateHelper = __importStar(__nccwpck_require__(8647)); const urlHelper = __importStar(__nccwpck_require__(9437)); +const git_command_manager_1 = __nccwpck_require__(738); function getSource(settings) { return __awaiter(this, void 0, void 0, function* () { // Repository URL @@ -1288,7 +1295,11 @@ function getSource(settings) { } // Sparse checkout if (!settings.sparseCheckout) { - yield git.disableSparseCheckout(); + let gitVersion = yield git.version(); + // no need to disable sparse-checkout if the installed git runtime doesn't even support it. + if (gitVersion.checkMinimum(git_command_manager_1.MinimumGitSparseCheckoutVersion)) { + yield git.disableSparseCheckout(); + } } else { core.startGroup('Setting up sparse checkout'); diff --git a/package-lock.json b/package-lock.json index 9834e50ee..f2c410044 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "checkout", - "version": "4.1.2", + "version": "4.1.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "checkout", - "version": "4.1.2", + "version": "4.1.3", "license": "MIT", "dependencies": { "@actions/core": "^1.10.0", diff --git a/package.json b/package.json index 651d6a02a..4bed13710 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "checkout", - "version": "4.1.2", + "version": "4.1.3", "description": "checkout action", "main": "lib/main.js", "scripts": { diff --git a/src/git-command-manager.ts b/src/git-command-manager.ts index 0f3fd25af..fa50321f8 100644 --- a/src/git-command-manager.ts +++ b/src/git-command-manager.ts @@ -11,7 +11,9 @@ import {GitVersion} from './git-version' // Auth header not supported before 2.9 // Wire protocol v2 not supported before 2.18 +// sparse-checkout not [well-]supported before 2.28 (see https://github.com/actions/checkout/issues/1386) export const MinimumGitVersion = new GitVersion('2.18') +export const MinimumGitSparseCheckoutVersion = new GitVersion('2.28') export interface IGitCommandManager { branchDelete(remote: boolean, branch: string): Promise @@ -60,6 +62,7 @@ export interface IGitCommandManager { tryDisableAutomaticGarbageCollection(): Promise tryGetFetchUrl(): Promise tryReset(): Promise + version(): Promise } export async function createCommandManager( @@ -83,6 +86,7 @@ class GitCommandManager { private lfs = false private doSparseCheckout = false private workingDirectory = '' + private gitVersion: GitVersion = new GitVersion() // Private constructor; use createCommandManager() private constructor() {} @@ -480,6 +484,10 @@ class GitCommandManager { return output.exitCode === 0 } + async version(): Promise { + return this.gitVersion + } + static async createCommandManager( workingDirectory: string, lfs: boolean, @@ -556,23 +564,23 @@ class GitCommandManager { // Git version core.debug('Getting git version') - let gitVersion = new GitVersion() + this.gitVersion = new GitVersion() let gitOutput = await this.execGit(['version']) let stdout = gitOutput.stdout.trim() if (!stdout.includes('\n')) { const match = stdout.match(/\d+\.\d+(\.\d+)?/) if (match) { - gitVersion = new GitVersion(match[0]) + this.gitVersion = new GitVersion(match[0]) } } - if (!gitVersion.isValid()) { + if (!this.gitVersion.isValid()) { throw new Error('Unable to determine git version') } // Minimum git version - if (!gitVersion.checkMinimum(MinimumGitVersion)) { + if (!this.gitVersion.checkMinimum(MinimumGitVersion)) { throw new Error( - `Minimum required git version is ${MinimumGitVersion}. Your git ('${this.gitPath}') is ${gitVersion}` + `Minimum required git version is ${MinimumGitVersion}. Your git ('${this.gitPath}') is ${this.gitVersion}` ) } @@ -606,16 +614,14 @@ class GitCommandManager { this.doSparseCheckout = doSparseCheckout if (this.doSparseCheckout) { - // The `git sparse-checkout` command was introduced in Git v2.25.0 - const minimumGitSparseCheckoutVersion = new GitVersion('2.25') - if (!gitVersion.checkMinimum(minimumGitSparseCheckoutVersion)) { + if (!this.gitVersion.checkMinimum(MinimumGitSparseCheckoutVersion)) { throw new Error( - `Minimum Git version required for sparse checkout is ${minimumGitSparseCheckoutVersion}. Your git ('${this.gitPath}') is ${gitVersion}` + `Minimum Git version required for sparse checkout is ${MinimumGitSparseCheckoutVersion}. Your git ('${this.gitPath}') is ${this.gitVersion}` ) } } // Set the user agent - const gitHttpUserAgent = `git/${gitVersion} (github-actions-checkout)` + const gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)` core.debug(`Set git useragent to: ${gitHttpUserAgent}`) this.gitEnv['GIT_HTTP_USER_AGENT'] = gitHttpUserAgent } diff --git a/src/git-source-provider.ts b/src/git-source-provider.ts index 05897222e..f723d94f4 100644 --- a/src/git-source-provider.ts +++ b/src/git-source-provider.ts @@ -9,7 +9,10 @@ import * as path from 'path' import * as refHelper from './ref-helper' import * as stateHelper from './state-helper' import * as urlHelper from './url-helper' -import {IGitCommandManager} from './git-command-manager' +import { + MinimumGitSparseCheckoutVersion, + IGitCommandManager +} from './git-command-manager' import {IGitSourceSettings} from './git-source-settings' export async function getSource(settings: IGitSourceSettings): Promise { @@ -209,7 +212,11 @@ export async function getSource(settings: IGitSourceSettings): Promise { // Sparse checkout if (!settings.sparseCheckout) { - await git.disableSparseCheckout() + let gitVersion = await git.version() + // no need to disable sparse-checkout if the installed git runtime doesn't even support it. + if (gitVersion.checkMinimum(MinimumGitSparseCheckoutVersion)) { + await git.disableSparseCheckout() + } } else { core.startGroup('Setting up sparse checkout') if (settings.sparseCheckoutConeMode) {