mirror of
https://github.com/actions/checkout.git
synced 2026-05-22 11:07:34 +03:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 67bd696108 |
@@ -974,46 +974,6 @@ describe('git-auth-helper tests', () => {
|
|||||||
).toBe(false)
|
).toBe(false)
|
||||||
expect((authHelper as any).testCredentialsConfigPath('')).toBe(false)
|
expect((authHelper as any).testCredentialsConfigPath('')).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
const includeIfCleanupRegex_matchesBothVariants =
|
|
||||||
'includeIf cleanup regex matches both gitdir: and gitdir/i: keys'
|
|
||||||
it(includeIfCleanupRegex_matchesBothVariants, async () => {
|
|
||||||
// The cleanup regex must match both variants so credential
|
|
||||||
// removal works regardless of which was written
|
|
||||||
const regex = /^includeIf\.gitdir(\/i)?:/
|
|
||||||
expect(regex.test('includeIf.gitdir:D:/workspaces/repo/.git.path')).toBe(
|
|
||||||
true
|
|
||||||
)
|
|
||||||
expect(regex.test('includeIf.gitdir/i:D:/Workspaces/repo/.git.path')).toBe(
|
|
||||||
true
|
|
||||||
)
|
|
||||||
expect(regex.test('includeIf.gitdir/i:/github/workspace/.git.path')).toBe(
|
|
||||||
true
|
|
||||||
)
|
|
||||||
expect(regex.test('includeIf.gitdir:~/projects/foo/.git.path')).toBe(true)
|
|
||||||
expect(regex.test('includeIf.onbranch:main.path')).toBe(false)
|
|
||||||
expect(regex.test('include.path')).toBe(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
const includeIfDirective_usesCorrectVariantForPlatform =
|
|
||||||
'includeIf directive uses gitdir/i on Windows and gitdir on other platforms'
|
|
||||||
it(includeIfDirective_usesCorrectVariantForPlatform, async () => {
|
|
||||||
await setup(includeIfDirective_usesCorrectVariantForPlatform)
|
|
||||||
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
|
|
||||||
await authHelper.configureAuth()
|
|
||||||
|
|
||||||
const localConfigContent = (
|
|
||||||
await fs.promises.readFile(localGitConfigPath)
|
|
||||||
).toString()
|
|
||||||
|
|
||||||
if (isWindows) {
|
|
||||||
expect(localConfigContent).toContain('includeIf.gitdir/i:')
|
|
||||||
expect(localConfigContent).not.toContain('includeIf.gitdir:')
|
|
||||||
} else {
|
|
||||||
expect(localConfigContent).toContain('includeIf.gitdir:')
|
|
||||||
expect(localConfigContent).not.toContain('includeIf.gitdir/i:')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
async function setup(testName: string): Promise<void> {
|
async function setup(testName: string): Promise<void> {
|
||||||
@@ -1143,6 +1103,7 @@ async function setup(testName: string): Promise<void> {
|
|||||||
),
|
),
|
||||||
tryDisableAutomaticGarbageCollection: jest.fn(),
|
tryDisableAutomaticGarbageCollection: jest.fn(),
|
||||||
tryGetFetchUrl: jest.fn(),
|
tryGetFetchUrl: jest.fn(),
|
||||||
|
tryGetObjectFormat: jest.fn(async () => ({format: '', succeeded: true})),
|
||||||
tryGetConfigValues: jest.fn(
|
tryGetConfigValues: jest.fn(
|
||||||
async (
|
async (
|
||||||
key: string,
|
key: string,
|
||||||
|
|||||||
@@ -378,6 +378,169 @@ describe('Test fetchDepth and fetchTags options', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('repository object format', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
jest.spyOn(fshelper, 'fileExistsSync').mockImplementation(jest.fn())
|
||||||
|
jest.spyOn(fshelper, 'directoryExistsSync').mockImplementation(jest.fn())
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.restoreAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('detects SHA-256 from a 64-character HEAD oid', async () => {
|
||||||
|
mockExec.mockImplementation((path, args, options) => {
|
||||||
|
if (args.includes('version')) {
|
||||||
|
options.listeners.stdout(Buffer.from('git version 2.50.1'))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.includes('ls-remote')) {
|
||||||
|
options.listeners.stdout(
|
||||||
|
Buffer.from(
|
||||||
|
'ref: refs/heads/main\tHEAD\n' +
|
||||||
|
'9422233ca7ee1b17f1e905d0e141faf0c401556c41cdc6acd71c6bd685da2e92\tHEAD\n'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
|
||||||
|
|
||||||
|
git = await commandManager.createCommandManager('test', false, false)
|
||||||
|
|
||||||
|
const objectFormat = await git.tryGetObjectFormat(
|
||||||
|
'https://github.com/example/repo'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(objectFormat).toEqual({format: 'sha256', succeeded: true})
|
||||||
|
expect(mockExec).toHaveBeenCalledWith(
|
||||||
|
expect.any(String),
|
||||||
|
[
|
||||||
|
'-c',
|
||||||
|
'protocol.version=2',
|
||||||
|
'ls-remote',
|
||||||
|
'--quiet',
|
||||||
|
'--exit-code',
|
||||||
|
'--symref',
|
||||||
|
'https://github.com/example/repo',
|
||||||
|
'HEAD'
|
||||||
|
],
|
||||||
|
expect.objectContaining({
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('detects SHA-1 from a 40-character HEAD oid', async () => {
|
||||||
|
mockExec.mockImplementation((path, args, options) => {
|
||||||
|
if (args.includes('version')) {
|
||||||
|
options.listeners.stdout(Buffer.from('git version 2.50.1'))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.includes('ls-remote')) {
|
||||||
|
options.listeners.stdout(
|
||||||
|
Buffer.from(
|
||||||
|
'ref: refs/heads/main\tHEAD\n' +
|
||||||
|
'c988866043f035e6a46509872215f91d879044c9\tHEAD\n'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
|
||||||
|
|
||||||
|
git = await commandManager.createCommandManager('test', false, false)
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
git.tryGetObjectFormat('https://github.com/example/repo')
|
||||||
|
).resolves.toEqual({format: 'sha1', succeeded: true})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns unsuccessful when HEAD does not resolve to a recognized object id', async () => {
|
||||||
|
mockExec.mockImplementation((path, args, options) => {
|
||||||
|
if (args.includes('version')) {
|
||||||
|
options.listeners.stdout(Buffer.from('git version 2.50.1'))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.includes('ls-remote')) {
|
||||||
|
options.listeners.stdout(Buffer.from('ref: refs/heads/main\tHEAD\n'))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
|
||||||
|
|
||||||
|
git = await commandManager.createCommandManager('test', false, false)
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
git.tryGetObjectFormat('https://github.com/example/repo')
|
||||||
|
).resolves.toEqual({format: '', succeeded: false})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns unsuccessful when object format detection cannot reach the remote', async () => {
|
||||||
|
mockExec.mockImplementation((path, args, options) => {
|
||||||
|
if (args.includes('version')) {
|
||||||
|
options.listeners.stdout(Buffer.from('git version 2.50.1'))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return 128
|
||||||
|
})
|
||||||
|
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
|
||||||
|
|
||||||
|
git = await commandManager.createCommandManager('test', false, false)
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
git.tryGetObjectFormat('https://github.com/example/repo')
|
||||||
|
).resolves.toEqual({format: '', succeeded: false})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('initializes SHA-256 repositories with the matching object format', async () => {
|
||||||
|
mockExec.mockImplementation((path, args, options) => {
|
||||||
|
if (args.includes('version')) {
|
||||||
|
options.listeners.stdout(Buffer.from('git version 2.50.1'))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
|
||||||
|
|
||||||
|
git = await commandManager.createCommandManager('test', false, false)
|
||||||
|
|
||||||
|
await git.init('sha256')
|
||||||
|
|
||||||
|
expect(mockExec).toHaveBeenCalledWith(
|
||||||
|
expect.any(String),
|
||||||
|
['init', '--object-format=sha256', 'test'],
|
||||||
|
expect.any(Object)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('initializes SHA-1 repositories with existing default arguments', async () => {
|
||||||
|
mockExec.mockImplementation((path, args, options) => {
|
||||||
|
if (args.includes('version')) {
|
||||||
|
options.listeners.stdout(Buffer.from('git version 2.50.1'))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
|
||||||
|
|
||||||
|
git = await commandManager.createCommandManager('test', false, false)
|
||||||
|
|
||||||
|
await git.init('sha1')
|
||||||
|
|
||||||
|
expect(mockExec).toHaveBeenCalledWith(
|
||||||
|
expect.any(String),
|
||||||
|
['init', 'test'],
|
||||||
|
expect.any(Object)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('git user-agent with orchestration ID', () => {
|
describe('git user-agent with orchestration ID', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
jest.spyOn(fshelper, 'fileExistsSync').mockImplementation(jest.fn())
|
jest.spyOn(fshelper, 'fileExistsSync').mockImplementation(jest.fn())
|
||||||
|
|||||||
@@ -501,6 +501,7 @@ async function setup(testName: string): Promise<void> {
|
|||||||
await fs.promises.stat(path.join(repositoryPath, '.git'))
|
await fs.promises.stat(path.join(repositoryPath, '.git'))
|
||||||
return repositoryUrl
|
return repositoryUrl
|
||||||
}),
|
}),
|
||||||
|
tryGetObjectFormat: jest.fn(async () => ({format: '', succeeded: true})),
|
||||||
tryGetConfigValues: jest.fn(),
|
tryGetConfigValues: jest.fn(),
|
||||||
tryGetConfigKeys: jest.fn(),
|
tryGetConfigKeys: jest.fn(),
|
||||||
tryReset: jest.fn(async () => {
|
tryReset: jest.fn(async () => {
|
||||||
|
|||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as github from '@actions/github'
|
||||||
|
import * as githubApiHelper from '../lib/github-api-helper'
|
||||||
|
|
||||||
|
describe('github-api-helper object format', () => {
|
||||||
|
let getOctokitSpy: jest.SpyInstance
|
||||||
|
let debugSpy: jest.SpyInstance
|
||||||
|
let repoGet: jest.Mock
|
||||||
|
let branchGet: jest.Mock
|
||||||
|
|
||||||
|
function mockObjectFormatApi(defaultBranch: string, commitSha: string): void {
|
||||||
|
repoGet = jest.fn(async () => ({
|
||||||
|
data: {
|
||||||
|
default_branch: defaultBranch
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
branchGet = jest.fn(async () => ({
|
||||||
|
data: {
|
||||||
|
commit: {
|
||||||
|
sha: commitSha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
getOctokitSpy = jest.spyOn(github, 'getOctokit').mockReturnValue({
|
||||||
|
rest: {
|
||||||
|
repos: {
|
||||||
|
get: repoGet,
|
||||||
|
getBranch: branchGet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any)
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
debugSpy = jest.spyOn(core, 'debug').mockImplementation(jest.fn())
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.restoreAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('detects SHA-256 from the default branch commit SHA', async () => {
|
||||||
|
const commitSha =
|
||||||
|
'9422233ca7ee1b17f1e905d0e141faf0c401556c41cdc6acd71c6bd685da2e92'
|
||||||
|
mockObjectFormatApi('main', commitSha)
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
githubApiHelper.tryGetRepositoryObjectFormat('token', 'owner', 'repo')
|
||||||
|
).resolves.toEqual({
|
||||||
|
defaultBranch: 'main',
|
||||||
|
format: 'sha256',
|
||||||
|
succeeded: true
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(getOctokitSpy).toHaveBeenCalledWith(
|
||||||
|
'token',
|
||||||
|
expect.objectContaining({baseUrl: 'https://api.github.com'})
|
||||||
|
)
|
||||||
|
expect(repoGet).toHaveBeenCalledWith({owner: 'owner', repo: 'repo'})
|
||||||
|
expect(branchGet).toHaveBeenCalledWith({
|
||||||
|
owner: 'owner',
|
||||||
|
repo: 'repo',
|
||||||
|
branch: 'main'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('detects SHA-1 from the default branch commit SHA', async () => {
|
||||||
|
mockObjectFormatApi('main', 'c988866043f035e6a46509872215f91d879044c9')
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
githubApiHelper.tryGetRepositoryObjectFormat('token', 'owner', 'repo')
|
||||||
|
).resolves.toEqual({defaultBranch: 'main', format: 'sha1', succeeded: true})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('detects object format from an existing commit without API calls', async () => {
|
||||||
|
const commitSha =
|
||||||
|
'9422233ca7ee1b17f1e905d0e141faf0c401556c41cdc6acd71c6bd685da2e92'
|
||||||
|
getOctokitSpy = jest.spyOn(github, 'getOctokit')
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
githubApiHelper.tryGetRepositoryObjectFormat(
|
||||||
|
'token',
|
||||||
|
'owner',
|
||||||
|
'repo',
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
commitSha
|
||||||
|
)
|
||||||
|
).resolves.toEqual({format: 'sha256', succeeded: true})
|
||||||
|
|
||||||
|
expect(getOctokitSpy).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('uses a branch ref directly without looking up the default branch', async () => {
|
||||||
|
const commitSha = 'c988866043f035e6a46509872215f91d879044c9'
|
||||||
|
repoGet = jest.fn()
|
||||||
|
branchGet = jest.fn(async () => ({
|
||||||
|
data: {
|
||||||
|
commit: {
|
||||||
|
sha: commitSha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
getOctokitSpy = jest.spyOn(github, 'getOctokit').mockReturnValue({
|
||||||
|
rest: {
|
||||||
|
repos: {
|
||||||
|
get: repoGet,
|
||||||
|
getBranch: branchGet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
githubApiHelper.tryGetRepositoryObjectFormat(
|
||||||
|
'token',
|
||||||
|
'owner',
|
||||||
|
'repo',
|
||||||
|
undefined,
|
||||||
|
'refs/heads/feature'
|
||||||
|
)
|
||||||
|
).resolves.toEqual({format: 'sha1', succeeded: true})
|
||||||
|
|
||||||
|
expect(repoGet).not.toHaveBeenCalled()
|
||||||
|
expect(branchGet).toHaveBeenCalledWith({
|
||||||
|
owner: 'owner',
|
||||||
|
repo: 'repo',
|
||||||
|
branch: 'feature'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns unsuccessful when the default branch commit SHA is not recognized', async () => {
|
||||||
|
mockObjectFormatApi('main', 'not-a-sha')
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
githubApiHelper.tryGetRepositoryObjectFormat('token', 'owner', 'repo')
|
||||||
|
).resolves.toEqual({format: '', succeeded: false})
|
||||||
|
expect(debugSpy).toHaveBeenCalledWith(
|
||||||
|
'Unable to determine repository object format from commit SHA'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns unsuccessful when the repository API lookup fails', async () => {
|
||||||
|
repoGet = jest.fn(async () => {
|
||||||
|
throw new Error('not found')
|
||||||
|
})
|
||||||
|
branchGet = jest.fn()
|
||||||
|
jest.spyOn(github, 'getOctokit').mockReturnValue({
|
||||||
|
rest: {
|
||||||
|
repos: {
|
||||||
|
get: repoGet,
|
||||||
|
getBranch: branchGet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
githubApiHelper.tryGetRepositoryObjectFormat('token', 'owner', 'repo')
|
||||||
|
).resolves.toEqual({format: '', succeeded: false})
|
||||||
|
expect(branchGet).not.toHaveBeenCalled()
|
||||||
|
expect(debugSpy).toHaveBeenCalledWith(
|
||||||
|
'Unable to determine repository object format: not found'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
Vendored
+136
-16
@@ -151,12 +151,6 @@ const stateHelper = __importStar(__nccwpck_require__(4866));
|
|||||||
const urlHelper = __importStar(__nccwpck_require__(9437));
|
const urlHelper = __importStar(__nccwpck_require__(9437));
|
||||||
const uuid_1 = __nccwpck_require__(5840);
|
const uuid_1 = __nccwpck_require__(5840);
|
||||||
const IS_WINDOWS = process.platform === 'win32';
|
const IS_WINDOWS = process.platform === 'win32';
|
||||||
// Use case-insensitive gitdir matching on Windows to handle path casing mismatches
|
|
||||||
// between the runner's GITHUB_WORKSPACE and the actual filesystem casing.
|
|
||||||
// See: https://github.com/actions/checkout/issues/2345
|
|
||||||
const INCLUDE_IF_GITDIR = IS_WINDOWS
|
|
||||||
? 'includeIf.gitdir/i:'
|
|
||||||
: 'includeIf.gitdir:';
|
|
||||||
const SSH_COMMAND_KEY = 'core.sshCommand';
|
const SSH_COMMAND_KEY = 'core.sshCommand';
|
||||||
function createAuthHelper(git, settings) {
|
function createAuthHelper(git, settings) {
|
||||||
return new GitAuthHelper(git, settings);
|
return new GitAuthHelper(git, settings);
|
||||||
@@ -276,7 +270,7 @@ class GitAuthHelper {
|
|||||||
let submoduleGitDir = path.dirname(configPath); // The config file is at .git/modules/submodule-name/config
|
let submoduleGitDir = path.dirname(configPath); // The config file is at .git/modules/submodule-name/config
|
||||||
submoduleGitDir = submoduleGitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
|
submoduleGitDir = submoduleGitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
|
||||||
// Configure host includeIf
|
// Configure host includeIf
|
||||||
yield this.git.config(`${INCLUDE_IF_GITDIR}${submoduleGitDir}.path`, credentialsConfigPath, false, // globalConfig?
|
yield this.git.config(`includeIf.gitdir:${submoduleGitDir}.path`, credentialsConfigPath, false, // globalConfig?
|
||||||
false, // add?
|
false, // add?
|
||||||
configPath);
|
configPath);
|
||||||
// Container submodule git directory
|
// Container submodule git directory
|
||||||
@@ -286,7 +280,7 @@ class GitAuthHelper {
|
|||||||
relativeSubmoduleGitDir = relativeSubmoduleGitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
|
relativeSubmoduleGitDir = relativeSubmoduleGitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
|
||||||
const containerSubmoduleGitDir = path.posix.join('/github/workspace', relativeSubmoduleGitDir);
|
const containerSubmoduleGitDir = path.posix.join('/github/workspace', relativeSubmoduleGitDir);
|
||||||
// Configure container includeIf
|
// Configure container includeIf
|
||||||
yield this.git.config(`${INCLUDE_IF_GITDIR}${containerSubmoduleGitDir}.path`, containerCredentialsPath, false, // globalConfig?
|
yield this.git.config(`includeIf.gitdir:${containerSubmoduleGitDir}.path`, containerCredentialsPath, false, // globalConfig?
|
||||||
false, // add?
|
false, // add?
|
||||||
configPath);
|
configPath);
|
||||||
}
|
}
|
||||||
@@ -416,10 +410,10 @@ class GitAuthHelper {
|
|||||||
let gitDir = path.join(this.git.getWorkingDirectory(), '.git');
|
let gitDir = path.join(this.git.getWorkingDirectory(), '.git');
|
||||||
gitDir = gitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
|
gitDir = gitDir.replace(/\\/g, '/'); // Use forward slashes, even on Windows
|
||||||
// Configure host includeIf
|
// Configure host includeIf
|
||||||
const hostIncludeKey = `${INCLUDE_IF_GITDIR}${gitDir}.path`;
|
const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`;
|
||||||
yield this.git.config(hostIncludeKey, credentialsConfigPath);
|
yield this.git.config(hostIncludeKey, credentialsConfigPath);
|
||||||
// Configure host includeIf for worktrees
|
// Configure host includeIf for worktrees
|
||||||
const hostWorktreeIncludeKey = `${INCLUDE_IF_GITDIR}${gitDir}/worktrees/*.path`;
|
const hostWorktreeIncludeKey = `includeIf.gitdir:${gitDir}/worktrees/*.path`;
|
||||||
yield this.git.config(hostWorktreeIncludeKey, credentialsConfigPath);
|
yield this.git.config(hostWorktreeIncludeKey, credentialsConfigPath);
|
||||||
// Container git directory
|
// Container git directory
|
||||||
const workingDirectory = this.git.getWorkingDirectory();
|
const workingDirectory = this.git.getWorkingDirectory();
|
||||||
@@ -431,10 +425,10 @@ class GitAuthHelper {
|
|||||||
// Container credentials config path
|
// Container credentials config path
|
||||||
const containerCredentialsPath = path.posix.join('/github/runner_temp', path.basename(credentialsConfigPath));
|
const containerCredentialsPath = path.posix.join('/github/runner_temp', path.basename(credentialsConfigPath));
|
||||||
// Configure container includeIf
|
// Configure container includeIf
|
||||||
const containerIncludeKey = `${INCLUDE_IF_GITDIR}${containerGitDir}.path`;
|
const containerIncludeKey = `includeIf.gitdir:${containerGitDir}.path`;
|
||||||
yield this.git.config(containerIncludeKey, containerCredentialsPath);
|
yield this.git.config(containerIncludeKey, containerCredentialsPath);
|
||||||
// Configure container includeIf for worktrees
|
// Configure container includeIf for worktrees
|
||||||
const containerWorktreeIncludeKey = `${INCLUDE_IF_GITDIR}${containerGitDir}/worktrees/*.path`;
|
const containerWorktreeIncludeKey = `includeIf.gitdir:${containerGitDir}/worktrees/*.path`;
|
||||||
yield this.git.config(containerWorktreeIncludeKey, containerCredentialsPath);
|
yield this.git.config(containerWorktreeIncludeKey, containerCredentialsPath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -571,7 +565,7 @@ class GitAuthHelper {
|
|||||||
const credentialsPaths = new Set();
|
const credentialsPaths = new Set();
|
||||||
try {
|
try {
|
||||||
// Get all includeIf.gitdir keys
|
// Get all includeIf.gitdir keys
|
||||||
const keys = yield this.git.tryGetConfigKeys('^includeIf\\.gitdir(/i)?:', false, // globalConfig?
|
const keys = yield this.git.tryGetConfigKeys('^includeIf\\.gitdir:', false, // globalConfig?
|
||||||
configPath);
|
configPath);
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
// Get all values for this key
|
// Get all values for this key
|
||||||
@@ -902,9 +896,14 @@ class GitCommandManager {
|
|||||||
getWorkingDirectory() {
|
getWorkingDirectory() {
|
||||||
return this.workingDirectory;
|
return this.workingDirectory;
|
||||||
}
|
}
|
||||||
init() {
|
init(objectFormat) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
yield this.execGit(['init', this.workingDirectory]);
|
const args = ['init'];
|
||||||
|
if (objectFormat === 'sha256') {
|
||||||
|
args.push('--object-format=sha256');
|
||||||
|
}
|
||||||
|
args.push(this.workingDirectory);
|
||||||
|
yield this.execGit(args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
isDetached() {
|
isDetached() {
|
||||||
@@ -1062,6 +1061,45 @@ class GitCommandManager {
|
|||||||
return stdout;
|
return stdout;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
tryGetObjectFormat(repositoryUrl) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
var _a;
|
||||||
|
try {
|
||||||
|
const output = yield 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: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`);
|
||||||
|
return { format: '', succeeded: false };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
tryGetConfigValues(configKey, globalConfig, configFile) {
|
tryGetConfigValues(configKey, globalConfig, configFile) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const args = ['config'];
|
const args = ['config'];
|
||||||
@@ -1490,10 +1528,24 @@ function getSource(settings) {
|
|||||||
}
|
}
|
||||||
// Save state for POST action
|
// Save state for POST action
|
||||||
stateHelper.setRepositoryPath(settings.repositoryPath);
|
stateHelper.setRepositoryPath(settings.repositoryPath);
|
||||||
|
let defaultBranch = '';
|
||||||
// Initialize the repository
|
// Initialize the repository
|
||||||
if (!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))) {
|
if (!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))) {
|
||||||
|
core.startGroup('Determining repository object format');
|
||||||
|
let objectFormatResult = yield githubApiHelper.tryGetRepositoryObjectFormat(settings.authToken, settings.repositoryOwner, settings.repositoryName, settings.githubServerUrl, settings.ref, settings.commit);
|
||||||
|
if (!objectFormatResult.succeeded) {
|
||||||
|
objectFormatResult = yield 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');
|
core.startGroup('Initializing the repository');
|
||||||
yield git.init();
|
yield git.init(objectFormat);
|
||||||
yield git.remoteAdd('origin', repositoryUrl);
|
yield git.remoteAdd('origin', repositoryUrl);
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
}
|
}
|
||||||
@@ -1517,6 +1569,10 @@ function getSource(settings) {
|
|||||||
if (settings.sshKey) {
|
if (settings.sshKey) {
|
||||||
settings.ref = yield git.getDefaultBranch(repositoryUrl);
|
settings.ref = yield git.getDefaultBranch(repositoryUrl);
|
||||||
}
|
}
|
||||||
|
else if (defaultBranch) {
|
||||||
|
core.info(`Default branch '${defaultBranch}'`);
|
||||||
|
settings.ref = `refs/heads/${defaultBranch}`;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
settings.ref = yield githubApiHelper.getDefaultBranch(settings.authToken, settings.repositoryOwner, settings.repositoryName, settings.githubServerUrl);
|
settings.ref = yield githubApiHelper.getDefaultBranch(settings.authToken, settings.repositoryOwner, settings.repositoryName, settings.githubServerUrl);
|
||||||
}
|
}
|
||||||
@@ -1816,6 +1872,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.downloadRepository = downloadRepository;
|
exports.downloadRepository = downloadRepository;
|
||||||
exports.getDefaultBranch = getDefaultBranch;
|
exports.getDefaultBranch = getDefaultBranch;
|
||||||
|
exports.tryGetRepositoryObjectFormat = tryGetRepositoryObjectFormat;
|
||||||
const assert = __importStar(__nccwpck_require__(9491));
|
const assert = __importStar(__nccwpck_require__(9491));
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const fs = __importStar(__nccwpck_require__(7147));
|
const fs = __importStar(__nccwpck_require__(7147));
|
||||||
@@ -1917,6 +1974,69 @@ function getDefaultBranch(authToken, owner, repo, baseUrl) {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function tryGetRepositoryObjectFormat(authToken, owner, repo, baseUrl, ref, commit) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
var _a;
|
||||||
|
try {
|
||||||
|
const commitFormat = getObjectFormat(commit);
|
||||||
|
if (commitFormat) {
|
||||||
|
return { format: commitFormat, succeeded: true };
|
||||||
|
}
|
||||||
|
const octokit = github.getOctokit(authToken, {
|
||||||
|
baseUrl: (0, url_helper_1.getServerApiUrl)(baseUrl)
|
||||||
|
});
|
||||||
|
let branchName = getBranchName(ref);
|
||||||
|
let defaultBranch = '';
|
||||||
|
if (!branchName) {
|
||||||
|
const repository = yield octokit.rest.repos.get({ owner, repo });
|
||||||
|
defaultBranch = repository.data.default_branch;
|
||||||
|
assert.ok(defaultBranch, 'default_branch cannot be empty');
|
||||||
|
branchName = defaultBranch;
|
||||||
|
}
|
||||||
|
const branch = yield 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: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`);
|
||||||
|
return { format: '', succeeded: false };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getBranchName(ref) {
|
||||||
|
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) {
|
||||||
|
if (/^[0-9a-fA-F]{64}$/.test(sha || '')) {
|
||||||
|
return 'sha256';
|
||||||
|
}
|
||||||
|
if (/^[0-9a-fA-F]{40}$/.test(sha || '')) {
|
||||||
|
return 'sha1';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
function downloadArchive(authToken, owner, repo, ref, commit, baseUrl) {
|
function downloadArchive(authToken, owner, repo, ref, commit, baseUrl) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const octokit = github.getOctokit(authToken, {
|
const octokit = github.getOctokit(authToken, {
|
||||||
|
|||||||
+7
-13
@@ -13,12 +13,6 @@ import {IGitCommandManager} from './git-command-manager'
|
|||||||
import {IGitSourceSettings} from './git-source-settings'
|
import {IGitSourceSettings} from './git-source-settings'
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32'
|
const IS_WINDOWS = process.platform === 'win32'
|
||||||
// Use case-insensitive gitdir matching on Windows to handle path casing mismatches
|
|
||||||
// between the runner's GITHUB_WORKSPACE and the actual filesystem casing.
|
|
||||||
// See: https://github.com/actions/checkout/issues/2345
|
|
||||||
const INCLUDE_IF_GITDIR = IS_WINDOWS
|
|
||||||
? 'includeIf.gitdir/i:'
|
|
||||||
: 'includeIf.gitdir:'
|
|
||||||
const SSH_COMMAND_KEY = 'core.sshCommand'
|
const SSH_COMMAND_KEY = 'core.sshCommand'
|
||||||
|
|
||||||
export interface IGitAuthHelper {
|
export interface IGitAuthHelper {
|
||||||
@@ -188,7 +182,7 @@ class GitAuthHelper {
|
|||||||
|
|
||||||
// Configure host includeIf
|
// Configure host includeIf
|
||||||
await this.git.config(
|
await this.git.config(
|
||||||
`${INCLUDE_IF_GITDIR}${submoduleGitDir}.path`,
|
`includeIf.gitdir:${submoduleGitDir}.path`,
|
||||||
credentialsConfigPath,
|
credentialsConfigPath,
|
||||||
false, // globalConfig?
|
false, // globalConfig?
|
||||||
false, // add?
|
false, // add?
|
||||||
@@ -210,7 +204,7 @@ class GitAuthHelper {
|
|||||||
|
|
||||||
// Configure container includeIf
|
// Configure container includeIf
|
||||||
await this.git.config(
|
await this.git.config(
|
||||||
`${INCLUDE_IF_GITDIR}${containerSubmoduleGitDir}.path`,
|
`includeIf.gitdir:${containerSubmoduleGitDir}.path`,
|
||||||
containerCredentialsPath,
|
containerCredentialsPath,
|
||||||
false, // globalConfig?
|
false, // globalConfig?
|
||||||
false, // add?
|
false, // add?
|
||||||
@@ -377,11 +371,11 @@ class GitAuthHelper {
|
|||||||
gitDir = gitDir.replace(/\\/g, '/') // Use forward slashes, even on Windows
|
gitDir = gitDir.replace(/\\/g, '/') // Use forward slashes, even on Windows
|
||||||
|
|
||||||
// Configure host includeIf
|
// Configure host includeIf
|
||||||
const hostIncludeKey = `${INCLUDE_IF_GITDIR}${gitDir}.path`
|
const hostIncludeKey = `includeIf.gitdir:${gitDir}.path`
|
||||||
await this.git.config(hostIncludeKey, credentialsConfigPath)
|
await this.git.config(hostIncludeKey, credentialsConfigPath)
|
||||||
|
|
||||||
// Configure host includeIf for worktrees
|
// Configure host includeIf for worktrees
|
||||||
const hostWorktreeIncludeKey = `${INCLUDE_IF_GITDIR}${gitDir}/worktrees/*.path`
|
const hostWorktreeIncludeKey = `includeIf.gitdir:${gitDir}/worktrees/*.path`
|
||||||
await this.git.config(hostWorktreeIncludeKey, credentialsConfigPath)
|
await this.git.config(hostWorktreeIncludeKey, credentialsConfigPath)
|
||||||
|
|
||||||
// Container git directory
|
// Container git directory
|
||||||
@@ -403,11 +397,11 @@ class GitAuthHelper {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Configure container includeIf
|
// Configure container includeIf
|
||||||
const containerIncludeKey = `${INCLUDE_IF_GITDIR}${containerGitDir}.path`
|
const containerIncludeKey = `includeIf.gitdir:${containerGitDir}.path`
|
||||||
await this.git.config(containerIncludeKey, containerCredentialsPath)
|
await this.git.config(containerIncludeKey, containerCredentialsPath)
|
||||||
|
|
||||||
// Configure container includeIf for worktrees
|
// Configure container includeIf for worktrees
|
||||||
const containerWorktreeIncludeKey = `${INCLUDE_IF_GITDIR}${containerGitDir}/worktrees/*.path`
|
const containerWorktreeIncludeKey = `includeIf.gitdir:${containerGitDir}/worktrees/*.path`
|
||||||
await this.git.config(
|
await this.git.config(
|
||||||
containerWorktreeIncludeKey,
|
containerWorktreeIncludeKey,
|
||||||
containerCredentialsPath
|
containerCredentialsPath
|
||||||
@@ -560,7 +554,7 @@ class GitAuthHelper {
|
|||||||
try {
|
try {
|
||||||
// Get all includeIf.gitdir keys
|
// Get all includeIf.gitdir keys
|
||||||
const keys = await this.git.tryGetConfigKeys(
|
const keys = await this.git.tryGetConfigKeys(
|
||||||
'^includeIf\\.gitdir(/i)?:',
|
'^includeIf\\.gitdir:',
|
||||||
false, // globalConfig?
|
false, // globalConfig?
|
||||||
configPath
|
configPath
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ import {GitVersion} from './git-version'
|
|||||||
export const MinimumGitVersion = new GitVersion('2.18')
|
export const MinimumGitVersion = new GitVersion('2.18')
|
||||||
export const MinimumGitSparseCheckoutVersion = new GitVersion('2.28')
|
export const MinimumGitSparseCheckoutVersion = new GitVersion('2.28')
|
||||||
|
|
||||||
|
export interface GitObjectFormatResult {
|
||||||
|
format: string
|
||||||
|
succeeded: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export interface IGitCommandManager {
|
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>
|
||||||
@@ -43,7 +48,7 @@ export interface IGitCommandManager {
|
|||||||
getDefaultBranch(repositoryUrl: string): Promise<string>
|
getDefaultBranch(repositoryUrl: string): Promise<string>
|
||||||
getSubmoduleConfigPaths(recursive: boolean): Promise<string[]>
|
getSubmoduleConfigPaths(recursive: boolean): Promise<string[]>
|
||||||
getWorkingDirectory(): string
|
getWorkingDirectory(): string
|
||||||
init(): Promise<void>
|
init(objectFormat?: string): Promise<void>
|
||||||
isDetached(): Promise<boolean>
|
isDetached(): Promise<boolean>
|
||||||
lfsFetch(ref: string): Promise<void>
|
lfsFetch(ref: string): Promise<void>
|
||||||
lfsInstall(): Promise<void>
|
lfsInstall(): Promise<void>
|
||||||
@@ -68,6 +73,7 @@ export interface IGitCommandManager {
|
|||||||
): Promise<boolean>
|
): Promise<boolean>
|
||||||
tryDisableAutomaticGarbageCollection(): Promise<boolean>
|
tryDisableAutomaticGarbageCollection(): Promise<boolean>
|
||||||
tryGetFetchUrl(): Promise<string>
|
tryGetFetchUrl(): Promise<string>
|
||||||
|
tryGetObjectFormat(repositoryUrl: string): Promise<GitObjectFormatResult>
|
||||||
tryGetConfigValues(
|
tryGetConfigValues(
|
||||||
configKey: string,
|
configKey: string,
|
||||||
globalConfig?: boolean,
|
globalConfig?: boolean,
|
||||||
@@ -364,8 +370,14 @@ class GitCommandManager {
|
|||||||
return this.workingDirectory
|
return this.workingDirectory
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(): Promise<void> {
|
async init(objectFormat?: string): Promise<void> {
|
||||||
await this.execGit(['init', this.workingDirectory])
|
const args = ['init']
|
||||||
|
if (objectFormat === 'sha256') {
|
||||||
|
args.push('--object-format=sha256')
|
||||||
|
}
|
||||||
|
args.push(this.workingDirectory)
|
||||||
|
|
||||||
|
await this.execGit(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
async isDetached(): Promise<boolean> {
|
async isDetached(): Promise<boolean> {
|
||||||
@@ -536,6 +548,55 @@ class GitCommandManager {
|
|||||||
return stdout
|
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(
|
async tryGetConfigValues(
|
||||||
configKey: string,
|
configKey: string,
|
||||||
globalConfig?: boolean,
|
globalConfig?: boolean,
|
||||||
|
|||||||
@@ -105,12 +105,36 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
|
|||||||
// Save state for POST action
|
// Save state for POST action
|
||||||
stateHelper.setRepositoryPath(settings.repositoryPath)
|
stateHelper.setRepositoryPath(settings.repositoryPath)
|
||||||
|
|
||||||
|
let defaultBranch = ''
|
||||||
|
|
||||||
// Initialize the repository
|
// Initialize the repository
|
||||||
if (
|
if (
|
||||||
!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))
|
!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')
|
core.startGroup('Initializing the repository')
|
||||||
await git.init()
|
await git.init(objectFormat)
|
||||||
await git.remoteAdd('origin', repositoryUrl)
|
await git.remoteAdd('origin', repositoryUrl)
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
}
|
}
|
||||||
@@ -138,6 +162,9 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
|
|||||||
core.startGroup('Determining the default branch')
|
core.startGroup('Determining the default branch')
|
||||||
if (settings.sshKey) {
|
if (settings.sshKey) {
|
||||||
settings.ref = await git.getDefaultBranch(repositoryUrl)
|
settings.ref = await git.getDefaultBranch(repositoryUrl)
|
||||||
|
} else if (defaultBranch) {
|
||||||
|
core.info(`Default branch '${defaultBranch}'`)
|
||||||
|
settings.ref = `refs/heads/${defaultBranch}`
|
||||||
} else {
|
} else {
|
||||||
settings.ref = await githubApiHelper.getDefaultBranch(
|
settings.ref = await githubApiHelper.getDefaultBranch(
|
||||||
settings.authToken,
|
settings.authToken,
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ import {getServerApiUrl} from './url-helper'
|
|||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32'
|
const IS_WINDOWS = process.platform === 'win32'
|
||||||
|
|
||||||
|
export interface RepositoryObjectFormatResult {
|
||||||
|
defaultBranch?: string
|
||||||
|
format: string
|
||||||
|
succeeded: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export async function downloadRepository(
|
export async function downloadRepository(
|
||||||
authToken: string,
|
authToken: string,
|
||||||
owner: 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(
|
async function downloadArchive(
|
||||||
authToken: string,
|
authToken: string,
|
||||||
owner: string,
|
owner: string,
|
||||||
|
|||||||
Reference in New Issue
Block a user