mirror of
https://github.com/actions/checkout.git
synced 2026-05-13 16:38:07 +00:00
Compare commits
6 Commits
a614ac3395
...
d00c4ca496
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d00c4ca496 | ||
|
|
900f2210b1 | ||
|
|
6b8be4cb30 | ||
|
|
47b9382799 | ||
|
|
5bbdf118df | ||
|
|
e72243fb91 |
@ -63,6 +63,11 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
|
|||||||
# Otherwise, uses the default branch.
|
# Otherwise, uses the default branch.
|
||||||
ref: ''
|
ref: ''
|
||||||
|
|
||||||
|
# Indicates whether to checkout the default repository branch if the requested ref
|
||||||
|
# does not exist
|
||||||
|
# Default: false
|
||||||
|
default-branch-checkout: ''
|
||||||
|
|
||||||
# Personal access token (PAT) used to fetch the repository. The PAT is configured
|
# 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
|
# with the local git config, which enables your scripts to run authenticated git
|
||||||
# commands. The post-job step removes the PAT.
|
# commands. The post-job step removes the PAT.
|
||||||
|
|||||||
@ -1164,6 +1164,7 @@ async function setup(testName: string): Promise<void> {
|
|||||||
nestedSubmodules: false,
|
nestedSubmodules: false,
|
||||||
persistCredentials: true,
|
persistCredentials: true,
|
||||||
ref: 'refs/heads/main',
|
ref: 'refs/heads/main',
|
||||||
|
defaultBranchCheckout: false,
|
||||||
repositoryName: 'my-repo',
|
repositoryName: 'my-repo',
|
||||||
repositoryOwner: 'my-org',
|
repositoryOwner: 'my-org',
|
||||||
repositoryPath: '',
|
repositoryPath: '',
|
||||||
|
|||||||
@ -80,6 +80,7 @@ describe('input-helper tests', () => {
|
|||||||
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.filter).toBe(undefined)
|
||||||
|
expect(settings.defaultBranchCheckout).toBe(false)
|
||||||
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)
|
||||||
@ -133,6 +134,16 @@ describe('input-helper tests', () => {
|
|||||||
expect(settings.commit).toBe('1111111111222222222233333333334444444444')
|
expect(settings.commit).toBe('1111111111222222222233333333334444444444')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('sets ref to empty when explicit sha-256', async () => {
|
||||||
|
inputs.ref =
|
||||||
|
'1111111111222222222233333333334444444444555555555566666666667777'
|
||||||
|
const settings: IGitSourceSettings = await inputHelper.getInputs()
|
||||||
|
expect(settings.ref).toBeFalsy()
|
||||||
|
expect(settings.commit).toBe(
|
||||||
|
'1111111111222222222233333333334444444444555555555566666666667777'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('sets sha to empty when explicit ref', async () => {
|
it('sets sha to empty when explicit ref', async () => {
|
||||||
inputs.ref = 'refs/heads/some-other-ref'
|
inputs.ref = 'refs/heads/some-other-ref'
|
||||||
const settings: IGitSourceSettings = await inputHelper.getInputs()
|
const settings: IGitSourceSettings = await inputHelper.getInputs()
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from 'assert'
|
||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as github from '@actions/github'
|
||||||
import * as refHelper from '../lib/ref-helper'
|
import * as refHelper from '../lib/ref-helper'
|
||||||
import {IGitCommandManager} from '../lib/git-command-manager'
|
import {IGitCommandManager} from '../lib/git-command-manager'
|
||||||
|
|
||||||
const commit = '1234567890123456789012345678901234567890'
|
const commit = '1234567890123456789012345678901234567890'
|
||||||
|
const sha256Commit =
|
||||||
|
'1234567890123456789012345678901234567890123456789012345678901234'
|
||||||
let git: IGitCommandManager
|
let git: IGitCommandManager
|
||||||
|
|
||||||
describe('ref-helper tests', () => {
|
describe('ref-helper tests', () => {
|
||||||
@ -37,6 +41,12 @@ describe('ref-helper tests', () => {
|
|||||||
expect(checkoutInfo.startPoint).toBeFalsy()
|
expect(checkoutInfo.startPoint).toBeFalsy()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('getCheckoutInfo sha-256 only', async () => {
|
||||||
|
const checkoutInfo = await refHelper.getCheckoutInfo(git, '', sha256Commit)
|
||||||
|
expect(checkoutInfo.ref).toBe(sha256Commit)
|
||||||
|
expect(checkoutInfo.startPoint).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
it('getCheckoutInfo refs/heads/', async () => {
|
it('getCheckoutInfo refs/heads/', async () => {
|
||||||
const checkoutInfo = await refHelper.getCheckoutInfo(
|
const checkoutInfo = await refHelper.getCheckoutInfo(
|
||||||
git,
|
git,
|
||||||
@ -227,4 +237,142 @@ describe('ref-helper tests', () => {
|
|||||||
'+refs/heads/my/branch:refs/remotes/origin/my/branch'
|
'+refs/heads/my/branch:refs/remotes/origin/my/branch'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('checkCommitInfo', () => {
|
||||||
|
const repositoryOwner = 'some-owner'
|
||||||
|
const repositoryName = 'some-repo'
|
||||||
|
const ref = 'refs/pull/123/merge'
|
||||||
|
const sha1Head = '1111111111222222222233333333334444444444'
|
||||||
|
const sha1Base = 'aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd'
|
||||||
|
const sha256Head =
|
||||||
|
'1111111111222222222233333333334444444444555555555566666666667777'
|
||||||
|
const sha256Base =
|
||||||
|
'aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffff0000'
|
||||||
|
let debugSpy: jest.SpyInstance
|
||||||
|
let getOctokitSpy: jest.SpyInstance
|
||||||
|
let repoGetSpy: jest.Mock
|
||||||
|
let originalEventName: string
|
||||||
|
let originalPayload: unknown
|
||||||
|
let originalRef: string
|
||||||
|
let originalSha: string
|
||||||
|
|
||||||
|
function setPullRequestContext(
|
||||||
|
expectedHeadSha: string,
|
||||||
|
expectedBaseSha: string,
|
||||||
|
mergeCommit: string
|
||||||
|
): void {
|
||||||
|
;(github.context as any).eventName = 'pull_request'
|
||||||
|
github.context.ref = ref
|
||||||
|
github.context.sha = mergeCommit
|
||||||
|
;(github.context as any).payload = {
|
||||||
|
action: 'synchronize',
|
||||||
|
after: expectedHeadSha,
|
||||||
|
number: 123,
|
||||||
|
pull_request: {
|
||||||
|
base: {
|
||||||
|
sha: expectedBaseSha
|
||||||
|
}
|
||||||
|
},
|
||||||
|
repository: {
|
||||||
|
private: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
originalEventName = github.context.eventName
|
||||||
|
originalPayload = github.context.payload
|
||||||
|
originalRef = github.context.ref
|
||||||
|
originalSha = github.context.sha
|
||||||
|
|
||||||
|
jest.spyOn(github.context, 'repo', 'get').mockReturnValue({
|
||||||
|
owner: repositoryOwner,
|
||||||
|
repo: repositoryName
|
||||||
|
})
|
||||||
|
debugSpy = jest.spyOn(core, 'debug').mockImplementation(jest.fn())
|
||||||
|
repoGetSpy = jest.fn(async () => ({}))
|
||||||
|
getOctokitSpy = jest.spyOn(github, 'getOctokit').mockReturnValue({
|
||||||
|
rest: {
|
||||||
|
repos: {
|
||||||
|
get: repoGetSpy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
;(github.context as any).eventName = originalEventName
|
||||||
|
;(github.context as any).payload = originalPayload
|
||||||
|
github.context.ref = originalRef
|
||||||
|
github.context.sha = originalSha
|
||||||
|
jest.restoreAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns early for SHA-1 merge commit', async () => {
|
||||||
|
setPullRequestContext(sha1Head, sha1Base, commit)
|
||||||
|
|
||||||
|
await refHelper.checkCommitInfo(
|
||||||
|
'token',
|
||||||
|
`Merge ${sha1Head} into ${sha1Base}`,
|
||||||
|
repositoryOwner,
|
||||||
|
repositoryName,
|
||||||
|
ref,
|
||||||
|
commit
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(getOctokitSpy).not.toHaveBeenCalled()
|
||||||
|
expect(repoGetSpy).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('matches SHA-256 merge commit info', async () => {
|
||||||
|
const actualHeadSha =
|
||||||
|
'9999999999888888888877777777776666666666555555555544444444443333'
|
||||||
|
setPullRequestContext(sha256Head, sha256Base, sha256Commit)
|
||||||
|
|
||||||
|
await refHelper.checkCommitInfo(
|
||||||
|
'token',
|
||||||
|
`Merge ${actualHeadSha} into ${sha256Base}`,
|
||||||
|
repositoryOwner,
|
||||||
|
repositoryName,
|
||||||
|
ref,
|
||||||
|
sha256Commit
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(getOctokitSpy).toHaveBeenCalledWith(
|
||||||
|
'token',
|
||||||
|
expect.objectContaining({
|
||||||
|
userAgent: expect.stringContaining(
|
||||||
|
`expected_head_sha=${sha256Head};actual_head_sha=${actualHeadSha}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
expect(repoGetSpy).toHaveBeenCalledWith({
|
||||||
|
owner: repositoryOwner,
|
||||||
|
repo: repositoryName
|
||||||
|
})
|
||||||
|
expect(debugSpy).toHaveBeenCalledWith(
|
||||||
|
`Expected head sha ${sha256Head}; actual head sha ${actualHeadSha}`
|
||||||
|
)
|
||||||
|
expect(debugSpy).not.toHaveBeenCalledWith('Unexpected message format')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not match 50-char hex as a valid merge', async () => {
|
||||||
|
const invalidHeadSha =
|
||||||
|
'99999999998888888888777777777766666666665555555555'
|
||||||
|
setPullRequestContext(sha1Head, sha1Base, commit)
|
||||||
|
|
||||||
|
await refHelper.checkCommitInfo(
|
||||||
|
'token',
|
||||||
|
`Merge ${invalidHeadSha} into ${sha1Base}`,
|
||||||
|
repositoryOwner,
|
||||||
|
repositoryName,
|
||||||
|
ref,
|
||||||
|
commit
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(getOctokitSpy).not.toHaveBeenCalled()
|
||||||
|
expect(repoGetSpy).not.toHaveBeenCalled()
|
||||||
|
expect(debugSpy).toHaveBeenCalledWith('Unexpected message format')
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -9,6 +9,9 @@ inputs:
|
|||||||
The branch, tag or SHA to checkout. When checking out the repository that
|
The branch, tag or SHA to checkout. When checking out the repository that
|
||||||
triggered a workflow, this defaults to the reference or SHA for that
|
triggered a workflow, this defaults to the reference or SHA for that
|
||||||
event. Otherwise, uses the default branch.
|
event. Otherwise, uses the default branch.
|
||||||
|
default-branch-checkout:
|
||||||
|
description: 'Indicates whether to checkout the default repository branch if the requested ref does not exist'
|
||||||
|
default: false
|
||||||
token:
|
token:
|
||||||
description: >
|
description: >
|
||||||
Personal access token (PAT) used to fetch the repository. The PAT is configured
|
Personal access token (PAT) used to fetch the repository. The PAT is configured
|
||||||
|
|||||||
28
dist/index.js
vendored
28
dist/index.js
vendored
@ -1529,7 +1529,7 @@ function getSource(settings) {
|
|||||||
else if (settings.sparseCheckout) {
|
else if (settings.sparseCheckout) {
|
||||||
fetchOptions.filter = 'blob:none';
|
fetchOptions.filter = 'blob:none';
|
||||||
}
|
}
|
||||||
if (settings.fetchDepth <= 0) {
|
if (settings.fetchDepth <= 0 || settings.defaultBranchCheckout) {
|
||||||
// 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);
|
||||||
yield git.fetch(refSpec, fetchOptions);
|
yield git.fetch(refSpec, fetchOptions);
|
||||||
@ -1562,7 +1562,22 @@ function getSource(settings) {
|
|||||||
core.endGroup();
|
core.endGroup();
|
||||||
// Checkout info
|
// Checkout info
|
||||||
core.startGroup('Determining the checkout info');
|
core.startGroup('Determining the checkout info');
|
||||||
const checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit);
|
let checkoutInfo;
|
||||||
|
try {
|
||||||
|
checkoutInfo = yield refHelper.getCheckoutInfo(git, settings.ref, settings.commit);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
if (settings.defaultBranchCheckout) {
|
||||||
|
core.info('Could not determine the checkout info. Trying the default repository branch');
|
||||||
|
const repositoryDefaultBranch = settings.sshKey
|
||||||
|
? yield git.getDefaultBranch(repositoryUrl)
|
||||||
|
: yield githubApiHelper.getDefaultBranch(settings.authToken, settings.repositoryOwner, settings.repositoryName);
|
||||||
|
checkoutInfo = yield refHelper.getCheckoutInfo(git, repositoryDefaultBranch, settings.commit);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
// LFS fetch
|
// LFS fetch
|
||||||
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
|
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
|
||||||
@ -2021,12 +2036,17 @@ function getInputs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SHA?
|
// SHA?
|
||||||
else if (result.ref.match(/^[0-9a-fA-F]{40}$/)) {
|
else if (result.ref.match(/^(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{64})$/)) {
|
||||||
result.commit = result.ref;
|
result.commit = result.ref;
|
||||||
result.ref = '';
|
result.ref = '';
|
||||||
}
|
}
|
||||||
core.debug(`ref = '${result.ref}'`);
|
core.debug(`ref = '${result.ref}'`);
|
||||||
core.debug(`commit = '${result.commit}'`);
|
core.debug(`commit = '${result.commit}'`);
|
||||||
|
// Default branch checkout
|
||||||
|
result.defaultBranchCheckout =
|
||||||
|
(core.getInput('default-branch-checkout') || 'false').toUpperCase() ===
|
||||||
|
'TRUE';
|
||||||
|
core.debug(`default-branch-checkout = '${result.defaultBranchCheckout}'`);
|
||||||
// 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}`);
|
||||||
@ -2444,7 +2464,7 @@ function checkCommitInfo(token, commitInfo, repositoryOwner, repositoryName, ref
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Extract details from message
|
// Extract details from message
|
||||||
const match = commitInfo.match(/Merge ([0-9a-f]{40}) into ([0-9a-f]{40})/);
|
const match = commitInfo.match(/Merge ([0-9a-f]{40}|[0-9a-f]{64}) into ([0-9a-f]{40}|[0-9a-f]{64})/);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
core.debug('Unexpected message format');
|
core.debug('Unexpected message format');
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -168,7 +168,7 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
|
|||||||
fetchOptions.filter = 'blob:none'
|
fetchOptions.filter = 'blob:none'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.fetchDepth <= 0) {
|
if (settings.fetchDepth <= 0 || settings.defaultBranchCheckout) {
|
||||||
// Fetch all branches and tags
|
// Fetch all branches and tags
|
||||||
let refSpec = refHelper.getRefSpecForAllHistory(
|
let refSpec = refHelper.getRefSpecForAllHistory(
|
||||||
settings.ref,
|
settings.ref,
|
||||||
@ -215,11 +215,34 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
|
|||||||
|
|
||||||
// Checkout info
|
// Checkout info
|
||||||
core.startGroup('Determining the checkout info')
|
core.startGroup('Determining the checkout info')
|
||||||
const checkoutInfo = await refHelper.getCheckoutInfo(
|
let checkoutInfo: refHelper.ICheckoutInfo
|
||||||
|
try {
|
||||||
|
checkoutInfo = await refHelper.getCheckoutInfo(
|
||||||
git,
|
git,
|
||||||
settings.ref,
|
settings.ref,
|
||||||
settings.commit
|
settings.commit
|
||||||
)
|
)
|
||||||
|
} catch (error) {
|
||||||
|
if (settings.defaultBranchCheckout) {
|
||||||
|
core.info(
|
||||||
|
'Could not determine the checkout info. Trying the default repository branch'
|
||||||
|
)
|
||||||
|
const repositoryDefaultBranch = settings.sshKey
|
||||||
|
? await git.getDefaultBranch(repositoryUrl)
|
||||||
|
: await githubApiHelper.getDefaultBranch(
|
||||||
|
settings.authToken,
|
||||||
|
settings.repositoryOwner,
|
||||||
|
settings.repositoryName
|
||||||
|
)
|
||||||
|
checkoutInfo = await refHelper.getCheckoutInfo(
|
||||||
|
git,
|
||||||
|
repositoryDefaultBranch,
|
||||||
|
settings.commit
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
|
|
||||||
// LFS fetch
|
// LFS fetch
|
||||||
|
|||||||
@ -19,6 +19,11 @@ export interface IGitSourceSettings {
|
|||||||
*/
|
*/
|
||||||
ref: string
|
ref: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether to checkout the default repository branch if the requested ref does not exist
|
||||||
|
*/
|
||||||
|
defaultBranchCheckout: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The commit to checkout
|
* The commit to checkout
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -71,13 +71,19 @@ export async function getInputs(): Promise<IGitSourceSettings> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SHA?
|
// SHA?
|
||||||
else if (result.ref.match(/^[0-9a-fA-F]{40}$/)) {
|
else if (result.ref.match(/^(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{64})$/)) {
|
||||||
result.commit = result.ref
|
result.commit = result.ref
|
||||||
result.ref = ''
|
result.ref = ''
|
||||||
}
|
}
|
||||||
core.debug(`ref = '${result.ref}'`)
|
core.debug(`ref = '${result.ref}'`)
|
||||||
core.debug(`commit = '${result.commit}'`)
|
core.debug(`commit = '${result.commit}'`)
|
||||||
|
|
||||||
|
// Default branch checkout
|
||||||
|
result.defaultBranchCheckout =
|
||||||
|
(core.getInput('default-branch-checkout') || 'false').toUpperCase() ===
|
||||||
|
'TRUE'
|
||||||
|
core.debug(`default-branch-checkout = '${result.defaultBranchCheckout}'`)
|
||||||
|
|
||||||
// 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}`)
|
||||||
|
|||||||
@ -258,7 +258,9 @@ export async function checkCommitInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract details from message
|
// Extract details from message
|
||||||
const match = commitInfo.match(/Merge ([0-9a-f]{40}) into ([0-9a-f]{40})/)
|
const match = commitInfo.match(
|
||||||
|
/Merge ([0-9a-f]{40}|[0-9a-f]{64}) into ([0-9a-f]{40}|[0-9a-f]{64})/
|
||||||
|
)
|
||||||
if (!match) {
|
if (!match) {
|
||||||
core.debug('Unexpected message format')
|
core.debug('Unexpected message format')
|
||||||
return
|
return
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user