Skip to content

Commit

Permalink
Merge branch 'main' into feat/config-self-hosted-yaml-json5
Browse files Browse the repository at this point in the history
  • Loading branch information
rarkins authored Dec 9, 2021
2 parents ab5357a + aa6f12a commit 2638f36
Show file tree
Hide file tree
Showing 19 changed files with 242 additions and 40 deletions.
25 changes: 25 additions & 0 deletions docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -2545,6 +2545,31 @@ If you wish to disable all updates outside of scheduled hours then configure thi
By default, Renovate will attempt to update all detected dependencies, regardless of whether they are defined using pinned single versions (e.g. `1.2.3`) or constraints/ranges (e.g. (`^1.2.3`).
You can set this option to `false` if you wish to disable updating for pinned (single version) dependencies specifically.

## userStrings

User-facing strings pertaining to the PR comment that gets posted when a PR is closed.
When a PR is closed, Renovate posts a comment to let users know that future updates will be ignored.

The following strings can currently be customized:

- `ignoreDigest`: Text of the PR comment for digest upgrades.
- `ignoreMajor`: Text of the PR comment for major upgrades.
- `ignoreOther`: Text of the PR comment for other (neither digest nor major) upgrades.
- `ignoreTopic`: Topic of the PR comment.

Example:

```json
{
"userStrings": {
"ignoreTopic": "Custom topic for PR comment",
"ignoreMajor": "Custom text for major upgrades.",
"ignoreDigest": "Custom text for digest upgrades.",
"ignoreOther": "Custom text for other upgrades."
}
}
```

## versioning

Usually, each language or package manager has a specific type of "versioning":
Expand Down
15 changes: 15 additions & 0 deletions lib/config/options/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2191,6 +2191,21 @@ const options: RenovateOptions[] = [
type: 'boolean',
default: false,
},
{
name: 'userStrings',
description:
'User-facing strings pertaining to the PR comment that gets posted when a PR is closed.',
type: 'object',
default: {
ignoreTopic: 'Renovate Ignore Notification',
ignoreMajor:
'As this PR has been closed unmerged, Renovate will ignore this upgrade and you will not receive PRs for *any* future {{{newMajor}}}.x releases. However, if you upgrade to {{{newMajor}}}.x manually then Renovate will reenable minor and patch updates automatically.',
ignoreDigest:
'As this PR has been closed unmerged, Renovate will ignore this upgrade and you will not receive PRs for *any* future {{{depName}}}:{{{currentValue}}} digest updates. Digest updates will resume if you update the specified tag at any time.',
ignoreOther:
'As this PR has been closed unmerged, Renovate will now ignore this update ({{{newValue}}}). You will still receive a PR once a newer version is released, so if you wish to permanently ignore this dependency, please add it to the `ignoreDeps` array of your renovate config.',
},
},
];

