Fix checkout init for SHA-256 repositories

This commit is contained in:
Yashwanth Anantharaju
2026-05-21 14:31:18 -04:00
parent 900f2210b1
commit 67bd696108
8 changed files with 634 additions and 7 deletions

View File

@@ -15,6 +15,11 @@ import {GitVersion} from './git-version'
export const MinimumGitVersion = new GitVersion('2.18')
export const MinimumGitSparseCheckoutVersion = new GitVersion('2.28')
export interface GitObjectFormatResult {
format: string
succeeded: boolean
}
export interface IGitCommandManager {
branchDelete(remote: boolean, branch: string): Promise<void>
branchExists(remote: boolean, pattern: string): Promise<boolean>
@@ -43,7 +48,7 @@ export interface IGitCommandManager {
getDefaultBranch(repositoryUrl: string): Promise<string>
getSubmoduleConfigPaths(recursive: boolean): Promise<string[]>
getWorkingDirectory(): string
init(): Promise<void>
init(objectFormat?: string): Promise<void>
isDetached(): Promise<boolean>
lfsFetch(ref: string): Promise<void>
lfsInstall(): Promise<void>
@@ -68,6 +73,7 @@ export interface IGitCommandManager {
): Promise<boolean>
tryDisableAutomaticGarbageCollection(): Promise<boolean>
tryGetFetchUrl(): Promise<string>
tryGetObjectFormat(repositoryUrl: string): Promise<GitObjectFormatResult>
tryGetConfigValues(
configKey: string,
globalConfig?: boolean,
@@ -364,8 +370,14 @@ class GitCommandManager {
return this.workingDirectory
}
async init(): Promise<void> {
await this.execGit(['init', this.workingDirectory])
async init(objectFormat?: string): Promise<void> {
const args = ['init']
if (objectFormat === 'sha256') {
args.push('--object-format=sha256')
}
args.push(this.workingDirectory)
await this.execGit(args)
}
async isDetached(): Promise<boolean> {
@@ -536,6 +548,55 @@ class GitCommandManager {
return stdout
}
async tryGetObjectFormat(
repositoryUrl: string
): Promise<GitObjectFormatResult> {
try {
const output = await this.execGit(
[
'-c',
'protocol.version=2',
'ls-remote',
'--quiet',
'--exit-code',
'--symref',
repositoryUrl,
'HEAD'
],
true,
true
)
if (output.exitCode !== 0) {
core.debug(
`Unable to determine repository object format: git ls-remote exited with ${output.exitCode}`
)
return {format: '', succeeded: false}
}
for (const line of output.stdout.trim().split('\n')) {
const [oid, ref] = line.split('\t')
if (ref !== 'HEAD') {
continue
}
if (/^[0-9a-fA-F]{64}$/.test(oid)) {
return {format: 'sha256', succeeded: true}
}
if (/^[0-9a-fA-F]{40}$/.test(oid)) {
return {format: 'sha1', succeeded: true}
}
}
core.debug('Unable to determine repository object format from HEAD')
return {format: '', succeeded: false}
} catch (err) {
core.debug(
`Unable to determine repository object format: ${(err as any)?.message ?? err}`
)
return {format: '', succeeded: false}
}
}
async tryGetConfigValues(
configKey: string,
globalConfig?: boolean,

View File

@@ -105,12 +105,36 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Save state for POST action
stateHelper.setRepositoryPath(settings.repositoryPath)
let defaultBranch = ''
// Initialize the repository
if (
!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))
) {
core.startGroup('Determining repository object format')
let objectFormatResult =
await githubApiHelper.tryGetRepositoryObjectFormat(
settings.authToken,
settings.repositoryOwner,
settings.repositoryName,
settings.githubServerUrl,
settings.ref,
settings.commit
)
if (!objectFormatResult.succeeded) {
objectFormatResult = await git.tryGetObjectFormat(repositoryUrl)
}
const objectFormat = objectFormatResult.succeeded
? objectFormatResult.format
: ''
defaultBranch = objectFormatResult.defaultBranch || ''
if (objectFormat === 'sha256') {
core.info('Detected SHA-256 repository object format')
}
core.endGroup()
core.startGroup('Initializing the repository')
await git.init()
await git.init(objectFormat)
await git.remoteAdd('origin', repositoryUrl)
core.endGroup()
}
@@ -138,6 +162,9 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
core.startGroup('Determining the default branch')
if (settings.sshKey) {
settings.ref = await git.getDefaultBranch(repositoryUrl)
} else if (defaultBranch) {
core.info(`Default branch '${defaultBranch}'`)
settings.ref = `refs/heads/${defaultBranch}`
} else {
settings.ref = await githubApiHelper.getDefaultBranch(
settings.authToken,

View File

@@ -11,6 +11,12 @@ import {getServerApiUrl} from './url-helper'
const IS_WINDOWS = process.platform === 'win32'
export interface RepositoryObjectFormatResult {
defaultBranch?: string
format: string
succeeded: boolean
}
export async function downloadRepository(
authToken: string,
owner: string,
@@ -122,6 +128,84 @@ export async function getDefaultBranch(
})
}
export async function tryGetRepositoryObjectFormat(
authToken: string,
owner: string,
repo: string,
baseUrl?: string,
ref?: string,
commit?: string
): Promise<RepositoryObjectFormatResult> {
try {
const commitFormat = getObjectFormat(commit)
if (commitFormat) {
return {format: commitFormat, succeeded: true}
}
const octokit = github.getOctokit(authToken, {
baseUrl: getServerApiUrl(baseUrl)
})
let branchName = getBranchName(ref)
let defaultBranch = ''
if (!branchName) {
const repository = await octokit.rest.repos.get({owner, repo})
defaultBranch = repository.data.default_branch
assert.ok(defaultBranch, 'default_branch cannot be empty')
branchName = defaultBranch
}
const branch = await octokit.rest.repos.getBranch({
owner,
repo,
branch: branchName
})
const branchFormat = getObjectFormat(branch.data.commit.sha)
if (branchFormat) {
return {
defaultBranch: defaultBranch || undefined,
format: branchFormat,
succeeded: true
}
}
core.debug('Unable to determine repository object format from commit SHA')
return {format: '', succeeded: false}
} catch (err) {
core.debug(
`Unable to determine repository object format: ${(err as any)?.message ?? err}`
)
return {format: '', succeeded: false}
}
}
function getBranchName(ref?: string): string {
if (!ref) {
return ''
}
const headsPrefix = 'refs/heads/'
if (ref.startsWith(headsPrefix)) {
return ref.substring(headsPrefix.length)
}
if (!ref.startsWith('refs/') && !getObjectFormat(ref)) {
return ref
}
return ''
}
function getObjectFormat(sha?: string): string {
if (/^[0-9a-fA-F]{64}$/.test(sha || '')) {
return 'sha256'
}
if (/^[0-9a-fA-F]{40}$/.test(sha || '')) {
return 'sha1'
}
return ''
}
async function downloadArchive(
authToken: string,
owner: string,