1
0
mirror of https://github.com/actions/checkout.git synced 2026-03-04 08:41:01 +08:00

Compare commits

...

9 Commits

Author SHA1 Message Date
Parker Michel
c27a716a6d
Merge 2449f8bb0b into 064fe7f331 2026-01-08 22:03:04 +01:00
Copilot
064fe7f331
Add orchestration_id to git user-agent when ACTIONS_ORCHESTRATION_ID is set (#2355)
* Initial plan

* Add orchestration ID support to git user-agent

Co-authored-by: TingluoHuang <1750815+TingluoHuang@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Improve tests to verify user-agent content and handle empty sanitized IDs

Co-authored-by: TingluoHuang <1750815+TingluoHuang@users.noreply.github.com>

* Simplify orchestration ID validation to accept any non-empty sanitized value

Co-authored-by: TingluoHuang <1750815+TingluoHuang@users.noreply.github.com>

* Remove test for orchestration ID with only invalid characters

Co-authored-by: TingluoHuang <1750815+TingluoHuang@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: TingluoHuang <1750815+TingluoHuang@users.noreply.github.com>
Co-authored-by: Tingluo Huang <tingluohuang@github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-08 15:07:38 -05:00
parker-michel-vanta
2449f8bb0b format 2025-07-16 10:37:01 -04:00
parker-michel-vanta
220570c515 build dist 2025-07-16 10:33:58 -04:00
parker-michel-vanta
819730283a updates 2025-07-16 10:33:10 -04:00
parker-michel-vanta
50ecf51910 Merge remote-tracking branch 'origin/main' into add-shallow-since-2025 2025-07-15 17:48:23 -04:00
satotake
72a87eaf9f build dist 2021-10-21 00:38:35 +09:00
satotake
9dceaac6c6 fix branch conditions 2021-10-21 00:18:19 +09:00
satotake
b0b939aaa5 add shallow-since option 2021-10-20 23:56:37 +09:00
9 changed files with 198 additions and 7 deletions

View File

@ -129,6 +129,9 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
# Default: 1
fetch-depth: ''
# Date like `2days` or `1970-01-01`. Fetch a history after the specified time.
shallow-since: ''
# Whether to fetch tags, even if fetch-depth > 0.
# Default: false
fetch-tags: ''

View File

@ -1157,6 +1157,7 @@ async function setup(testName: string): Promise<void> {
sparseCheckout: [],
sparseCheckoutConeMode: true,
fetchDepth: 1,
shallowSince: '',
fetchTags: false,
showProgress: true,
lfs: false,

View File

@ -376,3 +376,120 @@ describe('Test fetchDepth and fetchTags options', () => {
)
})
})
describe('git user-agent with orchestration ID', () => {
beforeEach(async () => {
jest.spyOn(fshelper, 'fileExistsSync').mockImplementation(jest.fn())
jest.spyOn(fshelper, 'directoryExistsSync').mockImplementation(jest.fn())
})
afterEach(() => {
jest.restoreAllMocks()
// Clean up environment variable to prevent test pollution
delete process.env['ACTIONS_ORCHESTRATION_ID']
})
it('should include orchestration ID in user-agent when ACTIONS_ORCHESTRATION_ID is set', async () => {
const orchId = 'test-orch-id-12345'
process.env['ACTIONS_ORCHESTRATION_ID'] = orchId
let capturedEnv: any = null
mockExec.mockImplementation((path, args, options) => {
if (args.includes('version')) {
options.listeners.stdout(Buffer.from('2.18'))
}
// Capture env on any command
capturedEnv = options.env
return 0
})
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
// Call a git command to trigger env capture after user-agent is set
await git.init()
// Verify the user agent includes the orchestration ID
expect(git).toBeDefined()
expect(capturedEnv).toBeDefined()
expect(capturedEnv['GIT_HTTP_USER_AGENT']).toBe(
`git/2.18 (github-actions-checkout) actions_orchestration_id/${orchId}`
)
})
it('should sanitize invalid characters in orchestration ID', async () => {
const orchId = 'test (with) special/chars'
process.env['ACTIONS_ORCHESTRATION_ID'] = orchId
let capturedEnv: any = null
mockExec.mockImplementation((path, args, options) => {
if (args.includes('version')) {
options.listeners.stdout(Buffer.from('2.18'))
}
// Capture env on any command
capturedEnv = options.env
return 0
})
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
// Call a git command to trigger env capture after user-agent is set
await git.init()
// Verify the user agent has sanitized orchestration ID (spaces, parentheses, slash replaced)
expect(git).toBeDefined()
expect(capturedEnv).toBeDefined()
expect(capturedEnv['GIT_HTTP_USER_AGENT']).toBe(
'git/2.18 (github-actions-checkout) actions_orchestration_id/test__with__special_chars'
)
})
it('should not modify user-agent when ACTIONS_ORCHESTRATION_ID is not set', async () => {
delete process.env['ACTIONS_ORCHESTRATION_ID']
let capturedEnv: any = null
mockExec.mockImplementation((path, args, options) => {
if (args.includes('version')) {
options.listeners.stdout(Buffer.from('2.18'))
}
// Capture env on any command
capturedEnv = options.env
return 0
})
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
// Call a git command to trigger env capture after user-agent is set
await git.init()
// Verify the user agent does NOT contain orchestration ID
expect(git).toBeDefined()
expect(capturedEnv).toBeDefined()
expect(capturedEnv['GIT_HTTP_USER_AGENT']).toBe(
'git/2.18 (github-actions-checkout)'
)
})
})

