mirror of https://github.com/renovatebot/renovate
319 lines
11 KiB
TypeScript
319 lines
11 KiB
TypeScript
import type { RequestError, Response } from 'got';
|
|
import type { RenovateConfig } from '../../../../../test/util';
|
|
import { partial, platform, scm } from '../../../../../test/util';
|
|
import { getConfig } from '../../../../config/defaults';
|
|
import { GlobalConfig } from '../../../../config/global';
|
|
import { logger } from '../../../../logger';
|
|
import type { PackageFile } from '../../../../modules/manager/types';
|
|
import type { Pr } from '../../../../modules/platform';
|
|
import * as memCache from '../../../../util/cache/memory';
|
|
import type { BranchConfig } from '../../../types';
|
|
import { OnboardingState } from '../common';
|
|
import { ensureOnboardingPr } from '.';
|
|
|
|
jest.mock('../../../../util/git');
|
|
|
|
describe('workers/repository/onboarding/pr/index', () => {
|
|
describe('ensureOnboardingPr()', () => {
|
|
let config: RenovateConfig;
|
|
let packageFiles: Record<string, PackageFile[]>;
|
|
let branches: BranchConfig[];
|
|
|
|
const bodyStruct = {
|
|
hash: '6aa71f8cb7b1503b883485c8f5bd564b31923b9c7fa765abe2a7338af40e03b1',
|
|
};
|
|
|
|
beforeEach(() => {
|
|
memCache.init();
|
|
config = {
|
|
...getConfig(),
|
|
errors: [],
|
|
warnings: [],
|
|
description: [],
|
|
};
|
|
packageFiles = { npm: [{ packageFile: 'package.json', deps: [] }] };
|
|
branches = [];
|
|
platform.massageMarkdown.mockImplementation((input) => input);
|
|
platform.createPr.mockResolvedValueOnce(partial<Pr>());
|
|
GlobalConfig.reset();
|
|
});
|
|
|
|
it('returns if onboarded', async () => {
|
|
config.repoIsOnboarded = true;
|
|
await expect(
|
|
ensureOnboardingPr(config, packageFiles, branches),
|
|
).resolves.not.toThrow();
|
|
expect(platform.createPr).toHaveBeenCalledTimes(0);
|
|
expect(platform.updatePr).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
it.each`
|
|
onboardingRebaseCheckbox | prUpdateRequested | expected
|
|
${false} | ${false} | ${1}
|
|
${false} | ${true} | ${1}
|
|
${true} | ${false} | ${0}
|
|
${true} | ${true} | ${1}
|
|
`(
|
|
'breaks early when onboarding ' +
|
|
'(onboardingRebaseCheckbox="$onboardingRebaseCheckbox", prUpdateRequeste="$prUpdateRequested" )',
|
|
async ({ onboardingRebaseCheckbox, prUpdateRequested, expected }) => {
|
|
config.repoIsOnboarded = false;
|
|
config.onboardingRebaseCheckbox = onboardingRebaseCheckbox;
|
|
OnboardingState.prUpdateRequested = prUpdateRequested;
|
|
await expect(
|
|
ensureOnboardingPr(config, packageFiles, branches),
|
|
).resolves.not.toThrow();
|
|
expect(platform.updatePr).toHaveBeenCalledTimes(0);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(expected);
|
|
},
|
|
);
|
|
|
|
it('creates PR', async () => {
|
|
await ensureOnboardingPr(config, packageFiles, branches);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('creates semantic PR', async () => {
|
|
await ensureOnboardingPr(
|
|
{
|
|
...config,
|
|
semanticCommitType: undefined, // should default to "chore"
|
|
semanticCommits: 'enabled',
|
|
},
|
|
packageFiles,
|
|
branches,
|
|
);
|
|
expect(platform.createPr).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
prTitle: 'chore: Configure Renovate',
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('creates PR with labels', async () => {
|
|
await ensureOnboardingPr(
|
|
{
|
|
...config,
|
|
labels: ['label'],
|
|
addLabels: ['label', 'additional-label'],
|
|
},
|
|
packageFiles,
|
|
branches,
|
|
);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(1);
|
|
expect(platform.createPr.mock.calls[0][0].labels).toEqual([
|
|
'additional-label',
|
|
'label',
|
|
]);
|
|
});
|
|
|
|
it.each`
|
|
onboardingRebaseCheckbox
|
|
${false}
|
|
${true}
|
|
`(
|
|
'creates PR with empty footer and header' +
|
|
'(onboardingRebaseCheckbox="$onboardingRebaseCheckbox")',
|
|
async ({ onboardingRebaseCheckbox }) => {
|
|
config.onboardingRebaseCheckbox = onboardingRebaseCheckbox;
|
|
OnboardingState.prUpdateRequested = true; // case 'false' is tested in "breaks early when onboarding"
|
|
await ensureOnboardingPr(
|
|
{
|
|
...config,
|
|
prHeader: '',
|
|
prFooter: '',
|
|
},
|
|
packageFiles,
|
|
branches,
|
|
);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(1);
|
|
expect(platform.createPr.mock.calls[0][0].prBody).toMatchSnapshot();
|
|
},
|
|
);
|
|
|
|
it.each`
|
|
onboardingRebaseCheckbox
|
|
${false}
|
|
${true}
|
|
`(
|
|
'creates PR with footer and header with trailing and leading newlines' +
|
|
'(onboardingRebaseCheckbox="$onboardingRebaseCheckbox")',
|
|
async ({ onboardingRebaseCheckbox }) => {
|
|
config.onboardingRebaseCheckbox = onboardingRebaseCheckbox;
|
|
OnboardingState.prUpdateRequested = true; // case 'false' is tested in "breaks early when onboarding"
|
|
await ensureOnboardingPr(
|
|
{
|
|
...config,
|
|
prHeader: '\r\r\nThis should not be the first line of the PR',
|
|
prFooter:
|
|
'There should be several empty lines at the end of the PR\r\n\n\n',
|
|
},
|
|
packageFiles,
|
|
branches,
|
|
);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(1);
|
|
expect(platform.createPr.mock.calls[0][0].prBody).toMatchSnapshot();
|
|
},
|
|
);
|
|
|
|
it.each`
|
|
onboardingRebaseCheckbox
|
|
${false}
|
|
${true}
|
|
`(
|
|
'creates PR with footer and header using templating' +
|
|
'(onboardingRebaseCheckbox="$onboardingRebaseCheckbox")',
|
|
async ({ onboardingRebaseCheckbox }) => {
|
|
config.baseBranch = 'some-branch';
|
|
config.repository = 'test';
|
|
config.onboardingRebaseCheckbox = onboardingRebaseCheckbox;
|
|
config.onboardingConfigFileName = undefined; // checks the case when fileName isn't available
|
|
OnboardingState.prUpdateRequested = true; // case 'false' is tested in "breaks early when onboarding"
|
|
await ensureOnboardingPr(
|
|
{
|
|
...config,
|
|
prHeader: 'This is a header for platform:{{platform}}',
|
|
prFooter:
|
|
'And this is a footer for repository:{{repository}} baseBranch:{{baseBranch}}',
|
|
},
|
|
packageFiles,
|
|
branches,
|
|
);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(1);
|
|
expect(platform.createPr.mock.calls[0][0].prBody).toMatch(
|
|
/platform:github/,
|
|
);
|
|
expect(platform.createPr.mock.calls[0][0].prBody).toMatch(
|
|
/repository:test/,
|
|
);
|
|
expect(platform.createPr.mock.calls[0][0].prBody).toMatchSnapshot();
|
|
},
|
|
);
|
|
|
|
it.each`
|
|
onboardingRebaseCheckbox
|
|
${false}
|
|
${true}
|
|
`(
|
|
'returns if PR does not need updating' +
|
|
'(onboardingRebaseCheckbox="$onboardingRebaseCheckbox")',
|
|
async ({ onboardingRebaseCheckbox }) => {
|
|
const hash =
|
|
'30029ee05ed80b34d2f743afda6e78fe20247a1eedaa9ce6a8070045c229ebfa'; // no rebase checkbox PR hash
|
|
config.onboardingRebaseCheckbox = onboardingRebaseCheckbox;
|
|
OnboardingState.prUpdateRequested = true; // case 'false' is tested in "breaks early when onboarding"
|
|
platform.getBranchPr.mockResolvedValue(
|
|
partial<Pr>({
|
|
title: 'Configure Renovate',
|
|
bodyStruct: onboardingRebaseCheckbox ? bodyStruct : { hash },
|
|
}),
|
|
);
|
|
await ensureOnboardingPr(config, packageFiles, branches);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(0);
|
|
expect(platform.updatePr).toHaveBeenCalledTimes(0);
|
|
},
|
|
);
|
|
|
|
it('ensures comment, when PR is conflicted', async () => {
|
|
config.baseBranch = 'some-branch';
|
|
platform.getBranchPr.mockResolvedValueOnce(
|
|
partial<Pr>({
|
|
title: 'Configure Renovate',
|
|
bodyStruct,
|
|
}),
|
|
);
|
|
scm.isBranchConflicted.mockResolvedValueOnce(true);
|
|
await ensureOnboardingPr(config, {}, branches);
|
|
expect(platform.ensureComment).toHaveBeenCalledTimes(1);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(0);
|
|
expect(platform.updatePr).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
it('updates PR when modified', async () => {
|
|
config.baseBranch = 'some-branch';
|
|
platform.getBranchPr.mockResolvedValueOnce(
|
|
partial<Pr>({
|
|
title: 'Configure Renovate',
|
|
bodyStruct,
|
|
}),
|
|
);
|
|
await ensureOnboardingPr(config, {}, branches);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(0);
|
|
expect(platform.updatePr).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('creates PR (no require config)', async () => {
|
|
config.requireConfig = 'optional';
|
|
await ensureOnboardingPr(config, packageFiles, branches);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('creates PR (require config)', async () => {
|
|
config.requireConfig = 'required';
|
|
await ensureOnboardingPr(config, packageFiles, branches);
|
|
expect(platform.createPr).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('dryrun of creates PR', async () => {
|
|
GlobalConfig.set({ dryRun: 'full' });
|
|
await ensureOnboardingPr(config, packageFiles, branches);
|
|
expect(logger.info).toHaveBeenCalledWith(
|
|
'DRY-RUN: Would check branch renovate/configure',
|
|
);
|
|
expect(logger.info).toHaveBeenLastCalledWith(
|
|
'DRY-RUN: Would create onboarding PR',
|
|
);
|
|
});
|
|
|
|
it('dryrun of updates PR', async () => {
|
|
GlobalConfig.set({ dryRun: 'full' });
|
|
platform.getBranchPr.mockResolvedValueOnce(
|
|
partial<Pr>({
|
|
title: 'Configure Renovate',
|
|
bodyStruct,
|
|
}),
|
|
);
|
|
await ensureOnboardingPr(config, packageFiles, branches);
|
|
expect(logger.info).toHaveBeenCalledWith(
|
|
'DRY-RUN: Would check branch renovate/configure',
|
|
);
|
|
expect(logger.info).toHaveBeenLastCalledWith(
|
|
'DRY-RUN: Would update onboarding PR',
|
|
);
|
|
});
|
|
|
|
describe('ensureOnboardingPr() throws', () => {
|
|
const response = partial<Response>({ statusCode: 422 });
|
|
const err = partial<RequestError>({ response });
|
|
|
|
beforeEach(() => {
|
|
GlobalConfig.reset();
|
|
scm.deleteBranch.mockResolvedValue();
|
|
platform.createPr.mockReset();
|
|
});
|
|
|
|
it('throws when trying to create a new PR', async () => {
|
|
platform.createPr.mockRejectedValueOnce(err);
|
|
await expect(
|
|
ensureOnboardingPr(config, packageFiles, branches),
|
|
).toReject();
|
|
expect(scm.deleteBranch).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
it('deletes branch when PR already exists but cannot find it', async () => {
|
|
response.body = {
|
|
errors: [{ message: 'A pull request already exists' }],
|
|
};
|
|
platform.createPr.mockRejectedValueOnce(err);
|
|
await expect(
|
|
ensureOnboardingPr(config, packageFiles, branches),
|
|
).toResolve();
|
|
expect(logger.warn).toHaveBeenCalledWith(
|
|
'Onboarding PR already exists but cannot find it. It was probably created by a different user.',
|
|
);
|
|
expect(scm.deleteBranch).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
});
|
|
});
|