Compare commits

..

16 Commits
v3 ... main

Author SHA1 Message Date
dependabot[bot]
8eb1f6a495
Bump @babel/traverse from 7.20.5 to 7.24.0 (#1642)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.20.5 to 7.24.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.0/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 13:09:59 -05:00
dependabot[bot]
556e4c3cb0
Bump tough-cookie from 4.0.0 to 4.1.3 (#1406)
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.0.0 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.0.0...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 12:49:25 -05:00
John Wesley Walker III
b32f140b0c
Warn on attempts to publish test-ubuntu-git from non-main branch. (#1623)
* Warn on attempts to publish test-ubuntu-git from non-main branch.
* Rename build step to clarify that Push is optional.
2024-02-22 14:38:58 +01:00
John Wesley Walker III
2650dbd060
Give test-ubuntu-git its own README (#1620)
* Give `test-ubuntu-git` its own `README`
* Refined title and description in `test-ubuntu-git.Dockerfile`
* nit accepted:  Remove double space

---------

Co-authored-by: Ferenc Hammerl <31069338+fhammerl@users.noreply.github.com>
2024-02-22 10:59:35 +01:00
Johannes Schindelin
aadec89964
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 <johannes.schindelin@gmx.de>
Co-authored-by: John Wesley Walker III <81404201+jww3@users.noreply.github.com>
2024-02-21 13:56:19 +01:00
John Wesley Walker III
df0bcddf6d
Refine workflow for generating test-ubuntu-git (#1617) 2024-02-21 12:46:47 +01:00
John Wesley Walker III
473055ba18
Create test-ubuntu-git Docker Container for Proxy Tests (#1616) 2024-02-20 17:08:08 +01:00
Cory Miller
b4ffde65f4
Link to release page from what's new section (#1514) 2023-10-17 11:52:30 -04:00
Peter Bengtsson
8530928916
Correct link to GitHub Docs (#1511)
No hardcoded language in the URL and uses the correct docs.github.com domain.
2023-10-13 11:07:47 -04:00
Josh Gross
7cdaf2fbc0
Update CODEOWNERS to Launch team (#1510) 2023-10-10 11:16:51 -04:00
Cory Miller
8ade135a41
Prepare 4.1.0 release (#1496) 2023-09-22 13:40:21 -04:00
Finley Garton
c533a0a4cf
Add support for partial checkout filters (#1396)
* added filter option & tests

* added build file

* fix test oversight

* added exit 1

* updated docs to specify override

* undo unneeded readme change

* set to undefined rather than empty string

* run git config in correct di

---------

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>
2023-09-22 13:30:36 -04:00
Varun Sivapalan
72f2cec99f
Update README.md for V4 (#1452)
* Update README.md for V4

* Update actionReference in generate-docs.ts for v4
2023-09-05 09:21:52 -04:00
Tatyana Kostromskaya
3df4ab11eb
Release 4.0.0 (#1447)
* Release 4.0.0

* Add new major version to workflow
2023-09-04 14:19:40 +02:00
Simon Baird
8b5e8b7687
Support fetching without the --progress option (#1067)
Setting the `show-progress` option to false in the `with` section of the
workflow step will cause git fetch to run without `--progress`.

The motivation is to be able to suppress the noisy progress status
output which adds many hundreds of "remote: Counting objects: 85%
(386/453)" and similar lines in the workflow log.

This should be sufficient to resolve #894 and its older friends,
though the solution is different to the one proposed there because
it doesn't use the --quiet flag. IIUC git doesn't show the progress
status by default since the output is not a terminal, so that's why
removing the --progress option is all that's needed.

Adding the --quiet flag doesn't make a lot of difference once the
--progress flag is removed, and actually I think using --quiet would
suppress some other more useful output that would be better left
visible.

Signed-off-by: Simon Baird <sbaird@redhat.com>
2023-09-01 14:19:18 -04:00
Tatyana Kostromskaya
97a652b800
Update default runtime to node20 (#1436)
* .

* update workflows
2023-08-29 17:01:52 +02:00
23 changed files with 577 additions and 16089 deletions

View File

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

View File

@ -7,13 +7,18 @@ on:
- main - main
- releases/* - 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: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/setup-node@v1 - uses: actions/setup-node@v1
with: with:
node-version: 16.x node-version: 20.x
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- run: npm ci - run: npm ci
- run: npm run build - run: npm run build
@ -72,6 +77,16 @@ jobs:
shell: bash shell: bash
run: __test__/verify-side-by-side.sh 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 # Sparse checkout
- name: Sparse checkout - name: Sparse checkout
uses: ./ uses: ./
@ -85,6 +100,16 @@ jobs:
- name: Verify sparse checkout - name: Verify sparse checkout
run: __test__/verify-sparse-checkout.sh 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) # Sparse checkout (non-cone mode)
- name: Sparse checkout (non-cone mode) - name: Sparse checkout (non-cone mode)
uses: ./ uses: ./
@ -165,7 +190,7 @@ jobs:
test-proxy: test-proxy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: alpine/git:latest image: ghcr.io/actions/test-ubuntu-git:main.20240221.114913.703z
options: --dns 127.0.0.1 options: --dns 127.0.0.1
services: services:
squid-proxy: squid-proxy:
@ -269,4 +294,4 @@ jobs:
- name: Fix Checkout v3 - name: Fix Checkout v3
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
path: v3 path: v3

View File

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

View File

@ -0,0 +1,59 @@
name: Publish test-ubuntu-git Container
on:
# Use an on demand workflow trigger.
# (Forked copies of actions/checkout won't have permission to update GHCR.io/actions,
# so avoid trigger events that run automatically.)
workflow_dispatch:
inputs:
publish:
description: 'Publish to ghcr.io? (main branch only)'
type: boolean
required: true
default: false
env:
REGISTRY: ghcr.io
IMAGE_NAME: actions/test-ubuntu-git
jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Use `docker/login-action` to log in to GHCR.io.
# Once published, the packages are scoped to the account defined here.
- name: Log in to the ghcr.io container registry
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Format Timestamp
id: timestamp
# Use `date` with a custom format to achieve the key=value format GITHUB_OUTPUT expects.
run: date -u "+now=%Y%m%d.%H%M%S.%3NZ" >> "$GITHUB_OUTPUT"
- name: Issue Image Publish Warning
if: ${{ inputs.publish && github.ref_name != 'main' }}
run: echo "::warning::test-ubuntu-git images can only be published from the actions/checkout 'main' branch. Workflow will continue with push/publish disabled."
# Use `docker/build-push-action` to build (and optionally publish) the image.
- name: Build Docker Image (with optional Push)
uses: docker/build-push-action@v5.1.0
with:
context: .
file: images/test-ubuntu-git.Dockerfile
# For now, attempts to push to ghcr.io must target the `main` branch.
# In the future, consider also allowing attempts from `releases/*` branches.
push: ${{ inputs.publish && github.ref_name == 'main' }}
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}.${{ steps.timestamp.outputs.now }}

View File

@ -1,5 +1,12 @@
# Changelog # 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 ## v3.6.0
- [Fix: Mark test scripts with Bash'isms to be run via Bash](https://github.com/actions/checkout/pull/1377) - [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) - [Add option to fetch tags even if fetch-depth > 0](https://github.com/actions/checkout/pull/579)

View File

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

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) [![Build and Test](https://github.com/actions/checkout/actions/workflows/test.yml/badge.svg)](https://github.com/actions/checkout/actions/workflows/test.yml)
# Checkout V3 # Checkout V4
This action checks-out your repository under `$GITHUB_WORKSPACE`, so your workflow can access it. 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://help.github.com/en/articles/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://docs.github.com/actions/using-workflows/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. 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,14 +12,13 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
# What's new # What's new
- Updated to the node16 runtime by default Please refer to the [release page](https://github.com/actions/checkout/releases/latest) for the latest release notes.
- 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 # Usage
<!-- start usage --> <!-- start usage -->
```yaml ```yaml
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
# Repository name with owner. For example, actions/checkout # Repository name with owner. For example, actions/checkout
# Default: ${{ github.repository }} # Default: ${{ github.repository }}
@ -74,8 +73,12 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
# Default: true # Default: true
clean: '' 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 # Do a sparse checkout on given patterns. Each pattern should be separated with
# new lines # new lines.
# Default: null # Default: null
sparse-checkout: '' sparse-checkout: ''
@ -91,6 +94,10 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
# Default: false # Default: false
fetch-tags: '' fetch-tags: ''
# Whether to show progress status output when fetching.
# Default: true
show-progress: ''
# Whether to download Git-LFS files # Whether to download Git-LFS files
# Default: false # Default: false
lfs: '' lfs: ''
@ -135,7 +142,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
```yaml ```yaml
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
sparse-checkout: . sparse-checkout: .
``` ```
@ -143,7 +150,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 and `.github` and `src` folder ## Fetch only the root files and `.github` and `src` folder
```yaml ```yaml
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
sparse-checkout: | sparse-checkout: |
.github .github
@ -153,7 +160,7 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
## Fetch only a single file ## Fetch only a single file
```yaml ```yaml
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
sparse-checkout: | sparse-checkout: |
README.md README.md
@ -163,7 +170,7 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
## Fetch all history for all tags and branches ## Fetch all history for all tags and branches
```yaml ```yaml
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
``` ```
@ -171,7 +178,7 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
## Checkout a different branch ## Checkout a different branch
```yaml ```yaml
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
ref: my-branch ref: my-branch
``` ```
@ -179,7 +186,7 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
## Checkout HEAD^ ## Checkout HEAD^
```yaml ```yaml
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
fetch-depth: 2 fetch-depth: 2
- run: git checkout HEAD^ - run: git checkout HEAD^
@ -189,12 +196,12 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
```yaml ```yaml
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
path: main path: main
- name: Checkout tools repo - name: Checkout tools repo
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
repository: my-org/my-tools repository: my-org/my-tools
path: my-tools path: my-tools
@ -205,10 +212,10 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
```yaml ```yaml
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Checkout tools repo - name: Checkout tools repo
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
repository: my-org/my-tools repository: my-org/my-tools
path: my-tools path: my-tools
@ -219,12 +226,12 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
```yaml ```yaml
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
path: main path: main
- name: Checkout private tools - name: Checkout private tools
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
repository: my-org/my-private-tools repository: my-org/my-private-tools
token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT
@ -237,7 +244,7 @@ When Git 2.18 or higher is not in your PATH, falls back to the REST API to downl
## Checkout pull request HEAD commit instead of merge commit ## Checkout pull request HEAD commit instead of merge commit
```yaml ```yaml
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
``` ```
@ -253,7 +260,7 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
``` ```
## Push a commit using the built-in token ## Push a commit using the built-in token
@ -264,7 +271,7 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- run: | - run: |
date > generated.txt date > generated.txt
git config user.name github-actions git config user.name github-actions

View File

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

View File

@ -135,7 +135,6 @@ describe('Test fetchDepth and fetchTags options', () => {
'protocol.version=2', 'protocol.version=2',
'fetch', 'fetch',
'--prune', '--prune',
'--progress',
'--no-recurse-submodules', '--no-recurse-submodules',
'--filter=filterValue', '--filter=filterValue',
'origin', 'origin',
@ -174,7 +173,6 @@ describe('Test fetchDepth and fetchTags options', () => {
'fetch', 'fetch',
'--no-tags', '--no-tags',
'--prune', '--prune',
'--progress',
'--no-recurse-submodules', '--no-recurse-submodules',
'--filter=filterValue', '--filter=filterValue',
'origin', 'origin',
@ -213,7 +211,6 @@ describe('Test fetchDepth and fetchTags options', () => {
'fetch', 'fetch',
'--no-tags', '--no-tags',
'--prune', '--prune',
'--progress',
'--no-recurse-submodules', '--no-recurse-submodules',
'--filter=filterValue', '--filter=filterValue',
'--depth=1', '--depth=1',
@ -252,7 +249,6 @@ describe('Test fetchDepth and fetchTags options', () => {
'protocol.version=2', 'protocol.version=2',
'fetch', 'fetch',
'--prune', '--prune',
'--progress',
'--no-recurse-submodules', '--no-recurse-submodules',
'--filter=filterValue', '--filter=filterValue',
'--depth=1', '--depth=1',
@ -263,4 +259,120 @@ describe('Test fetchDepth and fetchTags options', () => {
expect.any(Object) 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,6 +462,7 @@ async function setup(testName: string): Promise<void> {
branchList: jest.fn(async () => { branchList: jest.fn(async () => {
return [] return []
}), }),
disableSparseCheckout: jest.fn(),
sparseCheckout: jest.fn(), sparseCheckout: jest.fn(),
sparseCheckoutNonConeMode: jest.fn(), sparseCheckoutNonConeMode: jest.fn(),
checkout: jest.fn(), checkout: jest.fn(),

View File

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

16
__test__/verify-fetch-filter.sh Executable file
View File

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

@ -53,10 +53,15 @@ inputs:
clean: clean:
description: 'Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching' description: 'Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching'
default: true default: true
filter:
description: >
Partially clone against a given filter.
Overrides sparse-checkout if set.
default: null
sparse-checkout: sparse-checkout:
description: > description: >
Do a sparse checkout on given patterns. Do a sparse checkout on given patterns.
Each pattern should be separated with new lines Each pattern should be separated with new lines.
default: null default: null
sparse-checkout-cone-mode: sparse-checkout-cone-mode:
description: > description: >
@ -68,6 +73,9 @@ inputs:
fetch-tags: fetch-tags:
description: 'Whether to fetch tags, even if fetch-depth > 0.' description: 'Whether to fetch tags, even if fetch-depth > 0.'
default: false default: false
show-progress:
description: 'Whether to show progress status output when fetching.'
default: true
lfs: lfs:
description: 'Whether to download Git-LFS files' description: 'Whether to download Git-LFS files'
default: false default: false
@ -87,6 +95,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 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 required: false
runs: runs:
using: node16 using: node20
main: dist/index.js main: dist/index.js
post: dist/index.js post: dist/index.js

31
dist/index.js vendored
View File

@ -576,6 +576,11 @@ class GitCommandManager {
return result; return result;
}); });
} }
disableSparseCheckout() {
return __awaiter(this, void 0, void 0, function* () {
yield this.execGit(['sparse-checkout', 'disable']);
});
}
sparseCheckout(sparseCheckout) { sparseCheckout(sparseCheckout) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
yield this.execGit(['sparse-checkout', 'set', ...sparseCheckout]); yield this.execGit(['sparse-checkout', 'set', ...sparseCheckout]);
@ -640,7 +645,10 @@ class GitCommandManager {
if (!refSpec.some(x => x === refHelper.tagsRefSpec) && !options.fetchTags) { if (!refSpec.some(x => x === refHelper.tagsRefSpec) && !options.fetchTags) {
args.push('--no-tags'); args.push('--no-tags');
} }
args.push('--prune', '--progress', '--no-recurse-submodules'); args.push('--prune', '--no-recurse-submodules');
if (options.showProgress) {
args.push('--progress');
}
if (options.filter) { if (options.filter) {
args.push(`--filter=${options.filter}`); args.push(`--filter=${options.filter}`);
} }
@ -1241,8 +1249,12 @@ function getSource(settings) {
// Fetch // Fetch
core.startGroup('Fetching the repository'); core.startGroup('Fetching the repository');
const fetchOptions = {}; const fetchOptions = {};
if (settings.sparseCheckout) if (settings.filter) {
fetchOptions.filter = settings.filter;
}
else if (settings.sparseCheckout) {
fetchOptions.filter = 'blob:none'; fetchOptions.filter = 'blob:none';
}
if (settings.fetchDepth <= 0) { if (settings.fetchDepth <= 0) {
// Fetch all branches and tags // Fetch all branches and tags
let refSpec = refHelper.getRefSpecForAllHistory(settings.ref, settings.commit); let refSpec = refHelper.getRefSpecForAllHistory(settings.ref, settings.commit);
@ -1275,7 +1287,10 @@ function getSource(settings) {
core.endGroup(); core.endGroup();
} }
// Sparse checkout // Sparse checkout
if (settings.sparseCheckout) { if (!settings.sparseCheckout) {
yield git.disableSparseCheckout();
}
else {
core.startGroup('Setting up sparse checkout'); core.startGroup('Setting up sparse checkout');
if (settings.sparseCheckoutConeMode) { if (settings.sparseCheckoutConeMode) {
yield git.sparseCheckout(settings.sparseCheckout); yield git.sparseCheckout(settings.sparseCheckout);
@ -1720,6 +1735,12 @@ function getInputs() {
// Clean // Clean
result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE'; result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE';
core.debug(`clean = ${result.clean}`); core.debug(`clean = ${result.clean}`);
// Filter
const filter = core.getInput('filter');
if (filter) {
result.filter = filter;
}
core.debug(`filter = ${result.filter}`);
// Sparse checkout // Sparse checkout
const sparseCheckout = core.getMultilineInput('sparse-checkout'); const sparseCheckout = core.getMultilineInput('sparse-checkout');
if (sparseCheckout.length) { if (sparseCheckout.length) {
@ -1739,6 +1760,10 @@ function getInputs() {
result.fetchTags = result.fetchTags =
(core.getInput('fetch-tags') || 'false').toUpperCase() === 'TRUE'; (core.getInput('fetch-tags') || 'false').toUpperCase() === 'TRUE';
core.debug(`fetch tags = ${result.fetchTags}`); 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 // LFS
result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE'; result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE';
core.debug(`lfs = ${result.lfs}`); core.debug(`lfs = ${result.lfs}`);

View File

@ -0,0 +1,12 @@
# Defines the test-ubuntu-git Container Image.
# Consumed by actions/checkout CI/CD validation workflows.
FROM ubuntu:latest
RUN apt update
RUN apt install -y git
LABEL org.opencontainers.image.title="Ubuntu + git (validation image)"
LABEL org.opencontainers.image.description="Ubuntu image with git pre-installed. Intended primarily for testing `actions/checkout` during CI/CD workflows."
LABEL org.opencontainers.image.documentation="https://github.com/actions/checkout/tree/main/images/test-ubuntu-git.md"
LABEL org.opencontainers.image.licenses=MIT

15
images/test-ubuntu-git.md Normal file
View File

@ -0,0 +1,15 @@
# `test-ubuntu-git` Container Image
[![Publish test-ubuntu-git Container](https://github.com/actions/checkout/actions/workflows/update-test-ubuntu-git.yml/badge.svg)](https://github.com/actions/checkout/actions/workflows/update-test-ubuntu-git.yml)
## Purpose
`test-ubuntu-git` is a container image hosted on the GitHub Container Registry, `ghcr.io`.
It is intended primarily for testing the [`actions/checkout` repository](https://github.com/actions/checkout) as part of `actions/checkout`'s CI/CD workflows.
The composition of `test-ubuntu-git` is intentionally minimal. It is comprised of [git](https://git-scm.com/) installed on top of a [base-level ubuntu image](https://hub.docker.com/_/ubuntu/tags).
# License
`test-ubuntu-git` is released under the [MIT License](/LICENSE).

16241
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -17,6 +17,7 @@ export interface IGitCommandManager {
branchDelete(remote: boolean, branch: string): Promise<void> branchDelete(remote: boolean, branch: string): Promise<void>
branchExists(remote: boolean, pattern: string): Promise<boolean> branchExists(remote: boolean, pattern: string): Promise<boolean>
branchList(remote: boolean): Promise<string[]> branchList(remote: boolean): Promise<string[]>
disableSparseCheckout(): Promise<void>
sparseCheckout(sparseCheckout: string[]): Promise<void> sparseCheckout(sparseCheckout: string[]): Promise<void>
sparseCheckoutNonConeMode(sparseCheckout: string[]): Promise<void> sparseCheckoutNonConeMode(sparseCheckout: string[]): Promise<void>
checkout(ref: string, startPoint: string): Promise<void> checkout(ref: string, startPoint: string): Promise<void>
@ -34,6 +35,7 @@ export interface IGitCommandManager {
filter?: string filter?: string
fetchDepth?: number fetchDepth?: number
fetchTags?: boolean fetchTags?: boolean
showProgress?: boolean
} }
): Promise<void> ): Promise<void>
getDefaultBranch(repositoryUrl: string): Promise<string> getDefaultBranch(repositoryUrl: string): Promise<string>
@ -170,6 +172,10 @@ class GitCommandManager {
return result return result
} }
async disableSparseCheckout(): Promise<void> {
await this.execGit(['sparse-checkout', 'disable'])
}
async sparseCheckout(sparseCheckout: string[]): Promise<void> { async sparseCheckout(sparseCheckout: string[]): Promise<void> {
await this.execGit(['sparse-checkout', 'set', ...sparseCheckout]) await this.execGit(['sparse-checkout', 'set', ...sparseCheckout])
} }
@ -241,14 +247,22 @@ class GitCommandManager {
async fetch( async fetch(
refSpec: string[], refSpec: string[],
options: {filter?: string; fetchDepth?: number; fetchTags?: boolean} options: {
filter?: string
fetchDepth?: number
fetchTags?: boolean
showProgress?: boolean
}
): Promise<void> { ): Promise<void> {
const args = ['-c', 'protocol.version=2', 'fetch'] const args = ['-c', 'protocol.version=2', 'fetch']
if (!refSpec.some(x => x === refHelper.tagsRefSpec) && !options.fetchTags) { if (!refSpec.some(x => x === refHelper.tagsRefSpec) && !options.fetchTags) {
args.push('--no-tags') args.push('--no-tags')
} }
args.push('--prune', '--progress', '--no-recurse-submodules') args.push('--prune', '--no-recurse-submodules')
if (options.showProgress) {
args.push('--progress')
}
if (options.filter) { if (options.filter) {
args.push(`--filter=${options.filter}`) args.push(`--filter=${options.filter}`)

View File

@ -157,8 +157,15 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
filter?: string filter?: string
fetchDepth?: number fetchDepth?: number
fetchTags?: boolean fetchTags?: boolean
showProgress?: boolean
} = {} } = {}
if (settings.sparseCheckout) fetchOptions.filter = 'blob:none'
if (settings.filter) {
fetchOptions.filter = settings.filter
} else if (settings.sparseCheckout) {
fetchOptions.filter = 'blob:none'
}
if (settings.fetchDepth <= 0) { if (settings.fetchDepth <= 0) {
// Fetch all branches and tags // Fetch all branches and tags
let refSpec = refHelper.getRefSpecForAllHistory( let refSpec = refHelper.getRefSpecForAllHistory(
@ -201,7 +208,9 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
} }
// Sparse checkout // Sparse checkout
if (settings.sparseCheckout) { if (!settings.sparseCheckout) {
await git.disableSparseCheckout()
} else {
core.startGroup('Setting up sparse checkout') core.startGroup('Setting up sparse checkout')
if (settings.sparseCheckoutConeMode) { if (settings.sparseCheckoutConeMode) {
await git.sparseCheckout(settings.sparseCheckout) await git.sparseCheckout(settings.sparseCheckout)

View File

@ -29,6 +29,11 @@ export interface IGitSourceSettings {
*/ */
clean: boolean clean: boolean
/**
* The filter determining which objects to include
*/
filter: string | undefined
/** /**
* The array of folders to make the sparse checkout * The array of folders to make the sparse checkout
*/ */
@ -49,6 +54,11 @@ export interface IGitSourceSettings {
*/ */
fetchTags: boolean fetchTags: boolean
/**
* Indicates whether to use the --progress option when fetching
*/
showProgress: boolean
/** /**
* Indicates whether to fetch LFS objects * Indicates whether to fetch LFS objects
*/ */

View File

@ -82,6 +82,14 @@ export async function getInputs(): Promise<IGitSourceSettings> {
result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE' result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE'
core.debug(`clean = ${result.clean}`) core.debug(`clean = ${result.clean}`)
// Filter
const filter = core.getInput('filter')
if (filter) {
result.filter = filter
}
core.debug(`filter = ${result.filter}`)
// Sparse checkout // Sparse checkout
const sparseCheckout = core.getMultilineInput('sparse-checkout') const sparseCheckout = core.getMultilineInput('sparse-checkout')
if (sparseCheckout.length) { if (sparseCheckout.length) {
@ -105,6 +113,11 @@ export async function getInputs(): Promise<IGitSourceSettings> {
(core.getInput('fetch-tags') || 'false').toUpperCase() === 'TRUE' (core.getInput('fetch-tags') || 'false').toUpperCase() === 'TRUE'
core.debug(`fetch tags = ${result.fetchTags}`) 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 // LFS
result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE' result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE'
core.debug(`lfs = ${result.lfs}`) core.debug(`lfs = ${result.lfs}`)

View File

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