Skip to content

Commit

Permalink
use custom error
Browse files Browse the repository at this point in the history
  • Loading branch information
badmintoncryer committed Mar 6, 2025
1 parent 48ae4d0 commit 97d10d4
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 40 deletions.
12 changes: 6 additions & 6 deletions packages/aws-cdk-lib/aws-codebuild/lib/build-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Construct } from 'constructs';
import * as yaml_cfn from './private/yaml-cfn';
import { Project } from './project';
import * as s3_assets from '../../aws-s3-assets';
import { IResolveContext, Lazy, Stack } from '../../core';
import { IResolveContext, Lazy, Stack, UnscopedValidationError } from '../../core';

/**
* BuildSpec for CodeBuild projects
Expand Down Expand Up @@ -66,7 +66,7 @@ class AssetBuildSpec extends BuildSpec {

public toBuildSpec(scope?: Project): string {
if (!scope) {
throw new Error('`AssetBuildSpec` requires a `scope` argument');
throw new UnscopedValidationError('`AssetBuildSpec` requires a `scope` argument');
}

// If the same AssetCode is used multiple times, retain only the first instantiation.
Expand All @@ -76,7 +76,7 @@ class AssetBuildSpec extends BuildSpec {
...this.options,
});
} else if (Stack.of(this.asset) !== Stack.of(scope)) {
throw new Error(`Asset is already associated with another stack '${Stack.of(this.asset).stackName}'. ` +
throw new UnscopedValidationError(`Asset is already associated with another stack '${Stack.of(this.asset).stackName}'. ` +
'Create a new BuildSpec instance for every stack.');
}

Expand Down Expand Up @@ -155,18 +155,18 @@ class YamlBuildSpec extends BuildSpec {
*/
export function mergeBuildSpecs(lhs: BuildSpec, rhs: BuildSpec): BuildSpec {
if (!(lhs instanceof ObjectBuildSpec) || !(rhs instanceof ObjectBuildSpec)) {
throw new Error('Can only merge buildspecs created using BuildSpec.fromObject()');
throw new UnscopedValidationError('Can only merge buildspecs created using BuildSpec.fromObject()');
}

if (lhs.spec.version === '0.1') {
throw new Error('Cannot extend buildspec at version "0.1". Set the version to "0.2" or higher instead.');
throw new UnscopedValidationError('Cannot extend buildspec at version "0.1". Set the version to "0.2" or higher instead.');
}
if (lhs.spec.artifacts && rhs.spec.artifacts) {
// We decided to disallow merging of artifact specs, which is
// actually impossible since we can't merge two buildspecs with a
// single primary output into a buildspec with multiple outputs.
// In case of multiple outputs they must have identifiers but we won't have that information.
throw new Error('Only one build spec is allowed to specify artifacts.');
throw new UnscopedValidationError('Only one build spec is allowed to specify artifacts.');
}

const lhsSpec = JSON.parse(JSON.stringify(lhs.spec));
Expand Down
20 changes: 10 additions & 10 deletions packages/aws-cdk-lib/aws-codebuild/lib/fleet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Construct } from 'constructs';
import { CfnFleet } from './codebuild.generated';
import { ComputeType } from './compute-type';
import { EnvironmentType } from './environment-type';
import { Arn, ArnFormat, IResource, Resource, Size, Token } from '../../core';
import { Arn, ArnFormat, IResource, Resource, Size, Token, UnscopedValidationError, ValidationError } from '../../core';
import { addConstructMetadata } from '../../core/lib/metadata-resource';

