Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,7 @@ class GitConfigHelper {
this.extraheaderConfigPlaceholderValue = 'AUTHORIZATION: basic ***';
this.extraheaderConfigValueRegex = '^AUTHORIZATION:';
this.persistedExtraheaderConfigValue = '';
this.backedUpCredentialFiles = [];
this.git = git;
this.workingDirectory = this.git.getWorkingDirectory();
}
Expand Down Expand Up @@ -1182,12 +1183,16 @@ class GitConfigHelper {
return __awaiter(this, void 0, void 0, function* () {
const serverUrl = new url_1.URL(`https://${this.getGitRemote().hostname}`);
this.extraheaderConfigKey = `http.${serverUrl.origin}/.extraheader`;
// Backup checkout@v6 credential files if they exist
yield this.hideCredentialFiles();
// Save and unset persisted extraheader credential in git config if it exists
this.persistedExtraheaderConfigValue = yield this.getAndUnset();
});
}
restorePersistedAuth() {
return __awaiter(this, void 0, void 0, function* () {
// Restore checkout@v6 credential files if they were backed up
yield this.unhideCredentialFiles();
if (this.persistedExtraheaderConfigValue) {
try {
yield this.setExtraheaderConfig(this.persistedExtraheaderConfigValue);
Expand Down Expand Up @@ -1224,6 +1229,48 @@ class GitConfigHelper {
yield this.gitConfigStringReplace(this.extraheaderConfigPlaceholderValue, extraheaderConfigValue);
});
}
hideCredentialFiles() {
Copy link
Contributor Author

@ericsciple ericsciple Nov 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested E2E here:

Workflow YAML
jobs:
  test-checkout-v6:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout with v6
        uses: actions/checkout@v6

      - name: Make a test change
        run: |
          echo "Test change at $(date)" >> test-file.txt
          echo "This tests checkout@v6 compatibility"

      - name: Create Pull Request
        uses: ./
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: 'test: checkout@v6 compatibility test'
          title: 'Test: checkout@v6 compatibility'
          body: |
            Automated test of checkout@v6 compatibility fix
            
            This PR tests that create-pull-request works correctly with actions/checkout@v6
          branch: test/checkout-v6-compat
          delete-branch: true

  test-checkout-v5:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout with v5
        uses: actions/checkout@v5

      - name: Make a test change
        run: |
          echo "Test change at $(date)" >> test-file-v5.txt
          echo "This tests backward compatibility with checkout@v5"

      - name: Create Pull Request
        uses: ./
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: 'test: checkout@v5 backward compatibility test'
          title: 'Test: checkout@v5 compatibility'
          body: |
            Automated test of checkout@v5 backward compatibility
            
            This PR verifies that the fix doesn't break checkout@v5 workflows
          branch: test/checkout-v5-compat
          delete-branch: true

return __awaiter(this, void 0, void 0, function* () {
// Temporarily hide checkout@v6 credential files to avoid duplicate auth headers
const runnerTemp = process.env['RUNNER_TEMP'];
if (!runnerTemp) {
return;
}
try {
const files = yield fs.promises.readdir(runnerTemp);
for (const file of files) {
if (file.startsWith('git-credentials-') && file.endsWith('.config')) {
const sourcePath = path.join(runnerTemp, file);
const backupPath = `${sourcePath}.bak`;
yield fs.promises.rename(sourcePath, backupPath);
this.backedUpCredentialFiles.push(backupPath);
core.info(`Temporarily hiding checkout credential file: ${file} (will be restored after)`);
}
}
}
catch (e) {
// If directory doesn't exist or we can't read it, just continue
core.debug(`Could not backup credential files: ${utils.getErrorMessage(e)}`);
}
});
}
unhideCredentialFiles() {
return __awaiter(this, void 0, void 0, function* () {
// Restore checkout@v6 credential files that were backed up
for (const backupPath of this.backedUpCredentialFiles) {
try {
const originalPath = backupPath.replace(/\.bak$/, '');
yield fs.promises.rename(backupPath, originalPath);
const fileName = path.basename(originalPath);
core.info(`Restored checkout credential file: ${fileName}`);
}
catch (e) {
core.warning(`Failed to restore credential file ${backupPath}: ${utils.getErrorMessage(e)}`);
}
}
this.backedUpCredentialFiles = [];
});
}
getAndUnset() {
return __awaiter(this, void 0, void 0, function* () {
let configValue = '';
Expand Down
50 changes: 50 additions & 0 deletions src/git-config-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export class GitConfigHelper {
private extraheaderConfigPlaceholderValue = 'AUTHORIZATION: basic ***'
private extraheaderConfigValueRegex = '^AUTHORIZATION:'
private persistedExtraheaderConfigValue = ''
private backedUpCredentialFiles: string[] = []

private constructor(git: GitCommandManager) {
this.git = git
Expand Down Expand Up @@ -121,11 +122,15 @@ export class GitConfigHelper {
async savePersistedAuth(): Promise<void> {
const serverUrl = new URL(`https://${this.getGitRemote().hostname}`)
this.extraheaderConfigKey = `http.${serverUrl.origin}/.extraheader`
// Backup checkout@v6 credential files if they exist
await this.hideCredentialFiles()
// Save and unset persisted extraheader credential in git config if it exists
this.persistedExtraheaderConfigValue = await this.getAndUnset()
}

async restorePersistedAuth(): Promise<void> {
// Restore checkout@v6 credential files if they were backed up
await this.unhideCredentialFiles()
if (this.persistedExtraheaderConfigValue) {
try {
await this.setExtraheaderConfig(this.persistedExtraheaderConfigValue)
Expand Down Expand Up @@ -169,6 +174,51 @@ export class GitConfigHelper {
)
}

private async hideCredentialFiles(): Promise<void> {
// Temporarily hide checkout@v6 credential files to avoid duplicate auth headers
const runnerTemp = process.env['RUNNER_TEMP']
if (!runnerTemp) {
return
}

try {
const files = await fs.promises.readdir(runnerTemp)
for (const file of files) {
if (file.startsWith('git-credentials-') && file.endsWith('.config')) {
const sourcePath = path.join(runnerTemp, file)
const backupPath = `${sourcePath}.bak`
await fs.promises.rename(sourcePath, backupPath)
this.backedUpCredentialFiles.push(backupPath)
core.info(
`Temporarily hiding checkout credential file: ${file} (will be restored after)`
)
}
}
} catch (e) {
// If directory doesn't exist or we can't read it, just continue
core.debug(
`Could not backup credential files: ${utils.getErrorMessage(e)}`
)
}
}

private async unhideCredentialFiles(): Promise<void> {
// Restore checkout@v6 credential files that were backed up
for (const backupPath of this.backedUpCredentialFiles) {
try {
const originalPath = backupPath.replace(/\.bak$/, '')
await fs.promises.rename(backupPath, originalPath)
const fileName = path.basename(originalPath)
core.info(`Restored checkout credential file: ${fileName}`)
} catch (e) {
core.warning(
`Failed to restore credential file ${backupPath}: ${utils.getErrorMessage(e)}`
)
}
}
this.backedUpCredentialFiles = []
}

private async getAndUnset(): Promise<string> {
let configValue = ''
// Save and unset persisted extraheader credential in git config if it exists
Expand Down