1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-20 00:08:02 +01:00

feat: disallow description when no pattern exists (#4679)

This PR makes it so that adding a feature naming description when there
is no pattern is disallowed. It also changes the validation for feature
naming slightly so that it can return multiple errors at once.
This commit is contained in:
Thomas Heartman 2023-09-14 09:32:07 +02:00 committed by GitHub
parent 8c90b45896
commit 6dbea08d0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 17 deletions

View File

@ -4,7 +4,7 @@ import getProp from 'lodash.get';
import { ApiErrorSchema, UnleashError } from './unleash-error';
type ValidationErrorDescription = {
description: string;
description?: string;
message: string;
path?: string;
};

View File

@ -60,6 +60,24 @@ describe('validate incoming feature naming data', () => {
).toMatchObject({ state: 'invalid' });
}
});
test('feature naming data with a non-empty example but an empty pattern is invalid', () => {
expect(
checkFeatureNamingData({
pattern: '',
example: 'example',
}),
).toMatchObject({ state: 'invalid' });
});
test('feature naming data with a non-empty description but an empty pattern is invalid', () => {
expect(
checkFeatureNamingData({
pattern: '',
description: 'description',
}),
).toMatchObject({ state: 'invalid' });
});
});
describe('validate feature flag names against a pattern', () => {

View File

@ -4,25 +4,33 @@ const compileRegex = (pattern: string) => new RegExp(`^${pattern}$`);
export const checkFeatureNamingData = (
featureNaming?: IFeatureNaming,
): { state: 'valid' } | { state: 'invalid'; reason: string } => {
):
| { state: 'valid' }
| { state: 'invalid'; reasons: [string, ...string[]] } => {
if (featureNaming) {
const { pattern, example } = featureNaming;
if (
pattern != null &&
example &&
!example.match(compileRegex(pattern))
) {
return {
state: 'invalid',
reason: `You've provided a feature flag naming example ("${example}") that doesn't match your feature flag naming pattern ("${pattern}"). Please provide an example that matches your supplied pattern. Bear in mind that the pattern must match the whole example, as if it were surrounded by '^' and "$".`,
};
const { pattern, example, description } = featureNaming;
const errors: string[] = [];
if (pattern && example && !example.match(compileRegex(pattern))) {
errors.push(
`You've provided a feature flag naming example ("${example}") that doesn't match your feature flag naming pattern ("${pattern}"). Please provide an example that matches your supplied pattern. Bear in mind that the pattern must match the whole example, as if it were surrounded by '^' and "$".`,
);
}
if (!pattern && example) {
return {
state: 'invalid',
reason: "You've provided a feature flag naming example, but no feature flag naming pattern. You must specify a pattern to use an example.",
};
errors.push(
"You've provided a feature flag naming example, but no feature flag naming pattern. You must specify a pattern to use an example.",
);
}
if (!pattern && description) {
errors.push(
"You've provided a feature flag naming pattern description, but no feature flag naming pattern. You must have a pattern to use a description.",
);
}
const [first, ...rest] = errors;
if (first) {
return { state: 'invalid', reasons: [first, ...rest] };
}
}

View File

@ -176,7 +176,14 @@ export default class ProjectService {
const validationResult = checkFeatureNamingData(featureNaming);
if (validationResult.state === 'invalid') {
throw new BadDataError(validationResult.reason);
const [firstReason, ...remainingReasons] =
validationResult.reasons.map((message) => ({
message,
}));
throw new BadDataError(
'The feature naming pattern data you provided was invalid.',
[firstReason, ...remainingReasons],
);
}
if (featureNaming.pattern && !featureNaming.example) {