<commit_before>/**
 * @typedef { import('aws-lambda').SNSEvent } SNSEvent
 */

const AWS = require('aws-sdk');
const AdmZip = require('adm-zip');
const fs = require('fs');
const os = require('os');
const path = require('path');

const cloudformation = new AWS.CloudFormation({ apiVersion: '2010-05-15' });
const codepipeline = new AWS.CodePipeline({ apiVersion: '2015-07-09' });
const s3 = new AWS.S3({ apiVersion: '2006-03-01' });

/**
 * Downloads the given S3 object to a local file path
 * @param {string} bucketName
 * @param {string} objectKey
 * @param {string} filePath
 */
function s3GetObject(bucketName, objectKey, filePath) {
  return new Promise((resolve, reject) => {
    const file = fs.createWriteStream(filePath);
    const stream = s3
      .getObject({
        Bucket: bucketName,
        Key: objectKey,
      })
      .createReadStream();

    stream.on('error', reject);
    file.on('error', reject);

    file.on('finish', () => {
      resolve(filePath);
    });

    stream.pipe(file);
  });
}

/**
 * Publishes a Slack message to the relay SNS topic with information about a
 * CloudFormation change set. This is executed as an action within a
 * CodePipeline.
 * @param {SNSEvent} event
 * @returns {Promise<void>}
 */
