sparse-checkout: optionally turn off cone mode
While it _is_ true that cone mode is the default nowadays (mainly for performance reasons: code mode is much faster than non-cone mode), there _are_ legitimate use cases where non-cone mode is really useful. Let's add a flag to optionally disable cone mode. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
		
							parent
							
								
									9f59c817cf
								
							
						
					
					
						commit
						a241939688
					
				
							
								
								
									
										14
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							@ -85,6 +85,20 @@ jobs:
 | 
			
		||||
      - name: Verify sparse checkout
 | 
			
		||||
        run: __test__/verify-sparse-checkout.sh
 | 
			
		||||
 | 
			
		||||
      # Sparse checkout (non-cone mode)
 | 
			
		||||
      - name: Sparse checkout (non-cone mode)
 | 
			
		||||
        uses: ./
 | 
			
		||||
        with:
 | 
			
		||||
          sparse-checkout: |
 | 
			
		||||
            /__test__/
 | 
			
		||||
            /.github/
 | 
			
		||||
            /dist/
 | 
			
		||||
          sparse-checkout-cone-mode: false
 | 
			
		||||
          path: sparse-checkout-non-cone-mode
 | 
			
		||||
 | 
			
		||||
      - name: Verify sparse checkout (non-cone mode)
 | 
			
		||||
        run: __test__/verify-sparse-checkout-non-cone-mode.sh
 | 
			
		||||
 | 
			
		||||
      # LFS
 | 
			
		||||
      - name: Checkout LFS
 | 
			
		||||
        uses: ./
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							@ -79,6 +79,10 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
 | 
			
		||||
    # Default: null
 | 
			
		||||
    sparse-checkout: ''
 | 
			
		||||
 | 
			
		||||
    # Specifies whether to use cone-mode when doing a sparse checkout.
 | 
			
		||||
    # Default: true
 | 
			
		||||
    sparse-checkout-cone-mode: ''
 | 
			
		||||
 | 
			
		||||
    # Number of commits to fetch. 0 indicates all history for all branches and tags.
 | 
			
		||||
    # Default: 1
 | 
			
		||||
    fetch-depth: ''
 | 
			
		||||
@ -113,6 +117,7 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
 | 
			
		||||
 | 
			
		||||