/**
Expand Down Expand Up @@ -155,13 +155,13 @@ export class Fleet extends Resource implements IFleet {
public readonly fleetArn = fleetArn;

public get computeType(): FleetComputeType {
throw new Error('Cannot retrieve computeType property from an imported Fleet');
throw new UnscopedValidationError('Cannot retrieve computeType property from an imported Fleet');
}
public get environmentType(): EnvironmentType {
throw new Error('Cannot retrieve environmentType property from an imported Fleet');
throw new UnscopedValidationError('Cannot retrieve environmentType property from an imported Fleet');
}
public get computeConfiguration(): ComputeConfiguration | undefined {
throw new Error('Cannot retrieve computeConfiguration property from an imported Fleet');
throw new UnscopedValidationError('Cannot retrieve computeConfiguration property from an imported Fleet');
}
}

Expand Down Expand Up @@ -198,25 +198,25 @@ export class Fleet extends Resource implements IFleet {

if (props.fleetName && !Token.isUnresolved(props.fleetName)) {
if (props.fleetName.length < 2) {
throw new Error(`Fleet name can not be shorter than 2 characters but has ${props.fleetName.length} characters.`);
throw new ValidationError(`Fleet name can not be shorter than 2 characters but has ${props.fleetName.length} characters.`, this);
}
if (props.fleetName.length > 128) {
throw new Error(`Fleet name can not be longer than 128 characters but has ${props.fleetName.length} characters.`);
throw new ValidationError(`Fleet name can not be longer than 128 characters but has ${props.fleetName.length} characters.`, this);
}
}

if ((props.baseCapacity ?? 1) < 1) {
throw new Error('baseCapacity must be greater than or equal to 1');
throw new ValidationError('baseCapacity must be greater than or equal to 1', this);
}

if (
props.computeType === FleetComputeType.ATTRIBUTE_BASED &&
(!props.computeConfiguration || Object.keys(props.computeConfiguration).length === 0)
) {
throw new Error('At least one compute configuration criteria must be specified if computeType is "ATTRIBUTE_BASED"');
throw new ValidationError('At least one compute configuration criteria must be specified if computeType is "ATTRIBUTE_BASED"', this);
}
if (props.computeConfiguration && props.computeType !== FleetComputeType.ATTRIBUTE_BASED) {
throw new Error(`'computeConfiguration' can only be specified if 'computeType' is 'ATTRIBUTE_BASED', got: ${props.computeType}`);
throw new ValidationError(`'computeConfiguration' can only be specified if 'computeType' is 'ATTRIBUTE_BASED', got: ${props.computeType}`, this);
}

// Despite what the CloudFormation schema says, the numeric properties are not optional.
Expand Down Expand Up @@ -257,7 +257,7 @@ export class Fleet extends Resource implements IFleet {

private validatePositiveInteger(value: number, fieldName: string) {
if (!Token.isUnresolved(value) && (value < 0 || !Number.isInteger(value))) {
throw new Error(`${fieldName} must be a positive integer, got: ${value}`);
throw new ValidationError(`${fieldName} must be a positive integer, got: ${value}`, this);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export class LinuxGpuBuildImage implements IBindableBuildImage {
const imageAccount = account ?? core.Lazy.string({
produce: () => {
if (this._imageAccount === undefined) {
throw new Error('Make sure this \'LinuxGpuBuildImage\' is used in a CodeBuild Project construct');
throw new core.UnscopedValidationError('Make sure this \'LinuxGpuBuildImage\' is used in a CodeBuild Project construct');
}
return this._imageAccount;
},
Expand Down
30 changes: 15 additions & 15 deletions packages/aws-cdk-lib/aws-codebuild/lib/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import * as iam from '../../aws-iam';
import * as kms from '../../aws-kms';
import * as s3 from '../../aws-s3';
import * as secretsmanager from '../../aws-secretsmanager';
import { ArnFormat, Aws, Duration, IResource, Lazy, Names, PhysicalName, Reference, Resource, SecretValue, Stack, Token, TokenComparison, Tokenization } from '../../core';
import { ArnFormat, Aws, Duration, IResource, Lazy, Names, PhysicalName, Reference, Resource, SecretValue, Stack, Token, TokenComparison, Tokenization, UnscopedValidationError, ValidationError } from '../../core';
import { addConstructMetadata, MethodMetadata } from '../../core/lib/metadata-resource';

const VPC_POLICY_SYM = Symbol.for('@aws-cdk/aws-codebuild.roleVpcPolicy');
Expand Down Expand Up @@ -275,7 +275,7 @@ abstract class ProjectBase extends Resource implements IProject {
*/
public get connections(): ec2.Connections {
if (!this._connections) {
throw new Error('Only VPC-associated Projects have security groups to manage. Supply the "vpc" parameter when creating the Project');
throw new ValidationError('Only VPC-associated Projects have security groups to manage. Supply the "vpc" parameter when creating the Project', this);
}
return this._connections;
}
Expand Down Expand Up @@ -887,7 +887,7 @@ export class Project extends ProjectBase {
const fragments = Tokenization.reverseString(cfnEnvVariable.value);
for (const token of fragments.tokens) {
if (token instanceof SecretValue) {
throw new Error(`Plaintext environment variable '${name}' contains a secret value! ` +
throw new UnscopedValidationError(`Plaintext environment variable '${name}' contains a secret value! ` +
'This means the value of this variable will be visible in plain text in the AWS Console. ' +
"Please consider using CodeBuild's SecretsManager environment variables feature instead. " +
"If you'd like to continue with having this secret in the plaintext environment variables, " +
Expand Down Expand Up @@ -921,7 +921,7 @@ export class Project extends ProjectBase {
if (envVariableValue.startsWith('arn:')) {
const parsedArn = stack.splitArn(envVariableValue, ArnFormat.COLON_RESOURCE_NAME);
if (!parsedArn.resourceName) {
throw new Error('SecretManager ARN is missing the name of the secret: ' + envVariableValue);
throw new UnscopedValidationError('SecretManager ARN is missing the name of the secret: ' + envVariableValue);
}

// the value of the property can be a complex string, separated by ':';
Expand Down Expand Up @@ -1077,7 +1077,7 @@ export class Project extends ProjectBase {
this.source = props.source || new NoSource();
const sourceConfig = this.source.bind(this, this);
if (props.badge && !this.source.badgeSupported) {
throw new Error(`Badge is not supported for source type ${this.source.type}`);
throw new ValidationError(`Badge is not supported for source type ${this.source.type}`, this);
}

const artifacts = props.artifacts
Expand All @@ -1096,7 +1096,7 @@ export class Project extends ProjectBase {
const environmentVariables = props.environmentVariables || {};
const buildSpec = props.buildSpec;
if (this.source.type === NO_SOURCE_TYPE && (buildSpec === undefined || !buildSpec.isImmediate)) {
throw new Error("If the Project's source is NoSource, you need to provide a concrete buildSpec");
throw new ValidationError("If the Project's source is NoSource, you need to provide a concrete buildSpec", this);
}

this._secondarySources = [];
Expand All @@ -1119,7 +1119,7 @@ export class Project extends ProjectBase {

if (!Token.isUnresolved(props.autoRetryLimit) && (props.autoRetryLimit !== undefined)) {
if (props.autoRetryLimit < 0 || props.autoRetryLimit > 10) {
throw new Error(`autoRetryLimit must be a value between 0 and 10, got ${props.autoRetryLimit}.`);
throw new ValidationError(`autoRetryLimit must be a value between 0 and 10, got ${props.autoRetryLimit}.`, this);
}
}

Expand Down Expand Up @@ -1252,7 +1252,7 @@ export class Project extends ProjectBase {
@MethodMetadata()
public addSecondarySource(secondarySource: ISource): void {
if (!secondarySource.identifier) {
throw new Error('The identifier attribute is mandatory for secondary sources');
throw new ValidationError('The identifier attribute is mandatory for secondary sources', this);
}
const secondarySourceConfig = secondarySource.bind(this, this);
this._secondarySources.push(secondarySourceConfig.sourceProperty);
Expand Down Expand Up @@ -1284,7 +1284,7 @@ export class Project extends ProjectBase {
@MethodMetadata()
public addSecondaryArtifact(secondaryArtifact: IArtifacts): void {
if (!secondaryArtifact.identifier) {
throw new Error('The identifier attribute is mandatory for secondary artifacts');
throw new ValidationError('The identifier attribute is mandatory for secondary artifacts', this);
}
this._secondaryArtifacts.push(secondaryArtifact.bind(this, this).artifactsProperty);
}
Expand Down Expand Up @@ -1372,7 +1372,7 @@ export class Project extends ProjectBase {
errors.push(...this.validateLambdaBuildImage(this.buildImage, props));

if (errors.length > 0) {
throw new Error('Invalid CodeBuild environment: ' + errors.join('\n'));
throw new ValidationError('Invalid CodeBuild environment: ' + errors.join('\n'), this);
}

const imagePullPrincipalType = this.isLambdaBuildImage(this.buildImage) ? undefined :
Expand Down Expand Up @@ -1449,7 +1449,7 @@ export class Project extends ProjectBase {

// If the fleetArn is resolved, the fleet is imported and we cannot validate the environment type
if (Token.isUnresolved(fleet.fleetArn) && this.buildImage.type !== fleet.environmentType) {
throw new Error(`The environment type of the fleet (${fleet.environmentType}) must match the environment type of the build image (${this.buildImage.type})`);
throw new ValidationError(`The environment type of the fleet (${fleet.environmentType}) must match the environment type of the build image (${this.buildImage.type})`, this);
}

return { fleetArn: fleet.fleetArn };
Expand All @@ -1463,13 +1463,13 @@ export class Project extends ProjectBase {
*/
private configureVpc(props: ProjectProps): CfnProject.VpcConfigProperty | undefined {
if ((props.securityGroups || props.allowAllOutbound !== undefined) && !props.vpc) {
throw new Error('Cannot configure \'securityGroup\' or \'allowAllOutbound\' without configuring a VPC');
throw new ValidationError('Cannot configure \'securityGroup\' or \'allowAllOutbound\' without configuring a VPC', this);
}

if (!props.vpc) { return undefined; }

if ((props.securityGroups && props.securityGroups.length > 0) && props.allowAllOutbound !== undefined) {
throw new Error('Configure \'allowAllOutbound\' directly on the supplied SecurityGroup.');
throw new ValidationError('Configure \'allowAllOutbound\' directly on the supplied SecurityGroup.', this);
}

let securityGroups: ec2.ISecurityGroup[];
Expand Down Expand Up @@ -1515,7 +1515,7 @@ export class Project extends ProjectBase {
const status = (cloudWatchLogs.enabled ?? true) ? 'ENABLED' : 'DISABLED';

if (status === 'ENABLED' && !(cloudWatchLogs.logGroup)) {
throw new Error('Specifying a LogGroup is required if CloudWatch logging for CodeBuild is enabled');
throw new ValidationError('Specifying a LogGroup is required if CloudWatch logging for CodeBuild is enabled', this);
}
cloudWatchLogs.logGroup?.grantWrite(this);

Expand Down Expand Up @@ -1591,7 +1591,7 @@ export class Project extends ProjectBase {
if ((sourceType === CODEPIPELINE_SOURCE_ARTIFACTS_TYPE ||
artifactsType === CODEPIPELINE_SOURCE_ARTIFACTS_TYPE) &&
(sourceType !== artifactsType)) {
throw new Error('Both source and artifacts must be set to CodePipeline');
throw new ValidationError('Both source and artifacts must be set to CodePipeline', this);
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/aws-cdk-lib/aws-codebuild/lib/report-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export class ReportGroup extends ReportGroupBase {
this.exportBucket = props.exportBucket;

if (props.deleteReports && props.removalPolicy !== cdk.RemovalPolicy.DESTROY) {
throw new Error('Cannot use \'deleteReports\' property on a report group without setting removal policy to \'DESTROY\'.');
throw new cdk.ValidationError('Cannot use \'deleteReports\' property on a report group without setting removal policy to \'DESTROY\'.', this);
}
}
}
15 changes: 8 additions & 7 deletions packages/aws-cdk-lib/aws-codebuild/lib/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import * as codecommit from '../../aws-codecommit';
import * as iam from '../../aws-iam';
import * as s3 from '../../aws-s3';
import { UnscopedValidationError } from '../../core';

/**
* The type returned from `ISource#bind`.
Expand Down Expand Up @@ -246,7 +247,7 @@ export class FilterGroup {

private constructor(actions: Set<EventAction>, filters: CfnProject.WebhookFilterProperty[]) {
if (actions.size === 0) {
throw new Error('A filter group must contain at least one event action');
throw new UnscopedValidationError('A filter group must contain at least one event action');
}
this.actions = actions;
this.filters = filters;
Expand Down Expand Up @@ -491,7 +492,7 @@ export class FilterGroup {

private addBaseRefFilter(refName: string, include: boolean) {
if (this.actions.has(EventAction.PUSH)) {
throw new Error('A base reference condition cannot be added if a Group contains a PUSH event action');
throw new UnscopedValidationError('A base reference condition cannot be added if a Group contains a PUSH event action');
}
return this.addFilter(WebhookFilterTypes.BASE_REF, refName, include);
}
Expand Down Expand Up @@ -588,11 +589,11 @@ abstract class ThirdPartyGitSource extends GitSource {
const webhook = this.webhook ?? (anyFilterGroupsProvided ? true : undefined);

if (!webhook && anyFilterGroupsProvided) {
throw new Error('`webhookFilters` cannot be used when `webhook` is `false`');
throw new UnscopedValidationError('`webhookFilters` cannot be used when `webhook` is `false`');
}

if (!webhook && this.webhookTriggersBatchBuild) {
throw new Error('`webhookTriggersBatchBuild` cannot be used when `webhook` is `false`');
throw new UnscopedValidationError('`webhookTriggersBatchBuild` cannot be used when `webhook` is `false`');
}

const superConfig = super.bind(_scope, project);
Expand Down Expand Up @@ -829,11 +830,11 @@ class GitHubEnterpriseSource extends CommonGithubSource {

public bind(_scope: Construct, _project: IProject): SourceConfig {
if (this.hasCommitMessageFilterAndPrEvent()) {
throw new Error('COMMIT_MESSAGE filters cannot be used with GitHub Enterprise Server pull request events');
throw new UnscopedValidationError('COMMIT_MESSAGE filters cannot be used with GitHub Enterprise Server pull request events');
}

if (this.hasFilePathFilterAndPrEvent()) {
throw new Error('FILE_PATH filters cannot be used with GitHub Enterprise Server pull request events');
throw new UnscopedValidationError('FILE_PATH filters cannot be used with GitHub Enterprise Server pull request events');
}

const superConfig = super.bind(_scope, _project);
Expand Down Expand Up @@ -915,7 +916,7 @@ class BitBucketSource extends ThirdPartyGitSource {
public bind(_scope: Construct, _project: IProject): SourceConfig {
// BitBucket sources don't support the PULL_REQUEST_REOPENED event action
if (this.anyWebhookFilterContainsPrReopenedEventAction()) {
throw new Error('BitBucket sources do not support the PULL_REQUEST_REOPENED webhook event action');
throw new UnscopedValidationError('BitBucket sources do not support the PULL_REQUEST_REOPENED webhook event action');
}

const superConfig = super.bind(_scope, _project);
Expand Down

0 comments on commit 97d10d4

Please sign in to comment.