Search code examples
amazon-web-servicescontinuous-integrationaws-codebuildaws-event-bridge

AWS EventBridge: Get branch name and last commit author for AWS CodeBuild event rule


We're using CodeBuild and have implemented our own email build notification system (as seems to be required currently).

We use the same CodeBuild project to build all of our branches for the same Bitbucket repository and we use an EventBridge rule that triggers if that CodeBuild project fails. It then calls a Lambda function to issue a notification via a SNS topic.

We can get some basic information in the event passed to Lambda from EventBridge, such as the build number, project and status. But we need to include the branch the build was triggered for since it is confusing when these emails arrive and it's unclear what branch the error was on. Additionally, having the author of the commit triggering the build would be helpful to just email them rather than the more general notification we're currently doing.

Unfortunately neither the branch nor author seem to be in the event. Is there a way to include them or fetch them?

Our EventBridge event pattern is

{
  "detail": {
    "build-status": ["FAILED"],
    "project-name": ["api"]
  },
  "detail-type": ["CodeBuild Build State Change"],
  "source": ["aws.codebuild"]
}

Our Lambda is

const AWS = require("aws-sdk");

const snsTopicArn = process.env.TOPIC_ARN;

exports.handler = (event, context, callback) => {
  const status = event.detail["build-status"];
  const project = event.detail["project-name"];
  const buildLabel = event.detail["additional-information"]["build-number"];

  const account = event.account;
  const region = event.region;

  // determine the link to the build
  const buildFullId = event.detail["build-id"];
  const buildIdParts = buildFullId.split(":");
  const buildId = buildIdParts[buildIdParts.length - 1];
  const buildLink = `https://${region}.console.aws.amazon.com/codesuite/codebuild/${account}/projects/${project}/build/${project}%3A${buildId}/?region=${region}`;

  const subject = `${project} build ${buildLabel} ${status}`;

  const message = `${subject}\n\n${buildLink}`;

  const sns = new AWS.SNS();
  sns.publish(
    {
      TopicArn: snsTopicArn,
      Message: message,
      Subject: subject,
    },
    function (error, data) {
      if (error) console.log(error, error.stack);
      callback(error, data);
    }
  );
};

And we're getting events like this passed to our Lambda:

