Skip to content

Commit

Permalink
fix(config-validator): allow default null val for globalOptions (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
RahulGautamSingh committed Feb 28, 2024
1 parent 9f23946 commit 1efa2f2
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 112 deletions.
53 changes: 53 additions & 0 deletions lib/config/validation.spec.ts
Expand Up @@ -1251,6 +1251,39 @@ describe('config/validation', () => {
},
]);
});

it('validates options with different type but defaultValue=null', async () => {
const config = {
minimumReleaseAge: null,
groupName: null,
groupSlug: null,
dependencyDashboardLabels: null,
defaultRegistryUrls: null,
registryUrls: null,
hostRules: [
{
artifactAuth: null,
concurrentRequestLimit: null,
httpsCertificate: null,
httpsPrivateKey: null,
httpsCertificateAuthority: null,
},
],
encrypted: null,
milestone: null,
branchConcurrentLimit: null,
hashedBranchLength: null,
assigneesSampleSize: null,
reviewersSampleSize: null,
};
const { warnings, errors } = await configValidation.validateConfig(
false,
// @ts-expect-error: contains invalid values
config,
);
expect(warnings).toHaveLength(0);
expect(errors).toHaveLength(0);
});
});

describe('validate globalOptions()', () => {
Expand Down Expand Up @@ -1540,5 +1573,25 @@ describe('config/validation', () => {
expect(warnings).toHaveLength(0);
expect(errors).toHaveLength(0);
});

it('validates options with different type but defaultValue=null', async () => {
const config = {
onboardingCommitMessage: null,
dryRun: null,
logContext: null,
endpoint: null,
skipInstalls: null,
autodiscoverFilter: null,
autodiscoverNamespaces: null,
autodiscoverTopics: null,
};
const { warnings, errors } = await configValidation.validateConfig(
true,
// @ts-expect-error: contains invalid values
config,
);
expect(warnings).toHaveLength(0);
expect(errors).toHaveLength(0);
});
});
});
226 changes: 114 additions & 112 deletions lib/config/validation.ts
Expand Up @@ -828,139 +828,141 @@ async function validateGlobalConfig(
warnings: ValidationMessage[],
currentPath: string | undefined,
): Promise<void> {
if (type === 'string') {
if (is.string(val)) {
if (
key === 'onboardingConfigFileName' &&
!configFileNames.includes(val)
) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${configFileNames.join(', ')}.`,
});
} else if (
key === 'repositoryCache' &&
!['enabled', 'disabled', 'reset'].includes(val)
) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${['enabled', 'disabled', 'reset'].join(', ')}.`,
});
} else if (
key === 'dryRun' &&
!['extract', 'lookup', 'full'].includes(val)
) {
if (val !== null) {
if (type === 'string') {
if (is.string(val)) {
if (
key === 'onboardingConfigFileName' &&
!configFileNames.includes(val)
) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${configFileNames.join(', ')}.`,
});
} else if (
key === 'repositoryCache' &&
!['enabled', 'disabled', 'reset'].includes(val)
) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${['enabled', 'disabled', 'reset'].join(', ')}.`,
});
} else if (
key === 'dryRun' &&
!['extract', 'lookup', 'full'].includes(val)
) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${['extract', 'lookup', 'full'].join(', ')}.`,
});
} else if (
key === 'binarySource' &&
!['docker', 'global', 'install', 'hermit'].includes(val)
) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${['docker', 'global', 'install', 'hermit'].join(', ')}.`,
});
} else if (
key === 'requireConfig' &&
!['required', 'optional', 'ignored'].includes(val)
) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${['required', 'optional', 'ignored'].join(', ')}.`,
});
} else if (
key === 'gitUrl' &&
!['default', 'ssh', 'endpoint'].includes(val)
) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${['default', 'ssh', 'endpoint'].join(', ')}.`,
});
}
} else {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${['extract', 'lookup', 'full'].join(', ')}.`,
message: `Configuration option \`${currentPath}\` should be a string.`,
});
} else if (
key === 'binarySource' &&
!['docker', 'global', 'install', 'hermit'].includes(val)
) {
}
} else if (type === 'integer') {
if (!is.number(val)) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${['docker', 'global', 'install', 'hermit'].join(', ')}.`,
message: `Configuration option \`${currentPath}\` should be an integer. Found: ${JSON.stringify(
val,
)} (${typeof val}).`,
});
} else if (
key === 'requireConfig' &&
!['required', 'optional', 'ignored'].includes(val)
) {
}
} else if (type === 'boolean') {
if (val !== true && val !== false) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${['required', 'optional', 'ignored'].join(', ')}.`,
message: `Configuration option \`${currentPath}\` should be a boolean. Found: ${JSON.stringify(
val,
)} (${typeof val}).`,
});
} else if (
key === 'gitUrl' &&
!['default', 'ssh', 'endpoint'].includes(val)
) {
}
} else if (type === 'array') {
if (is.array(val)) {
if (key === 'gitNoVerify') {
const allowedValues = ['commit', 'push'];
for (const value of val as string[]) {
if (!allowedValues.includes(value)) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value for \`${currentPath}\`. The allowed values are ${allowedValues.join(', ')}.`,
});
}
}
}
} else {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${['default', 'ssh', 'endpoint'].join(', ')}.`,
message: `Configuration option \`${currentPath}\` should be a list (Array).`,
});
}
} else {
warnings.push({
topic: 'Configuration Error',
message: `Configuration option \`${currentPath}\` should be a string.`,
});
}
} else if (type === 'integer') {
if (!is.number(val)) {
warnings.push({
topic: 'Configuration Error',
message: `Configuration option \`${currentPath}\` should be an integer. Found: ${JSON.stringify(
val,
)} (${typeof val}).`,
});
}
} else if (type === 'boolean') {
if (val !== true && val !== false) {
warnings.push({
topic: 'Configuration Error',
message: `Configuration option \`${currentPath}\` should be a boolean. Found: ${JSON.stringify(
val,
)} (${typeof val}).`,
});
}
} else if (type === 'array') {
if (is.array(val)) {
if (key === 'gitNoVerify') {
const allowedValues = ['commit', 'push'];
for (const value of val as string[]) {
if (!allowedValues.includes(value)) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value for \`${currentPath}\`. The allowed values are ${allowedValues.join(', ')}.`,
});
} else if (type === 'object') {
if (is.plainObject(val)) {
if (key === 'onboardingConfig') {
const subValidation = await validateConfig(false, val);
for (const warning of subValidation.warnings.concat(
subValidation.errors,
)) {
warnings.push(warning);
}
}
}
} else {
warnings.push({
topic: 'Configuration Error',
message: `Configuration option \`${currentPath}\` should be a list (Array).`,
});
}
} else if (type === 'object') {
if (is.plainObject(val)) {
if (key === 'onboardingConfig') {
const subValidation = await validateConfig(false, val);
for (const warning of subValidation.warnings.concat(
subValidation.errors,
)) {
warnings.push(warning);
}
} else if (key === 'force') {
const subValidation = await validateConfig(true, val);
for (const warning of subValidation.warnings.concat(
subValidation.errors,
)) {
warnings.push(warning);
}
} else if (key === 'cacheTtlOverride') {
for (const [subKey, subValue] of Object.entries(val)) {
if (!is.number(subValue)) {
} else if (key === 'force') {
const subValidation = await validateConfig(true, val);
for (const warning of subValidation.warnings.concat(
subValidation.errors,
)) {
warnings.push(warning);
}
} else if (key === 'cacheTtlOverride') {
for (const [subKey, subValue] of Object.entries(val)) {
if (!is.number(subValue)) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid \`${currentPath}.${subKey}\` configuration: value must be an integer.`,
});
}
}
} else {
const res = validatePlainObject(val);
if (res !== true) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid \`${currentPath}.${subKey}\` configuration: value must be an integer.`,
message: `Invalid \`${currentPath}.${res}\` configuration: value must be a string.`,
});
}
}
} else {
const res = validatePlainObject(val);
if (res !== true) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid \`${currentPath}.${res}\` configuration: value must be a string.`,
});
}
warnings.push({
topic: 'Configuration Error',
message: `Configuration option \`${currentPath}\` should be a JSON object.`,
});
}
} else {
warnings.push({
topic: 'Configuration Error',
message: `Configuration option \`${currentPath}\` should be a JSON object.`,
});
}
}
}
Expand Down

0 comments on commit 1efa2f2

Please sign in to comment.