export function getOptions(): RenovateOptions[] {
Expand Down
40 changes: 40 additions & 0 deletions lib/config/presets/internal/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const staticGroups = {
'group:jekyllEcosystem',
'group:jestPlusTSJest',
'group:jestPlusTypes',
'group:kubernetes',
'group:polymer',
'group:resilience4j',
'group:rubyOmniauth',
Expand Down Expand Up @@ -493,6 +494,45 @@ const staticGroups = {
},
],
},
kubernetes: {
description: 'Group kubernetes packages together',
packageRules: [
{
matchDatasources: ['go'],
groupName: 'kubernetes packages',
groupSlug: 'kubernetes-go',
matchPackagePrefixes: [
'k8s.io/api',
'k8s.io/apiextensions-apiserver',
'k8s.io/apimachinery',
'k8s.io/apiserver',
'k8s.io/cli-runtime',
'k8s.io/client-go',
'k8s.io/cloud-provider',
'k8s.io/cluster-bootstrap',
'k8s.io/code-generator',
'k8s.io/component-base',
'k8s.io/controller-manager',
'k8s.io/cri-api',
// 'k8s.io/csi-api', has not go.mod set up and does not follow the versioning of other repos
'k8s.io/csi-translation-lib',
'k8s.io/kube-aggregator',
'k8s.io/kube-controller-manager',
'k8s.io/kube-proxy',
'k8s.io/kube-scheduler',
'k8s.io/kubectl',
'k8s.io/kubelet',
'k8s.io/legacy-cloud-providers',
'k8s.io/metrics',
'k8s.io/mount-utils',
'k8s.io/pod-security-admission',
'k8s.io/sample-apiserver',
'k8s.io/sample-cli-plugin',
'k8s.io/sample-controller',
],
},
],
},
googleapis: {
description: 'Group googleapis packages together',
packageRules: [
Expand Down
1 change: 1 addition & 0 deletions lib/config/presets/internal/monorepo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ const repoGroups = {
'opentelemetry-js': 'https://github.com/open-telemetry/opentelemetry-js',
'opentelemetry-dotnet':
'https://github.com/open-telemetry/opentelemetry-dotnet',
'opentelemetry-go': 'https://github.com/open-telemetry/opentelemetry-go',
picassojs: 'https://github.com/qlik-oss/picasso.js',
pnpjs: 'https://github.com/pnp/pnpjs',
playwright: 'https://github.com/Microsoft/playwright',
Expand Down
14 changes: 14 additions & 0 deletions lib/datasource/terraform-module/base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ExternalHostError } from '../../types/errors/external-host-error';
import { cache } from '../../util/cache/package/decorator';
import type { HttpError } from '../../util/http/types';
import { ensureTrailingSlash } from '../../util/url';
import { Datasource } from '../datasource';
import type { ServiceDiscoveryResult } from './types';
Expand Down Expand Up @@ -26,4 +28,16 @@ export abstract class TerraformDatasource extends Datasource {
private static getDiscoveryUrl(registryUrl: string): string {
return `${ensureTrailingSlash(registryUrl)}.well-known/terraform.json`;
}

override handleSpecificErrors(err: HttpError): void {
const failureCodes = ['EAI_AGAIN'];
// istanbul ignore if
if (failureCodes.includes(err.code)) {
throw new ExternalHostError(err);
}
// istanbul ignore if
if (err.response?.statusCode === 503) {
throw new ExternalHostError(err);
}
}
}
10 changes: 0 additions & 10 deletions lib/datasource/terraform-module/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { logger } from '../../logger';
import { ExternalHostError } from '../../types/errors/external-host-error';
import { cache } from '../../util/cache/package/decorator';
import type { HttpError } from '../../util/http/types';
import { regEx } from '../../util/regex';
import * as hashicorpVersioning from '../../versioning/hashicorp';
import type { GetReleasesConfig, ReleaseResult } from '../types';
Expand Down Expand Up @@ -83,14 +81,6 @@ export class TerraformModuleDatasource extends TerraformDatasource {
return dep;
}

override handleSpecificErrors(err: HttpError): void {
const failureCodes = ['EAI_AGAIN'];
// istanbul ignore if
if (failureCodes.includes(err.code)) {
throw new ExternalHostError(err);
}
}

private static getRegistryRepository(
lookupName: string,
registryUrl: string
Expand Down
8 changes: 8 additions & 0 deletions lib/manager/nuget/__fixtures__/with-whitespaces/NuGet.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="My Package Source" value="https://my.myget.org/F/my/auth/guid/api/v3/index.json" />
</packageSources>
</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>

</Project>
3 changes: 2 additions & 1 deletion lib/manager/nuget/artifacts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { join } from 'path';
import { quote } from 'shlex';
import { GlobalConfig } from '../../config/global';
import { TEMPORARY_ERROR } from '../../constants/error-messages';
import { id, parseRegistryUrl } from '../../datasource/nuget';
Expand Down Expand Up @@ -45,7 +46,7 @@ async function addSourceCmds(
let addSourceCmd = `dotnet nuget add source ${registryInfo.feedUrl} --configfile ${nugetConfigFile}`;
if (registry.name) {
// Add name for registry, if known.
addSourceCmd += ` --name ${registry.name}`;
addSourceCmd += ` --name ${quote(registry.name)}`;
}
if (username && password) {
// Add registry credentials from host rules, if configured.
Expand Down
20 changes: 20 additions & 0 deletions lib/manager/nuget/extract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,26 @@ describe('manager/nuget/extract', () => {
],
});
});

it('handles NuGet.config with whitespaces in package source keys', async () => {
const packageFile = 'with-whitespaces/with-whitespaces.csproj';
const contents = loadFixture(packageFile);
expect(await extractPackageFile(contents, packageFile, config)).toEqual({
deps: [
{
currentValue: '12.0.3',
datasource: 'nuget',
depName: 'Newtonsoft.Json',
depType: 'nuget',
registryUrls: [
'https://api.nuget.org/v3/index.json#protocolVersion=3',
'https://my.myget.org/F/my/auth/guid/api/v3/index.json',
],
},
],
});
});

it('ignores local feed in NuGet.config', async () => {
const packageFile =
'with-local-feed-in-config-file/with-local-feed-in-config-file.csproj';
Expand Down
1 change: 1 addition & 0 deletions lib/manager/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export interface LookupUpdate {
pendingVersions?: string[];
newVersion?: string;
updateType?: UpdateType;
userStrings?: Record<string, string>;
}

export interface PackageDependency<T = Record<string, any>> extends Package<T> {
Expand Down
7 changes: 7 additions & 0 deletions lib/util/git/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ describe('util/git/index', () => {
await base.cleanup();
});

describe('validateGitVersion()', () => {
it('has a git version greater or equal to the minimum required', async () => {
const res = await git.validateGitVersion();
expect(res).toBeTrue();
});
});

describe('checkoutBranch(branchName)', () => {
it('sets the base branch as master', async () => {
await expect(git.checkoutBranch(defaultBranch)).resolves.not.toThrow();
Expand Down
37 changes: 37 additions & 0 deletions lib/util/git/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { logger } from '../../logger';
import { ExternalHostError } from '../../types/errors/external-host-error';
import type { GitProtocol } from '../../types/git';
import { api as semverCoerced } from '../../versioning/semver-coerced';
import { Limit, incLimitedValue } from '../../workers/global/limits';
import { regEx } from '../regex';
import { parseGitAuthor } from './author';
Expand Down Expand Up @@ -143,6 +144,41 @@ let gitInitialized: boolean;

let privateKeySet = false;

export const GIT_MINIMUM_VERSION = '2.33.0'; // git show-current

export async function validateGitVersion(): Promise<boolean> {
let version: string;
const globalGit = Git();
try {
const raw = await globalGit.raw(['--version']);
for (const section of raw.split(/\s+/)) {
if (semverCoerced.isVersion(section)) {
version = section;
break;
}
}
} catch (err) /* istanbul ignore next */ {
logger.error({ err }, 'Error fetching git version');
return false;
}
// istanbul ignore if
if (
!(
version &&
(version === GIT_MINIMUM_VERSION ||
semverCoerced.isGreaterThan(version, GIT_MINIMUM_VERSION))
)
) {
logger.error(
{ detectedVersion: version, minimumVersion: GIT_MINIMUM_VERSION },
'Git version needs upgrading'
);
return false;
}
logger.debug(`Found valid git version: ${version}`);
return true;
}

async function fetchBranchCommits(): Promise<void> {
config.branchCommits = {};
const opts = ['ls-remote', '--heads', config.url];
Expand Down Expand Up @@ -520,6 +556,7 @@ export async function isBranchModified(branchName: string): Promise<boolean> {
config.ignoredAuthors.some((ignoredAuthor) => lastAuthor === ignoredAuthor)
) {
// author matches - branch has not been modified
logger.debug({ branchName }, 'Branch has not been modified');
config.branchIsModified[branchName] = false;
return false;
}
Expand Down
10 changes: 5 additions & 5 deletions lib/workers/branch/handle-existing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@ import { logger } from '../../logger';
import { Pr, platform } from '../../platform';
import { PrState } from '../../types';
import { branchExists, deleteBranch } from '../../util/git';
import * as template from '../../util/template';
import { BranchConfig } from '../types';

export async function handlepr(config: BranchConfig, pr: Pr): Promise<void> {
if (pr.state === PrState.Closed) {
let content;
if (config.updateType === 'major') {
content = `As this PR has been closed unmerged, Renovate will ignore this upgrade and you will not receive PRs for *any* future ${config.newMajor}.x releases. However, if you upgrade to ${config.newMajor}.x manually then Renovate will then reenable updates for minor and patch updates automatically.`;
content = template.compile(config.userStrings.ignoreMajor, config);
} else if (config.updateType === 'digest') {
content = `As this PR has been closed unmerged, Renovate will ignore this upgrade updateType and you will not receive PRs for *any* future ${config.depName}:${config.currentValue} digest updates. Digest updates will resume if you update the specified tag at any time.`;
content = template.compile(config.userStrings.ignoreDigest, config);
} else {
content = `As this PR has been closed unmerged, Renovate will now ignore this update (${config.newValue}). You will still receive a PR once a newer version is released, so if you wish to permanently ignore this dependency, please add it to the \`ignoreDeps\` array of your renovate config.`;
content = template.compile(config.userStrings.ignoreOther, config);
}
content +=
'\n\nIf this PR was closed by mistake or you changed your mind, you can simply rename this PR and you will soon get a fresh replacement PR opened.';
if (!config.suppressNotifications.includes('prIgnoreNotification')) {
const ignoreTopic = `Renovate Ignore Notification`;
if (GlobalConfig.get('dryRun')) {
logger.info(
`DRY-RUN: Would ensure closed PR comment in PR #${pr.number}`
);
} else {
await platform.ensureComment({
number: pr.number,
topic: ignoreTopic,
topic: config.userStrings.ignoreTopic,
content,
});
}
Expand Down
1 change: 1 addition & 0 deletions lib/workers/branch/reuse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export async function shouldReuseExistingBranch(
logger.debug('Cannot rebase branch as it has been modified');
return { reuseExistingBranch: true, isModified: true };
}
logger.debug('Branch is unmodified, so can be rebased');
return { reuseExistingBranch: false };
}
logger.debug('Branch is up-to-date');
Expand Down
21 changes: 21 additions & 0 deletions lib/workers/global/initialize.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { git } from '../../../test/util';
import type { RenovateConfig } from '../../config/types';
import { globalInitialize } from './initialize';

jest.mock('../../util/git');

describe('workers/global/initialize', () => {
describe('checkVersions()', () => {
it('throws if invalid version', async () => {
const config: RenovateConfig = {};
git.validateGitVersion.mockResolvedValueOnce(false);
await expect(globalInitialize(config)).rejects.toThrow();
});

it('returns if valid git version', async () => {
const config: RenovateConfig = {};
git.validateGitVersion.mockResolvedValueOnce(true);
await expect(globalInitialize(config)).toResolve();
});
});
});
9 changes: 9 additions & 0 deletions lib/workers/global/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { logger } from '../../logger';
import { initPlatform } from '../../platform';
import * as packageCache from '../../util/cache/package';
import { setEmojiConfig } from '../../util/emoji';
import { validateGitVersion } from '../../util/git';
import { Limit, setMaxLimit } from './limits';

async function setDirectories(input: AllConfig): Promise<AllConfig> {
Expand Down Expand Up @@ -34,10 +35,18 @@ function limitCommitsPerRun(config: RenovateConfig): void {
setMaxLimit(Limit.Commits, limit);
}

async function checkVersions(): Promise<void> {
const validGitVersion = await validateGitVersion();
if (!validGitVersion) {
throw new Error('Init: git version needs upgrading');
}
}

export async function globalInitialize(
config_: RenovateConfig
): Promise<RenovateConfig> {
let config = config_;
await checkVersions();
config = await initPlatform(config);
config = await setDirectories(config);
packageCache.init(config);
Expand Down
Loading

0 comments on commit 2638f36

Please sign in to comment.