From aadec899646c8e0f34c52d9219c2faac36626b55 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 21 Feb 2024 13:56:19 +0100 Subject: [PATCH] Explicitly disable sparse checkout unless asked for (#1598) When a worktree is reused by actions/checkout and the first time sparse checkout was enabled, we need to ensure that the second time it is only a sparse checkout if explicitly asked for. Otherwise, we need to disable the sparse checkout so that a full checkout is the outcome of this Action. ## Details * If no `sparse-checkout` parameter is specified, disable it This should allow users to reuse existing folders when running `actions/checkout` where a previous run asked for a sparse checkout but the current run does not ask for a sparse checkout. This fixes https://github.com/actions/checkout/issues/1475 There are use cases in particular with non-ephemeral (self-hosted) runners where an existing worktree (that has been initialized as a sparse checkout) is reused in subsequent CI runs (where `actions/checkout` is run _without_ any `sparse-checkout` parameter). In these scenarios, we need to make sure that the sparse checkout is disabled before checking out the files. ### Also includes: * npm run build * ci: verify that an existing sparse checkout can be made unsparse * Added a clarifying comment about test branches. * `test-proxy` now uses newly-minted `test-ubuntu-git` container image from ghcr.io --------- Signed-off-by: Johannes Schindelin Co-authored-by: John Wesley Walker III <81404201+jww3@users.noreply.github.com> --- .github/workflows/test.yml | 19 +++++++++++++++++-- __test__/git-auth-helper.test.ts | 1 + __test__/git-directory-helper.test.ts | 1 + dist/index.js | 10 +++++++++- src/git-command-manager.ts | 5 +++++ src/git-source-provider.ts | 4 +++- 6 files changed, 36 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 15996ee..d8c83ac 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,6 +7,11 @@ on: - main - releases/* + +# Note that when you see patterns like "ref: test-data/v2/basic" within this workflow, +# these refer to "test-data" branches on this actions/checkout repo. +# (For example, test-data/v2/basic -> https://github.com/actions/checkout/tree/test-data/v2/basic) + jobs: build: runs-on: ubuntu-latest @@ -95,6 +100,16 @@ jobs: - name: Verify sparse checkout run: __test__/verify-sparse-checkout.sh + # Disabled sparse checkout in existing checkout + - name: Disabled sparse checkout + uses: ./ + with: + path: sparse-checkout + + - name: Verify disabled sparse checkout + shell: bash + run: set -x && ls -l sparse-checkout/src/git-command-manager.ts + # Sparse checkout (non-cone mode) - name: Sparse checkout (non-cone mode) uses: ./ @@ -175,7 +190,7 @@ jobs: test-proxy: runs-on: ubuntu-latest container: - image: alpine/git:latest + image: ghcr.io/actions/test-ubuntu-git:main.20240221.114913.703z options: --dns 127.0.0.1 services: squid-proxy: @@ -279,4 +294,4 @@ jobs: - name: Fix Checkout v3 uses: actions/checkout@v3 with: - path: v3 \ No newline at end of file + path: v3 diff --git a/__test__/git-auth-helper.test.ts b/__test__/git-auth-helper.test.ts index 411faed..a75b79d 100644 --- a/__test__/git-auth-helper.test.ts +++ b/__test__/git-auth-helper.test.ts @@ -727,6 +727,7 @@ async function setup(testName: string): Promise { branchDelete: jest.fn(), branchExists: jest.fn(), branchList: jest.fn(), + disableSparseCheckout: jest.fn(), sparseCheckout: jest.fn(), sparseCheckoutNonConeMode: jest.fn(), checkout: jest.fn(), diff --git a/__test__/git-directory-helper.test.ts b/__test__/git-directory-helper.test.ts index 362133f..79e0538 100644 --- a/__test__/git-directory-helper.test.ts +++ b/__test__/git-directory-helper.test.ts @@ -462,6 +462,7 @@ async function setup(testName: string): Promise { branchList: jest.fn(async () => { return [] }), + disableSparseCheckout: jest.fn(), sparseCheckout: jest.fn(), sparseCheckoutNonConeMode: jest.fn(), checkout: jest.fn(), diff --git a/dist/index.js b/dist/index.js index ddf2b3d..1389602 100644 --- a/dist/index.js +++ b/dist/index.js @@ -576,6 +576,11 @@ class GitCommandManager { return result; }); } + disableSparseCheckout() { + return __awaiter(this, void 0, void 0, function* () { + yield this.execGit(['sparse-checkout', 'disable']); + }); + } sparseCheckout(sparseCheckout) { return __awaiter(this, void 0, void 0, function* () { yield this.execGit(['sparse-checkout', 'set', ...sparseCheckout]); @@ -1282,7 +1287,10 @@ function getSource(settings) { core.endGroup(); } // Sparse checkout - if (settings.sparseCheckout) { + if (!settings.sparseCheckout) { + yield git.disableSparseCheckout(); + } + else { core.startGroup('Setting up sparse checkout'); if (settings.sparseCheckoutConeMode) { yield git.sparseCheckout(settings.sparseCheckout); diff --git a/src/git-command-manager.ts b/src/git-command-manager.ts index 7752cfa..0f3fd25 100644 --- a/src/git-command-manager.ts +++ b/src/git-command-manager.ts @@ -17,6 +17,7 @@ export interface IGitCommandManager { branchDelete(remote: boolean, branch: string): Promise branchExists(remote: boolean, pattern: string): Promise branchList(remote: boolean): Promise + disableSparseCheckout(): Promise sparseCheckout(sparseCheckout: string[]): Promise sparseCheckoutNonConeMode(sparseCheckout: string[]): Promise checkout(ref: string, startPoint: string): Promise @@ -171,6 +172,10 @@ class GitCommandManager { return result } + async disableSparseCheckout(): Promise { + await this.execGit(['sparse-checkout', 'disable']) + } + async sparseCheckout(sparseCheckout: string[]): Promise { await this.execGit(['sparse-checkout', 'set', ...sparseCheckout]) } diff --git a/src/git-source-provider.ts b/src/git-source-provider.ts index 5c98e9f..0589722 100644 --- a/src/git-source-provider.ts +++ b/src/git-source-provider.ts @@ -208,7 +208,9 @@ export async function getSource(settings: IGitSourceSettings): Promise { } // Sparse checkout - if (settings.sparseCheckout) { + if (!settings.sparseCheckout) { + await git.disableSparseCheckout() + } else { core.startGroup('Setting up sparse checkout') if (settings.sparseCheckoutConeMode) { await git.sparseCheckout(settings.sparseCheckout)