View File

@ -74,6 +74,8 @@ inputs:
fetch-depth:
description: 'Number of commits to fetch. 0 indicates all history for all branches and tags.'
default: 1
shallow-since:
description: 'Date like `2days` or `1970-01-01`. Fetch a history after the specified time.'
fetch-tags:
description: 'Whether to fetch tags, even if fetch-depth > 0.'
default: false

View File

@ -72,6 +72,8 @@ We want to take this opportunity to make behavioral changes, from v1. This docum
fetch-depth:
description: 'Number of commits to fetch. 0 indicates all history for all tags and branches.'
default: 1
shallow-since:
description: 'Date like `2days` or `1970-01-01`. Fetch a history after the specified time.'
lfs:
description: 'Whether to download Git-LFS files'
default: false
@ -155,7 +157,7 @@ Fetch only the SHA being built and set depth=1. This significantly reduces the f
If a SHA isn't available (e.g. multi repo), then fetch only the specified ref with depth=1.
The input `fetch-depth` can be used to control the depth.
The input `fetch-depth` and `shallow-since` can be used to control the depth.
Note:
- Fetching a single commit is supported by Git wire protocol version 2. The git client uses protocol version 0 by default. The desired protocol version can be overridden in the git config or on the fetch command line invocation (`-c protocol.version=2`). We will override on the fetch command line, for transparency.

26
dist/index.js vendored
View File

@ -841,6 +841,9 @@ class GitCommandManager {
if (options.filter) {
args.push(`--filter=${options.filter}`);
}
if (options.shallowSince) {
args.push(`--shallow-since=${options.shallowSince}`);
}
if (options.fetchDepth && options.fetchDepth > 0) {
args.push(`--depth=${options.fetchDepth}`);
}
@ -981,13 +984,16 @@ class GitCommandManager {
yield this.execGit(args);
});
}
submoduleUpdate(fetchDepth, recursive) {
submoduleUpdate(fetchDepth, recursive, shallowSince) {
return __awaiter(this, void 0, void 0, function* () {
const args = ['-c', 'protocol.version=2'];
args.push('submodule', 'update', '--init', '--force');
if (fetchDepth > 0) {
args.push(`--depth=${fetchDepth}`);
}
if (shallowSince) {
args.push(`--shallow-since=${shallowSince}`);
}
if (recursive) {
args.push('--recursive');
}
@ -1206,7 +1212,17 @@ class GitCommandManager {
}
}
// Set the user agent
const gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)`;
let gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)`;
// Append orchestration ID if set
const orchId = process.env['ACTIONS_ORCHESTRATION_ID'];
if (orchId) {
// Sanitize the orchestration ID to ensure it contains only valid characters
// Valid characters: 0-9, a-z, _, -, .
const sanitizedId = orchId.replace(/[^a-z0-9_.-]/gi, '_');
if (sanitizedId) {
gitHttpUserAgent = `${gitHttpUserAgent} actions_orchestration_id/${sanitizedId}`;
}
}
core.debug(`Set git useragent to: ${gitHttpUserAgent}`);
this.gitEnv['GIT_HTTP_USER_AGENT'] = gitHttpUserAgent;
});
@ -2029,6 +2045,12 @@ function getInputs() {
result.fetchDepth = 0;
}
core.debug(`fetch depth = ${result.fetchDepth}`);
// Shallow since
if (core.getInput('fetch-depth') && core.getInput('shallow-since')) {
throw new Error('`fetch-depth` and `shallow-since` cannot be used at the same time');
}
result.shallowSince = core.getInput('shallow-since');
core.debug(`shallow since = ${result.shallowSince}`);
// Fetch tags
result.fetchTags =
(core.getInput('fetch-tags') || 'false').toUpperCase() === 'TRUE';

