DEV Community

Cover image for Alexa for CI/CD: Putting it all together - Part 3
Moataz Nabil for AWS Community Builders

Posted on • Originally published at blog.bitrise.io

Alexa for CI/CD: Putting it all together - Part 3

In the previous two parts in this series, we created our Lambda function and the Alexa Skill. In this tutorial, we’ll learn how to connect Amazon Alexa Skill to the AWS Lambda function to trigger Bitrise builds via a voice user interface.

Sounds good? Let’s get started!

The solution

As we know AWS Lambda function needs to be triggered by any supported triggers. Because of this, we will use Alexa and Alexa Skill Kit (ASK) to trigger the function. Inside the function, we will add our logic to receive the voice command from Alexa and pass it to Bitrise API using the POST endpoint to trigger a new build in our Bitrise app. Then, we will get the response from Lambda to the Alexa as a JSON output.

1

Previously our Lambda function was using the following code to trigger the build via the POST endpoint:

var request = require('request');

let app_slug = process.env.APP_SLUG
let api_key = process.env.API_KEY

var options = {
  'method': 'POST',
  'url': 'https://api.bitrise.io/v0.1/apps/'+app_slug+'/builds',
  'headers': {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': api_key
  },
  body: JSON.stringify({
   'build_params': {
      'branch': 'chapter-3',
      'workflow_id': 'primary'
    },
    'hook_info': {
      'type': 'bitrise'
    }
  })

};

exports.handler =  async function(event, response) {
  console.log(response.body);
  return "done..."
}

request(options, function (error,response) {
  if (error) throw new Error(error);
  console.log(response.body);
});
Enter fullscreen mode Exit fullscreen mode

But with the Alexa Skill Kit, we need to change this handler and the code logic with something to work with the voice command and the Skill Kit by the following code:

var request = require('request');

exports.handler = (event, context, callback) => {

    try {
        if (event.request.type === 'LaunchRequest') {
            callback(null, buildResponse('Hello from Bitrise'));
        } else if (event.request.type === 'IntentRequest') {
            const intentName = event.request.intent.name;

            if (intentName === 'triggerBuild') {

                buildBitriseApp(function (err, result) {
                    if(!err) callback(null, buildResponse('The build was launched! make sure you take a look.'));
                    else callback(null, buildResponse("Please check your build logs. Something went wrong."));
                });
            } else {
                callback(null, buildResponse("Sorry, i don't understand"));
            }
        } else if (event.request.type === 'SessionEndedRequest') {
            callback(null, buildResponse('Session Ended'));
        }
    } catch (e) {
        context.fail(`Exception: ${e}`);
    }
};

function buildResponse(response) {
    return {
        version: '1.0',
        response: {
            outputSpeech: {
                type: 'PlainText',
                text: response,
            },
            shouldEndSession: true,
        },
        sessionAttributes: {},
    };
}

let api_key = process.env.API_PERSONAL_KEY;
let app_slug = process.env.APP_SLUG;