- [Fetch only the root files](#Fetch-only-the-root-files)
 | 
			
		||||
- [Fetch only the root files and `.github` and `src` folder](#Fetch-only-the-root-files-and-github-and-src-folder)
 | 
			
		||||
- [Fetch only a single file](#Fetch-only-a-single-file)
 | 
			
		||||
- [Fetch all history for all tags and branches](#Fetch-all-history-for-all-tags-and-branches)
 | 
			
		||||
- [Checkout a different branch](#Checkout-a-different-branch)
 | 
			
		||||
- [Checkout HEAD^](#Checkout-HEAD)
 | 
			
		||||
@ -141,6 +146,16 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
 | 
			
		||||
      src
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Fetch only a single file
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
- uses: actions/checkout@v3
 | 
			
		||||
  with:
 | 
			
		||||
    sparse-checkout: |
 | 
			
		||||
      README.md
 | 
			
		||||
    sparse-checkout-cone-mode: false
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Fetch all history for all tags and branches
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
 | 
			
		||||
@ -728,6 +728,7 @@ async function setup(testName: string): Promise<void> {
 | 
			
		||||
    branchExists: jest.fn(),
 | 
			
		||||
    branchList: jest.fn(),
 | 
			
		||||
    sparseCheckout: jest.fn(),
 | 
			
		||||
    sparseCheckoutNonConeMode: jest.fn(),
 | 
			
		||||
    checkout: jest.fn(),
 | 
			
		||||
    checkoutDetach: jest.fn(),
 | 
			
		||||
    config: jest.fn(
 | 
			
		||||
@ -802,6 +803,7 @@ async function setup(testName: string): Promise<void> {
 | 
			
		||||
    clean: true,
 | 
			
		||||
    commit: '',
 | 
			
		||||
    sparseCheckout: [],
 | 
			
		||||
    sparseCheckoutConeMode: true,
 | 
			
		||||
    fetchDepth: 1,
 | 
			
		||||
    lfs: false,
 | 
			
		||||
    submodules: false,
 | 
			
		||||
 | 
			
		||||
@ -463,6 +463,7 @@ async function setup(testName: string): Promise<void> {
 | 
			
		||||
      return []
 | 
			
		||||
    }),
 | 
			
		||||
    sparseCheckout: jest.fn(),
 | 
			
		||||
    sparseCheckoutNonConeMode: jest.fn(),
 | 
			
		||||
    checkout: jest.fn(),
 | 
			
		||||
    checkoutDetach: jest.fn(),
 | 
			
		||||
    config: jest.fn(),
 | 
			
		||||
 | 
			
		||||
@ -80,6 +80,7 @@ describe('input-helper tests', () => {
 | 
			
		||||
    expect(settings.commit).toBeTruthy()
 | 
			
		||||
    expect(settings.commit).toBe('1234567890123456789012345678901234567890')
 | 
			
		||||
    expect(settings.sparseCheckout).toBe(undefined)
 | 
			
		||||
    expect(settings.sparseCheckoutConeMode).toBe(true)
 | 
			
		||||
    expect(settings.fetchDepth).toBe(1)
 | 
			
		||||
    expect(settings.lfs).toBe(false)
 | 
			
		||||
    expect(settings.ref).toBe('refs/heads/some-ref')
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										51
									
								
								__test__/verify-sparse-checkout-non-cone-mode.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										51
									
								
								__test__/verify-sparse-checkout-non-cone-mode.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,51 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
# Verify .git folder
 | 
			
		||||
if [ ! -d "./sparse-checkout-non-cone-mode/.git" ]; then
 | 
			
		||||
  echo "Expected ./sparse-checkout-non-cone-mode/.git folder to exist"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Verify sparse-checkout (non-cone-mode)
 | 
			
		||||
cd sparse-checkout-non-cone-mode
 | 
			
		||||
 | 
			
		||||
ENABLED=$(git config --local --get-all core.sparseCheckout)
 | 
			
		||||
 | 
			
		||||
if [ "$?" != "0" ]; then
 | 
			
		||||
    echo "Failed to verify that sparse-checkout is enabled"
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Check that sparse-checkout is enabled
 | 
			
		||||
if [ "$ENABLED" != "true" ]; then
 | 
			
		||||
  echo "Expected sparse-checkout to be enabled (is: $ENABLED)"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
SPARSE_CHECKOUT_FILE=$(git rev-parse --git-path info/sparse-checkout)
 | 
			
		||||
 | 
			
		||||
if [ "$?" != "0" ]; then
 | 
			
		||||
    echo "Failed to validate sparse-checkout"
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Check that sparse-checkout list is not empty
 | 
			
		||||
if [ ! -f "$SPARSE_CHECKOUT_FILE" ]; then
 | 
			
		||||
  echo "Expected sparse-checkout file to exist"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Check that all folders from sparse-checkout exists
 | 
			
		||||
for pattern in $(cat "$SPARSE_CHECKOUT_FILE")
 | 
			
		||||
do
 | 
			
		||||
  if [ ! -d "${pattern#/}" ]; then
 | 
			
		||||
    echo "Expected directory '${pattern#/}' to exist"
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# Verify that the root directory is not checked out
 | 
			
		||||
if [ -f README.md ]; then
 | 
			
		||||
  echo "Expected top-level files not to exist"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
@ -58,6 +58,10 @@ inputs:
 | 
			
		||||
      Do a sparse checkout on given patterns.
 | 
			
		||||
      Each pattern should be separated with new lines
 | 
			
		||||
    default: null
 | 
			
		||||
  sparse-checkout-cone-mode:
 | 
			
		||||
    description: >
 | 
			
		||||
      Specifies whether to use cone-mode when doing a sparse checkout.
 | 
			
		||||
    default: true
 | 
			
		||||
  fetch-depth:
 | 
			
		||||
    description: 'Number of commits to fetch. 0 indicates all history for all branches and tags.'
 | 
			
		||||
    default: 1
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
								
							@ -470,6 +470,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
 | 
			
		||||
exports.createCommandManager = exports.MinimumGitVersion = void 0;
 | 
			
		||||
const core = __importStar(__nccwpck_require__(2186));
 | 
			
		||||
const exec = __importStar(__nccwpck_require__(1514));
 | 
			
		||||
const fs = __importStar(__nccwpck_require__(7147));
 | 
			
		||||
const fshelper = __importStar(__nccwpck_require__(7219));
 | 
			
		||||
const io = __importStar(__nccwpck_require__(7436));
 | 
			
		||||
const path = __importStar(__nccwpck_require__(1017));
 | 
			
		||||
@ -579,6 +580,18 @@ class GitCommandManager {
 | 
			
		||||
            yield this.execGit(['sparse-checkout', 'set', ...sparseCheckout]);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    sparseCheckoutNonConeMode(sparseCheckout) {
 | 
			
		||||
        return __awaiter(this, void 0, void 0, function* () {
 | 
			
		||||
            yield this.execGit(['config', 'core.sparseCheckout', 'true']);
 | 
			
		||||
            const output = yield this.execGit([
 | 
			
		||||
                'rev-parse',
 | 
			
		||||
                '--git-path',
 | 
			
		||||
                'info/sparse-checkout'
 | 
			
		||||
            ]);
 | 
			
		||||
            const sparseCheckoutPath = path.join(this.workingDirectory, output.stdout.trimRight());
 | 
			
		||||
            yield fs.promises.appendFile(sparseCheckoutPath, `\n${sparseCheckout.join('\n')}\n`);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    checkout(ref, startPoint) {
 | 
			
		||||
        return __awaiter(this, void 0, void 0, function* () {
 | 
			
		||||
            const args = ['checkout', '--progress', '--force'];
 | 
			
		||||
@ -1253,7 +1266,12 @@ function getSource(settings) {
 | 
			
		||||
            // Sparse checkout
 | 
			
		||||
            if (settings.sparseCheckout) {
 | 
			
		||||
                core.startGroup('Setting up sparse checkout');
 | 
			
		||||
                if (settings.sparseCheckoutConeMode) {
 | 
			
		||||
                    yield git.sparseCheckout(settings.sparseCheckout);
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    yield git.sparseCheckoutNonConeMode(settings.sparseCheckout);
 | 
			
		||||
                }
 | 
			
		||||
                core.endGroup();
 | 
			
		||||
            }
 | 
			
		||||
            // Checkout
 | 
			
		||||
@ -1697,6 +1715,9 @@ function getInputs() {
 | 
			
		||||
            result.sparseCheckout = sparseCheckout;
 | 
			
		||||
            core.debug(`sparse checkout = ${result.sparseCheckout}`);
 | 
			
		||||
        }
 | 
			
		||||
        result.sparseCheckoutConeMode =
 | 
			
		||||
            (core.getInput('sparse-checkout-cone-mode') || 'true').toUpperCase() ===
 | 
			
		||||
                'TRUE';
 | 
			
		||||
        // Fetch depth
 | 
			
		||||
        result.fetchDepth = Math.floor(Number(core.getInput('fetch-depth') || '1'));
 | 
			
		||||
        if (isNaN(result.fetchDepth) || result.fetchDepth < 0) {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
import * as core from '@actions/core'
 | 
			
		||||
import * as exec from '@actions/exec'
 | 
			
		||||
import * as fs from 'fs'
 | 
			
		||||
import * as fshelper from './fs-helper'
 | 
			
		||||
import * as io from '@actions/io'
 | 
			
		||||
import * as path from 'path'
 | 
			
		||||
@ -17,6 +18,7 @@ export interface IGitCommandManager {
 | 
			
		||||
  branchExists(remote: boolean, pattern: string): Promise<boolean>
 | 
			
		||||
  branchList(remote: boolean): Promise<string[]>
 | 
			
		||||
  sparseCheckout(sparseCheckout: string[]): Promise<void>
 | 
			
		||||
  sparseCheckoutNonConeMode(sparseCheckout: string[]): Promise<void>
 | 
			
		||||
  checkout(ref: string, startPoint: string): Promise<void>
 | 
			
		||||
  checkoutDetach(): Promise<void>
 | 
			
		||||
  config(
 | 
			
		||||
@ -165,6 +167,23 @@ class GitCommandManager {
 | 
			
		||||
    await this.execGit(['sparse-checkout', 'set', ...sparseCheckout])
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async sparseCheckoutNonConeMode(sparseCheckout: string[]): Promise<void> {
 | 
			
		||||
    await this.execGit(['config', 'core.sparseCheckout', 'true'])
 | 
			
		||||
    const output = await this.execGit([
 | 
			
		||||
      'rev-parse',
 | 
			
		||||
      '--git-path',
 | 
			
		||||
      'info/sparse-checkout'
 | 
			
		||||
    ])
 | 
			
		||||
    const sparseCheckoutPath = path.join(
 | 
			
		||||
      this.workingDirectory,
 | 
			
		||||
      output.stdout.trimRight()
 | 
			
		||||
    )
 | 
			
		||||
    await fs.promises.appendFile(
 | 
			
		||||
      sparseCheckoutPath,
 | 
			
		||||
      `\n${sparseCheckout.join('\n')}\n`
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async checkout(ref: string, startPoint: string): Promise<void> {
 | 
			
		||||
    const args = ['checkout', '--progress', '--force']
 | 
			
		||||
    if (startPoint) {
 | 
			
		||||
 | 
			
		||||
@ -197,7 +197,11 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
 | 
			
		||||
    // Sparse checkout
 | 
			
		||||
    if (settings.sparseCheckout) {
 | 
			
		||||
      core.startGroup('Setting up sparse checkout')
 | 
			
		||||
      if (settings.sparseCheckoutConeMode) {
 | 
			
		||||
        await git.sparseCheckout(settings.sparseCheckout)
 | 
			
		||||
      } else {
 | 
			
		||||
        await git.sparseCheckoutNonConeMode(settings.sparseCheckout)
 | 
			
		||||
      }
 | 
			
		||||
      core.endGroup()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -34,6 +34,11 @@ export interface IGitSourceSettings {
 | 
			
		||||
   */
 | 
			
		||||
  sparseCheckout: string[]
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Indicates whether to use cone mode in the sparse checkout (if any)
 | 
			
		||||
   */
 | 
			
		||||
  sparseCheckoutConeMode: boolean
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The depth when fetching
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
@ -89,6 +89,10 @@ export async function getInputs(): Promise<IGitSourceSettings> {
 | 
			
		||||
    core.debug(`sparse checkout = ${result.sparseCheckout}`)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  result.sparseCheckoutConeMode =
 | 
			
		||||
    (core.getInput('sparse-checkout-cone-mode') || 'true').toUpperCase() ===
 | 
			
		||||
    'TRUE'
 | 
			
		||||
 | 
			
		||||
  // Fetch depth
 | 
			
		||||
  result.fetchDepth = Math.floor(Number(core.getInput('fetch-depth') || '1'))
 | 
			
		||||
  if (isNaN(result.fetchDepth) || result.fetchDepth < 0) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user