Compare commits

..

1 Commits

Author SHA1 Message Date
Luke Tomlinson 719fedec20 Use rev-list for tags 2023-05-30 19:07:40 +00:00
23 changed files with 16147 additions and 1022 deletions

View File

@ -24,10 +24,10 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set Node.js 20.x
- name: Set Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: 20.x
node-version: 16.x
- name: Install dependencies
run: npm ci

View File

@ -13,7 +13,7 @@ jobs:
steps:
- uses: actions/setup-node@v1
with:
node-version: 20.x
node-version: 16.x
- uses: actions/checkout@v3
- run: npm ci
- run: npm run build
@ -72,43 +72,6 @@ jobs:
shell: bash
run: __test__/verify-side-by-side.sh
# Filter
- name: Fetch filter
uses: ./
with:
filter: 'blob:none'
path: fetch-filter
- name: Verify fetch filter
run: __test__/verify-fetch-filter.sh
# Sparse checkout
- name: Sparse checkout
uses: ./
with:
sparse-checkout: |
__test__
.github
dist
path: sparse-checkout
- 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: ./

View File

@ -11,7 +11,6 @@ on:
type: choice
description: The major version to update
options:
- v4
- v3
- v2

View File

@ -1,21 +1,5 @@
# Changelog
## v4.1.0
- [Add support for partial checkout filters](https://github.com/actions/checkout/pull/1396)
## v4.0.0
- [Support fetching without the --progress option](https://github.com/actions/checkout/pull/1067)
- [Update to node20](https://github.com/actions/checkout/pull/1436)
## v3.6.0
- [Fix: Mark test scripts with Bash'isms to be run via Bash](https://github.com/actions/checkout/pull/1377)
- [Add option to fetch tags even if fetch-depth > 0](https://github.com/actions/checkout/pull/579)
## v3.5.3
- [Fix: Checkout fail in self-hosted runners when faulty submodule are checked-in](https://github.com/actions/checkout/pull/1196)
- [Fix typos found by codespell](https://github.com/actions/checkout/pull/1287)
- [Add support for sparse checkouts](https://github.com/actions/checkout/pull/1369)
## v3.5.2
- [Fix api endpoint for GHES](https://github.com/actions/checkout/pull/1289)

View File

@ -1 +1 @@
* @actions/actions-launch
* @actions/actions-runtime

View File

@ -1,10 +1,10 @@
[![Build and Test](https://github.com/actions/checkout/actions/workflows/test.yml/badge.svg)](https://github.com/actions/checkout/actions/workflows/test.yml)
# Checkout V4
# Checkout V3
This action checks-out your repository under `$GITHUB_WORKSPACE`, so your workflow can access it.
Only a single commit is fetched by default, for the ref/SHA that triggered the workflow. Set `fetch-depth: 0` to fetch all history for all branches and tags. Refer [here](https://docs.github.com/actions/using-workflows/events-that-trigger-workflows) to learn which commit `$GITHUB_SHA` points to for different events.
Only a single commit is fetched by default, for the ref/SHA that triggered the workflow. Set `fetch-depth: 0` to fetch all history for all branches and tags. Refer [here](https://help.github.com/en/articles/events-that-trigger-workflows) to learn which commit `$GITHUB_SHA` points to for different events.
The auth token is persisted in the local git config. This enables your scripts to run authenticated git commands. The token is removed during post-job cleanup. Set `persist-credentials: false` to opt-out.
@ -12,13 +12,14 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
# What's new
Please refer to the [release page](https://github.com/actions/checkout/releases/latest) for the latest release notes.
- Updated to the node16 runtime by default
- This requires a minimum [Actions Runner](https://github.com/actions/runner/releases/tag/v2.285.0) version of v2.285.0 to run, which is by default available in GHES 3.4 or later.
# Usage
<!-- start usage -->
```yaml
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
# Repository name with owner. For example, actions/checkout
# Default: ${{ github.repository }}
@ -73,31 +74,10 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
# Default: true
clean: ''
# Partially clone against a given filter. Overrides sparse-checkout if set.
# Default: null
filter: ''
# Do a sparse checkout on given patterns. Each pattern should be separated with
# new lines.
# 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: ''
# Whether to fetch tags, even if fetch-depth > 0.
# Default: false
fetch-tags: ''
# Whether to show progress status output when fetching.
# Default: true
show-progress: ''
# Whether to download Git-LFS files
# Default: false
lfs: ''
@ -126,9 +106,6 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
# Scenarios
- [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)
@ -139,38 +116,10 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
- [Checkout pull request on closed event](#Checkout-pull-request-on-closed-event)
- [Push a commit using the built-in token](#Push-a-commit-using-the-built-in-token)
## Fetch only the root files
```yaml
- uses: actions/checkout@v4
with:
sparse-checkout: .
```
## Fetch only the root files and `.github` and `src` folder
```yaml
- uses: actions/checkout@v4
with:
sparse-checkout: |
.github
src
```
## Fetch only a single file
```yaml
- uses: actions/checkout@v4
with:
sparse-checkout: |
README.md
sparse-checkout-cone-mode: false
```
## Fetch all history for all tags and branches
```yaml
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
fetch-depth: 0
```
@ -178,7 +127,7 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
## Checkout a different branch
```yaml
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
ref: my-branch
```
@ -186,7 +135,7 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
## Checkout HEAD^
```yaml
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
fetch-depth: 2
- run: git checkout HEAD^
@ -196,12 +145,12 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
```yaml
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
path: main
- name: Checkout tools repo
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
repository: my-org/my-tools
path: my-tools
@ -212,10 +161,10 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
```yaml
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Checkout tools repo
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
repository: my-org/my-tools
path: my-tools
@ -226,12 +175,12 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
```yaml
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
path: main
- name: Checkout private tools
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
repository: my-org/my-private-tools
token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT
@ -244,7 +193,7 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
## Checkout pull request HEAD commit instead of merge commit
```yaml
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
```
@ -260,7 +209,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
```
## Push a commit using the built-in token
@ -271,7 +220,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- run: |
date > generated.txt
git config user.name github-actions

View File

@ -727,8 +727,6 @@ async function setup(testName: string): Promise<void> {
branchDelete: jest.fn(),
branchExists: jest.fn(),
branchList: jest.fn(),
sparseCheckout: jest.fn(),
sparseCheckoutNonConeMode: jest.fn(),
checkout: jest.fn(),
checkoutDetach: jest.fn(),
config: jest.fn(
@ -802,12 +800,7 @@ async function setup(testName: string): Promise<void> {
authToken: 'some auth token',
clean: true,
commit: '',
filter: undefined,
sparseCheckout: [],
sparseCheckoutConeMode: true,
fetchDepth: 1,
fetchTags: false,
showProgress: true,
lfs: false,
submodules: false,
nestedSubmodules: false,

View File

@ -39,12 +39,7 @@ describe('git-auth-helper tests', () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
git = await commandManager.createCommandManager(workingDirectory, lfs)
let branches = await git.branchList(false)
@ -75,12 +70,7 @@ describe('git-auth-helper tests', () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
git = await commandManager.createCommandManager(workingDirectory, lfs)
let branches = await git.branchList(false)
@ -88,291 +78,3 @@ describe('git-auth-helper tests', () => {
expect(branches.sort()).toEqual(['foo'].sort())
})
})
describe('Test fetchDepth and fetchTags options', () => {
beforeEach(async () => {
jest.spyOn(fshelper, 'fileExistsSync').mockImplementation(jest.fn())
jest.spyOn(fshelper, 'directoryExistsSync').mockImplementation(jest.fn())
mockExec.mockImplementation((path, args, options) => {
console.log(args, options.listeners.stdout)
if (args.includes('version')) {
options.listeners.stdout(Buffer.from('2.18'))
}
return 0
})
})
afterEach(() => {
jest.restoreAllMocks()
})
it('should call execGit with the correct arguments when fetchDepth is 0 and fetchTags is true', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchDepth: 0,
fetchTags: true
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--prune',
'--no-recurse-submodules',
'--filter=filterValue',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when fetchDepth is 0 and fetchTags is false', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchDepth: 0,
fetchTags: false
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--no-tags',
'--prune',
'--no-recurse-submodules',
'--filter=filterValue',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when fetchDepth is 1 and fetchTags is false', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchDepth: 1,
fetchTags: false
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--no-tags',
'--prune',
'--no-recurse-submodules',
'--filter=filterValue',
'--depth=1',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when fetchDepth is 1 and fetchTags is true', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchDepth: 1,
fetchTags: true
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--prune',
'--no-recurse-submodules',
'--filter=filterValue',
'--depth=1',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when showProgress is true', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
showProgress: true
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--no-tags',
'--prune',
'--no-recurse-submodules',
'--progress',
'--filter=filterValue',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when fetchDepth is 42 and showProgress is true', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchDepth: 42,
showProgress: true
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--no-tags',
'--prune',
'--no-recurse-submodules',
'--progress',
'--filter=filterValue',
'--depth=42',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when fetchTags is true and showProgress is true', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchTags: true,
showProgress: true
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--prune',
'--no-recurse-submodules',
'--progress',
'--filter=filterValue',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
})

View File

@ -462,8 +462,6 @@ async function setup(testName: string): Promise<void> {
branchList: jest.fn(async () => {
return []
}),
sparseCheckout: jest.fn(),
sparseCheckoutNonConeMode: jest.fn(),
checkout: jest.fn(),
checkoutDetach: jest.fn(),
config: jest.fn(),

View File

@ -79,12 +79,7 @@ describe('input-helper tests', () => {
expect(settings.clean).toBe(true)
expect(settings.commit).toBeTruthy()
expect(settings.commit).toBe('1234567890123456789012345678901234567890')
expect(settings.filter).toBe(undefined)
expect(settings.sparseCheckout).toBe(undefined)
expect(settings.sparseCheckoutConeMode).toBe(true)
expect(settings.fetchDepth).toBe(1)
expect(settings.fetchTags).toBe(false)
expect(settings.showProgress).toBe(true)
expect(settings.lfs).toBe(false)
expect(settings.ref).toBe('refs/heads/some-ref')
expect(settings.repositoryName).toBe('some-repo')

View File

@ -1,16 +0,0 @@
#!/bin/bash
# Verify .git folder
if [ ! -d "./fetch-filter/.git" ]; then
echo "Expected ./fetch-filter/.git folder to exist"
exit 1
fi
# Verify .git/config contains partialclonefilter
CLONE_FILTER=$(git -C fetch-filter config --local --get remote.origin.partialclonefilter)
if [ "$CLONE_FILTER" != "blob:none" ]; then
echo "Expected ./fetch-filter/.git/config to have 'remote.origin.partialclonefilter' set to 'blob:none'"
exit 1
fi

View File

@ -1,51 +0,0 @@
#!/bin/bash
# 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

View File

@ -1,63 +0,0 @@
#!/bin/bash
# Verify .git folder
if [ ! -d "./sparse-checkout/.git" ]; then
echo "Expected ./sparse-checkout/.git folder to exist"
exit 1
fi
# Verify sparse-checkout
cd sparse-checkout
SPARSE=$(git sparse-checkout list)
if [ "$?" != "0" ]; then
echo "Failed to validate sparse-checkout"
exit 1
fi
# Check that sparse-checkout list is not empty
if [ -z "$SPARSE" ]; then
echo "Expected sparse-checkout list to not be empty"
exit 1
fi
# Check that all folders of the sparse checkout exist
for pattern in $SPARSE
do
if [ ! -d "$pattern" ]; then
echo "Expected directory '$pattern' to exist"
exit 1
fi
done
checkSparse () {
if [ ! -d "./$1" ]; then
echo "Expected directory '$1' to exist"
exit 1
fi
for file in $(git ls-tree -r --name-only HEAD $1)
do
if [ ! -f "$file" ]; then
echo "Expected file '$file' to exist"
exit 1
fi
done
}
# Check that all folders and their children have been checked out
checkSparse __test__
checkSparse .github
checkSparse dist
# Check that only sparse-checkout folders have been checked out
for pattern in $(git ls-tree --name-only HEAD)
do
if [ -d "$pattern" ]; then
if [[ "$pattern" != "__test__" && "$pattern" != ".github" && "$pattern" != "dist" ]]; then
echo "Expected directory '$pattern' to not exist"
exit 1
fi
fi
done

View File

@ -53,29 +53,9 @@ inputs:
clean:
description: 'Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching'
default: true
filter:
description: >
Partially clone against a given filter.
Overrides sparse-checkout if set.
default: null
sparse-checkout:
description: >
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
fetch-tags:
description: 'Whether to fetch tags, even if fetch-depth > 0.'
default: false
show-progress:
description: 'Whether to show progress status output when fetching.'
default: true
lfs:
description: 'Whether to download Git-LFS files'
default: false
@ -95,6 +75,6 @@ inputs:
description: The base URL for the GitHub instance that you are trying to clone from, will use environment defaults to fetch from the same instance that the workflow is running from unless specified. Example URLs are https://github.com or https://my-ghes-server.example.com
required: false
runs:
using: node20
using: node16
main: dist/index.js
post: dist/index.js

127
dist/index.js vendored
View File

@ -470,7 +470,6 @@ 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));
@ -481,9 +480,9 @@ const git_version_1 = __nccwpck_require__(3142);
// Auth header not supported before 2.9
// Wire protocol v2 not supported before 2.18
exports.MinimumGitVersion = new git_version_1.GitVersion('2.18');
function createCommandManager(workingDirectory, lfs, doSparseCheckout) {
function createCommandManager(workingDirectory, lfs) {
return __awaiter(this, void 0, void 0, function* () {
return yield GitCommandManager.createCommandManager(workingDirectory, lfs, doSparseCheckout);
return yield GitCommandManager.createCommandManager(workingDirectory, lfs);
});
}
exports.createCommandManager = createCommandManager;
@ -496,7 +495,6 @@ class GitCommandManager {
};
this.gitPath = '';
this.lfs = false;
this.doSparseCheckout = false;
this.workingDirectory = '';
}
branchDelete(remote, branch) {
@ -576,23 +574,6 @@ class GitCommandManager {
return result;
});
}
sparseCheckout(sparseCheckout) {
return __awaiter(this, void 0, void 0, function* () {
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'];
@ -634,21 +615,15 @@ class GitCommandManager {
return output.exitCode === 0;
});
}
fetch(refSpec, options) {
fetch(refSpec, fetchDepth) {
return __awaiter(this, void 0, void 0, function* () {
const args = ['-c', 'protocol.version=2', 'fetch'];
if (!refSpec.some(x => x === refHelper.tagsRefSpec) && !options.fetchTags) {
if (!refSpec.some(x => x === refHelper.tagsRefSpec)) {
args.push('--no-tags');
}
args.push('--prune', '--no-recurse-submodules');
if (options.showProgress) {
args.push('--progress');
}
if (options.filter) {
args.push(`--filter=${options.filter}`);
}
if (options.fetchDepth && options.fetchDepth > 0) {
args.push(`--depth=${options.fetchDepth}`);
args.push('--prune', '--progress', '--no-recurse-submodules');
if (fetchDepth && fetchDepth > 0) {
args.push(`--depth=${fetchDepth}`);
}
else if (fshelper.fileExistsSync(path.join(this.workingDirectory, '.git', 'shallow'))) {
args.push('--unshallow');
@ -721,8 +696,8 @@ class GitCommandManager {
}
log1(format) {
return __awaiter(this, void 0, void 0, function* () {
const args = format ? ['log', '-1', format] : ['log', '-1'];
const silent = format ? false : true;
var args = format ? ['log', '-1', format] : ['log', '-1'];
var silent = format ? false : true;
const output = yield this.execGit(args, false, silent);
return output.stdout;
});
@ -747,6 +722,18 @@ class GitCommandManager {
return output.stdout.trim();
});
}
/**
* Lists SHAs pointed to by a revision.
* @param {string} ref For example: 'refs/heads/main' or '/refs/tags/v1'
* @param {number} numberOfRefs
* @param value
*/
revList(ref, numberOfRefs) {
return __awaiter(this, void 0, void 0, function* () {
const output = yield this.execGit(['rev-list', ref, `-${numberOfRefs}`]);
return output.stdout.trim();
});
}
setEnvironmentVariable(name, value) {
this.gitEnv[name] = value;
}
@ -845,10 +832,10 @@ class GitCommandManager {
return output.exitCode === 0;
});
}
static createCommandManager(workingDirectory, lfs, doSparseCheckout) {
static createCommandManager(workingDirectory, lfs) {
return __awaiter(this, void 0, void 0, function* () {
const result = new GitCommandManager();
yield result.initializeCommandManager(workingDirectory, lfs, doSparseCheckout);
yield result.initializeCommandManager(workingDirectory, lfs);
return result;
});
}
@ -884,7 +871,7 @@ class GitCommandManager {
return result;
});
}
initializeCommandManager(workingDirectory, lfs, doSparseCheckout) {
initializeCommandManager(workingDirectory, lfs) {
return __awaiter(this, void 0, void 0, function* () {
this.workingDirectory = workingDirectory;
// Git-lfs will try to pull down assets if any of the local/user/system setting exist.
@ -936,14 +923,6 @@ class GitCommandManager {
throw new Error(`Minimum required git-lfs version is ${minimumGitLfsVersion}. Your git-lfs ('${gitLfsPath}') is ${gitLfsVersion}`);
}
}
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}`);
}
}
// Set the user agent
const gitHttpUserAgent = `git/${gitVersion} (github-actions-checkout)`;
core.debug(`Set git useragent to: ${gitHttpUserAgent}`);
@ -1243,29 +1222,20 @@ function getSource(settings) {
}
// Fetch
core.startGroup('Fetching the repository');
const fetchOptions = {};
if (settings.filter) {
fetchOptions.filter = settings.filter;
}
else if (settings.sparseCheckout) {
fetchOptions.filter = 'blob:none';
}
if (settings.fetchDepth <= 0) {
// Fetch all branches and tags
let refSpec = refHelper.getRefSpecForAllHistory(settings.ref, settings.commit);
yield git.fetch(refSpec, fetchOptions);
yield git.fetch(refSpec);
// When all history is fetched, the ref we're interested in may have moved to a different
// commit (push or force push). If so, fetch again with a targeted refspec.
if (!(yield refHelper.testRef(git, settings.ref, settings.commit))) {
refSpec = refHelper.getRefSpec(settings.ref, settings.commit);
yield git.fetch(refSpec, fetchOptions);
yield git.fetch(refSpec);
}
}
else {
fetchOptions.fetchDepth = settings.fetchDepth;
fetchOptions.fetchTags = settings.fetchTags;
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit);
yield git.fetch(refSpec, fetchOptions);
yield git.fetch(refSpec, settings.fetchDepth);
}
core.endGroup();
// Checkout info
@ -1275,23 +1245,11 @@ function getSource(settings) {
// LFS fetch
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
// Explicit lfs fetch will fetch lfs objects in parallel.
// For sparse checkouts, let `checkout` fetch the needed objects lazily.
if (settings.lfs && !settings.sparseCheckout) {
if (settings.lfs) {
core.startGroup('Fetching LFS objects');
yield git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref);
core.endGroup();
}
// 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
core.startGroup('Checking out the ref');
yield git.checkout(checkoutInfo.ref, checkoutInfo.startPoint);
@ -1345,7 +1303,7 @@ function cleanup(repositoryPath) {
}
let git;
try {
git = yield gitCommandManager.createCommandManager(repositoryPath, false, false);
git = yield gitCommandManager.createCommandManager(repositoryPath, false);
}
catch (_a) {
return;
@ -1376,7 +1334,7 @@ function getGitCommandManager(settings) {
return __awaiter(this, void 0, void 0, function* () {
core.info(`Working directory is '${settings.repositoryPath}'`);
try {
return yield gitCommandManager.createCommandManager(settings.repositoryPath, settings.lfs, settings.sparseCheckout != null);
return yield gitCommandManager.createCommandManager(settings.repositoryPath, settings.lfs);
}
catch (err) {
// Git is required for LFS
@ -1727,35 +1685,12 @@ function getInputs() {
// Clean
result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE';
core.debug(`clean = ${result.clean}`);
// Filter
const filter = core.getInput('filter');
if (filter) {
result.filter = filter;
}
core.debug(`filter = ${result.filter}`);
// Sparse checkout
const sparseCheckout = core.getMultilineInput('sparse-checkout');
if (sparseCheckout.length) {
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) {
result.fetchDepth = 0;
}
core.debug(`fetch depth = ${result.fetchDepth}`);
// Fetch tags
result.fetchTags =
(core.getInput('fetch-tags') || 'false').toUpperCase() === 'TRUE';
core.debug(`fetch tags = ${result.fetchTags}`);
// Show fetch progress
result.showProgress =
(core.getInput('show-progress') || 'true').toUpperCase() === 'TRUE';
core.debug(`show progress = ${result.showProgress}`);
// LFS
result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE';
core.debug(`lfs = ${result.lfs}`);
@ -2059,7 +1994,7 @@ function testRef(git, ref, commit) {
// refs/tags/
else if (upperRef.startsWith('REFS/TAGS/')) {
const tagName = ref.substring('refs/tags/'.length);
return ((yield git.tagExists(tagName)) && commit === (yield git.revParse(ref)));
return ((yield git.tagExists(tagName)) && commit === (yield git.revList(ref, 1)));
}
// Unexpected
else {

16211
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "checkout",
"version": "4.1.0",
"version": "3.5.2",
"description": "checkout action",
"main": "lib/main.js",
"scripts": {
@ -37,7 +37,7 @@
},
"devDependencies": {
"@types/jest": "^27.0.2",
"@types/node": "^20.5.3",
"@types/node": "^12.7.12",
"@types/uuid": "^3.4.6",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
@ -52,4 +52,4 @@
"ts-jest": "^27.0.7",
"typescript": "^4.4.4"
}
}
}

View File

@ -1,6 +1,5 @@
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,8 +16,6 @@ export interface IGitCommandManager {
branchDelete(remote: boolean, branch: string): Promise<void>
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(
@ -28,15 +25,7 @@ export interface IGitCommandManager {
add?: boolean
): Promise<void>
configExists(configKey: string, globalConfig?: boolean): Promise<boolean>
fetch(
refSpec: string[],
options: {
filter?: string
fetchDepth?: number
fetchTags?: boolean
showProgress?: boolean
}
): Promise<void>
fetch(refSpec: string[], fetchDepth?: number): Promise<void>
getDefaultBranch(repositoryUrl: string): Promise<string>
getWorkingDirectory(): string
init(): Promise<void>
@ -46,6 +35,7 @@ export interface IGitCommandManager {
log1(format?: string): Promise<string>
remoteAdd(remoteName: string, remoteUrl: string): Promise<void>
removeEnvironmentVariable(name: string): void
revList(ref: string, numberOfRefs: number): Promise<string>
revParse(ref: string): Promise<string>
setEnvironmentVariable(name: string, value: string): void
shaExists(sha: string): Promise<boolean>
@ -63,14 +53,9 @@ export interface IGitCommandManager {
export async function createCommandManager(
workingDirectory: string,
lfs: boolean,
doSparseCheckout: boolean
lfs: boolean
): Promise<IGitCommandManager> {
return await GitCommandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
return await GitCommandManager.createCommandManager(workingDirectory, lfs)
}
class GitCommandManager {
@ -80,7 +65,6 @@ class GitCommandManager {
}
private gitPath = ''
private lfs = false
private doSparseCheckout = false
private workingDirectory = ''
// Private constructor; use createCommandManager()
@ -171,27 +155,6 @@ class GitCommandManager {
return result
}
async sparseCheckout(sparseCheckout: string[]): Promise<void> {
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) {
@ -240,31 +203,15 @@ class GitCommandManager {
return output.exitCode === 0
}
async fetch(
refSpec: string[],
options: {
filter?: string
fetchDepth?: number
fetchTags?: boolean
showProgress?: boolean
}
): Promise<void> {
async fetch(refSpec: string[], fetchDepth?: number): Promise<void> {
const args = ['-c', 'protocol.version=2', 'fetch']
if (!refSpec.some(x => x === refHelper.tagsRefSpec) && !options.fetchTags) {
if (!refSpec.some(x => x === refHelper.tagsRefSpec)) {
args.push('--no-tags')
}
args.push('--prune', '--no-recurse-submodules')
if (options.showProgress) {
args.push('--progress')
}
if (options.filter) {
args.push(`--filter=${options.filter}`)
}
if (options.fetchDepth && options.fetchDepth > 0) {
args.push(`--depth=${options.fetchDepth}`)
args.push('--prune', '--progress', '--no-recurse-submodules')
if (fetchDepth && fetchDepth > 0) {
args.push(`--depth=${fetchDepth}`)
} else if (
fshelper.fileExistsSync(
path.join(this.workingDirectory, '.git', 'shallow')
@ -343,8 +290,8 @@ class GitCommandManager {
}
async log1(format?: string): Promise<string> {
const args = format ? ['log', '-1', format] : ['log', '-1']
const silent = format ? false : true
var args = format ? ['log', '-1', format] : ['log', '-1']
var silent = format ? false : true
const output = await this.execGit(args, false, silent)
return output.stdout
}
@ -368,6 +315,17 @@ class GitCommandManager {
return output.stdout.trim()
}
/**
* Lists SHAs pointed to by a revision.
* @param {string} ref For example: 'refs/heads/main' or '/refs/tags/v1'
* @param {number} numberOfRefs
* @param value
*/
async revList(ref: string, numberOfRefs: number): Promise<string> {
const output = await this.execGit(['rev-list', ref, `-${numberOfRefs}`])
return output.stdout.trim()
}
setEnvironmentVariable(name: string, value: string): void {
this.gitEnv[name] = value
}
@ -477,15 +435,10 @@ class GitCommandManager {
static async createCommandManager(
workingDirectory: string,
lfs: boolean,
doSparseCheckout: boolean
lfs: boolean
): Promise<GitCommandManager> {
const result = new GitCommandManager()
await result.initializeCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
await result.initializeCommandManager(workingDirectory, lfs)
return result
}
@ -535,8 +488,7 @@ class GitCommandManager {
private async initializeCommandManager(
workingDirectory: string,
lfs: boolean,
doSparseCheckout: boolean
lfs: boolean
): Promise<void> {
this.workingDirectory = workingDirectory
@ -599,16 +551,6 @@ 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)) {
throw new Error(
`Minimum Git version required for sparse checkout is ${minimumGitSparseCheckoutVersion}. Your git ('${this.gitPath}') is ${gitVersion}`
)
}
}
// Set the user agent
const gitHttpUserAgent = `git/${gitVersion} (github-actions-checkout)`
core.debug(`Set git useragent to: ${gitHttpUserAgent}`)

View File

@ -153,38 +153,23 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Fetch
core.startGroup('Fetching the repository')
const fetchOptions: {
filter?: string
fetchDepth?: number
fetchTags?: boolean
showProgress?: boolean
} = {}
if (settings.filter) {
fetchOptions.filter = settings.filter
} else if (settings.sparseCheckout) {
fetchOptions.filter = 'blob:none'
}
if (settings.fetchDepth <= 0) {
// Fetch all branches and tags
let refSpec = refHelper.getRefSpecForAllHistory(
settings.ref,
settings.commit
)
await git.fetch(refSpec, fetchOptions)
await git.fetch(refSpec)
// When all history is fetched, the ref we're interested in may have moved to a different
// commit (push or force push). If so, fetch again with a targeted refspec.
if (!(await refHelper.testRef(git, settings.ref, settings.commit))) {
refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
await git.fetch(refSpec, fetchOptions)
await git.fetch(refSpec)
}
} else {
fetchOptions.fetchDepth = settings.fetchDepth
fetchOptions.fetchTags = settings.fetchTags
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
await git.fetch(refSpec, fetchOptions)
await git.fetch(refSpec, settings.fetchDepth)
}
core.endGroup()
@ -200,24 +185,12 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
// LFS fetch
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
// Explicit lfs fetch will fetch lfs objects in parallel.
// For sparse checkouts, let `checkout` fetch the needed objects lazily.
if (settings.lfs && !settings.sparseCheckout) {
if (settings.lfs) {
core.startGroup('Fetching LFS objects')
await git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref)
core.endGroup()
}
// 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()
}
// Checkout
core.startGroup('Checking out the ref')
await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
@ -288,11 +261,7 @@ export async function cleanup(repositoryPath: string): Promise<void> {
let git: IGitCommandManager
try {
git = await gitCommandManager.createCommandManager(
repositoryPath,
false,
false
)
git = await gitCommandManager.createCommandManager(repositoryPath, false)
} catch {
return
}
@ -328,8 +297,7 @@ async function getGitCommandManager(
try {
return await gitCommandManager.createCommandManager(
settings.repositoryPath,
settings.lfs,
settings.sparseCheckout != null
settings.lfs
)
} catch (err) {
// Git is required for LFS

View File

@ -29,36 +29,11 @@ export interface IGitSourceSettings {
*/
clean: boolean
/**
* The filter determining which objects to include
*/
filter: string | undefined
/**
* The array of folders to make the sparse checkout
*/
sparseCheckout: string[]
/**
* Indicates whether to use cone mode in the sparse checkout (if any)
*/
sparseCheckoutConeMode: boolean
/**
* The depth when fetching
*/
fetchDepth: number
/**
* Fetch tags, even if fetchDepth > 0 (default: false)
*/
fetchTags: boolean
/**
* Indicates whether to use the --progress option when fetching
*/
showProgress: boolean
/**
* Indicates whether to fetch LFS objects
*/

View File

@ -82,25 +82,6 @@ export async function getInputs(): Promise<IGitSourceSettings> {
result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE'
core.debug(`clean = ${result.clean}`)
// Filter
const filter = core.getInput('filter')
if (filter) {
result.filter = filter
}
core.debug(`filter = ${result.filter}`)
// Sparse checkout
const sparseCheckout = core.getMultilineInput('sparse-checkout')
if (sparseCheckout.length) {
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) {
@ -108,16 +89,6 @@ export async function getInputs(): Promise<IGitSourceSettings> {
}
core.debug(`fetch depth = ${result.fetchDepth}`)
// Fetch tags
result.fetchTags =
(core.getInput('fetch-tags') || 'false').toUpperCase() === 'TRUE'
core.debug(`fetch tags = ${result.fetchTags}`)
// Show fetch progress
result.showProgress =
(core.getInput('show-progress') || 'true').toUpperCase() === 'TRUE'
core.debug(`show progress = ${result.showProgress}`)
// LFS
result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE'
core.debug(`lfs = ${result.lfs}`)

View File

@ -120,7 +120,7 @@ function updateUsage(
}
updateUsage(
'actions/checkout@v4',
'actions/checkout@v3',
path.join(__dirname, '..', '..', 'action.yml'),
path.join(__dirname, '..', '..', 'README.md')
)

View File

@ -167,7 +167,7 @@ export async function testRef(
else if (upperRef.startsWith('REFS/TAGS/')) {
const tagName = ref.substring('refs/tags/'.length)
return (
(await git.tagExists(tagName)) && commit === (await git.revParse(ref))
(await git.tagExists(tagName)) && commit === (await git.revList(ref, 1))
)
}
// Unexpected