exports.handler = async (event, context) => {
  console.log(JSON.stringify(event));

  const job = event['CodePipeline.job'];

  try {
    // Make a folder to hold local copies of the input artifacts
    fs.mkdirSync(path.join(os.tmpdir(), context.awsRequestId));

    const inputArtifacts = job.data.inputArtifacts;

    // Download the template config Zip file, and extract the stack parameters
    // from it
    const configZipTempPath = path.join(
      os.tmpdir(),
      context.awsRequestId,
      'config.zip',
    );
    const configArtifact = inputArtifacts.find((a) =>
      [
        'TemplateConfigStagingZipArtifact',
        'TemplateConfigProductionZipArtifact',
      ].includes(a.name),
    );
    await s3GetObject(
      configArtifact.location.s3Location.bucketName,
      configArtifact.location.s3Location.objectKey,
      configZipTempPath,
    );
    const configZip = new AdmZip(configZipTempPath);
    const configJson = configZip.readAsText('staging.json');
    const config = JSON.parse(configJson);
    const configParams = config.Parameters;

    // Download the Infrastructure repo Zip file, extract root.yml, and send
    // it back to S3 so that the change set can reference it directly
    const repoZipTempPath = path.join(
      os.tmpdir(),
      context.awsRequestId,
      'repo.zip',
    );
    const repoArtifact = inputArtifacts.find(
      (a) => a.name === 'InfrastructureRepoSourceArtifact',
    );
    await s3GetObject(
      repoArtifact.location.s3Location.bucketName,
      repoArtifact.location.s3Location.objectKey,
      repoZipTempPath,
    );
    const repoZip = new AdmZip(repoZipTempPath);
    const rootYaml = repoZip.readAsText('stacks/root.yml');
    const rootYamlObjectKey = `${repoArtifact.location.s3Location.objectKey}/${context.awsRequestId}`;
    await s3
      .putObject({
        Bucket: repoArtifact.location.s3Location.bucketName,
        Key: rootYamlObjectKey,
        Body: rootYaml,
      })
      .promise();

    const actionConfig = job.data.actionConfiguration;
    const userParamsJson = actionConfig.configuration.UserParameters;
    const userParams = JSON.parse(userParamsJson);

    const stackName = userParams.StackName;
    const changeSetName = userParams.ChangeSetName;
    const paramOverrides = userParams.ParameterOverrides;
    const roleArn = userParams.RoleArn;

    const changeSetParams = Object.assign(configParams, paramOverrides);
    const changeSetParamsArray = Object.keys(changeSetParams).map((k) => ({
      ParameterKey: k,
      ParameterValue: changeSetParams[k],
    }));

    const existingChangeSet = await cloudformation
      .describeChangeSet({
        StackName: stackName,
        ChangeSetName: changeSetName,
      })
      .promise();

    if (existingChangeSet?.ExecutionStatus === 'EXECUTE_IN_PROGRESS') {
      // Don't try to delete a change set that is currently executing. (I don't
      // know if that's even possible.)
      await codepipeline
        .putJobFailureResult({
          jobId: job.id,
          failureDetails: {
            message: `Can't delete in progress change set`,
            type: 'JobFailed',
          },
        })
        .promise();
      return;
    } else if (existingChangeSet?.ChangeSetId) {
      await cloudformation
        .deleteChangeSet({
          StackName: stackName,
          ChangeSetName: changeSetName,
        })
        .promise();
    }
<commit_msg>Wrap change set describe in try/catch<commit_after>/**
 * @typedef { import('aws-lambda').SNSEvent } SNSEvent
 */

const AWS = require('aws-sdk');
const AdmZip = require('adm-zip');
const fs = require('fs');
const os = require('os');
const path = require('path');

const cloudformation = new AWS.CloudFormation({ apiVersion: '2010-05-15' });
const codepipeline = new AWS.CodePipeline({ apiVersion: '2015-07-09' });
const s3 = new AWS.S3({ apiVersion: '2006-03-01' });

/**
 * Downloads the given S3 object to a local file path
 * @param {string} bucketName
 * @param {string} objectKey
 * @param {string} filePath
 */
function s3GetObject(bucketName, objectKey, filePath) {
  return new Promise((resolve, reject) => {
    const file = fs.createWriteStream(filePath);
    const stream = s3
      .getObject({
        Bucket: bucketName,
        Key: objectKey,
      })
      .createReadStream();

    stream.on('error', reject);
    file.on('error', reject);

    file.on('finish', () => {
      resolve(filePath);
    });

    stream.pipe(file);
  });
}

/**
 * Publishes a Slack message to the relay SNS topic with information about a
 * CloudFormation change set. This is executed as an action within a
 * CodePipeline.
 * @param {SNSEvent} event
 * @returns {Promise<void>}
 */
exports.handler = async (event, context) => {
  console.log(JSON.stringify(event));

  const job = event['CodePipeline.job'];

  try {
    // Make a folder to hold local copies of the input artifacts
    fs.mkdirSync(path.join(os.tmpdir(), context.awsRequestId));

    const inputArtifacts = job.data.inputArtifacts;

    // Download the template config Zip file, and extract the stack parameters
    // from it
    const configZipTempPath = path.join(
      os.tmpdir(),
      context.awsRequestId,
      'config.zip',
    );
    const configArtifact = inputArtifacts.find((a) =>
      [
        'TemplateConfigStagingZipArtifact',
        'TemplateConfigProductionZipArtifact',
      ].includes(a.name),
    );
    await s3GetObject(
      configArtifact.location.s3Location.bucketName,
      configArtifact.location.s3Location.objectKey,
      configZipTempPath,
    );
    const configZip = new AdmZip(configZipTempPath);
    const configJson = configZip.readAsText('staging.json');
    const config = JSON.parse(configJson);
    const configParams = config.Parameters;

    // Download the Infrastructure repo Zip file, extract root.yml, and send
    // it back to S3 so that the change set can reference it directly
    const repoZipTempPath = path.join(
      os.tmpdir(),
      context.awsRequestId,
      'repo.zip',
    );
    const repoArtifact = inputArtifacts.find(
      (a) => a.name === 'InfrastructureRepoSourceArtifact',
    );
    await s3GetObject(
      repoArtifact.location.s3Location.bucketName,
      repoArtifact.location.s3Location.objectKey,
      repoZipTempPath,
    );
    const repoZip = new AdmZip(repoZipTempPath);
    const rootYaml = repoZip.readAsText('stacks/root.yml');
    const rootYamlObjectKey = `${repoArtifact.location.s3Location.objectKey}/${context.awsRequestId}`;
    await s3
      .putObject({
        Bucket: repoArtifact.location.s3Location.bucketName,
        Key: rootYamlObjectKey,
        Body: rootYaml,
      })
      .promise();

    const actionConfig = job.data.actionConfiguration;
    const userParamsJson = actionConfig.configuration.UserParameters;
    const userParams = JSON.parse(userParamsJson);

    const stackName = userParams.StackName;
    const changeSetName = userParams.ChangeSetName;
    const paramOverrides = userParams.ParameterOverrides;
    const roleArn = userParams.RoleArn;

    const changeSetParams = Object.assign(configParams, paramOverrides);
    const changeSetParamsArray = Object.keys(changeSetParams).map((k) => ({
      ParameterKey: k,
      ParameterValue: changeSetParams[k],
    }));

    let existingChangeSet;
    try {
      existingChangeSet = await cloudformation
        .describeChangeSet({
          StackName: stackName,
          ChangeSetName: changeSetName,
        })
        .promise();

      if (existingChangeSet?.ExecutionStatus === 'EXECUTE_IN_PROGRESS') {
        // Don't try to delete a change set that is currently executing. (I don't
        // know if that's even possible.)
        await codepipeline
          .putJobFailureResult({
            jobId: job.id,
            failureDetails: {
              message: `Can't delete in progress change set`,
              type: 'JobFailed',
            },
          })
          .promise();
        return;
      } else if (existingChangeSet?.ChangeSetId) {
        await cloudformation
          .deleteChangeSet({
            StackName: stackName,
            ChangeSetName: changeSetName,
          })
          .promise();
      }
    } catch (e) {}

{'fraction_non_alphanumeric': 0.11427366645582965, 'fraction_numerical': 0.008222643896268185, 'mean_word_length': 2.933250414593698, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '951532', 'n_tokens_mistral': 2836, 'n_tokens_neox': 2733, 'n_words': 673}