constructor()

in packages/aws-cdk-lib/aws-codebuild/lib/project.ts [1060:1222]


  constructor(scope: Construct, id: string, props: ProjectProps) {
    super(scope, id, {
      physicalName: props.projectName,
    });
    // Enhanced CDK Analytics Telemetry
    addConstructMetadata(this, props);

    this.role = props.role || new iam.Role(this, 'Role', {
      roleName: PhysicalName.GENERATE_IF_NEEDED,
      assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'),
    });
    this.grantPrincipal = this.role;

    this.buildImage = (props.environment && props.environment.buildImage) || LinuxBuildImage.STANDARD_7_0;

    // let source "bind" to the project. this usually involves granting permissions
    // for the code build role to interact with the source.
    this.source = props.source || new NoSource();
    const sourceConfig = this.source.bind(this, this);
    if (props.badge && !this.source.badgeSupported) {
      throw new ValidationError(`Badge is not supported for source type ${this.source.type}`, this);
    }

    const artifacts = props.artifacts
      ? props.artifacts
      : (this.source.type === CODEPIPELINE_SOURCE_ARTIFACTS_TYPE
        ? new CodePipelineArtifacts()
        : new NoArtifacts());
    const artifactsConfig = artifacts.bind(this, this);

    const cache = props.cache || Cache.none();

    // give the caching strategy the option to grant permissions to any required resources
    cache._bind(this);

    // Inject download commands for asset if requested
    const environmentVariables = props.environmentVariables || {};
    const buildSpec = props.buildSpec;
    if (this.source.type === NO_SOURCE_TYPE && (buildSpec === undefined || !buildSpec.isImmediate)) {
      throw new ValidationError("If the Project's source is NoSource, you need to provide a concrete buildSpec", this);
    }

    this._secondarySources = [];
    this._secondarySourceVersions = [];
    this._fileSystemLocations = [];
    for (const secondarySource of props.secondarySources || []) {
      this.addSecondarySource(secondarySource);
    }

    this._secondaryArtifacts = [];
    for (const secondaryArtifact of props.secondaryArtifacts || []) {
      this.addSecondaryArtifact(secondaryArtifact);
    }

    this.validateCodePipelineSettings(artifacts);

    for (const fileSystemLocation of props.fileSystemLocations || []) {
      this.addFileSystemLocation(fileSystemLocation);
    }

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

    const resource = new CfnProject(this, 'Resource', {
      description: props.description,
      source: {
        ...sourceConfig.sourceProperty,
        buildSpec: buildSpec && buildSpec.toBuildSpec(this),
      },
      artifacts: artifactsConfig.artifactsProperty,
      serviceRole: this.role.roleArn,
      environment: this.renderEnvironment(props, environmentVariables),
      fileSystemLocations: Lazy.any({ produce: () => this.renderFileSystemLocations() }),
      // lazy, because we have a setter for it in setEncryptionKey
      // The 'alias/aws/s3' default is necessary because leaving the `encryptionKey` field
      // empty will not remove existing encryptionKeys during an update (ref. t/D17810523)
      encryptionKey: Lazy.string({ produce: () => this._encryptionKey ? this._encryptionKey.keyArn : 'alias/aws/s3' }),
      badgeEnabled: props.badge,
      cache: cache._toCloudFormation(),
      name: this.physicalName,
      timeoutInMinutes: props.timeout && props.timeout.toMinutes(),
      queuedTimeoutInMinutes: props.queuedTimeout && props.queuedTimeout.toMinutes(),
      concurrentBuildLimit: props.concurrentBuildLimit,
      secondarySources: Lazy.any({ produce: () => this.renderSecondarySources() }),
      secondarySourceVersions: Lazy.any({ produce: () => this.renderSecondarySourceVersions() }),
      secondaryArtifacts: Lazy.any({ produce: () => this.renderSecondaryArtifacts() }),
      triggers: sourceConfig.buildTriggers,
      sourceVersion: sourceConfig.sourceVersion,
      vpcConfig: this.configureVpc(props),
      visibility: props.visibility,
      logsConfig: this.renderLoggingConfiguration(props.logging),
      buildBatchConfig: Lazy.any({
        produce: () => {
          const config: CfnProject.ProjectBuildBatchConfigProperty | undefined = this._batchServiceRole ? {
            serviceRole: this._batchServiceRole.roleArn,
          } : undefined;
          return config;
        },
      }),
      autoRetryLimit: props.autoRetryLimit,
    });

    this.addVpcRequiredPermissions(props, resource);

    this.projectArn = this.getResourceArnAttribute(resource.attrArn, {
      service: 'codebuild',
      resource: 'project',
      resourceName: this.physicalName,
    });
    this.projectName = this.getResourceNameAttribute(resource.ref);

    this.addToRolePolicy(this.createLoggingPermission());
    // add permissions to create and use test report groups
    // with names starting with the project's name,
    // unless the customer explicitly opts out of it
    if (props.grantReportGroupPermissions !== false) {
      this.addToRolePolicy(new iam.PolicyStatement({
        actions: [
          'codebuild:CreateReportGroup',
          'codebuild:CreateReport',
          'codebuild:UpdateReport',
          'codebuild:BatchPutTestCases',
          'codebuild:BatchPutCodeCoverages',
        ],
        resources: [renderReportGroupArn(this, `${this.projectName}-*`)],
      }));
    }

    // https://docs.aws.amazon.com/codebuild/latest/userguide/session-manager.html
    if (props.ssmSessionPermissions) {
      this.addToRolePolicy(new iam.PolicyStatement({
        actions: [
          // For the SSM channel
          'ssmmessages:CreateControlChannel',
          'ssmmessages:CreateDataChannel',
          'ssmmessages:OpenControlChannel',
          'ssmmessages:OpenDataChannel',
          // In case the SSM session is set up to log commands to CloudWatch
          'logs:DescribeLogGroups',
          'logs:CreateLogStream',
          'logs:PutLogEvents',
          // In case the SSM session is set up to log commands to S3.
          's3:GetEncryptionConfiguration',
          's3:PutObject',
        ],
        resources: ['*'],
      }));
    }

    if (props.encryptionKey) {
      this.encryptionKey = props.encryptionKey;
    }

    // bind
    if (isBindableBuildImage(this.buildImage)) {
      this.buildImage.bind(this, this, {});
    }

    this.node.addValidation({ validate: () => this.validateProject() });
  }