Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/actions/checkout/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
# Default: false
single-branch: ''

# Additional refs to fetch. Each ref should be separated with new lines. For
# example, to fetch all tags: `refs/tags/*:refs/tags/*`
# Default: refs/heads/main
additional-fetch-refs: ''

# Personal access token (PAT) used to fetch the repository. The PAT is configured
# with the local git config, which enables your scripts to run authenticated git
# commands. The post-job step removes the PAT.
Expand Down
1 change: 1 addition & 0 deletions .github/actions/checkout/__test__/git-auth-helper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,7 @@ async function setup(testName: string): Promise<void> {
submodulesFilter: undefined,
persistCredentials: true,
ref: 'refs/heads/main',
additionalFetchRefs: [],
repositoryName: 'my-repo',
repositoryOwner: 'my-org',
repositoryPath: '',
Expand Down
52 changes: 43 additions & 9 deletions .github/actions/checkout/__test__/ref-helper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,59 +132,93 @@ describe('ref-helper tests', () => {

it('getRefSpec requires ref or commit', async () => {
assert.throws(
() => refHelper.getRefSpec('', ''),
() => refHelper.getRefSpec('', '', []),
/Args ref and commit cannot both be empty/
)
})

it('getRefSpec sha + refs/heads/', async () => {
const refSpec = refHelper.getRefSpec('refs/heads/my/branch', commit)
const refSpec = refHelper.getRefSpec('refs/heads/my/branch', commit, [])
expect(refSpec.length).toBe(1)
expect(refSpec[0]).toBe(`+${commit}:refs/remotes/origin/my/branch`)
})

it('getRefSpec sha + refs/pull/', async () => {
const refSpec = refHelper.getRefSpec('refs/pull/123/merge', commit)
const refSpec = refHelper.getRefSpec('refs/pull/123/merge', commit, [])
expect(refSpec.length).toBe(1)
expect(refSpec[0]).toBe(`+${commit}:refs/remotes/pull/123/merge`)
})

it('getRefSpec sha + refs/tags/', async () => {
const refSpec = refHelper.getRefSpec('refs/tags/my-tag', commit)
const refSpec = refHelper.getRefSpec('refs/tags/my-tag', commit, [])
expect(refSpec.length).toBe(1)
expect(refSpec[0]).toBe(`+${commit}:refs/tags/my-tag`)
})

it('getRefSpec sha only', async () => {
const refSpec = refHelper.getRefSpec('', commit)
const refSpec = refHelper.getRefSpec('', commit, [])
expect(refSpec.length).toBe(1)
expect(refSpec[0]).toBe(commit)
})

it('getRefSpec unqualified ref only', async () => {
const refSpec = refHelper.getRefSpec('my-ref', '')
const refSpec = refHelper.getRefSpec('my-ref', '', [])
expect(refSpec.length).toBe(2)
expect(refSpec[0]).toBe('+refs/heads/my-ref*:refs/remotes/origin/my-ref*')
expect(refSpec[1]).toBe('+refs/tags/my-ref*:refs/tags/my-ref*')
})

it('getRefSpec refs/heads/ only', async () => {
const refSpec = refHelper.getRefSpec('refs/heads/my/branch', '')
const refSpec = refHelper.getRefSpec('refs/heads/my/branch', '', [])
expect(refSpec.length).toBe(1)
expect(refSpec[0]).toBe(
'+refs/heads/my/branch:refs/remotes/origin/my/branch'
)
})

it('getRefSpec refs/pull/ only', async () => {
const refSpec = refHelper.getRefSpec('refs/pull/123/merge', '')
const refSpec = refHelper.getRefSpec('refs/pull/123/merge', '', [])
expect(refSpec.length).toBe(1)
expect(refSpec[0]).toBe('+refs/pull/123/merge:refs/remotes/pull/123/merge')
})

it('getRefSpec refs/tags/ only', async () => {
const refSpec = refHelper.getRefSpec('refs/tags/my-tag', '')
const refSpec = refHelper.getRefSpec('refs/tags/my-tag', '', [])
expect(refSpec.length).toBe(1)
expect(refSpec[0]).toBe('+refs/tags/my-tag:refs/tags/my-tag')
})

it('getRefSpec additional fetch refs unqualified', async () => {
const refSpec = refHelper.getRefSpec('refs/heads/main', '', [
'viable/strict'
])
expect(refSpec.length).toBe(3)
expect(refSpec[0]).toBe('+refs/heads/main:refs/remotes/origin/main')
expect(refSpec[1]).toBe(
'+refs/heads/viable/strict*:refs/remotes/origin/viable/strict*'
)
expect(refSpec[2]).toBe(
'+refs/tags/viable/strict*:refs/tags/viable/strict*'
)
})

it('getRefSpec additional fetch refs heads only', async () => {
const refSpec = refHelper.getRefSpec('refs/heads/main', '', [
'refs/heads/viable/strict'
])
expect(refSpec.length).toBe(2)
expect(refSpec[0]).toBe('+refs/heads/main:refs/remotes/origin/main')
expect(refSpec[1]).toBe(
'+refs/heads/viable/strict:refs/remotes/origin/viable/strict'
)
})

it('getRefSpec additional fetch refs tags only', async () => {
const refSpec = refHelper.getRefSpec('refs/heads/main', '', [
'refs/tags/my-tag'
])
expect(refSpec.length).toBe(2)
expect(refSpec[0]).toBe('+refs/heads/main:refs/remotes/origin/main')
expect(refSpec[1]).toBe('+refs/tags/my-tag:refs/tags/my-tag')
})
})
5 changes: 5 additions & 0 deletions .github/actions/checkout/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ inputs:
history leading to the specified ref is fetched. When false, the full history
is fetched.
default: "false"
additional-fetch-refs:
description: >
Additional refs to fetch. Each ref should be separated with new lines.
For example, to fetch all tags: `refs/tags/*:refs/tags/*`
default: refs/heads/main
token:
description: >
Personal access token (PAT) used to fetch the repository. The PAT is configured
Expand Down
23 changes: 19 additions & 4 deletions .github/actions/checkout/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1525,20 +1525,20 @@ function getSource(settings) {
}
if (settings.fetchDepth <= 0) {
let refSpec = settings.singleBranch
? refHelper.getRefSpec(settings.ref, settings.commit)
? refHelper.getRefSpec(settings.ref, settings.commit, settings.additionalFetchRefs)
: refHelper.getRefSpecForAllHistory(settings.ref, settings.commit);
yield git.fetch(refSpec, fetchOptions);
// 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);
refSpec = refHelper.getRefSpec(settings.ref, settings.commit, settings.additionalFetchRefs);
yield git.fetch(refSpec, fetchOptions);
}
}
else {
fetchOptions.fetchDepth = settings.fetchDepth;
fetchOptions.fetchTags = settings.fetchTags;
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit);
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit, settings.additionalFetchRefs);
yield git.fetch(refSpec, fetchOptions);
}
core.endGroup();
Expand Down Expand Up @@ -2013,6 +2013,10 @@ function getInputs() {
result.singleBranch =
(core.getInput('single-branch') || 'false').toUpperCase() === 'TRUE';
core.debug(`single branch = ${result.singleBranch}`);
// Additional fetch refs
result.additionalFetchRefs =
core.getMultilineInput('additional-fetch-refs') || [];
core.debug(`additional fetch refs = ${JSON.stringify(result.additionalFetchRefs)}`);
// Clean
result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE';
core.debug(`clean = ${result.clean}`);
Expand Down Expand Up @@ -2223,6 +2227,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.tagsRefSpec = void 0;
exports.getCheckoutInfo = getCheckoutInfo;
exports.getRefSpecForAllHistory = getRefSpecForAllHistory;
exports.getSingleRefSpec = getSingleRefSpec;
exports.getRefSpec = getRefSpec;
exports.testRef = testRef;
exports.checkCommitInfo = checkCommitInfo;
Expand Down Expand Up @@ -2287,7 +2292,7 @@ function getRefSpecForAllHistory(ref, commit) {
}
return result;
}
function getRefSpec(ref, commit) {
function getSingleRefSpec(ref, commit) {
if (!ref && !commit) {
throw new Error('Args ref and commit cannot both be empty');
}
Expand Down Expand Up @@ -2335,6 +2340,16 @@ function getRefSpec(ref, commit) {
return [`+${ref}:${ref}`];
}
}
function getRefSpec(ref, commit, additionalFetchRefs) {
const result = [];
const singleRefSpec = getSingleRefSpec(ref, commit);
result.push(...singleRefSpec);
for (const additionalRef of additionalFetchRefs) {
const additionalRefSpec = getSingleRefSpec(additionalRef, '');
result.push(...additionalRefSpec);
}
return result;
}
/**
* Tests whether the initial fetch created the ref at the expected commit
*/
Expand Down
18 changes: 15 additions & 3 deletions .github/actions/checkout/src/git-source-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,20 +171,32 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {

if (settings.fetchDepth <= 0) {
let refSpec: string[] = settings.singleBranch
? refHelper.getRefSpec(settings.ref, settings.commit)
? refHelper.getRefSpec(
settings.ref,
settings.commit,
settings.additionalFetchRefs
)
: refHelper.getRefSpecForAllHistory(settings.ref, settings.commit)
await git.fetch(refSpec, fetchOptions)

// 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)
refSpec = refHelper.getRefSpec(
settings.ref,
settings.commit,
settings.additionalFetchRefs
)
await git.fetch(refSpec, fetchOptions)
}
} else {
fetchOptions.fetchDepth = settings.fetchDepth
fetchOptions.fetchTags = settings.fetchTags
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
const refSpec = refHelper.getRefSpec(
settings.ref,
settings.commit,
settings.additionalFetchRefs
)
await git.fetch(refSpec, fetchOptions)
}
core.endGroup()
Expand Down
5 changes: 5 additions & 0 deletions .github/actions/checkout/src/git-source-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export interface IGitSourceSettings {
*/
singleBranch: boolean

/**
* Additional fetch refs
*/
additionalFetchRefs: string[]

/**
* Indicates whether to clean the repository
*/
Expand Down
7 changes: 7 additions & 0 deletions .github/actions/checkout/src/input-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ export async function getInputs(): Promise<IGitSourceSettings> {
(core.getInput('single-branch') || 'false').toUpperCase() === 'TRUE'
core.debug(`single branch = ${result.singleBranch}`)

// Additional fetch refs
result.additionalFetchRefs =
core.getMultilineInput('additional-fetch-refs') || []
core.debug(
`additional fetch refs = ${JSON.stringify(result.additionalFetchRefs)}`
)

// Clean
result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE'
core.debug(`clean = ${result.clean}`)
Expand Down
17 changes: 16 additions & 1 deletion .github/actions/checkout/src/ref-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export function getRefSpecForAllHistory(ref: string, commit: string): string[] {
return result
}

export function getRefSpec(ref: string, commit: string): string[] {
export function getSingleRefSpec(ref: string, commit: string): string[] {
if (!ref && !commit) {
throw new Error('Args ref and commit cannot both be empty')
}
Expand Down Expand Up @@ -127,6 +127,21 @@ export function getRefSpec(ref: string, commit: string): string[] {
}
}

export function getRefSpec(
ref: string,
commit: string,
additionalFetchRefs: string[]
): string[] {
const result: string[] = []
const singleRefSpec: string[] = getSingleRefSpec(ref, commit)
result.push(...singleRefSpec)
for (const additionalRef of additionalFetchRefs) {
const additionalRefSpec = getSingleRefSpec(additionalRef, '')
result.push(...additionalRefSpec)
}
return result
}

/**
* Tests whether the initial fetch created the ref at the expected commit
*/
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/checkout-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ jobs:
- name: Verify fetch filter
run: __test__/verify-fetch-filter.sh

# Additional fetch refs
- name: Additional fetch refs
uses: ./.github/actions/checkout/
with:
path: .github/actions/checkout/additional-fetch-refs
additional-fetch-refs: |
refs/heads/main

# Sparse checkout
- name: Sparse checkout
uses: ./.github/actions/checkout/
Expand Down