diff --git a/packages/@aws-cdk/aws-glue-alpha/.eslintrc.js b/packages/@aws-cdk/aws-glue-alpha/.eslintrc.js index b284f20df26e9..d636e867bdb90 100644 --- a/packages/@aws-cdk/aws-glue-alpha/.eslintrc.js +++ b/packages/@aws-cdk/aws-glue-alpha/.eslintrc.js @@ -4,5 +4,12 @@ baseConfig.parserOptions.project = __dirname + '/tsconfig.json'; baseConfig.rules['import/no-extraneous-dependencies'] = ['error', { devDependencies: true, peerDependencies: true } ]; baseConfig.rules['import/order'] = 'off'; baseConfig.rules['@aws-cdk/invalid-cfn-imports'] = 'off'; +baseConfig.rules["@cdklabs/no-throw-default-error"] = ["error"]; +baseConfig.overrides.push({ + files: ["./test/**"], + rules: { + "@cdklabs/no-throw-default-error": "off", + }, +}); module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/code.ts b/packages/@aws-cdk/aws-glue-alpha/lib/code.ts index 3a8a11b2fac95..2c8c43cb6d9e2 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/code.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/code.ts @@ -66,7 +66,7 @@ export class AssetCode extends Code { super(); if (fs.lstatSync(this.path).isDirectory()) { - throw new Error(`Code path ${this.path} is a directory. Only files are supported`); + throw new cdk.UnscopedValidationError(`Code path ${this.path} is a directory. Only files are supported`); } } @@ -78,7 +78,7 @@ export class AssetCode extends Code { ...this.options, }); } else if (cdk.Stack.of(this.asset) !== cdk.Stack.of(scope)) { - throw new Error(`Asset is already associated with another stack '${cdk.Stack.of(this.asset).stackName}'. ` + + throw new cdk.UnscopedValidationError(`Asset is already associated with another stack '${cdk.Stack.of(this.asset).stackName}'. ` + 'Create a new Code instance for every stack.'); } this.asset.grantRead(grantable); diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/database.ts b/packages/@aws-cdk/aws-glue-alpha/lib/database.ts index 72043edffb74d..716df1c8b18b3 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/database.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/database.ts @@ -1,4 +1,4 @@ -import { ArnFormat, IResource, Lazy, Names, Resource, Stack } from 'aws-cdk-lib/core'; +import { ArnFormat, IResource, Lazy, Names, Resource, Stack, UnscopedValidationError } from 'aws-cdk-lib/core'; import { Construct } from 'constructs'; import { CfnDatabase } from 'aws-cdk-lib/aws-glue'; import { addConstructMetadata } from 'aws-cdk-lib/core/lib/metadata-resource'; @@ -152,12 +152,12 @@ export class Database extends Resource implements IDatabase { function validateLocationUri(locationUri: string): void { if (locationUri.length < 1 || locationUri.length > 1024) { - throw new Error(`locationUri length must be (inclusively) between 1 and 1024, got ${locationUri.length}`); + throw new UnscopedValidationError(`locationUri length must be (inclusively) between 1 and 1024, got ${locationUri.length}`); } } function validateDescription(description: string): void { if (description.length > 2048) { - throw new Error(`description length must be less than or equal to 2048, got ${description.length}`); + throw new UnscopedValidationError(`description length must be less than or equal to 2048, got ${description.length}`); } } diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/external-table.ts b/packages/@aws-cdk/aws-glue-alpha/lib/external-table.ts index d807d6e945334..b192387562cb2 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/external-table.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/external-table.ts @@ -6,6 +6,7 @@ import { Column } from './schema'; import { PartitionIndex, TableBase, TableBaseProps } from './table-base'; import { addConstructMetadata, MethodMetadata } from 'aws-cdk-lib/core/lib/metadata-resource'; import { propertyInjectable } from 'aws-cdk-lib/core/lib/prop-injectable'; +import { ValidationError } from 'aws-cdk-lib'; export interface ExternalTableProps extends TableBaseProps { /** @@ -90,7 +91,7 @@ export class ExternalTable extends TableBase { }, parameters: props.storageParameters ? props.storageParameters.reduce((acc, param) => { if (param.key in acc) { - throw new Error(`Duplicate storage parameter key: ${param.key}`); + throw new ValidationError(`Duplicate storage parameter key: ${param.key}`, this); } const key = param.key; acc[key] = param.value; diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/jobs/job.ts b/packages/@aws-cdk/aws-glue-alpha/lib/jobs/job.ts index 4102e53068b70..9c3f4fb0e5fe7 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/jobs/job.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/jobs/job.ts @@ -488,7 +488,7 @@ export abstract class Job extends JobBase { const reservedArgs = new Set(['--debug', '--mode', '--JOB_NAME']); Object.keys(defaultArguments).forEach((arg) => { if (reservedArgs.has(arg)) { - throw new Error(`The ${arg} argument is reserved by Glue. Don't set it`); + throw new cdk.ValidationError(`The ${arg} argument is reserved by Glue. Don't set it`, this); } }); } diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/jobs/ray-job.ts b/packages/@aws-cdk/aws-glue-alpha/lib/jobs/ray-job.ts index 4da14d3de50be..19084c4970d64 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/jobs/ray-job.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/jobs/ray-job.ts @@ -5,6 +5,7 @@ import { Construct } from 'constructs'; import { JobType, GlueVersion, WorkerType, Runtime } from '../constants'; import { addConstructMetadata } from 'aws-cdk-lib/core/lib/metadata-resource'; import { propertyInjectable } from 'aws-cdk-lib/core/lib/prop-injectable'; +import { ValidationError } from 'aws-cdk-lib/core'; /** * Properties for creating a Ray Glue job @@ -77,7 +78,7 @@ export class RayJob extends Job { }; if (props.workerType && props.workerType !== WorkerType.Z_2X) { - throw new Error('Ray jobs only support Z.2X worker type'); + throw new ValidationError('Ray jobs only support Z.2X worker type', this); } const jobResource = new CfnJob(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/jobs/scala-spark-etl-job.ts b/packages/@aws-cdk/aws-glue-alpha/lib/jobs/scala-spark-etl-job.ts index 43841741c37bc..9370ae505c598 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/jobs/scala-spark-etl-job.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/jobs/scala-spark-etl-job.ts @@ -5,6 +5,7 @@ import { Code } from '../code'; import { SparkJob, SparkJobProps } from './spark-job'; import { addConstructMetadata } from 'aws-cdk-lib/core/lib/metadata-resource'; import { propertyInjectable } from 'aws-cdk-lib/core/lib/prop-injectable'; +import { ValidationError } from 'aws-cdk-lib/core'; /** * Properties for creating a Scala Spark ETL job @@ -89,7 +90,7 @@ export class ScalaSparkEtlJob extends SparkJob { }; if ((!props.workerType && props.numberOfWorkers !== undefined) || (props.workerType && props.numberOfWorkers === undefined)) { - throw new Error('Both workerType and numberOfWorkers must be set'); + throw new ValidationError('Both workerType and numberOfWorkers must be set', this); } const jobResource = new CfnJob(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/jobs/scala-spark-streaming-job.ts b/packages/@aws-cdk/aws-glue-alpha/lib/jobs/scala-spark-streaming-job.ts index 85c09836cd09f..d1af5623fe525 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/jobs/scala-spark-streaming-job.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/jobs/scala-spark-streaming-job.ts @@ -5,6 +5,7 @@ import { Code } from '../code'; import { SparkJob, SparkJobProps } from './spark-job'; import { addConstructMetadata } from 'aws-cdk-lib/core/lib/metadata-resource'; import { propertyInjectable } from 'aws-cdk-lib/core/lib/prop-injectable'; +import { ValidationError } from 'aws-cdk-lib/core'; /** * Properties for creating a Scala Spark ETL job @@ -89,7 +90,7 @@ export class ScalaSparkStreamingJob extends SparkJob { }; if ((!props.workerType && props.numberOfWorkers !== undefined) || (props.workerType && props.numberOfWorkers === undefined)) { - throw new Error('Both workerType and numberOfWorkers must be set'); + throw new ValidationError('Both workerType and numberOfWorkers must be set', this); } const jobResource = new CfnJob(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/jobs/spark-job.ts b/packages/@aws-cdk/aws-glue-alpha/lib/jobs/spark-job.ts index 9e1ceaaa203bb..f54359c9b8ab2 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/jobs/spark-job.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/jobs/spark-job.ts @@ -4,7 +4,7 @@ import { addConstructMetadata } from 'aws-cdk-lib/core/lib/metadata-resource'; import * as constructs from 'constructs'; import { Code } from '../code'; import { Job, JobProps } from './job'; -import { Token } from 'aws-cdk-lib'; +import { Token, UnscopedValidationError } from 'aws-cdk-lib'; import { EOL } from 'os'; /** @@ -198,7 +198,7 @@ function validateSparkUiPrefix(prefix?: string): void { } if (errors.length > 0) { - throw new Error(`Invalid prefix format (value: ${prefix})${EOL}${errors.join(EOL)}`); + throw new UnscopedValidationError(`Invalid prefix format (value: ${prefix})${EOL}${errors.join(EOL)}`); } } diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/s3-table.ts b/packages/@aws-cdk/aws-glue-alpha/lib/s3-table.ts index 86d72a5c5272d..90f23af751b36 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/s3-table.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/s3-table.ts @@ -7,6 +7,7 @@ import { Column } from './schema'; import { PartitionIndex, TableBase, TableBaseProps } from './table-base'; import { addConstructMetadata, MethodMetadata } from 'aws-cdk-lib/core/lib/metadata-resource'; import { propertyInjectable } from 'aws-cdk-lib/core/lib/prop-injectable'; +import { UnscopedValidationError, ValidationError } from 'aws-cdk-lib'; /** * Encryption options for a Table. @@ -162,7 +163,7 @@ export class S3Table extends TableBase { }, parameters: props.storageParameters ? props.storageParameters.reduce((acc, param) => { if (param.key in acc) { - throw new Error(`Duplicate storage parameter key: ${param.key}`); + throw new ValidationError(`Duplicate storage parameter key: ${param.key}`, this); } const key = param.key; acc[key] = param.value; @@ -264,7 +265,7 @@ function createBucket(table: S3Table, props: S3TableProps) { let bucket = props.bucket; if (bucket && (props.encryption !== undefined && props.encryption !== TableEncryption.CLIENT_SIDE_KMS)) { - throw new Error('you can not specify encryption settings if you also provide a bucket'); + throw new UnscopedValidationError('you can not specify encryption settings if you also provide a bucket'); } const encryption = props.encryption || TableEncryption.S3_MANAGED; diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/schema.ts b/packages/@aws-cdk/aws-glue-alpha/lib/schema.ts index aba682da7e0df..2f000daa4e0db 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/schema.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/schema.ts @@ -1,3 +1,5 @@ +import { UnscopedValidationError } from 'aws-cdk-lib'; + /** * A column of a table. */ @@ -137,10 +139,10 @@ export class Schema { */ public static char(length: number): Type { if (length <= 0 || length > 255) { - throw new Error(`char length must be (inclusively) between 1 and 255, but was ${length}`); + throw new UnscopedValidationError(`char length must be (inclusively) between 1 and 255, but was ${length}`); } if (length % 1 !== 0) { - throw new Error(`char length must be a positive integer, was ${length}`); + throw new UnscopedValidationError(`char length must be a positive integer, was ${length}`); } return { isPrimitive: true, @@ -155,10 +157,10 @@ export class Schema { */ public static varchar(length: number): Type { if (length <= 0 || length > 65535) { - throw new Error(`varchar length must be (inclusively) between 1 and 65535, but was ${length}`); + throw new UnscopedValidationError(`varchar length must be (inclusively) between 1 and 65535, but was ${length}`); } if (length % 1 !== 0) { - throw new Error(`varchar length must be a positive integer, was ${length}`); + throw new UnscopedValidationError(`varchar length must be a positive integer, was ${length}`); } return { isPrimitive: true, @@ -186,7 +188,7 @@ export class Schema { */ public static map(keyType: Type, valueType: Type): Type { if (!keyType.isPrimitive) { - throw new Error(`the key type of a 'map' must be a primitive, but was ${keyType.inputString}`); + throw new UnscopedValidationError(`the key type of a 'map' must be a primitive, but was ${keyType.inputString}`); } return { isPrimitive: false, diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/security-configuration.ts b/packages/@aws-cdk/aws-glue-alpha/lib/security-configuration.ts index 266e277c434d2..392a3011ea801 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/security-configuration.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/security-configuration.ts @@ -202,7 +202,7 @@ export class SecurityConfiguration extends cdk.Resource implements ISecurityConf addConstructMetadata(this, props); if (!props.s3Encryption && !props.cloudWatchEncryption && !props.jobBookmarksEncryption) { - throw new Error('One of cloudWatchEncryption, jobBookmarksEncryption or s3Encryption must be defined'); + throw new cdk.ValidationError('One of cloudWatchEncryption, jobBookmarksEncryption or s3Encryption must be defined', this); } const kmsKeyCreationRequired = diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/table-base.ts b/packages/@aws-cdk/aws-glue-alpha/lib/table-base.ts index 5172909b866d8..e423b99419c92 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/table-base.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/table-base.ts @@ -1,6 +1,6 @@ import { CfnTable } from 'aws-cdk-lib/aws-glue'; import * as iam from 'aws-cdk-lib/aws-iam'; -import { ArnFormat, Fn, IResource, Lazy, Names, Resource, Stack } from 'aws-cdk-lib/core'; +import { ArnFormat, Fn, IResource, Lazy, Names, Resource, Stack, UnscopedValidationError, ValidationError } from 'aws-cdk-lib/core'; import * as cr from 'aws-cdk-lib/custom-resources'; import { AwsCustomResource } from 'aws-cdk-lib/custom-resources'; import { Construct } from 'constructs'; @@ -270,7 +270,7 @@ export abstract class TableBase extends Resource implements ITable { public addPartitionIndex(index: PartitionIndex) { const numPartitions = this.partitionIndexCustomResources.length; if (numPartitions >= 3) { - throw new Error('Maximum number of partition indexes allowed is 3'); + throw new ValidationError('Maximum number of partition indexes allowed is 3', this); } this.validatePartitionIndex(index); @@ -316,14 +316,14 @@ export abstract class TableBase extends Resource implements ITable { private validatePartitionIndex(index: PartitionIndex) { if (index.indexName !== undefined && (index.indexName.length < 1 || index.indexName.length > 255)) { - throw new Error(`Index name must be between 1 and 255 characters, but got ${index.indexName.length}`); + throw new ValidationError(`Index name must be between 1 and 255 characters, but got ${index.indexName.length}`, this); } if (!this.partitionKeys || this.partitionKeys.length === 0) { - throw new Error('The table must have partition keys to create a partition index'); + throw new ValidationError('The table must have partition keys to create a partition index', this); } const keyNames = this.partitionKeys.map(pk => pk.name); if (!index.keyNames.every(k => keyNames.includes(k))) { - throw new Error(`All index keys must also be partition keys. Got ${index.keyNames} but partition key names are ${keyNames}`); + throw new ValidationError(`All index keys must also be partition keys. Got ${index.keyNames} but partition key names are ${keyNames}`, this); } } @@ -357,13 +357,13 @@ export abstract class TableBase extends Resource implements ITable { function validateSchema(columns: Column[], partitionKeys?: Column[]): void { if (columns.length === 0) { - throw new Error('you must specify at least one column for the table'); + throw new UnscopedValidationError('you must specify at least one column for the table'); } // Check there is at least one column and no duplicated column names or partition keys. const names = new Set(); (columns.concat(partitionKeys || [])).forEach(column => { if (names.has(column.name)) { - throw new Error(`column names and partition keys must be unique, but \'${column.name}\' is duplicated`); + throw new UnscopedValidationError(`column names and partition keys must be unique, but \'${column.name}\' is duplicated`); } names.add(column.name); }); diff --git a/packages/@aws-cdk/aws-glue-alpha/lib/triggers/workflow.ts b/packages/@aws-cdk/aws-glue-alpha/lib/triggers/workflow.ts index c8cfd4e3dfd76..d1ef141fa3c95 100644 --- a/packages/@aws-cdk/aws-glue-alpha/lib/triggers/workflow.ts +++ b/packages/@aws-cdk/aws-glue-alpha/lib/triggers/workflow.ts @@ -266,9 +266,9 @@ export abstract class WorkflowBase extends cdk.Resource implements IWorkflow { private renderAction(action: Action): CfnTrigger.ActionProperty { // Validate that either job or crawler is provided, but not both if (!action.job && !action.crawler) { - throw new Error('You must provide either a job or a crawler for the action.'); + throw new cdk.ValidationError('You must provide either a job or a crawler for the action.', this); } else if (action.job && action.crawler) { - throw new Error('You cannot provide both a job and a crawler for the action.'); + throw new cdk.ValidationError('You cannot provide both a job and a crawler for the action.', this); } return { @@ -284,19 +284,19 @@ export abstract class WorkflowBase extends cdk.Resource implements IWorkflow { const conditions = props.predicate.conditions?.map(condition => { // Validate that either job or crawler is provided, but not both if (!condition.job && !condition.crawlerName) { - throw new Error('You must provide either a job or a crawler for the condition.'); + throw new cdk.ValidationError('You must provide either a job or a crawler for the condition.', this); } else if (condition.job && condition.crawlerName) { - throw new Error('You cannot provide both a job and a crawler for the condition.'); + throw new cdk.ValidationError('You cannot provide both a job and a crawler for the condition.', this); } // Validate that if job is provided, job state is also provided if (condition.job && !condition.state) { - throw new Error('If you provide a job for the condition, you must also provide a job state.'); + throw new cdk.ValidationError('If you provide a job for the condition, you must also provide a job state.', this); } // Validate that if crawler is provided, crawler state is also provided if (condition.crawlerName && !condition.crawlState) { - throw new Error('If you provide a crawler for the condition, you must also provide a crawler state.'); + throw new cdk.ValidationError('If you provide a crawler for the condition, you must also provide a crawler state.', this); } return {