fix: use showFileAtRefBase64 to read per-commit file contents (#3744)
* GitCommandManager: add a function to get a file's contents at a specific revision * use showFileAtRef instead of readFileBase64 * Teach GitCommandManager.exec about an object of exec parameters so we can add more * Encode the showFiletRef output as base64 out of the gate * Fix missing async for function * Use Buffer.concat to avoid issues with partial data streams * formatting --------- Co-authored-by: gustavderdrache <alex.ford@determinate.systems>
This commit is contained in:

committed by
GitHub

parent
367180cbdf
commit
dd2324fc52
@ -19,7 +19,7 @@ export async function getWorkingBaseAndType(
|
||||
): Promise<[string, WorkingBaseType]> {
|
||||
const symbolicRefResult = await git.exec(
|
||||
['symbolic-ref', 'HEAD', '--short'],
|
||||
true
|
||||
{allowAllExitCodes: true}
|
||||
)
|
||||
if (symbolicRefResult.exitCode == 0) {
|
||||
// A ref is checked out
|
||||
@ -200,7 +200,7 @@ export async function createOrUpdateBranch(
|
||||
} else {
|
||||
aopts.push('-A')
|
||||
}
|
||||
await git.exec(aopts, true)
|
||||
await git.exec(aopts, {allowAllExitCodes: true})
|
||||
const popts = ['-m', commitMessage]
|
||||
if (signoff) {
|
||||
popts.push('--signoff')
|
||||
|
@ -211,6 +211,7 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
|
||||
const stashed = await git.stashPush(['--include-untracked'])
|
||||
await git.checkout(inputs.branch)
|
||||
const pushSignedCommitsResult = await ghBranch.pushSignedCommits(
|
||||
git,
|
||||
result.branchCommits,
|
||||
result.baseCommit,
|
||||
repoPath,
|
||||
|
@ -21,6 +21,11 @@ export type Commit = {
|
||||
unparsedChanges: string[]
|
||||
}
|
||||
|
||||
export type ExecOpts = {
|
||||
allowAllExitCodes?: boolean
|
||||
encoding?: 'utf8' | 'base64'
|
||||
}
|
||||
|
||||
export class GitCommandManager {
|
||||
private gitPath: string
|
||||
private workingDirectory: string
|
||||
@ -66,7 +71,7 @@ export class GitCommandManager {
|
||||
args.push(...options)
|
||||
}
|
||||
|
||||
return await this.exec(args, allowAllExitCodes)
|
||||
return await this.exec(args, {allowAllExitCodes: allowAllExitCodes})
|
||||
}
|
||||
|
||||
async commit(
|
||||
@ -82,7 +87,7 @@ export class GitCommandManager {
|
||||
args.push(...options)
|
||||
}
|
||||
|
||||
return await this.exec(args, allowAllExitCodes)
|
||||
return await this.exec(args, {allowAllExitCodes: allowAllExitCodes})
|
||||
}
|
||||
|
||||
async config(
|
||||
@ -113,7 +118,7 @@ export class GitCommandManager {
|
||||
configKey,
|
||||
configValue
|
||||
],
|
||||
true
|
||||
{allowAllExitCodes: true}
|
||||
)
|
||||
return output.exitCode === 0
|
||||
}
|
||||
@ -222,7 +227,7 @@ export class GitCommandManager {
|
||||
if (options) {
|
||||
args.push(...options)
|
||||
}
|
||||
const output = await this.exec(args, true)
|
||||
const output = await this.exec(args, {allowAllExitCodes: true})
|
||||
return output.exitCode === 1
|
||||
}
|
||||
|
||||
@ -278,6 +283,12 @@ export class GitCommandManager {
|
||||
return output.stdout.trim()
|
||||
}
|
||||
|
||||
async showFileAtRefBase64(ref: string, path: string): Promise<string> {
|
||||
const args = ['show', `${ref}:${path}`]
|
||||
const output = await this.exec(args, {encoding: 'base64'})
|
||||
return output.stdout.trim()
|
||||
}
|
||||
|
||||
async stashPush(options?: string[]): Promise<boolean> {
|
||||
const args = ['stash', 'push']
|
||||
if (options) {
|
||||
@ -326,7 +337,7 @@ export class GitCommandManager {
|
||||
configKey,
|
||||
configValue
|
||||
],
|
||||
true
|
||||
{allowAllExitCodes: true}
|
||||
)
|
||||
return output.exitCode === 0
|
||||
}
|
||||
@ -334,7 +345,7 @@ export class GitCommandManager {
|
||||
async tryGetRemoteUrl(): Promise<string> {
|
||||
const output = await this.exec(
|
||||
['config', '--local', '--get', 'remote.origin.url'],
|
||||
true
|
||||
{allowAllExitCodes: true}
|
||||
)
|
||||
|
||||
if (output.exitCode !== 0) {
|
||||
@ -349,7 +360,10 @@ export class GitCommandManager {
|
||||
return stdout
|
||||
}
|
||||
|
||||
async exec(args: string[], allowAllExitCodes = false): Promise<GitOutput> {
|
||||
async exec(
|
||||
args: string[],
|
||||
{encoding = 'utf8', allowAllExitCodes = false}: ExecOpts = {}
|
||||
): Promise<GitOutput> {
|
||||
const result = new GitOutput()
|
||||
|
||||
const env = {}
|
||||
@ -357,8 +371,10 @@ export class GitCommandManager {
|
||||
env[key] = process.env[key]
|
||||
}
|
||||
|
||||
const stdout: string[] = []
|
||||
const stderr: string[] = []
|
||||
const stdout: Buffer[] = []
|
||||
let stdoutLength = 0
|
||||
const stderr: Buffer[] = []
|
||||
let stderrLength = 0
|
||||
|
||||
const options = {
|
||||
cwd: this.workingDirectory,
|
||||
@ -366,17 +382,19 @@ export class GitCommandManager {
|
||||
ignoreReturnCode: allowAllExitCodes,
|
||||
listeners: {
|
||||
stdout: (data: Buffer) => {
|
||||
stdout.push(data.toString())
|
||||
stdout.push(data)
|
||||
stdoutLength += data.length
|
||||
},
|
||||
stderr: (data: Buffer) => {
|
||||
stderr.push(data.toString())
|
||||
stderr.push(data)
|
||||
stderrLength += data.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.exitCode = await exec.exec(`"${this.gitPath}"`, args, options)
|
||||
result.stdout = stdout.join('')
|
||||
result.stderr = stderr.join('')
|
||||
result.stdout = Buffer.concat(stdout, stdoutLength).toString(encoding)
|
||||
result.stderr = Buffer.concat(stderr, stderrLength).toString(encoding)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as core from '@actions/core'
|
||||
import {Inputs} from './create-pull-request'
|
||||
import {Commit} from './git-command-manager'
|
||||
import {Commit, GitCommandManager} from './git-command-manager'
|
||||
import {Octokit, OctokitOptions, throttleOptions} from './octokit-client'
|
||||
import pLimit from 'p-limit'
|
||||
import * as utils from './utils'
|
||||
@ -220,6 +220,7 @@ export class GitHubHelper {
|
||||
}
|
||||
|
||||
async pushSignedCommits(
|
||||
git: GitCommandManager,
|
||||
branchCommits: Commit[],
|
||||
baseCommit: Commit,
|
||||
repoPath: string,
|
||||
@ -233,6 +234,7 @@ export class GitHubHelper {
|
||||
}
|
||||
for (const commit of branchCommits) {
|
||||
headCommit = await this.createCommit(
|
||||
git,
|
||||
commit,
|
||||
headCommit,
|
||||
repoPath,
|
||||
@ -244,6 +246,7 @@ export class GitHubHelper {
|
||||
}
|
||||
|
||||
private async createCommit(
|
||||
git: GitCommandManager,
|
||||
commit: Commit,
|
||||
parentCommit: CommitResponse,
|
||||
repoPath: string,
|
||||
@ -269,10 +272,10 @@ export class GitHubHelper {
|
||||
let sha: string | null = null
|
||||
if (status === 'A' || status === 'M') {
|
||||
try {
|
||||
const {data: blob} = await blobCreationLimit(() =>
|
||||
const {data: blob} = await blobCreationLimit(async () =>
|
||||
this.octokit.rest.git.createBlob({
|
||||
...repository,
|
||||
content: utils.readFileBase64([repoPath, path]),
|
||||
content: await git.showFileAtRefBase64(commit.sha, path),
|
||||
encoding: 'base64'
|
||||
})
|
||||
)
|
||||
|
10
src/utils.ts
10
src/utils.ts
@ -126,16 +126,6 @@ export function readFile(path: string): string {
|
||||
return fs.readFileSync(path, 'utf-8')
|
||||
}
|
||||
|
||||
export function readFileBase64(pathParts: string[]): string {
|
||||
const resolvedPath = path.resolve(...pathParts)
|
||||
if (fs.lstatSync(resolvedPath).isSymbolicLink()) {
|
||||
return fs
|
||||
.readlinkSync(resolvedPath, {encoding: 'buffer'})
|
||||
.toString('base64')
|
||||
}
|
||||
return fs.readFileSync(resolvedPath).toString('base64')
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
function hasErrorCode(error: any): error is {code: string} {
|
||||
return typeof (error && error.code) === 'string'
|
||||
|
Reference in New Issue
Block a user