View File

@ -37,6 +37,7 @@ export interface IGitCommandManager {
options: {
filter?: string
fetchDepth?: number
shallowSince?: string
fetchTags?: boolean
showProgress?: boolean
}
@ -56,8 +57,12 @@ export interface IGitCommandManager {
shaExists(sha: string): Promise<boolean>
submoduleForeach(command: string, recursive: boolean): Promise<string>
submoduleSync(recursive: boolean): Promise<void>
submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void>
submoduleStatus(): Promise<boolean>
submoduleUpdate(
fetchDepth: number,
recursive: boolean,
shallowSince?: string
): Promise<void>
tagExists(pattern: string): Promise<boolean>
tryClean(): Promise<boolean>
tryConfigUnset(configKey: string, globalConfig?: boolean): Promise<boolean>
@ -280,6 +285,7 @@ class GitCommandManager {
options: {
filter?: string
fetchDepth?: number
shallowSince?: string
fetchTags?: boolean
showProgress?: boolean
}
@ -298,6 +304,10 @@ class GitCommandManager {
args.push(`--filter=${options.filter}`)
}
if (options.shallowSince) {
args.push(`--shallow-since=${options.shallowSince}`)
}
if (options.fetchDepth && options.fetchDepth > 0) {
args.push(`--depth=${options.fetchDepth}`)
} else if (
@ -448,13 +458,21 @@ class GitCommandManager {
await this.execGit(args)
}
async submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void> {
async submoduleUpdate(
fetchDepth: number,
recursive: boolean,
shallowSince?: string
): Promise<void> {
const args = ['-c', 'protocol.version=2']
args.push('submodule', 'update', '--init', '--force')
if (fetchDepth > 0) {
args.push(`--depth=${fetchDepth}`)
}
if (shallowSince) {
args.push(`--shallow-since=${shallowSince}`)
}
if (recursive) {
args.push('--recursive')
}
@ -730,7 +748,19 @@ class GitCommandManager {
}
}
// Set the user agent
const gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)`
let gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)`
// Append orchestration ID if set
const orchId = process.env['ACTIONS_ORCHESTRATION_ID']
if (orchId) {
// Sanitize the orchestration ID to ensure it contains only valid characters
// Valid characters: 0-9, a-z, _, -, .
const sanitizedId = orchId.replace(/[^a-z0-9_.-]/gi, '_')
if (sanitizedId) {
gitHttpUserAgent = `${gitHttpUserAgent} actions_orchestration_id/${sanitizedId}`
}
}
core.debug(`Set git useragent to: ${gitHttpUserAgent}`)
this.gitEnv['GIT_HTTP_USER_AGENT'] = gitHttpUserAgent
}

View File

@ -50,7 +50,12 @@ export interface IGitSourceSettings {
fetchDepth: number
/**
* Fetch tags, even if fetchDepth > 0 (default: false)
* Deepen or shorten the history of a shallow repository to include all reachable commits after
*/
shallowSince: string
/**
* Fetch tags, even if fetchDepth > 0 (default: false)
*/
fetchTags: boolean

View File

@ -108,6 +108,15 @@ export async function getInputs(): Promise<IGitSourceSettings> {
}
core.debug(`fetch depth = ${result.fetchDepth}`)
// Shallow since
if (core.getInput('fetch-depth') && core.getInput('shallow-since')) {
throw new Error(
'`fetch-depth` and `shallow-since` cannot be used at the same time'
)
}
result.shallowSince = core.getInput('shallow-since')
core.debug(`shallow since = ${result.shallowSince}`)
// Fetch tags
result.fetchTags =
(core.getInput('fetch-tags') || 'false').toUpperCase() === 'TRUE'