function buildBitriseApp(callback) {
var options = {
  'method': 'POST',
  'url': 'https://api.bitrise.io/v0.1/apps/'+app_slug+'/builds',
  'headers': {
    'Authorization': api_key
  },
  body: JSON.stringify({
    "User-Agent": "alexa-skill",
    "hook_info": {
      "type": "bitrise"
    },
    "build_params": {
      "branch": 'main',
      "workflow_id": 'primary'
    }
  })
};
    request.post(options, function(error, response, body){
        if(error){
            callback("ERROR");

        } else {
            callback(null,"SUCCESS");
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

In the above code, we are specifying that when we launch the skill we’ll receive a message “Hello from Bitrise” and check if the intentName is “triggerBuild”.

We can call the function “buildResponse”, which calls the POST endpoint from Bitrise API with the payload that we added, specifying the following parameters:

  • API Key
  • App Slug
  • Branch Name
  • Workflow ID

And we already added the API Key and the App Slug as Lambda Environment Variables.

Click the Deploy button to save the changes.

2

Now it’s time to add the Alexa Skill Kit as a trigger for our Lambda function.

Click on the + Add trigger button in the Function Overview and the trigger configuration and select the Alexa Skills kit.

3

Then you can add your Skill ID and click the add button. You can get the Skill ID from the Endpoint menu in the Skill Kit build section.

4

5

And now the trigger should be displayed like this:

6

On the other side, you need to add the Lambda ARN from the Lambda function page.

7

And go to the Alexa Skill kit by opening the Endpoint option in the build section and pasting the ARN there, then clicking Save Endpoint and choosing yes.

After that, click on the Code button and you will see a notification that the default endpoint has changed and is no longer hosted by Alexa because it’s now on AWS and Lambda.

8

Test the integration between Lambda and Alexa

Now click on the Test button to go to the Alexa Simulator page. And in the development write the following phrase:

Alexa, open bitrise ci” and click the Enter button

9

To trigger a new build you can write: “Alexa, ask bitrise ci trigger a new bitrise build” and click the Enter button

10

Open your Bitrise Dashboard and, if the command ran successfully, you will notice that the build was triggered successfully and you can abort it after that to save your credits.

11

We did it! Congratulations you have successfully triggered your first build using Bitrise API, Lambda via Alexa Skill kit.

Amazing!

Specifying the git branch name and the workflow name using Slots

You may notice that in our Lambda function we are using hardcoded values like the branch name and the workflow name as build parameters.

"build_params": {
      "branch": 'main',
      "workflow_id": 'primary'
    }
Enter fullscreen mode Exit fullscreen mode

But what if I need to use different values... Can I do that?

Of course, you can!

In the first part, we mentioned that Alexa Skill has a key feature which is Slots and you can use them as variables that you provide with a name and a slot type for each slot in your interaction model.

Let’s do it then!

In your Alexa Skills Console, click on Build then click on Slot Types, and click Add Slot Type.

12

  • Add BranchName and click the Next button
  • Enter default values such as main and master

13

  • Add another Slot WorkflowName click the Next button
  • Enter default values such as deploy and primary

14

Click on Intents then triggerBuild intent
Change the Sample Utterance to be like the following:

15

The Slots will be added under Intent Slots and make sure that the Slot Type is what we created previously.

16

var request = require('request');

var workflowSlot;
var branchSlot;

exports.handler = (event, context, callback) => {

    try {
        if (event.request.type === 'LaunchRequest') {
            callback(null, buildResponse('Hello from Bitrise'));
        } else if (event.request.type === 'IntentRequest') {
            const intentName = event.request.intent.name;
            workflowSlot = event.request.intent.slots.WorkflowName.value;
            branchSlot = event.request.intent.slots.BranchName.value;

            if (intentName === 'triggerBuild') {

                buildBitriseApp(function (err, result) {
                    if(!err) callback(null, buildResponse('The build was launched with '+ workflowSlot +' workflow for '+ branchSlot + ' branch. make sure you take a look.'));
                    else callback(null, buildResponse("Please check your build logs. Something went wrong."));
                });
            } else {
                callback(null, buildResponse("Sorry, i don't understand"));
            }
        } else if (event.request.type === 'SessionEndedRequest') {
            callback(null, buildResponse('Session Ended'));
        }
    } catch (e) {
        context.fail(`Exception: ${e}`);
    }
};

function buildResponse(response) {
    return {
        version: '1.0',
        response: {
            outputSpeech: {
                type: 'PlainText',
                text: response,
            },
            shouldEndSession: true,
        },
        sessionAttributes: {},
    };
}

let api_key = process.env.API_PERSONAL_KEY;
let app_slug = process.env.APP_SLUG;

function buildBitriseApp(callback) {
var options = {
  'method': 'POST',
  'url': 'https://api.bitrise.io/v0.1/apps/'+app_slug+'/builds',
  'headers': {
    'Authorization': api_key
  },
  body: JSON.stringify({
    "User-Agent": "alexa-skill",
    "hook_info": {
      "type": "bitrise"
    },
    "build_params": {
      "branch": branchSlot,
      "workflow_id": workflowSlot
    }
  })
};
    request.post(options, function(error, response, body){
        if(error){
            callback("ERROR");

        } else {
            callback(null,"SUCCESS");
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

In the above code we added these values:

var workflowSlot;
var branchSlot;

workflowSlot = event.request.intent.slots.WorkflowName.value;
branchSlot = event.request.intent.slots.BranchName.value;

And in the build parameters we replace the hardcoded values: 
"build_params": {
      "branch": branchSlot,
      "workflow_id": workflowSlot
    }
Enter fullscreen mode Exit fullscreen mode

Click Deploy to save the changes and now you can test your Alexa Skills Kit.

In the Alexa Simulator write the following phrase:

“Alexa, ask bitrise ci trigger build for primary workflow for main branch”

Note: You should have a workflow and branch name with the same values otherwise the build will not be triggered

I will try to use different apps and specify the workflow name and the branch name as well.

16

Monitor AWS Lambda with CloudWatch

You can also check the runtime metrics for your functions on Amazon CloudWatch. The metrics shown are an aggregate view of all function runtime activity.

17

What’s next?

In the next article, we will distribute our Alexa Skills Kit to be able to use in our AWS organization.

Top comments (1)

Collapse
 
abdullahparacha profile image
Abdullah Paracha

Good effort, worth to explore