mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-24 22:48:06 +00:00
3842ec0cf2
As noted in #46438, when a branch updates a tool constraint, i.e.
`constraints.golang` from `1.25` to `1.27`, any `postUpgradeTasks` with
`installTools` (and any artifact updates) in that branch would still use
the constraint from the base branch's config.
Similar to d6946be005, we should make sure
that a change to `constraints` results in a fingerprint change, so it's
clear that the branch needs reprocessing.
Although we'd excluded `postUpgradeTasks[].installTools` at that point,
we need to take them into account now, as they can affect the contents
of the branch, especially when changing `constraints`' current values.
This only includes known Containerbase tools, to avoid branch
fingerprint changes on unrelated `constraints` like `ghActionsLock`.
Co-authored-by: Claude Opus 5.5 <jamie.tanna+amp@mend.io>
Co-authored-by: Claude Sonnet 5.5 <jamie.tanna+claude-code@mend.io>
768 lines
23 KiB
TypeScript
768 lines
23 KiB
TypeScript
import { isString } from '@sindresorhus/is';
|
|
import { DateTime } from 'luxon';
|
|
import type { RenovateConfig } from '~test/util.ts';
|
|
import { fakeSha, logger, partial, scm } from '~test/util.ts';
|
|
import { getConfig } from '../../../config/defaults.ts';
|
|
import { GlobalConfig } from '../../../config/global.ts';
|
|
import { addMeta } from '../../../logger/index.ts';
|
|
import { hashMap } from '../../../modules/manager/index.ts';
|
|
import * as _repoCache from '../../../util/cache/repository/index.ts';
|
|
import type {
|
|
BranchCache,
|
|
RepoCacheData,
|
|
} from '../../../util/cache/repository/types.ts';
|
|
import { fingerprint } from '../../../util/fingerprint.ts';
|
|
import { counts } from '../../global/limits.ts';
|
|
import type { BranchConfig, BranchUpgradeConfig } from '../../types.ts';
|
|
import * as _branchWorker from '../update/branch/index.ts';
|
|
import * as _limits from './limits.ts';
|
|
import {
|
|
compareCacheFingerprint,
|
|
generateCommitFingerprintConfig,
|
|
syncBranchState,
|
|
writeUpdates,
|
|
} from './write.ts';
|
|
|
|
vi.mock('../../../util/cache/repository/index.ts');
|
|
vi.mock('./limits.ts');
|
|
vi.mock('../update/branch/index.ts');
|
|
|
|
const branchWorker = vi.mocked(_branchWorker);
|
|
const limits = vi.mocked(_limits);
|
|
const repoCache = vi.mocked(_repoCache);
|
|
|
|
let config: RenovateConfig;
|
|
|
|
const branchSha = fakeSha('sha');
|
|
const baseBranchSha = fakeSha('base_sha');
|
|
const newBranchSha = fakeSha('new_sha');
|
|
const newBaseBranchSha = fakeSha('new_base_sha');
|
|
|
|
beforeEach(() => {
|
|
config = getConfig();
|
|
counts.clear();
|
|
repoCache.getCache.mockReturnValue({});
|
|
limits.getConcurrentPrsCount.mockResolvedValue(0);
|
|
limits.getConcurrentBranchesCount.mockResolvedValue(0);
|
|
limits.getPrHourlyCount.mockResolvedValue(0);
|
|
limits.getCommitsHourlyCount.mockResolvedValue(0);
|
|
});
|
|
|
|
describe('workers/repository/process/write', () => {
|
|
describe('writeUpdates()', () => {
|
|
it('stops after automerge', async () => {
|
|
const branches: BranchConfig[] = [
|
|
{
|
|
branchName: 'test_branch',
|
|
baseBranch: 'base',
|
|
manager: 'npm',
|
|
upgrades: [],
|
|
},
|
|
{
|
|
branchName: 'test_branch',
|
|
baseBranch: 'base',
|
|
manager: 'npm',
|
|
upgrades: [],
|
|
},
|
|
{
|
|
branchName: 'test_branch',
|
|
baseBranch: 'base',
|
|
manager: 'npm',
|
|
automergeType: 'pr-comment',
|
|
ignoreTests: true,
|
|
upgrades: [],
|
|
},
|
|
{
|
|
branchName: 'test_branch',
|
|
baseBranch: 'base',
|
|
manager: 'npm',
|
|
upgrades: [],
|
|
},
|
|
{
|
|
branchName: 'test_branch',
|
|
baseBranch: 'base',
|
|
manager: 'npm',
|
|
upgrades: [],
|
|
},
|
|
];
|
|
scm.branchExists.mockResolvedValue(true);
|
|
branchWorker.processBranch.mockResolvedValueOnce({
|
|
branchExists: true,
|
|
result: 'pr-created',
|
|
});
|
|
branchWorker.processBranch.mockResolvedValueOnce({
|
|
branchExists: false,
|
|
result: 'already-existed',
|
|
});
|
|
branchWorker.processBranch.mockResolvedValueOnce({
|
|
branchExists: false,
|
|
result: 'automerged',
|
|
});
|
|
branchWorker.processBranch.mockResolvedValueOnce({
|
|
branchExists: false,
|
|
result: 'automerged',
|
|
});
|
|
GlobalConfig.set({ dryRun: 'full' });
|
|
const res = await writeUpdates(config, branches);
|
|
expect(res).toBe('automerged');
|
|
expect(branchWorker.processBranch).toHaveBeenCalledTimes(4);
|
|
});
|
|
|
|
it('counts vulnerability alert branches separately', async () => {
|
|
const branches = partial<BranchConfig[]>([
|
|
{
|
|
baseBranch: 'main',
|
|
branchName: 'regular',
|
|
upgrades: partial<BranchUpgradeConfig>([{ prConcurrentLimit: 10 }]),
|
|
manager: 'npm',
|
|
},
|
|
{
|
|
baseBranch: 'main',
|
|
branchName: 'vulnerability',
|
|
isVulnerabilityAlert: true,
|
|
upgrades: partial<BranchUpgradeConfig>([{ prConcurrentLimit: 10 }]),
|
|
manager: 'npm',
|
|
},
|
|
]);
|
|
repoCache.getCache.mockReturnValueOnce({});
|
|
branchWorker.processBranch.mockResolvedValue({
|
|
branchExists: true,
|
|
result: 'pr-created',
|
|
});
|
|
// each branch is checked twice: before processing, then after
|
|
scm.branchExists
|
|
.mockResolvedValueOnce(false)
|
|
.mockResolvedValueOnce(true)
|
|
.mockResolvedValueOnce(false)
|
|
.mockResolvedValue(true);
|
|
GlobalConfig.set({ dryRun: 'full' });
|
|
|
|
await writeUpdates(config, branches);
|
|
|
|
expect(counts.get('Branches')).toBe(1);
|
|
expect(counts.get('VulnerabilityBranches')).toBe(1);
|
|
expect(limits.getConcurrentPrsCount).toHaveBeenCalledWith(config, [
|
|
branches[0],
|
|
]);
|
|
expect(limits.getConcurrentPrsCount).toHaveBeenCalledWith(config, [
|
|
branches[1],
|
|
]);
|
|
expect(limits.getConcurrentBranchesCount).toHaveBeenCalledWith([
|
|
branches[0],
|
|
]);
|
|
expect(limits.getConcurrentBranchesCount).toHaveBeenCalledWith([
|
|
branches[1],
|
|
]);
|
|
});
|
|
|
|
it('increments branch counter', async () => {
|
|
const branchName = 'branchName';
|
|
const branches = partial<BranchConfig[]>([
|
|
{
|
|
baseBranch: 'main',
|
|
branchName,
|
|
upgrades: partial<BranchUpgradeConfig>([{ prConcurrentLimit: 10 }]),
|
|
manager: 'npm',
|
|
},
|
|
{
|
|
baseBranch: 'dev',
|
|
branchName,
|
|
upgrades: partial<BranchUpgradeConfig>([{ prConcurrentLimit: 10 }]),
|
|
manager: 'npm',
|
|
},
|
|
]);
|
|
repoCache.getCache.mockReturnValueOnce({});
|
|
branchWorker.processBranch.mockResolvedValueOnce({
|
|
branchExists: true,
|
|
result: 'pr-created',
|
|
});
|
|
|
|
limits.getConcurrentPrsCount.mockResolvedValue(0);
|
|
limits.getConcurrentBranchesCount.mockResolvedValue(0);
|
|
limits.getPrHourlyCount.mockResolvedValue(0);
|
|
|
|
scm.branchExists.mockResolvedValueOnce(false).mockResolvedValue(true);
|
|
GlobalConfig.set({ dryRun: 'full' });
|
|
config.baseBranchPatterns = ['main', 'dev'];
|
|
await writeUpdates(config, branches);
|
|
expect(counts.get('Branches')).toBe(1);
|
|
expect(addMeta).toHaveBeenNthCalledWith(1, {
|
|
baseBranch: 'main',
|
|
branch: branchName,
|
|
});
|
|
expect(addMeta).toHaveBeenNthCalledWith(2, {
|
|
baseBranch: 'dev',
|
|
branch: branchName,
|
|
});
|
|
});
|
|
|
|
it('return no-work if branch fingerprint is not different', async () => {
|
|
const branches: BranchConfig[] = [
|
|
{
|
|
branchName: 'new/some-branch',
|
|
baseBranch: 'base',
|
|
manager: 'npm',
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'npm',
|
|
}),
|
|
],
|
|
},
|
|
];
|
|
repoCache.getCache.mockReturnValueOnce({
|
|
branches: [
|
|
partial<BranchCache>({
|
|
branchName: 'new/some-branch',
|
|
sha: '111',
|
|
commitFingerprint: '111',
|
|
}),
|
|
],
|
|
});
|
|
branchWorker.processBranch.mockResolvedValueOnce({
|
|
branchExists: true,
|
|
result: 'no-work',
|
|
});
|
|
await expect(writeUpdates(config, branches)).resolves.toBe('done');
|
|
});
|
|
|
|
it('updates branch fingerprint when new commit is made', async () => {
|
|
const branches: BranchConfig[] = [
|
|
{
|
|
branchName: 'new/some-branch',
|
|
baseBranch: 'base',
|
|
manager: 'npm',
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'unknown-manager',
|
|
}),
|
|
],
|
|
},
|
|
];
|
|
repoCache.getCache.mockReturnValueOnce({
|
|
branches: [
|
|
partial<BranchCache>({
|
|
branchName: 'new/some-branch',
|
|
commitFingerprint: '222',
|
|
}),
|
|
],
|
|
});
|
|
branchWorker.processBranch.mockResolvedValueOnce({
|
|
branchExists: true,
|
|
updatesVerified: true,
|
|
result: 'done',
|
|
commitSha: 'some-value',
|
|
});
|
|
const branch = branches[0];
|
|
const managers = [
|
|
...new Set(
|
|
branch.upgrades
|
|
.map((upgrade) => hashMap.get(upgrade.manager) ?? upgrade.manager)
|
|
.filter(isString),
|
|
),
|
|
].sort();
|
|
const commitFingerprint = fingerprint({
|
|
commitFingerprintConfig: generateCommitFingerprintConfig(branch),
|
|
managers,
|
|
});
|
|
await expect(writeUpdates(config, branches)).resolves.toBe('done');
|
|
expect(branch.commitFingerprint).toBe(commitFingerprint);
|
|
});
|
|
|
|
it('caches same fingerprint when no commit is made and branch cache existed', async () => {
|
|
const branches: BranchConfig[] = [
|
|
{
|
|
branchName: 'new/some-branch',
|
|
baseBranch: 'base_branch',
|
|
manager: 'npm',
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'unknown-manager',
|
|
}),
|
|
],
|
|
},
|
|
];
|
|
const branch = branches[0];
|
|
const managers = [
|
|
...new Set(
|
|
branch.upgrades
|
|
.map((upgrade) => hashMap.get(upgrade.manager) ?? upgrade.manager)
|
|
.filter(isString),
|
|
),
|
|
].sort();
|
|
|
|
const commitFingerprint = fingerprint({
|
|
branch,
|
|
managers,
|
|
});
|
|
repoCache.getCache.mockReturnValueOnce({
|
|
branches: [
|
|
partial<BranchCache>({
|
|
branchName: 'new/some-branch',
|
|
baseBranch: 'base_branch',
|
|
commitFingerprint,
|
|
}),
|
|
],
|
|
});
|
|
branchWorker.processBranch.mockResolvedValueOnce({
|
|
branchExists: true,
|
|
result: 'done',
|
|
});
|
|
scm.branchExists.mockResolvedValue(true);
|
|
config.repositoryCache = 'enabled';
|
|
await expect(writeUpdates(config, branches)).resolves.toBe('done');
|
|
expect(branch.commitFingerprint).toBe(commitFingerprint);
|
|
});
|
|
|
|
it('caches same fingerprint when no commit is made', async () => {
|
|
const branches: BranchConfig[] = [
|
|
{
|
|
branchName: 'new/some-branch',
|
|
baseBranch: 'base_branch',
|
|
manager: 'npm',
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'unknown-manager',
|
|
}),
|
|
],
|
|
},
|
|
];
|
|
const branch = branches[0];
|
|
const managers = [
|
|
...new Set(
|
|
branch.upgrades
|
|
.map((upgrade) => hashMap.get(upgrade.manager) ?? upgrade.manager)
|
|
.filter(isString),
|
|
),
|
|
].sort();
|
|
const commitFingerprint = fingerprint({
|
|
branch,
|
|
managers,
|
|
});
|
|
repoCache.getCache.mockReturnValueOnce({
|
|
branches: [
|
|
partial<BranchCache>({
|
|
branchName: 'new/some-branch',
|
|
baseBranch: 'base_branch',
|
|
commitFingerprint,
|
|
}),
|
|
],
|
|
});
|
|
branchWorker.processBranch.mockResolvedValueOnce({
|
|
branchExists: true,
|
|
result: 'done',
|
|
});
|
|
await expect(writeUpdates(config, branches)).resolves.toBe('done');
|
|
expect(branch.commitFingerprint).toBe(commitFingerprint);
|
|
});
|
|
|
|
it('creates new branchCache when cache is not enabled', async () => {
|
|
const branches: BranchConfig[] = [
|
|
{
|
|
branchName: 'new/some-branch',
|
|
baseBranch: 'base_branch',
|
|
manager: 'npm',
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'npm',
|
|
}),
|
|
],
|
|
},
|
|
];
|
|
const repoCacheObj = partial<RepoCacheData>();
|
|
repoCache.getCache.mockReturnValueOnce(repoCacheObj);
|
|
branchWorker.processBranch.mockResolvedValueOnce({
|
|
branchExists: true,
|
|
result: 'no-work',
|
|
});
|
|
scm.getBranchCommit
|
|
.mockResolvedValueOnce(branchSha)
|
|
.mockResolvedValueOnce(baseBranchSha);
|
|
scm.branchExists.mockResolvedValueOnce(true);
|
|
await writeUpdates(config, branches);
|
|
expect(logger.logger.debug).not.toHaveBeenCalledWith(
|
|
'No branch cache found for new/some-branch',
|
|
);
|
|
expect(repoCacheObj).toEqual({
|
|
branches: [
|
|
{
|
|
branchName: 'new/some-branch',
|
|
baseBranch: 'base_branch',
|
|
baseBranchSha,
|
|
sha: branchSha,
|
|
},
|
|
],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('generateCommitFingerprintConfig()', () => {
|
|
it('does not include postUpgradeTasks when not set', () => {
|
|
const branch = partial<BranchConfig>({
|
|
upgrades: [partial<BranchUpgradeConfig>({ manager: 'npm' })],
|
|
});
|
|
const [res] = generateCommitFingerprintConfig(branch);
|
|
expect(res.postUpgradeTasks).toBeUndefined();
|
|
});
|
|
|
|
it('includes postUpgradeTasks commands and fileFilters', () => {
|
|
const branch = partial<BranchConfig>({
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'npm',
|
|
postUpgradeTasks: {
|
|
commands: ['echo hello'],
|
|
fileFilters: ['**/*.txt'],
|
|
executionMode: 'update',
|
|
installTools: { node: {} },
|
|
},
|
|
}),
|
|
],
|
|
});
|
|
const [res] = generateCommitFingerprintConfig(branch);
|
|
expect(res.postUpgradeTasks).toEqual({
|
|
commands: ['echo hello'],
|
|
fileFilters: ['**/*.txt'],
|
|
installTools: { node: {} },
|
|
});
|
|
});
|
|
|
|
it('includes only the constraints for tools', () => {
|
|
const branch = partial<BranchConfig>({
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'gomod',
|
|
constraints: {
|
|
golang: '1.27',
|
|
// not a Containerbase tool, so won't be included
|
|
ghActionsLock: 'v0.3.0',
|
|
},
|
|
}),
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'github-actions',
|
|
constraints: { ghActionsLock: 'v0.3.0' },
|
|
}),
|
|
],
|
|
});
|
|
const [withTool, withoutTool] = generateCommitFingerprintConfig(branch);
|
|
expect(withTool.constraints).toEqual({ golang: '1.27' });
|
|
expect(withoutTool).not.toHaveProperty('constraints');
|
|
});
|
|
|
|
it('changes fingerprint when a tool constraint changes', () => {
|
|
const branch125 = partial<BranchConfig>({
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'gomod',
|
|
constraints: { golang: '1.25' },
|
|
}),
|
|
],
|
|
});
|
|
const branch127 = partial<BranchConfig>({
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'gomod',
|
|
constraints: { golang: '1.27' },
|
|
}),
|
|
],
|
|
});
|
|
expect(fingerprint(generateCommitFingerprintConfig(branch125))).not.toBe(
|
|
fingerprint(generateCommitFingerprintConfig(branch127)),
|
|
);
|
|
});
|
|
|
|
it('changes fingerprint when postUpgradeTasks installTools change', () => {
|
|
const branchWithoutTools = partial<BranchConfig>({
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'npm',
|
|
postUpgradeTasks: {
|
|
commands: ['echo hello'],
|
|
executionMode: 'update',
|
|
},
|
|
}),
|
|
],
|
|
});
|
|
const branchWithTools = partial<BranchConfig>({
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'npm',
|
|
postUpgradeTasks: {
|
|
commands: ['echo hello'],
|
|
executionMode: 'update',
|
|
installTools: { node: {} },
|
|
},
|
|
}),
|
|
],
|
|
});
|
|
expect(
|
|
fingerprint(generateCommitFingerprintConfig(branchWithoutTools)),
|
|
).not.toBe(fingerprint(generateCommitFingerprintConfig(branchWithTools)));
|
|
});
|
|
|
|
it('changes fingerprint when postUpgradeTasks commands change', () => {
|
|
const branchWithoutTasks = partial<BranchConfig>({
|
|
upgrades: [partial<BranchUpgradeConfig>({ manager: 'npm' })],
|
|
});
|
|
const branchWithTasks = partial<BranchConfig>({
|
|
upgrades: [
|
|
partial<BranchUpgradeConfig>({
|
|
manager: 'npm',
|
|
postUpgradeTasks: {
|
|
commands: ['echo hello'],
|
|
executionMode: 'update',
|
|
},
|
|
}),
|
|
],
|
|
});
|
|
const fingerprintWithoutTasks = fingerprint(
|
|
generateCommitFingerprintConfig(branchWithoutTasks),
|
|
);
|
|
const fingerprintWithTasks = fingerprint(
|
|
generateCommitFingerprintConfig(branchWithTasks),
|
|
);
|
|
expect(fingerprintWithoutTasks).not.toBe(fingerprintWithTasks);
|
|
});
|
|
});
|
|
|
|
describe('canSkipBranchUpdateCheck()', () => {
|
|
let branchCache: BranchCache = {
|
|
branchName: 'branch',
|
|
baseBranch: 'base',
|
|
baseBranchSha,
|
|
sha: branchSha,
|
|
upgrades: [],
|
|
automerge: false,
|
|
prNo: null,
|
|
};
|
|
|
|
it('returns false if no cache', () => {
|
|
branchCache = {
|
|
...branchCache,
|
|
branchName: 'new/some-branch',
|
|
sha: '111',
|
|
};
|
|
expect(compareCacheFingerprint(branchCache, '222')).toBe(
|
|
'no-fingerprint',
|
|
);
|
|
});
|
|
|
|
it('returns false when fingerprints are not same', () => {
|
|
branchCache = {
|
|
...branchCache,
|
|
branchName: 'new/some-branch',
|
|
sha: '111',
|
|
commitFingerprint: '211',
|
|
};
|
|
expect(compareCacheFingerprint(branchCache, '222')).toBe('no-match');
|
|
});
|
|
|
|
it('returns true', () => {
|
|
branchCache = {
|
|
...branchCache,
|
|
branchName: 'new/some-branch',
|
|
sha: '111',
|
|
commitFingerprint: '222',
|
|
};
|
|
expect(compareCacheFingerprint(branchCache, '222')).toBe('matched');
|
|
});
|
|
});
|
|
|
|
describe('syncBranchState()', () => {
|
|
it('creates minimal branch state when cache is not populated', () => {
|
|
const repoCacheObj = partial<RepoCacheData>();
|
|
repoCache.getCache.mockReturnValue(repoCacheObj);
|
|
scm.getBranchCommit.mockResolvedValueOnce(branchSha);
|
|
scm.getBranchCommit.mockResolvedValueOnce(baseBranchSha);
|
|
return expect(
|
|
syncBranchState('branch_name', 'base_branch'),
|
|
).resolves.toEqual({
|
|
branchName: 'branch_name',
|
|
sha: branchSha,
|
|
baseBranch: 'base_branch',
|
|
baseBranchSha,
|
|
});
|
|
});
|
|
|
|
it('when base branch name is different updates it and invalidates related cache', () => {
|
|
const repoCacheObj: RepoCacheData = {
|
|
branches: [
|
|
{
|
|
branchName: 'branch_name',
|
|
baseBranch: 'base_branch',
|
|
sha: branchSha,
|
|
baseBranchSha,
|
|
isModified: true,
|
|
pristine: false,
|
|
upgrades: [],
|
|
automerge: false,
|
|
prNo: null,
|
|
},
|
|
],
|
|
};
|
|
repoCache.getCache.mockReturnValue(repoCacheObj);
|
|
scm.getBranchCommit.mockResolvedValueOnce(branchSha);
|
|
scm.getBranchCommit.mockResolvedValueOnce(baseBranchSha);
|
|
return expect(
|
|
syncBranchState('branch_name', 'new_base_branch'),
|
|
).resolves.toEqual({
|
|
branchName: 'branch_name',
|
|
sha: branchSha,
|
|
baseBranch: 'new_base_branch',
|
|
baseBranchSha,
|
|
pristine: false,
|
|
upgrades: [],
|
|
automerge: false,
|
|
prNo: null,
|
|
});
|
|
});
|
|
|
|
it('when base branch sha is different updates it and invalidates related values', () => {
|
|
const repoCacheObj: RepoCacheData = {
|
|
branches: [
|
|
{
|
|
branchName: 'branch_name',
|
|
sha: branchSha,
|
|
baseBranch: 'base_branch',
|
|
baseBranchSha,
|
|
isBehindBase: true,
|
|
pristine: false,
|
|
upgrades: [],
|
|
automerge: false,
|
|
prNo: null,
|
|
},
|
|
],
|
|
};
|
|
repoCache.getCache.mockReturnValue(repoCacheObj);
|
|
scm.getBranchCommit.mockResolvedValueOnce(branchSha);
|
|
scm.getBranchCommit.mockResolvedValueOnce(newBaseBranchSha);
|
|
return expect(
|
|
syncBranchState('branch_name', 'base_branch'),
|
|
).resolves.toEqual({
|
|
branchName: 'branch_name',
|
|
sha: branchSha,
|
|
baseBranch: 'base_branch',
|
|
baseBranchSha: newBaseBranchSha,
|
|
upgrades: [],
|
|
pristine: false,
|
|
automerge: false,
|
|
prNo: null,
|
|
});
|
|
});
|
|
|
|
it('when branch sha is different updates it and invalidates related values', () => {
|
|
const repoCacheObj: RepoCacheData = {
|
|
branches: [
|
|
{
|
|
branchName: 'branch_name',
|
|
sha: branchSha,
|
|
baseBranch: 'base_branch',
|
|
baseBranchSha,
|
|
isBehindBase: true,
|
|
isModified: true,
|
|
pristine: true,
|
|
isConflicted: true,
|
|
commitFingerprint: '123',
|
|
upgrades: [],
|
|
automerge: false,
|
|
prNo: null,
|
|
},
|
|
],
|
|
};
|
|
repoCache.getCache.mockReturnValue(repoCacheObj);
|
|
scm.getBranchCommit.mockResolvedValueOnce(newBranchSha);
|
|
scm.getBranchCommit.mockResolvedValueOnce(baseBranchSha);
|
|
return expect(
|
|
syncBranchState('branch_name', 'base_branch'),
|
|
).resolves.toEqual({
|
|
branchName: 'branch_name',
|
|
sha: newBranchSha,
|
|
baseBranch: 'base_branch',
|
|
baseBranchSha,
|
|
upgrades: [],
|
|
pristine: false,
|
|
automerge: false,
|
|
prNo: null,
|
|
});
|
|
});
|
|
|
|
it('when branch sha is different updates it and sets commitTimestamp', async () => {
|
|
const repoCacheObj: RepoCacheData = {
|
|
branches: [
|
|
{
|
|
branchName: 'branch_name',
|
|
sha: branchSha,
|
|
baseBranch: 'base_branch',
|
|
baseBranchSha,
|
|
isBehindBase: true,
|
|
isModified: true,
|
|
pristine: true,
|
|
isConflicted: true,
|
|
commitFingerprint: '123',
|
|
upgrades: [],
|
|
automerge: false,
|
|
prNo: null,
|
|
},
|
|
],
|
|
};
|
|
const commitDate = DateTime.fromISO('2023-05-20T14:25:30.123Z').toUTC();
|
|
repoCache.getCache.mockReturnValue(repoCacheObj);
|
|
scm.getBranchCommit.mockResolvedValueOnce(newBranchSha);
|
|
scm.getBranchCommit.mockResolvedValueOnce(baseBranchSha);
|
|
scm.getBranchUpdateDate.mockResolvedValueOnce(commitDate);
|
|
await expect(
|
|
syncBranchState('branch_name', 'base_branch'),
|
|
).resolves.toEqual({
|
|
branchName: 'branch_name',
|
|
sha: newBranchSha,
|
|
baseBranch: 'base_branch',
|
|
baseBranchSha,
|
|
commitTimestamp: '2023-05-20T14:25:30.123Z',
|
|
upgrades: [],
|
|
pristine: false,
|
|
automerge: false,
|
|
prNo: null,
|
|
});
|
|
});
|
|
|
|
it('no change if all parameters are same', () => {
|
|
const repoCacheObj: RepoCacheData = {
|
|
branches: [
|
|
{
|
|
branchName: 'branch_name',
|
|
sha: branchSha,
|
|
baseBranch: 'base_branch',
|
|
baseBranchSha,
|
|
isBehindBase: true,
|
|
isModified: true,
|
|
isConflicted: true,
|
|
commitFingerprint: '123',
|
|
upgrades: [],
|
|
automerge: false,
|
|
prNo: null,
|
|
pristine: true,
|
|
},
|
|
],
|
|
};
|
|
repoCache.getCache.mockReturnValue(repoCacheObj);
|
|
scm.getBranchCommit.mockResolvedValueOnce(branchSha);
|
|
scm.getBranchCommit.mockResolvedValueOnce(baseBranchSha);
|
|
return expect(
|
|
syncBranchState('branch_name', 'base_branch'),
|
|
).resolves.toEqual({
|
|
branchName: 'branch_name',
|
|
sha: branchSha,
|
|
baseBranch: 'base_branch',
|
|
baseBranchSha,
|
|
isBehindBase: true,
|
|
isModified: true,
|
|
isConflicted: true,
|
|
commitFingerprint: '123',
|
|
upgrades: [],
|
|
automerge: false,
|
|
prNo: null,
|
|
pristine: true,
|
|
});
|
|
});
|
|
});
|
|
});
|