{
  "version": "0",
  "id": "...",
  "detail-type": "CodeBuild Build State Change",
  "source": "aws.codebuild",
  "account": "...",
  "time": "2022-08-24T09:01:14Z",
  "region": "eu-west-2",
  "resources": [
    "arn:aws:codebuild:eu-west-2:...:build/demo-release-deployment:..."
  ],
  "detail": {
    "build-status": "FAILED",
    "project-name": "demo-release-deployment",
    "build-id": "arn:aws:codebuild:eu-west-2:...:build/demo-release-deployment:...",
    "additional-information": {
      "cache": {
        "type": "NO_CACHE"
      },
      "build-number": 18,
      "timeout-in-minutes": 10,
      "build-complete": true,
      "initiator": "...",
      "build-start-time": "Aug 24, 2022 8:57:39 AM",
      "source": {
        "report-build-status": true,
        "buildspec": "",
        "location": "...@bitbucket.org/.../build-test.git>https://...@bitbucket.org/.../build-test.git",
        "git-clone-depth": 1,
        "type": "BITBUCKET",
        "git-submodules-config": {
          "fetch-submodules": true
        }
      },
      "artifact": {
        "location": ""
      },
      "environment": {
        "image": "aws/codebuild/amazonlinux2-x86_64-standard:4.0",
        "privileged-mode": false,
        "image-pull-credentials-type": "CODEBUILD",
        "compute-type": "BUILD_GENERAL1_SMALL",
        "type": "LINUX_CONTAINER",
        "environment-variables": []
      },
      "logs": {
        "group-name": "demo-deployment",
        "stream-name": "demo-deployment/...",
        "deep-link": "https://console.aws.amazon.com/cloudwatch/home?region=eu-west-2#logEvent:group=demo-deployment;stream=demo-deployment/..."
      },
      "phases": [
        {
          "phase-context": [],
          "start-time": "Aug 24, 2022 8:57:39 AM",
          "end-time": "Aug 24, 2022 8:57:39 AM",
          "duration-in-seconds": 0,
          "phase-type": "SUBMITTED",
          "phase-status": "SUCCEEDED"
        },
        {
          "phase-context": [],
          "start-time": "Aug 24, 2022 8:57:39 AM",
          "end-time": "Aug 24, 2022 8:58:51 AM",
          "duration-in-seconds": 72,
          "phase-type": "QUEUED",
          "phase-status": "SUCCEEDED"
        },
        {
          "phase-context": [": "],
          "start-time": "Aug 24, 2022 8:58:51 AM",
          "end-time": "Aug 24, 2022 9:00:59 AM",
          "duration-in-seconds": 127,
          "phase-type": "PROVISIONING",
          "phase-status": "SUCCEEDED"
        },
        {
          "phase-context": [": "],
          "start-time": "Aug 24, 2022 9:00:59 AM",
          "end-time": "Aug 24, 2022 9:01:06 AM",
          "duration-in-seconds": 6,
          "phase-type": "DOWNLOAD_SOURCE",
          "phase-status": "SUCCEEDED"
        },
        {
          "phase-context": [": "],
          "start-time": "Aug 24, 2022 9:01:06 AM",
          "end-time": "Aug 24, 2022 9:01:06 AM",
          "duration-in-seconds": 0,
          "phase-type": "INSTALL",
          "phase-status": "SUCCEEDED"
        },
        {
          "phase-context": [": "],
          "start-time": "Aug 24, 2022 9:01:06 AM",
          "end-time": "Aug 24, 2022 9:01:06 AM",
          "duration-in-seconds": 0,
          "phase-type": "PRE_BUILD",
          "phase-status": "SUCCEEDED"
        },
        {
          "phase-context": [
            "COMMAND_EXECUTION_ERROR: Error while executing command: npm publish. Reason: exit status 1"
          ],
          "start-time": "Aug 24, 2022 9:01:06 AM",
          "end-time": "Aug 24, 2022 9:01:11 AM",
          "duration-in-seconds": 4,
          "phase-type": "BUILD",
          "phase-status": "FAILED"
        },
        {
          "phase-context": [": "],
          "start-time": "Aug 24, 2022 9:01:11 AM",
          "end-time": "Aug 24, 2022 9:01:11 AM",
          "duration-in-seconds": 0,
          "phase-type": "POST_BUILD",
          "phase-status": "SUCCEEDED"
        },
        {
          "phase-context": [": "],
          "start-time": "Aug 24, 2022 9:01:11 AM",
          "end-time": "Aug 24, 2022 9:01:11 AM",
          "duration-in-seconds": 0,
          "phase-type": "UPLOAD_ARTIFACTS",
          "phase-status": "SUCCEEDED"
        },
        {
          "phase-context": [": "],
          "start-time": "Aug 24, 2022 9:01:11 AM",
          "end-time": "Aug 24, 2022 9:01:13 AM",
          "duration-in-seconds": 2,
          "phase-type": "FINALIZING",
          "phase-status": "SUCCEEDED"
        },
        {
          "start-time": "Aug 24, 2022 9:01:13 AM",
          "phase-type": "COMPLETED"
        }
      ],
      "queued-timeout-in-minutes": 480
    },
    "current-phase": "COMPLETED",
    "current-phase-context": "[: ]",
    "version": "1"
  }
}

Solution

  • I had the same task. I tried to find any solution. I tried to implement the following script: https://github.com/thii/aws-codebuild-extras. But there is a problem with moving environment variables to lambda.

    So finally I solved it using the following steps:

    1. I print author email in buildSpec.yml file:
      pre_build:
        commands:
          - AUTHOR_EMAIL="$(git log -1 --pretty=%ae)"
          - echo "CODEBUILD_GIT_AUTHOR_EMAIL=$AUTHOR_EMAIL"
    
    1. I get all logs from CloudWatch in my lambda handler and find string by pattern ^CODEBUILD_GIT_AUTHOR_EMAIL=(.*)$
    2. I send message to this email using AWS SES inside my lambda handler

    Very bad solution, but it works. I can't cost more time for this task