mirror of
https://github.com/actions/checkout.git
synced 2026-06-23 17:43:52 +08:00
Compare commits
4 Commits
v5
...
cecd92d856
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cecd92d856 | ||
|
|
524dcd0a11 | ||
|
|
3ee49d2c6b | ||
|
|
ff7abcd0c3 |
105
.github/workflows/generator-generic-ossf-slsa3-publish.yml
vendored
Normal file
105
.github/workflows/generator-generic-ossf-slsa3-publish.yml
vendored
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
# This workflow uses actions that are not certified by GitHub.
|
||||||
|
# They are provided by a third-party and are governed by
|
||||||
|
# separate terms of service, privacy policy, and support
|
||||||
|
# documentation.
|
||||||
|
|
||||||
|
# This workflow lets you generate SLSA provenance file for your project.
|
||||||
|
# The generation satisfies level 3 for the provenance requirements - see https://slsa.dev/spec/v0.1/requirements
|
||||||
|
# The project is an initiative of the OpenSSF (openssf.org) and is developed at
|
||||||
|
# https://github.com/slsa-framework/slsa-github-generator.
|
||||||
|
# The provenance file can be verified using https://github.com/slsa-framework/slsa-verifier.
|
||||||
|
# For more information about SLSA and how it improves the supply-chain, visit slsa.dev.
|
||||||
|
|
||||||
|
name: SLSA generic generator
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
digests: ${{ steps.hash.outputs.digests }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# ========================================================
|
||||||
|
#
|
||||||
|
# Step 1: Build your artifacts.
|
||||||
|
#
|
||||||
|
# ========================================================
|
||||||
|
- name: Build artifacts
|
||||||
|
run: |
|
||||||
|
# These are some amazing artifacts.
|
||||||
|
echo "artifact1" > artifact1
|
||||||
|
echo "artifact2" > artifact2
|
||||||
|
|
||||||
|
# ========================================================
|
||||||
|
#
|
||||||
|
# Step 2: Add a step to generate the provenance subjects
|
||||||
|
# as shown below. Update the sha256 sum arguments
|
||||||
|
# to include all binaries that you generate
|
||||||
|
# provenance for.
|
||||||
|
#
|
||||||
|
# ========================================================
|
||||||
|
- name: Generate subject for provenance
|
||||||
|
id: hash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# List the artifacts the provenance will refer to.
|
||||||
|
files=$(ls artifact*)
|
||||||
|
# Generate the subjects (base64 encoded).
|
||||||
|
echo "hashes=$(sha256sum $files | base64 -w0)" >> "${GITHUB_OUTPUT}"
|
||||||
|
|
||||||
|
provenance:
|
||||||
|
needs: [build]
|
||||||
|
permissions: - name: Deploy HelmFile
|
||||||
|
# You may pin to the exact commit or the version.
|
||||||
|
# uses: cloudposse/github-action-deploy-helmfile@fcc0ea83519505047bd34a4e017f1d0c3516a5cc
|
||||||
|
uses: cloudposse/github-action-deploy-helmfile@0.7.0
|
||||||
|
with:
|
||||||
|
# Cluster name
|
||||||
|
cluster:
|
||||||
|
# AWS region
|
||||||
|
aws-region: # optional, default is us-east-1
|
||||||
|
# The path where lives the helmfile.
|
||||||
|
helmfile-path: # optional, default is deploy
|
||||||
|
# Helmfile name
|
||||||
|
helmfile: # optional, default is helmfile.yaml
|
||||||
|
# Operation with helmfiles. (valid options - `deploy`, `destroy`)
|
||||||
|
operation: # default is deploy
|
||||||
|
# Helmfile environment
|
||||||
|
environment: # optional, default is preview
|
||||||
|
# Git SHA
|
||||||
|
gitref-sha: # optional, default is
|
||||||
|
# Kubernetes namespace
|
||||||
|
namespace:
|
||||||
|
# Docker image
|
||||||
|
image:
|
||||||
|
# Docker image tag
|
||||||
|
image-tag:
|
||||||
|
# Debug mode
|
||||||
|
debug: # optional, default is false
|
||||||
|
# The name of the label used to describe the helm release
|
||||||
|
release_label_name: # optional, default is release
|
||||||
|
# YAML string with extra values to use in a helmfile deploy
|
||||||
|
values_yaml: # optional
|
||||||
|
# Helm version
|
||||||
|
helm_version: # optional, default is 3.11.1
|
||||||
|
# Helmfile version
|
||||||
|
helmfile_version: # optional, default is 0.143.5
|
||||||
|
# Kubectl version
|
||||||
|
kubectl_version: # optional, default is 1.26.3
|
||||||
|
# Kubectl version
|
||||||
|
chamber_version: # optional, default is 2.11.1
|
||||||
|
|
||||||
|
actions: read # To read the workflow path.
|
||||||
|
id-token: write # To sign the provenance.
|
||||||
|
contents: write # To add assets to a release.
|
||||||
|
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.4.0
|
||||||
|
with:
|
||||||
|
base64-subjects: "${{ needs.build.outputs.digests }}"
|
||||||
|
upload-assets: true # Optional: Upload to a new release
|
||||||
@@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
# Checkout V5
|
# Checkout V5
|
||||||
|
|
||||||
Checkout v5 now supports Node.js 24
|
## What's new
|
||||||
|
|
||||||
|
- Updated to the node24 runtime
|
||||||
|
- This requires a minimum Actions Runner version of [v2.327.1](https://github.com/actions/runner/releases/tag/v2.327.1) to run.
|
||||||
|
|
||||||
|
|
||||||
# Checkout V4
|
# Checkout V4
|
||||||
|
|
||||||
@@ -154,9 +158,10 @@ Please refer to the [release page](https://github.com/actions/checkout/releases/
|
|||||||
# Scenarios
|
# Scenarios
|
||||||
|
|
||||||
- [Checkout V5](#checkout-v5)
|
- [Checkout V5](#checkout-v5)
|
||||||
|
- [What's new](#whats-new)
|
||||||
- [Checkout V4](#checkout-v4)
|
- [Checkout V4](#checkout-v4)
|
||||||
- [Note](#note)
|
- [Note](#note)
|
||||||
- [What's new](#whats-new)
|
- [What's new](#whats-new-1)
|
||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
- [Scenarios](#scenarios)
|
- [Scenarios](#scenarios)
|
||||||
- [Fetch only the root files](#fetch-only-the-root-files)
|
- [Fetch only the root files](#fetch-only-the-root-files)
|
||||||
|
|||||||
@@ -675,283 +675,6 @@ describe('git-auth-helper tests', () => {
|
|||||||
expect(gitConfigContent.indexOf('http.')).toBeLessThan(0)
|
expect(gitConfigContent.indexOf('http.')).toBeLessThan(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
const removeAuth_removesV6StyleCredentials =
|
|
||||||
'removeAuth removes v6 style credentials'
|
|
||||||
it(removeAuth_removesV6StyleCredentials, async () => {
|
|
||||||
// Arrange
|
|
||||||
await setup(removeAuth_removesV6StyleCredentials)
|
|
||||||
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
|
|
||||||
await authHelper.configureAuth()
|
|
||||||
|
|
||||||
// Manually create v6-style credentials that would be left by v6
|
|
||||||
const credentialsFileName =
|
|
||||||
'git-credentials-12345678-1234-1234-1234-123456789abc.config'
|
|
||||||
const credentialsFilePath = path.join(runnerTemp, credentialsFileName)
|
|
||||||
const basicCredential = Buffer.from(
|
|
||||||
`x-access-token:${settings.authToken}`,
|
|
||||||
'utf8'
|
|
||||||
).toString('base64')
|
|
||||||
const credentialsContent = `[http "https://github.com/"]\n\textraheader = AUTHORIZATION: basic ${basicCredential}\n`
|
|
||||||
await fs.promises.writeFile(credentialsFilePath, credentialsContent)
|
|
||||||
|
|
||||||
// Add includeIf entries to local git config (simulating v6 configuration)
|
|
||||||
const hostGitDir = path.join(workspace, '.git').replace(/\\/g, '/')
|
|
||||||
await fs.promises.appendFile(
|
|
||||||
localGitConfigPath,
|
|
||||||
`[includeIf "gitdir:${hostGitDir}/"]\n\tpath = ${credentialsFilePath}\n`
|
|
||||||
)
|
|
||||||
await fs.promises.appendFile(
|
|
||||||
localGitConfigPath,
|
|
||||||
`[includeIf "gitdir:/github/workspace/.git/"]\n\tpath = /github/runner_temp/${credentialsFileName}\n`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Verify v6 style config exists
|
|
||||||
let gitConfigContent = (
|
|
||||||
await fs.promises.readFile(localGitConfigPath)
|
|
||||||
).toString()
|
|
||||||
expect(gitConfigContent.indexOf('includeIf')).toBeGreaterThanOrEqual(0)
|
|
||||||
expect(
|
|
||||||
gitConfigContent.indexOf(credentialsFilePath)
|
|
||||||
).toBeGreaterThanOrEqual(0)
|
|
||||||
await fs.promises.stat(credentialsFilePath) // Verify file exists
|
|
||||||
|
|
||||||
// Mock the git methods to handle v6 cleanup
|
|
||||||
const mockTryGetConfigKeys = git.tryGetConfigKeys as jest.Mock<any, any>
|
|
||||||
mockTryGetConfigKeys.mockResolvedValue([
|
|
||||||
`includeIf.gitdir:${hostGitDir}/.path`,
|
|
||||||
'includeIf.gitdir:/github/workspace/.git/.path'
|
|
||||||
])
|
|
||||||
|
|
||||||
const mockTryGetConfigValues = git.tryGetConfigValues as jest.Mock<any, any>
|
|
||||||
mockTryGetConfigValues.mockImplementation(async (key: string) => {
|
|
||||||
if (key === `includeIf.gitdir:${hostGitDir}/.path`) {
|
|
||||||
return [credentialsFilePath]
|
|
||||||
}
|
|
||||||
if (key === 'includeIf.gitdir:/github/workspace/.git/.path') {
|
|
||||||
return [`/github/runner_temp/${credentialsFileName}`]
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
})
|
|
||||||
|
|
||||||
const mockTryConfigUnsetValue = git.tryConfigUnsetValue as jest.Mock<
|
|
||||||
any,
|
|
||||||
any
|
|
||||||
>
|
|
||||||
mockTryConfigUnsetValue.mockImplementation(
|
|
||||||
async (
|
|
||||||
key: string,
|
|
||||||
value: string,
|
|
||||||
globalConfig?: boolean,
|
|
||||||
configPath?: string
|
|
||||||
) => {
|
|
||||||
const targetPath = configPath || localGitConfigPath
|
|
||||||
let content = await fs.promises.readFile(targetPath, 'utf8')
|
|
||||||
// Remove the includeIf section
|
|
||||||
const lines = content
|
|
||||||
.split('\n')
|
|
||||||
.filter(line => !line.includes('includeIf') && !line.includes(value))
|
|
||||||
await fs.promises.writeFile(targetPath, lines.join('\n'))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await authHelper.removeAuth()
|
|
||||||
|
|
||||||
// Assert includeIf entries removed from local git config
|
|
||||||
gitConfigContent = (
|
|
||||||
await fs.promises.readFile(localGitConfigPath)
|
|
||||||
).toString()
|
|
||||||
expect(gitConfigContent.indexOf('includeIf')).toBeLessThan(0)
|
|
||||||
expect(gitConfigContent.indexOf(credentialsFilePath)).toBeLessThan(0)
|
|
||||||
|
|
||||||
// Assert credentials config file deleted
|
|
||||||
try {
|
|
||||||
await fs.promises.stat(credentialsFilePath)
|
|
||||||
throw new Error('Credentials file should have been deleted')
|
|
||||||
} catch (err) {
|
|
||||||
if ((err as any)?.code !== 'ENOENT') {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const removeAuth_removesV6StyleCredentialsFromSubmodules =
|
|
||||||
'removeAuth removes v6 style credentials from submodules'
|
|
||||||
it(removeAuth_removesV6StyleCredentialsFromSubmodules, async () => {
|
|
||||||
// Arrange
|
|
||||||
await setup(removeAuth_removesV6StyleCredentialsFromSubmodules)
|
|
||||||
|
|
||||||
// Create fake submodule config paths
|
|
||||||
const submodule1Dir = path.join(workspace, '.git', 'modules', 'submodule-1')
|
|
||||||
const submodule1ConfigPath = path.join(submodule1Dir, 'config')
|
|
||||||
await fs.promises.mkdir(submodule1Dir, {recursive: true})
|
|
||||||
await fs.promises.writeFile(submodule1ConfigPath, '')
|
|
||||||
|
|
||||||
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
|
|
||||||
await authHelper.configureAuth()
|
|
||||||
|
|
||||||
// Create v6-style credentials file
|
|
||||||
const credentialsFileName =
|
|
||||||
'git-credentials-abcdef12-3456-7890-abcd-ef1234567890.config'
|
|
||||||
const credentialsFilePath = path.join(runnerTemp, credentialsFileName)
|
|
||||||
const basicCredential = Buffer.from(
|
|
||||||
`x-access-token:${settings.authToken}`,
|
|
||||||
'utf8'
|
|
||||||
).toString('base64')
|
|
||||||
const credentialsContent = `[http "https://github.com/"]\n\textraheader = AUTHORIZATION: basic ${basicCredential}\n`
|
|
||||||
await fs.promises.writeFile(credentialsFilePath, credentialsContent)
|
|
||||||
|
|
||||||
// Add includeIf entries to submodule config
|
|
||||||
const submodule1GitDir = submodule1Dir.replace(/\\/g, '/')
|
|
||||||
await fs.promises.appendFile(
|
|
||||||
submodule1ConfigPath,
|
|
||||||
`[includeIf "gitdir:${submodule1GitDir}/"]\n\tpath = ${credentialsFilePath}\n`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Verify submodule config has includeIf entry
|
|
||||||
let submoduleConfigContent = (
|
|
||||||
await fs.promises.readFile(submodule1ConfigPath)
|
|
||||||
).toString()
|
|
||||||
expect(submoduleConfigContent.indexOf('includeIf')).toBeGreaterThanOrEqual(
|
|
||||||
0
|
|
||||||
)
|
|
||||||
expect(
|
|
||||||
submoduleConfigContent.indexOf(credentialsFilePath)
|
|
||||||
).toBeGreaterThanOrEqual(0)
|
|
||||||
|
|
||||||
// Mock getSubmoduleConfigPaths
|
|
||||||
const mockGetSubmoduleConfigPaths =
|
|
||||||
git.getSubmoduleConfigPaths as jest.Mock<any, any>
|
|
||||||
mockGetSubmoduleConfigPaths.mockResolvedValue([submodule1ConfigPath])
|
|
||||||
|
|
||||||
// Mock tryGetConfigKeys for submodule
|
|
||||||
const mockTryGetConfigKeys = git.tryGetConfigKeys as jest.Mock<any, any>
|
|
||||||
mockTryGetConfigKeys.mockImplementation(
|
|
||||||
async (pattern: string, globalConfig?: boolean, configPath?: string) => {
|
|
||||||
if (configPath === submodule1ConfigPath) {
|
|
||||||
return [`includeIf.gitdir:${submodule1GitDir}/.path`]
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mock tryGetConfigValues for submodule
|
|
||||||
const mockTryGetConfigValues = git.tryGetConfigValues as jest.Mock<any, any>
|
|
||||||
mockTryGetConfigValues.mockImplementation(
|
|
||||||
async (key: string, globalConfig?: boolean, configPath?: string) => {
|
|
||||||
if (
|
|
||||||
configPath === submodule1ConfigPath &&
|
|
||||||
key === `includeIf.gitdir:${submodule1GitDir}/.path`
|
|
||||||
) {
|
|
||||||
return [credentialsFilePath]
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mock tryConfigUnsetValue for submodule
|
|
||||||
const mockTryConfigUnsetValue = git.tryConfigUnsetValue as jest.Mock<
|
|
||||||
any,
|
|
||||||
any
|
|
||||||
>
|
|
||||||
mockTryConfigUnsetValue.mockImplementation(
|
|
||||||
async (
|
|
||||||
key: string,
|
|
||||||
value: string,
|
|
||||||
globalConfig?: boolean,
|
|
||||||
configPath?: string
|
|
||||||
) => {
|
|
||||||
const targetPath = configPath || localGitConfigPath
|
|
||||||
let content = await fs.promises.readFile(targetPath, 'utf8')
|
|
||||||
const lines = content
|
|
||||||
.split('\n')
|
|
||||||
.filter(line => !line.includes('includeIf') && !line.includes(value))
|
|
||||||
await fs.promises.writeFile(targetPath, lines.join('\n'))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await authHelper.removeAuth()
|
|
||||||
|
|
||||||
// Assert submodule includeIf entries removed
|
|
||||||
submoduleConfigContent = (
|
|
||||||
await fs.promises.readFile(submodule1ConfigPath)
|
|
||||||
).toString()
|
|
||||||
expect(submoduleConfigContent.indexOf('includeIf')).toBeLessThan(0)
|
|
||||||
expect(submoduleConfigContent.indexOf(credentialsFilePath)).toBeLessThan(0)
|
|
||||||
|
|
||||||
// Assert credentials file deleted
|
|
||||||
try {
|
|
||||||
await fs.promises.stat(credentialsFilePath)
|
|
||||||
throw new Error('Credentials file should have been deleted')
|
|
||||||
} catch (err) {
|
|
||||||
if ((err as any)?.code !== 'ENOENT') {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const removeAuth_skipsV6CleanupWhenEnvVarSet =
|
|
||||||
'removeAuth skips v6 cleanup when ACTIONS_CHECKOUT_SKIP_V6_CLEANUP is set'
|
|
||||||
it(removeAuth_skipsV6CleanupWhenEnvVarSet, async () => {
|
|
||||||
// Arrange
|
|
||||||
await setup(removeAuth_skipsV6CleanupWhenEnvVarSet)
|
|
||||||
|
|
||||||
// Set the skip environment variable
|
|
||||||
process.env['ACTIONS_CHECKOUT_SKIP_V6_CLEANUP'] = '1'
|
|
||||||
|
|
||||||
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
|
|
||||||
await authHelper.configureAuth()
|
|
||||||
|
|
||||||
// Create v6-style credentials file in RUNNER_TEMP
|
|
||||||
const credentialsFileName = 'git-credentials-test-uuid-1234-5678.config'
|
|
||||||
const credentialsFilePath = path.join(runnerTemp, credentialsFileName)
|
|
||||||
const credentialsContent =
|
|
||||||
'[http "https://github.com/"]\n\textraheader = AUTHORIZATION: basic token\n'
|
|
||||||
await fs.promises.writeFile(credentialsFilePath, credentialsContent)
|
|
||||||
|
|
||||||
// Add includeIf section to local git config (separate from http.* config)
|
|
||||||
const includeIfSection = `\n[includeIf "gitdir:/some/path/.git/"]\n\tpath = ${credentialsFilePath}\n`
|
|
||||||
await fs.promises.appendFile(localGitConfigPath, includeIfSection)
|
|
||||||
|
|
||||||
// Verify v6 style config exists
|
|
||||||
let gitConfigContent = (
|
|
||||||
await fs.promises.readFile(localGitConfigPath)
|
|
||||||
).toString()
|
|
||||||
expect(gitConfigContent.indexOf('includeIf')).toBeGreaterThanOrEqual(0)
|
|
||||||
await fs.promises.stat(credentialsFilePath) // Verify file exists
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await authHelper.removeAuth()
|
|
||||||
|
|
||||||
// Assert v5 cleanup still happened (http.* removed)
|
|
||||||
gitConfigContent = (
|
|
||||||
await fs.promises.readFile(localGitConfigPath)
|
|
||||||
).toString()
|
|
||||||
expect(
|
|
||||||
gitConfigContent.indexOf('http.https://github.com/.extraheader')
|
|
||||||
).toBeLessThan(0)
|
|
||||||
|
|
||||||
// Assert v6 cleanup was skipped - includeIf should still be present
|
|
||||||
expect(gitConfigContent.indexOf('includeIf')).toBeGreaterThanOrEqual(0)
|
|
||||||
expect(
|
|
||||||
gitConfigContent.indexOf(credentialsFilePath)
|
|
||||||
).toBeGreaterThanOrEqual(0)
|
|
||||||
|
|
||||||
// Assert credentials file still exists (wasn't deleted)
|
|
||||||
await fs.promises.stat(credentialsFilePath) // File should still exist
|
|
||||||
|
|
||||||
// Assert debug message was logged
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
|
||||||
'Skipping v6 style cleanup due to ACTIONS_CHECKOUT_SKIP_V6_CLEANUP'
|
|
||||||
)
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
delete process.env['ACTIONS_CHECKOUT_SKIP_V6_CLEANUP']
|
|
||||||
})
|
|
||||||
|
|
||||||
const removeGlobalConfig_removesOverride =
|
const removeGlobalConfig_removesOverride =
|
||||||
'removeGlobalConfig removes override'
|
'removeGlobalConfig removes override'
|
||||||
it(removeGlobalConfig_removesOverride, async () => {
|
it(removeGlobalConfig_removesOverride, async () => {
|
||||||
@@ -1073,18 +796,6 @@ async function setup(testName: string): Promise<void> {
|
|||||||
),
|
),
|
||||||
tryDisableAutomaticGarbageCollection: jest.fn(),
|
tryDisableAutomaticGarbageCollection: jest.fn(),
|
||||||
tryGetFetchUrl: jest.fn(),
|
tryGetFetchUrl: jest.fn(),
|
||||||
getSubmoduleConfigPaths: jest.fn(async () => {
|
|
||||||
return []
|
|
||||||
}),
|
|
||||||
tryConfigUnsetValue: jest.fn(async () => {
|
|
||||||
return true
|
|
||||||
}),
|
|
||||||
tryGetConfigValues: jest.fn(async () => {
|
|
||||||
return []
|
|
||||||
}),
|
|
||||||
tryGetConfigKeys: jest.fn(async () => {
|
|
||||||
return []
|
|
||||||
}),
|
|
||||||
tryReset: jest.fn(),
|
tryReset: jest.fn(),
|
||||||
version: jest.fn()
|
version: jest.fn()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -499,18 +499,6 @@ 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
|
||||||
}),
|
}),
|
||||||
getSubmoduleConfigPaths: jest.fn(async () => {
|
|
||||||
return []
|
|
||||||
}),
|
|
||||||
tryConfigUnsetValue: jest.fn(async () => {
|
|
||||||
return true
|
|
||||||
}),
|
|
||||||
tryGetConfigValues: jest.fn(async () => {
|
|
||||||
return []
|
|
||||||
}),
|
|
||||||
tryGetConfigKeys: jest.fn(async () => {
|
|
||||||
return []
|
|
||||||
}),
|
|
||||||
tryReset: jest.fn(async () => {
|
tryReset: jest.fn(async () => {
|
||||||
return true
|
return true
|
||||||
}),
|
}),
|
||||||
|
|||||||
151
dist/index.js
vendored
151
dist/index.js
vendored
@@ -411,50 +411,8 @@ class GitAuthHelper {
|
|||||||
}
|
}
|
||||||
removeToken() {
|
removeToken() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// Remove HTTP extra header from local git config and submodule configs
|
// HTTP extra header
|
||||||
yield this.removeGitConfig(this.tokenConfigKey);
|
yield this.removeGitConfig(this.tokenConfigKey);
|
||||||
//
|
|
||||||
// Cleanup actions/checkout@v6 style credentials
|
|
||||||
//
|
|
||||||
const skipV6Cleanup = process.env['ACTIONS_CHECKOUT_SKIP_V6_CLEANUP'];
|
|
||||||
if (skipV6Cleanup === '1' || (skipV6Cleanup === null || skipV6Cleanup === void 0 ? void 0 : skipV6Cleanup.toLowerCase()) === 'true') {
|
|
||||||
core.debug('Skipping v6 style cleanup due to ACTIONS_CHECKOUT_SKIP_V6_CLEANUP');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// Collect credentials config paths that need to be removed
|
|
||||||
const credentialsPaths = new Set();
|
|
||||||
// Remove includeIf entries that point to git-credentials-*.config files
|
|
||||||
const mainCredentialsPaths = yield this.removeIncludeIfCredentials();
|
|
||||||
mainCredentialsPaths.forEach(path => credentialsPaths.add(path));
|
|
||||||
// Remove submodule includeIf entries that point to git-credentials-*.config files
|
|
||||||
try {
|
|
||||||
const submoduleConfigPaths = yield this.git.getSubmoduleConfigPaths(true);
|
|
||||||
for (const configPath of submoduleConfigPaths) {
|
|
||||||
const submoduleCredentialsPaths = yield this.removeIncludeIfCredentials(configPath);
|
|
||||||
submoduleCredentialsPaths.forEach(path => credentialsPaths.add(path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
core.debug(`Unable to get submodule config paths: ${err}`);
|
|
||||||
}
|
|
||||||
// Remove credentials config files
|
|
||||||
for (const credentialsPath of credentialsPaths) {
|
|
||||||
// Only remove credentials config files if they are under RUNNER_TEMP
|
|
||||||
const runnerTemp = process.env['RUNNER_TEMP'];
|
|
||||||
if (runnerTemp && credentialsPath.startsWith(runnerTemp)) {
|
|
||||||
try {
|
|
||||||
yield io.rmRF(credentialsPath);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
core.debug(`Failed to remove credentials config '${credentialsPath}': ${err}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
core.debug(`Failed to cleanup v6 style credentials: ${err}`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
removeGitConfig(configKey_1) {
|
removeGitConfig(configKey_1) {
|
||||||
@@ -472,49 +430,6 @@ class GitAuthHelper {
|
|||||||
`sh -c "git config --local --name-only --get-regexp '${pattern}' && git config --local --unset-all '${configKey}' || :"`, true);
|
`sh -c "git config --local --name-only --get-regexp '${pattern}' && git config --local --unset-all '${configKey}' || :"`, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Removes includeIf entries that point to git-credentials-*.config files.
|
|
||||||
* This handles cleanup of credentials configured by newer versions of the action.
|
|
||||||
* @param configPath Optional path to a specific git config file to operate on
|
|
||||||
* @returns Array of unique credentials config file paths that were found and removed
|
|
||||||
*/
|
|
||||||
removeIncludeIfCredentials(configPath) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const credentialsPaths = new Set();
|
|
||||||
try {
|
|
||||||
// Get all includeIf.gitdir keys
|
|
||||||
const keys = yield this.git.tryGetConfigKeys('^includeIf\\.gitdir:', false, // globalConfig?
|
|
||||||
configPath);
|
|
||||||
for (const key of keys) {
|
|
||||||
// Get all values for this key
|
|
||||||
const values = yield this.git.tryGetConfigValues(key, false, // globalConfig?
|
|
||||||
configPath);
|
|
||||||
if (values.length > 0) {
|
|
||||||
// Remove only values that match git-credentials-<uuid>.config pattern
|
|
||||||
for (const value of values) {
|
|
||||||
if (this.testCredentialsConfigPath(value)) {
|
|
||||||
credentialsPaths.add(value);
|
|
||||||
yield this.git.tryConfigUnsetValue(key, value, false, configPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
// Ignore errors - this is cleanup code
|
|
||||||
core.debug(`Error during includeIf cleanup${configPath ? ` for ${configPath}` : ''}: ${err}`);
|
|
||||||
}
|
|
||||||
return Array.from(credentialsPaths);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Tests if a path matches the git-credentials-*.config pattern used by newer versions.
|
|
||||||
* @param path The path to test
|
|
||||||
* @returns True if the path matches the credentials config pattern
|
|
||||||
*/
|
|
||||||
testCredentialsConfigPath(path) {
|
|
||||||
return /git-credentials-[0-9a-f-]+\.config$/i.test(path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -791,16 +706,6 @@ class GitCommandManager {
|
|||||||
throw new Error('Unexpected output when retrieving default branch');
|
throw new Error('Unexpected output when retrieving default branch');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getSubmoduleConfigPaths(recursive) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
// Get submodule config file paths.
|
|
||||||
// Use `--show-origin` to get the config file path for each submodule.
|
|
||||||
const output = yield this.submoduleForeach(`git config --local --show-origin --name-only --get-regexp remote.origin.url`, recursive);
|
|
||||||
// Extract config file paths from the output (lines starting with "file:").
|
|
||||||
const configPaths = output.match(/(?<=(^|\n)file:)[^\t]+(?=\tremote\.origin\.url)/g) || [];
|
|
||||||
return configPaths;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getWorkingDirectory() {
|
getWorkingDirectory() {
|
||||||
return this.workingDirectory;
|
return this.workingDirectory;
|
||||||
}
|
}
|
||||||
@@ -931,20 +836,6 @@ class GitCommandManager {
|
|||||||
return output.exitCode === 0;
|
return output.exitCode === 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
tryConfigUnsetValue(configKey, configValue, globalConfig, configFile) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const args = ['config'];
|
|
||||||
if (configFile) {
|
|
||||||
args.push('--file', configFile);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
args.push(globalConfig ? '--global' : '--local');
|
|
||||||
}
|
|
||||||
args.push('--unset', configKey, configValue);
|
|
||||||
const output = yield this.execGit(args, true);
|
|
||||||
return output.exitCode === 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
tryDisableAutomaticGarbageCollection() {
|
tryDisableAutomaticGarbageCollection() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const output = yield this.execGit(['config', '--local', 'gc.auto', '0'], true);
|
const output = yield this.execGit(['config', '--local', 'gc.auto', '0'], true);
|
||||||
@@ -964,46 +855,6 @@ class GitCommandManager {
|
|||||||
return stdout;
|
return stdout;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
tryGetConfigValues(configKey, globalConfig, configFile) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const args = ['config'];
|
|
||||||
if (configFile) {
|
|
||||||
args.push('--file', configFile);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
args.push(globalConfig ? '--global' : '--local');
|
|
||||||
}
|
|
||||||
args.push('--get-all', configKey);
|
|
||||||
const output = yield this.execGit(args, true);
|
|
||||||
if (output.exitCode !== 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return output.stdout
|
|
||||||
.trim()
|
|
||||||
.split('\n')
|
|
||||||
.filter(value => value.trim());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
tryGetConfigKeys(pattern, globalConfig, configFile) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const args = ['config'];
|
|
||||||
if (configFile) {
|
|
||||||
args.push('--file', configFile);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
args.push(globalConfig ? '--global' : '--local');
|
|
||||||
}
|
|
||||||
args.push('--name-only', '--get-regexp', pattern);
|
|
||||||
const output = yield this.execGit(args, true);
|
|
||||||
if (output.exitCode !== 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return output.stdout
|
|
||||||
.trim()
|
|
||||||
.split('\n')
|
|
||||||
.filter(key => key.trim());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
tryReset() {
|
tryReset() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const output = yield this.execGit(['reset', '--hard', 'HEAD'], true);
|
const output = yield this.execGit(['reset', '--hard', 'HEAD'], true);
|
||||||
|
|||||||
108
release,tagset
Normal file
108
release,tagset
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
- uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
# Repository name with owner. For example, actions/checkout
|
||||||
|
# Default: ${{ github.repository }}
|
||||||
|
repository: ''
|
||||||
|
|
||||||
|
# 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 event.
|
||||||
|
# Otherwise, uses the default branch.
|
||||||
|
ref: ''
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# We recommend using a service account with the least permissions necessary. Also
|
||||||
|
# when generating a new PAT, select the least scopes necessary.
|
||||||
|
#
|
||||||
|
# [Learn more about creating and using encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
|
||||||
|
#
|
||||||
|
# Default: ${{ github.token }}
|
||||||
|
token: ''
|
||||||
|
|
||||||
|
# SSH key used to fetch the repository. The SSH key is configured with the local
|
||||||
|
# git config, which enables your scripts to run authenticated git commands. The
|
||||||
|
# post-job step removes the SSH key.
|
||||||
|
#
|
||||||
|
# We recommend using a service account with the least permissions necessary.
|
||||||
|
#
|
||||||
|
# [Learn more about creating and using encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
|
||||||
|
ssh-key: ''
|
||||||
|
|
||||||
|
# Known hosts in addition to the user and global host key database. The public SSH
|
||||||
|
# keys for a host may be obtained using the utility `ssh-keyscan`. For example,
|
||||||
|
# `ssh-keyscan github.com`. The public key for github.com is always implicitly
|
||||||
|
# added.
|
||||||
|
ssh-known-hosts: ''
|
||||||
|
|
||||||
|
# Whether to perform strict host key checking. When true, adds the options
|
||||||
|
# `StrictHostKeyChecking=yes` and `CheckHostIP=no` to the SSH command line. Use
|
||||||
|
# the input `ssh-known-hosts` to configure additional hosts.
|
||||||
|
# Default: true
|
||||||
|
ssh-strict: ''
|
||||||
|
|
||||||
|
# The user to use when connecting to the remote SSH host. By default 'git' is
|
||||||
|
# used.
|
||||||
|
# Default: git
|
||||||
|
ssh-user: ''
|
||||||
|
|
||||||
|
# Whether to configure the token or SSH key with the local git config
|
||||||
|
# Default: true
|
||||||
|
persist-credentials: ''
|
||||||
|
|
||||||
|
# Relative path under $GITHUB_WORKSPACE to place the repository
|
||||||
|
path: ''
|
||||||
|
|
||||||
|
# Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching
|
||||||
|
# Default: true
|
||||||
|
clean: ''
|
||||||
|
|
||||||
|
# Partially clone against a given filter. Overrides sparse-checkout if set.
|
||||||
|
# Default: null
|
||||||
|
filter: ''
|
||||||
|
|
||||||
|
# Do a sparse checkout on given patterns. Each pattern should be separated with
|
||||||
|
# new lines.
|
||||||
|
# Default: null
|
||||||
|
sparse-checkout: ''
|
||||||
|
|
||||||
|
# Specifies whether to use cone-mode when doing a sparse checkout.
|
||||||
|
# Default: true
|
||||||
|
sparse-checkout-cone-mode: ''
|
||||||
|
|
||||||
|
# Number of commits to fetch. 0 indicates all history for all branches and tags.
|
||||||
|
# Default: 1
|
||||||
|
fetch-depth: ''
|
||||||
|
|
||||||
|
# Whether to fetch tags, even if fetch-depth > 0.
|
||||||
|
# Default: false
|
||||||
|
fetch-tags: ''
|
||||||
|
|
||||||
|
# Whether to show progress status output when fetching.
|
||||||
|
# Default: true
|
||||||
|
show-progress: ''
|
||||||
|
|
||||||
|
# Whether to download Git-LFS files
|
||||||
|
# Default: false
|
||||||
|
lfs: ''
|
||||||
|
|
||||||
|
# Whether to checkout submodules: `true` to checkout submodules or `recursive` to
|
||||||
|
# recursively checkout submodules.
|
||||||
|
#
|
||||||
|
# When the `ssh-key` input is not provided, SSH URLs beginning with
|
||||||
|
# `git@github.com:` are converted to HTTPS.
|
||||||
|
#
|
||||||
|
# Default: false
|
||||||
|
submodules: ''
|
||||||
|
|
||||||
|
# Add repository path as safe.directory for Git global config by running `git
|
||||||
|
# config --global --add safe.directory <path>`
|
||||||
|
# Default: true
|
||||||
|
set-safe-directory: ''
|
||||||
|
|
||||||
|
# The base URL for the GitHub instance that you are trying to clone from, will use
|
||||||
|
# environment defaults to fetch from the same instance that the workflow is
|
||||||
|
# running from unless specified. Example URLs are https://github.com or
|
||||||
|
# https://my-ghes-server.example.com
|
||||||
|
github-server-url: ''
|
||||||
@@ -346,58 +346,8 @@ class GitAuthHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async removeToken(): Promise<void> {
|
private async removeToken(): Promise<void> {
|
||||||
// Remove HTTP extra header from local git config and submodule configs
|
// HTTP extra header
|
||||||
await this.removeGitConfig(this.tokenConfigKey)
|
await this.removeGitConfig(this.tokenConfigKey)
|
||||||
|
|
||||||
//
|
|
||||||
// Cleanup actions/checkout@v6 style credentials
|
|
||||||
//
|
|
||||||
const skipV6Cleanup = process.env['ACTIONS_CHECKOUT_SKIP_V6_CLEANUP']
|
|
||||||
if (skipV6Cleanup === '1' || skipV6Cleanup?.toLowerCase() === 'true') {
|
|
||||||
core.debug(
|
|
||||||
'Skipping v6 style cleanup due to ACTIONS_CHECKOUT_SKIP_V6_CLEANUP'
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Collect credentials config paths that need to be removed
|
|
||||||
const credentialsPaths = new Set<string>()
|
|
||||||
|
|
||||||
// Remove includeIf entries that point to git-credentials-*.config files
|
|
||||||
const mainCredentialsPaths = await this.removeIncludeIfCredentials()
|
|
||||||
mainCredentialsPaths.forEach(path => credentialsPaths.add(path))
|
|
||||||
|
|
||||||
// Remove submodule includeIf entries that point to git-credentials-*.config files
|
|
||||||
try {
|
|
||||||
const submoduleConfigPaths =
|
|
||||||
await this.git.getSubmoduleConfigPaths(true)
|
|
||||||
for (const configPath of submoduleConfigPaths) {
|
|
||||||
const submoduleCredentialsPaths =
|
|
||||||
await this.removeIncludeIfCredentials(configPath)
|
|
||||||
submoduleCredentialsPaths.forEach(path => credentialsPaths.add(path))
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
core.debug(`Unable to get submodule config paths: ${err}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove credentials config files
|
|
||||||
for (const credentialsPath of credentialsPaths) {
|
|
||||||
// Only remove credentials config files if they are under RUNNER_TEMP
|
|
||||||
const runnerTemp = process.env['RUNNER_TEMP']
|
|
||||||
if (runnerTemp && credentialsPath.startsWith(runnerTemp)) {
|
|
||||||
try {
|
|
||||||
await io.rmRF(credentialsPath)
|
|
||||||
} catch (err) {
|
|
||||||
core.debug(
|
|
||||||
`Failed to remove credentials config '${credentialsPath}': ${err}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
core.debug(`Failed to cleanup v6 style credentials: ${err}`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async removeGitConfig(
|
private async removeGitConfig(
|
||||||
@@ -421,59 +371,4 @@ class GitAuthHelper {
|
|||||||
true
|
true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes includeIf entries that point to git-credentials-*.config files.
|
|
||||||
* This handles cleanup of credentials configured by newer versions of the action.
|
|
||||||
* @param configPath Optional path to a specific git config file to operate on
|
|
||||||
* @returns Array of unique credentials config file paths that were found and removed
|
|
||||||
*/
|
|
||||||
private async removeIncludeIfCredentials(
|
|
||||||
configPath?: string
|
|
||||||
): Promise<string[]> {
|
|
||||||
const credentialsPaths = new Set<string>()
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Get all includeIf.gitdir keys
|
|
||||||
const keys = await this.git.tryGetConfigKeys(
|
|
||||||
'^includeIf\\.gitdir:',
|
|
||||||
false, // globalConfig?
|
|
||||||
configPath
|
|
||||||
)
|
|
||||||
|
|
||||||
for (const key of keys) {
|
|
||||||
// Get all values for this key
|
|
||||||
const values = await this.git.tryGetConfigValues(
|
|
||||||
key,
|
|
||||||
false, // globalConfig?
|
|
||||||
configPath
|
|
||||||
)
|
|
||||||
if (values.length > 0) {
|
|
||||||
// Remove only values that match git-credentials-<uuid>.config pattern
|
|
||||||
for (const value of values) {
|
|
||||||
if (this.testCredentialsConfigPath(value)) {
|
|
||||||
credentialsPaths.add(value)
|
|
||||||
await this.git.tryConfigUnsetValue(key, value, false, configPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// Ignore errors - this is cleanup code
|
|
||||||
core.debug(
|
|
||||||
`Error during includeIf cleanup${configPath ? ` for ${configPath}` : ''}: ${err}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.from(credentialsPaths)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests if a path matches the git-credentials-*.config pattern used by newer versions.
|
|
||||||
* @param path The path to test
|
|
||||||
* @returns True if the path matches the credentials config pattern
|
|
||||||
*/
|
|
||||||
private testCredentialsConfigPath(path: string): boolean {
|
|
||||||
return /git-credentials-[0-9a-f-]+\.config$/i.test(path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ export interface IGitCommandManager {
|
|||||||
}
|
}
|
||||||
): Promise<void>
|
): Promise<void>
|
||||||
getDefaultBranch(repositoryUrl: string): Promise<string>
|
getDefaultBranch(repositoryUrl: string): Promise<string>
|
||||||
getSubmoduleConfigPaths(recursive: boolean): Promise<string[]>
|
|
||||||
getWorkingDirectory(): string
|
getWorkingDirectory(): string
|
||||||
init(): Promise<void>
|
init(): Promise<void>
|
||||||
isDetached(): Promise<boolean>
|
isDetached(): Promise<boolean>
|
||||||
@@ -60,24 +59,8 @@ export interface IGitCommandManager {
|
|||||||
tagExists(pattern: string): Promise<boolean>
|
tagExists(pattern: string): Promise<boolean>
|
||||||
tryClean(): Promise<boolean>
|
tryClean(): Promise<boolean>
|
||||||
tryConfigUnset(configKey: string, globalConfig?: boolean): Promise<boolean>
|
tryConfigUnset(configKey: string, globalConfig?: boolean): Promise<boolean>
|
||||||
tryConfigUnsetValue(
|
|
||||||
configKey: string,
|
|
||||||
configValue: string,
|
|
||||||
globalConfig?: boolean,
|
|
||||||
configFile?: string
|
|
||||||
): Promise<boolean>
|
|
||||||
tryDisableAutomaticGarbageCollection(): Promise<boolean>
|
tryDisableAutomaticGarbageCollection(): Promise<boolean>
|
||||||
tryGetFetchUrl(): Promise<string>
|
tryGetFetchUrl(): Promise<string>
|
||||||
tryGetConfigValues(
|
|
||||||
configKey: string,
|
|
||||||
globalConfig?: boolean,
|
|
||||||
configFile?: string
|
|
||||||
): Promise<string[]>
|
|
||||||
tryGetConfigKeys(
|
|
||||||
pattern: string,
|
|
||||||
globalConfig?: boolean,
|
|
||||||
configFile?: string
|
|
||||||
): Promise<string[]>
|
|
||||||
tryReset(): Promise<boolean>
|
tryReset(): Promise<boolean>
|
||||||
version(): Promise<GitVersion>
|
version(): Promise<GitVersion>
|
||||||
}
|
}
|
||||||
@@ -340,21 +323,6 @@ class GitCommandManager {
|
|||||||
throw new Error('Unexpected output when retrieving default branch')
|
throw new Error('Unexpected output when retrieving default branch')
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSubmoduleConfigPaths(recursive: boolean): Promise<string[]> {
|
|
||||||
// Get submodule config file paths.
|
|
||||||
// Use `--show-origin` to get the config file path for each submodule.
|
|
||||||
const output = await this.submoduleForeach(
|
|
||||||
`git config --local --show-origin --name-only --get-regexp remote.origin.url`,
|
|
||||||
recursive
|
|
||||||
)
|
|
||||||
|
|
||||||
// Extract config file paths from the output (lines starting with "file:").
|
|
||||||
const configPaths =
|
|
||||||
output.match(/(?<=(^|\n)file:)[^\t]+(?=\tremote\.origin\.url)/g) || []
|
|
||||||
|
|
||||||
return configPaths
|
|
||||||
}
|
|
||||||
|
|
||||||
getWorkingDirectory(): string {
|
getWorkingDirectory(): string {
|
||||||
return this.workingDirectory
|
return this.workingDirectory
|
||||||
}
|
}
|
||||||
@@ -487,24 +455,6 @@ class GitCommandManager {
|
|||||||
return output.exitCode === 0
|
return output.exitCode === 0
|
||||||
}
|
}
|
||||||
|
|
||||||
async tryConfigUnsetValue(
|
|
||||||
configKey: string,
|
|
||||||
configValue: string,
|
|
||||||
globalConfig?: boolean,
|
|
||||||
configFile?: string
|
|
||||||
): Promise<boolean> {
|
|
||||||
const args = ['config']
|
|
||||||
if (configFile) {
|
|
||||||
args.push('--file', configFile)
|
|
||||||
} else {
|
|
||||||
args.push(globalConfig ? '--global' : '--local')
|
|
||||||
}
|
|
||||||
args.push('--unset', configKey, configValue)
|
|
||||||
|
|
||||||
const output = await this.execGit(args, true)
|
|
||||||
return output.exitCode === 0
|
|
||||||
}
|
|
||||||
|
|
||||||
async tryDisableAutomaticGarbageCollection(): Promise<boolean> {
|
async tryDisableAutomaticGarbageCollection(): Promise<boolean> {
|
||||||
const output = await this.execGit(
|
const output = await this.execGit(
|
||||||
['config', '--local', 'gc.auto', '0'],
|
['config', '--local', 'gc.auto', '0'],
|
||||||
@@ -531,56 +481,6 @@ class GitCommandManager {
|
|||||||
return stdout
|
return stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
async tryGetConfigValues(
|
|
||||||
configKey: string,
|
|
||||||
globalConfig?: boolean,
|
|
||||||
configFile?: string
|
|
||||||
): Promise<string[]> {
|
|
||||||
const args = ['config']
|
|
||||||
if (configFile) {
|
|
||||||
args.push('--file', configFile)
|
|
||||||
} else {
|
|
||||||
args.push(globalConfig ? '--global' : '--local')
|
|
||||||
}
|
|
||||||
args.push('--get-all', configKey)
|
|
||||||
|
|
||||||
const output = await this.execGit(args, true)
|
|
||||||
|
|
||||||
if (output.exitCode !== 0) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return output.stdout
|
|
||||||
.trim()
|
|
||||||
.split('\n')
|
|
||||||
.filter(value => value.trim())
|
|
||||||
}
|
|
||||||
|
|
||||||
async tryGetConfigKeys(
|
|
||||||
pattern: string,
|
|
||||||
globalConfig?: boolean,
|
|
||||||
configFile?: string
|
|
||||||
): Promise<string[]> {
|
|
||||||
const args = ['config']
|
|
||||||
if (configFile) {
|
|
||||||
args.push('--file', configFile)
|
|
||||||
} else {
|
|
||||||
args.push(globalConfig ? '--global' : '--local')
|
|
||||||
}
|
|
||||||
args.push('--name-only', '--get-regexp', pattern)
|
|
||||||
|
|
||||||
const output = await this.execGit(args, true)
|
|
||||||
|
|
||||||
if (output.exitCode !== 0) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return output.stdout
|
|
||||||
.trim()
|
|
||||||
.split('\n')
|
|
||||||
.filter(key => key.trim())
|
|
||||||
}
|
|
||||||
|
|
||||||
async tryReset(): Promise<boolean> {
|
async tryReset(): Promise<boolean> {
|
||||||
const output = await this.execGit(['reset', '--hard', 'HEAD'], true)
|
const output = await this.execGit(['reset', '--hard', 'HEAD'], true)
|
||||||
return output.exitCode === 0
|
return output.exitCode === 0
|
||||||
|
|||||||
Reference in New Issue
Block a user