mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-11 22:46:27 +00:00
feat(git): Add helpers for platform-native commit (#13955)
Co-authored-by: Rhys Arkins <rhys@arkins.net>
This commit is contained in:
parent
5ab9faf589
commit
9809ba476b
3 changed files with 85 additions and 4 deletions
|
@ -753,4 +753,29 @@ describe('util/git/index', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('pushCommitAsRef', () => {
|
||||||
|
it('creates non-branch ref', async () => {
|
||||||
|
const commit = git.getBranchCommit('develop');
|
||||||
|
await git.pushCommitAsRef(commit, 'refs/foo/bar');
|
||||||
|
const repo = Git(tmpDir.path);
|
||||||
|
const res = (await repo.raw(['ls-remote'])).split(/\s+/);
|
||||||
|
expect(res).toContain('refs/foo/bar');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('listCommitTree', () => {
|
||||||
|
it('creates non-branch ref', async () => {
|
||||||
|
const commit = git.getBranchCommit('develop');
|
||||||
|
const res = await git.listCommitTree(commit);
|
||||||
|
expect(res).toEqual([
|
||||||
|
{
|
||||||
|
mode: '100644',
|
||||||
|
path: 'past_file',
|
||||||
|
sha: '913705ab2ca79368053a476efa48aa6912d052c5',
|
||||||
|
type: 'blob',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -40,6 +40,7 @@ import type {
|
||||||
LocalConfig,
|
LocalConfig,
|
||||||
StatusResult,
|
StatusResult,
|
||||||
StorageConfig,
|
StorageConfig,
|
||||||
|
TreeItem,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export { setNoVerify } from './config';
|
export { setNoVerify } from './config';
|
||||||
|
@ -704,11 +705,12 @@ export async function prepareCommit({
|
||||||
}: CommitFilesConfig): Promise<CommitResult | null> {
|
}: CommitFilesConfig): Promise<CommitResult | null> {
|
||||||
const { localDir } = GlobalConfig.get();
|
const { localDir } = GlobalConfig.get();
|
||||||
await syncGit();
|
await syncGit();
|
||||||
logger.debug(`Preparing files for commiting to branch ${branchName}`);
|
logger.debug(`Preparing files for committing to branch ${branchName}`);
|
||||||
await handleCommitAuth(localDir);
|
await handleCommitAuth(localDir);
|
||||||
try {
|
try {
|
||||||
await git.reset(ResetMode.HARD);
|
await git.reset(ResetMode.HARD);
|
||||||
await git.raw(['clean', '-fd']);
|
await git.raw(['clean', '-fd']);
|
||||||
|
const parentCommitSha = config.currentBranchSha;
|
||||||
await git.checkout(['-B', branchName, 'origin/' + config.currentBranch]);
|
await git.checkout(['-B', branchName, 'origin/' + config.currentBranch]);
|
||||||
const deletedFiles: string[] = [];
|
const deletedFiles: string[] = [];
|
||||||
const addedModifiedFiles: string[] = [];
|
const addedModifiedFiles: string[] = [];
|
||||||
|
@ -787,7 +789,7 @@ export async function prepareCommit({
|
||||||
{ deletedFiles, ignoredFiles, result: commitRes },
|
{ deletedFiles, ignoredFiles, result: commitRes },
|
||||||
`git commit`
|
`git commit`
|
||||||
);
|
);
|
||||||
const commit = commitRes?.commit || 'unknown';
|
const commitSha = commitRes?.commit || 'unknown';
|
||||||
if (!force && !(await hasDiff(`origin/${branchName}`))) {
|
if (!force && !(await hasDiff(`origin/${branchName}`))) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
{ branchName, deletedFiles, addedModifiedFiles, ignoredFiles },
|
{ branchName, deletedFiles, addedModifiedFiles, ignoredFiles },
|
||||||
|
@ -797,7 +799,8 @@ export async function prepareCommit({
|
||||||
}
|
}
|
||||||
|
|
||||||
const result: CommitResult = {
|
const result: CommitResult = {
|
||||||
sha: commit,
|
parentCommitSha,
|
||||||
|
commitSha,
|
||||||
files: files.filter((fileChange) => {
|
files: files.filter((fileChange) => {
|
||||||
if (fileChange.type === 'deletion') {
|
if (fileChange.type === 'deletion') {
|
||||||
return deletedFiles.includes(fileChange.path);
|
return deletedFiles.includes(fileChange.path);
|
||||||
|
@ -898,3 +901,48 @@ export function getUrl({
|
||||||
pathname: repository + '.git',
|
pathname: repository + '.git',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function pushCommitAsRef(
|
||||||
|
commitSha: string,
|
||||||
|
refName: string
|
||||||
|
): Promise<void> {
|
||||||
|
await git.raw(['update-ref', refName, commitSha]);
|
||||||
|
await git.raw(['push', '--force', 'origin', refName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const treeItemRegex = regEx(
|
||||||
|
/^(?<mode>\d{6})\s+(?<type>blob|tree)\s+(?<sha>[0-9a-f]{40})\s+(?<path>.*)$/
|
||||||
|
);
|
||||||
|
|
||||||
|
const treeShaRegex = regEx(/tree\s+(?<treeSha>[0-9a-f]{40})\s*/);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* $ git cat-file -p <commit-sha>
|
||||||
|
*
|
||||||
|
* > tree <tree-sha>
|
||||||
|
* > parent 59b8b0e79319b7dc38f7a29d618628f3b44c2fd7
|
||||||
|
* > ...
|
||||||
|
*
|
||||||
|
* $ git cat-file -p <tree-sha>
|
||||||
|
*
|
||||||
|
* > 040000 tree 389400684d1f004960addc752be13097fe85d776 .devcontainer
|
||||||
|
* > 100644 blob 7d2edde437ad4e7bceb70dbfe70e93350d99c98b .editorconfig
|
||||||
|
* > ...
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export async function listCommitTree(commitSha: string): Promise<TreeItem[]> {
|
||||||
|
const commitOutput = await git.raw(['cat-file', '-p', commitSha]);
|
||||||
|
const { treeSha } = treeShaRegex.exec(commitOutput)?.groups ?? {};
|
||||||
|
const contents = await git.raw(['cat-file', '-p', treeSha]);
|
||||||
|
const lines = contents.split(newlineRegex);
|
||||||
|
const result: TreeItem[] = [];
|
||||||
|
for (const line of lines) {
|
||||||
|
const matchGroups = treeItemRegex.exec(line)?.groups;
|
||||||
|
if (matchGroups) {
|
||||||
|
const { path, mode, type, sha } = matchGroups;
|
||||||
|
result.push({ path, mode, type, sha });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -93,10 +93,18 @@ export interface SourceBranchConflict {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommitResult {
|
export interface CommitResult {
|
||||||
sha: string;
|
parentCommitSha: string;
|
||||||
|
commitSha: string;
|
||||||
files: FileChange[];
|
files: FileChange[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TreeItem {
|
||||||
|
path: string;
|
||||||
|
mode: string;
|
||||||
|
type: string;
|
||||||
|
sha: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a git authentication rule in the form of e.g.:
|
* Represents a git authentication rule in the form of e.g.:
|
||||||
* git config --global url."https://api@github.com/".insteadOf "https://github.com/"
|
* git config --global url."https://api@github.com/".insteadOf "https://github.com/"
|
||||||
|
|
Loading…
Reference in a new issue