Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: improve branch cache logic #17538

Closed
Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
4176d6e
update interfaces
RahulGautamSingh Aug 29, 2022
5687ce9
implement new logic
RahulGautamSingh Aug 30, 2022
5c1f03c
new logic flow for branch cache
RahulGautamSingh Aug 31, 2022
4fd6135
Merge branch 'main' into test/conflict
RahulGautamSingh Aug 31, 2022
5f98200
refactor
RahulGautamSingh Aug 31, 2022
9ea5550
disapply partial<T>
RahulGautamSingh Aug 31, 2022
6c9bddf
Merge branch 'main' into test/conflict
RahulGautamSingh Aug 31, 2022
e75af3d
refactor: concise comment
RahulGautamSingh Aug 31, 2022
738ea12
test: add more tests
RahulGautamSingh Aug 31, 2022
89faad0
refactor: use baseBranchName
RahulGautamSingh Aug 31, 2022
cb3de5b
refactor: update comments
RahulGautamSingh Aug 31, 2022
d8a6668
fix : lint error
RahulGautamSingh Aug 31, 2022
3466ef5
Merge branch 'main' into test/conflict
RahulGautamSingh Aug 31, 2022
e31803e
test: cover gitConflict removal
RahulGautamSingh Sep 1, 2022
13aa84d
refactor: cache-conflict code
RahulGautamSingh Sep 1, 2022
fd835d3
use truthy checks instead of falsy
RahulGautamSingh Sep 1, 2022
3c6be15
Merge branch 'main' into test/conflict
RahulGautamSingh Sep 1, 2022
0f29ba4
test: add set-branch-sha.spec.ts
RahulGautamSingh Sep 1, 2022
4d72d3f
Update lib/util/git/conflicts-cache.ts
RahulGautamSingh Sep 2, 2022
436b53d
feat: update isBranchBehindBase cache-logic
RahulGautamSingh Sep 2, 2022
529b0aa
fix: lint issue
RahulGautamSingh Sep 2, 2022
2683125
fix coverage
RahulGautamSingh Sep 2, 2022
fd5a44f
Merge branch 'main' into test/conflict
RahulGautamSingh Sep 2, 2022
b1aad2c
remove only
RahulGautamSingh Sep 2, 2022
f5e341e
apply suggestions
RahulGautamSingh Sep 4, 2022
608d343
fix coverage
RahulGautamSingh Sep 4, 2022
4b7bf77
fix coverage
RahulGautamSingh Sep 4, 2022
91c490d
Merge branch 'renovatebot:main' into test/conflict
RahulGautamSingh Sep 5, 2022
19f182a
add test for parent-sha-cache
RahulGautamSingh Sep 5, 2022
f60c542
Merge branch 'test/conflict' of https://github.com/RahulGautamSingh/r…
RahulGautamSingh Sep 5, 2022
0ad539e
fix failing tests
RahulGautamSingh Sep 5, 2022
da9d9a0
add baseBranch arg to isBranchBehindBase()
RahulGautamSingh Sep 5, 2022
f4e68df
Merge branch 'main' into test/conflict
RahulGautamSingh Sep 6, 2022
599da96
Merge branch 'main' into test/conflict
RahulGautamSingh Sep 7, 2022
632419c
update logic as per linked issue
RahulGautamSingh Sep 7, 2022
79ba5a4
pass correct argument
RahulGautamSingh Sep 7, 2022
197dd7f
update tests to fix coverage and handle new logic
RahulGautamSingh Sep 7, 2022
66a88e8
Merge branch 'main' into test/conflict
RahulGautamSingh Sep 7, 2022
817cbc3
fix coverage issue
RahulGautamSingh Sep 7, 2022
5c7aef1
Merge branch 'test/conflict' of https://github.com/RahulGautamSingh/r…
RahulGautamSingh Sep 7, 2022
badcf61
Merge branch 'main' into test/conflict
RahulGautamSingh Sep 7, 2022
7164d52
remove code that creates branch in setX fns
RahulGautamSingh Sep 9, 2022
82330d9
refactor: comments
RahulGautamSingh Sep 9, 2022
90d25b2
test: update expected log
RahulGautamSingh Sep 9, 2022
b063881
refactor: convert to pure fns
RahulGautamSingh Sep 10, 2022
54b2d65
refactor: tests + modified-cache logic flow + log msgs
RahulGautamSingh Sep 10, 2022
039dfbe
Merge branch 'main' into test/conflict
RahulGautamSingh Sep 10, 2022
67ef0d0
reactor: create branch-cache regardless of repositoryCache value
RahulGautamSingh Sep 14, 2022
c98ce6a
Merge branch 'main' into test/conflict
RahulGautamSingh Sep 14, 2022
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
7 changes: 5 additions & 2 deletions lib/util/cache/repository/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ export interface BranchUpgradeCache {
export interface BranchCache {
automerge: boolean;
branchName: string;
isModified: boolean;
isModified: boolean | null;
isConflicted: boolean | null;
prNo: number | null;
sha: string | null;
parentSha: string | null;
baseBranchName: string;
baseBranchSha: string | null; // recent baseBranch SHA
parentSha: string | null; // baseBranch SHA when branch-commit was made by bot
upgrades: BranchUpgradeCache[];
branchFingerprint?: string;
}
Expand Down
6 changes: 3 additions & 3 deletions lib/util/git/behind-base-branch-cache.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { getCache } from '../cache/repository';

// Compare cached parent Sha of a branch to the fetched base-branch sha to determine whether the branch is behind the base
// Compare cached parentSha of a branch to the fetched base-branch sha to determine whether the branch is behind the base
// Since cache is updated after each run, this will be sufficient to determine whether a branch is behind its parent.
export function getCachedBehindBaseResult(
branchName: string,
currentBaseBranchSha: string
baseBranchSha: string
): boolean | null {
const cache = getCache();
const { branches = [] } = cache;
Expand All @@ -16,5 +16,5 @@ export function getCachedBehindBaseResult(
return null;
}

return currentBaseBranchSha !== cachedBranch.parentSha;
return baseBranchSha !== cachedBranch.parentSha;
}
181 changes: 117 additions & 64 deletions lib/util/git/conflicts-cache.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mocked } from '../../../test/util';
import { mocked, partial } from '../../../test/util';
import * as _repositoryCache from '../cache/repository';
import type { RepoCacheData } from '../cache/repository/types';
import type { BranchCache, RepoCacheData } from '../cache/repository/types';
import {
getCachedConflictResult,
setCachedConflictResult,
Expand All @@ -22,119 +22,172 @@ describe('util/git/conflicts-cache', () => {
expect(getCachedConflictResult('foo', '111', 'bar', '222')).toBeNull();
});

it('returns null if target key not found', () => {
expect(getCachedConflictResult('foo', '111', 'bar', '222')).toBeNull();
it('returns null if target branch name mismatch', () => {
repoCache.branches = [
partial<BranchCache>({
baseBranchName: 'foo',
branchName: 'aaa',
sha: '444',
baseBranchSha: '121',
isConflicted: true,
}),
];
expect(
getCachedConflictResult('not_foo', '111', 'bar', '222')
).toBeNull();
});

it('returns null if target SHA has changed', () => {
repoCache.gitConflicts = {
foo: { targetBranchSha: 'aaa', sourceBranches: {} },
};
expect(getCachedConflictResult('foo', '111', 'bar', '222')).toBeNull();
repoCache.branches = [
partial<BranchCache>({
baseBranchName: 'foo',
branchName: 'aaa',
sha: '444',
baseBranchSha: '121',
isConflicted: true,
}),
];
expect(getCachedConflictResult('foo', '111', 'aaa', '444')).toBeNull();
});

it('returns null if source key not found', () => {
repoCache.gitConflicts = {
foo: { targetBranchSha: '111', sourceBranches: {} },
};
it('returns null if source branch not found', () => {
repoCache.branches = [
partial<BranchCache>({
baseBranchName: 'foo',
baseBranchSha: '121',
isConflicted: true,
}),
];
expect(getCachedConflictResult('foo', '111', 'bar', '222')).toBeNull();
});

it('returns null if source key has changed', () => {
repoCache.gitConflicts = {
foo: {
targetBranchSha: '111',
sourceBranches: {
bar: { sourceBranchSha: 'bbb', isConflicted: true },
},
},
};
it('returns null if source branch sha has changed', () => {
repoCache.branches = [
partial<BranchCache>({
baseBranchName: 'foo',
branchName: 'bar',
sha: '212',
baseBranchSha: '111',
isConflicted: true,
}),
];
expect(getCachedConflictResult('foo', '111', 'bar', '222')).toBeNull();
});

it('returns true', () => {
repoCache.gitConflicts = {
foo: {
targetBranchSha: '111',
sourceBranches: {
bar: { sourceBranchSha: '222', isConflicted: true },
},
},
};
repoCache.branches = [
partial<BranchCache>({
baseBranchName: 'foo',
branchName: 'bar',
sha: '222',
baseBranchSha: '111',
isConflicted: true,
}),
];
expect(getCachedConflictResult('foo', '111', 'bar', '222')).toBeTrue();
});

it('returns false', () => {
repoCache.branches = [
partial<BranchCache>({
baseBranchName: 'foo',
branchName: 'bar',
sha: '222',
baseBranchSha: '111',
isConflicted: false,
}),
];
expect(getCachedConflictResult('foo', '111', 'bar', '222')).toBeFalse();
});

it('returns null and removes gitConflicts', () => {
repoCache.branches = [
partial<BranchCache>({
baseBranchName: 'foo',
branchName: 'bar',
sha: '222',
baseBranchSha: '111',
isConflicted: false,
}),
];
repoCache.gitConflicts = {
foo: {
targetBranchSha: '111',
targetBranchName: {
targetBranchSha: 'target_sha',
sourceBranches: {
bar: { sourceBranchSha: '222', isConflicted: false },
sourceBranchName: {
sourceBranchSha: 'source_sha',
isConflicted: false,
},
},
},
};
expect(getCachedConflictResult('foo', '111', 'bar', '222')).toBeFalse();
expect(repoCache.gitConflicts).toBeUndefined();
});
});

describe('setCachedConflictResult', () => {
it('sets value for unpopulated cache', () => {
setCachedConflictResult('foo', '111', 'bar', '222', true);
expect(repoCache).toEqual({
gitConflicts: {
foo: {
targetBranchSha: '111',
sourceBranches: {
bar: { sourceBranchSha: '222', isConflicted: true },
},
branches: [
{
baseBranchName: 'foo',
branchName: 'bar',
sha: '222',
baseBranchSha: '111',
isConflicted: true,
},
},
],
});
});

it('replaces value when source SHA has changed', () => {
setCachedConflictResult('foo', '111', 'bar', '222', false);
it('replaces value when branch SHA has changed', () => {
setCachedConflictResult('foo', '101', 'bar', '222', false);
setCachedConflictResult('foo', '111', 'bar', '333', false);
setCachedConflictResult('foo', '111', 'bar', '444', true);
setCachedConflictResult('foo', '121', 'bar', '444', true);
expect(repoCache).toEqual({
gitConflicts: {
foo: {
targetBranchSha: '111',
sourceBranches: {
bar: { sourceBranchSha: '444', isConflicted: true },
},
branches: [
{
baseBranchName: 'foo',
branchName: 'bar',
sha: '444',
baseBranchSha: '121',
isConflicted: true,
},
},
],
});
});

it('replaces value when target SHA has changed', () => {
it('replaces value when target branch SHA has changed', () => {
setCachedConflictResult('foo', '111', 'bar', '222', false);
setCachedConflictResult('foo', 'aaa', 'bar', '222', true);
expect(repoCache).toEqual({
gitConflicts: {
foo: {
targetBranchSha: 'aaa',
sourceBranches: {
bar: { sourceBranchSha: '222', isConflicted: true },
},
branches: [
{
baseBranchName: 'foo',
branchName: 'bar',
sha: '222',
baseBranchSha: 'aaa',
isConflicted: true,
},
},
],
});
});

it('replaces value when both target and source SHA have changed', () => {
setCachedConflictResult('foo', '111', 'bar', '222', true);
setCachedConflictResult('foo', 'aaa', 'bar', 'bbb', false);
expect(repoCache).toEqual({
gitConflicts: {
foo: {
targetBranchSha: 'aaa',
sourceBranches: {
bar: { sourceBranchSha: 'bbb', isConflicted: false },
},
branches: [
{
baseBranchName: 'foo',
branchName: 'bar',
sha: 'bbb',
baseBranchSha: 'aaa',
isConflicted: false,
},
},
],
});
});
});
Expand Down
62 changes: 32 additions & 30 deletions lib/util/git/conflicts-cache.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import { getCache } from '../cache/repository';
import type { BranchCache } from '../cache/repository/types';

export function getCachedConflictResult(
targetBranchName: string,
targetBranchSha: string,
sourceBranchName: string,
sourceBranchSha: string
): boolean | null {
const { gitConflicts } = getCache();
if (!gitConflicts) {
return null;
}

const targetBranchConflicts = gitConflicts[targetBranchName];
if (targetBranchConflicts?.targetBranchSha !== targetBranchSha) {
return null;
const cache = getCache();
if (cache.gitConflicts) {
delete cache.gitConflicts;
}
cache.branches ??= [];
const branch = cache.branches.find(
(br) => br.branchName === sourceBranchName
);

const sourceBranchConflict =
targetBranchConflicts.sourceBranches[sourceBranchName];
if (sourceBranchConflict?.sourceBranchSha !== sourceBranchSha) {
return null;
if (
branch?.baseBranchName === targetBranchName &&
branch?.baseBranchSha === targetBranchSha &&
branch?.sha === sourceBranchSha
) {
return branch.isConflicted;
}

return sourceBranchConflict.isConflicted;
return null;
}

export function setCachedConflictResult(
Expand All @@ -33,24 +35,24 @@ export function setCachedConflictResult(
isConflicted: boolean
): void {
const cache = getCache();
cache.gitConflicts ??= {};
const { gitConflicts } = cache;

let targetBranchConflicts = gitConflicts[targetBranchName];
if (targetBranchConflicts?.targetBranchSha !== targetBranchSha) {
gitConflicts[targetBranchName] = {
targetBranchSha,
sourceBranches: {},
};
targetBranchConflicts = gitConflicts[targetBranchName];
cache.branches ??= [];
let branch = cache.branches.find((br) => br.branchName === sourceBranchName);

if (!branch) {
branch = {
branchName: sourceBranchName,
baseBranchName: targetBranchName,
} as BranchCache;
cache.branches?.push(branch);
}

const sourceBranchConflict =
targetBranchConflicts.sourceBranches[sourceBranchName];
if (sourceBranchConflict?.sourceBranchSha !== sourceBranchSha) {
targetBranchConflicts.sourceBranches[sourceBranchName] = {
sourceBranchSha,
isConflicted,
};
if (branch.baseBranchSha !== targetBranchSha) {
branch.baseBranchSha = targetBranchSha;
}

if (branch.sha !== sourceBranchSha) {
branch.sha = sourceBranchSha;
}

branch.isConflicted = isConflicted;
}
17 changes: 0 additions & 17 deletions lib/util/git/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,23 +315,6 @@ describe('util/git/index', () => {
});
});

describe('getBranchParentSha(branchName)', () => {
it('should return sha if found', async () => {
const parentSha = await git.getBranchParentSha('renovate/future_branch');
expect(parentSha).toHaveLength(40);
expect(parentSha).toEqual(git.getBranchCommit(defaultBranch));
});

it('should return null if not found', async () => {
expect(await git.getBranchParentSha('not_found')).toBeNull();
});

it('should return cached value', async () => {
parentShaCache.getCachedBranchParentShaResult.mockReturnValueOnce('111');
expect(await git.getBranchParentSha('not_found')).toBe('111');
});
});

describe('getBranchFiles(branchName)', () => {
it('detects changed files compared to current base branch', async () => {
const file: FileChange = {
Expand Down
Loading