DevOps your Alexa Skill
Tags: actionshackathon
Published: 2020-09-13 11:02:42


### My Workflow

"DevOps is the union of people, process, and products to enable continuous delivery of value to our end users." - Donovan Brown, Microsoft

DevOps is a "culture" which have a set of practices that combines software development (Dev) and information-technology operations (Ops) which aims to shorten the systems development life cycle and provide continuous delivery with high software quality. DevOps culture develops "production-first mindset". 
In terms of Alexa, DevOps can help us to quickly ship the highest quality of our Skill to the end customers.
This post contains materials from different resources that can be seen on Resources section.

#### Prerequisites

Here you have the technologies used in this project
1. Amazon Developer Account - [How to get it](http://developer.amazon.com/)
2. AWS Account - [Sign up here for free](https://aws.amazon.com/)
3. ASK CLI - [Install and configure ASK CLI](https://developer.amazon.com/es-ES/docs/alexa/smapi/quick-start-alexa-skills-kit-command-line-interface.html)
4. GitHub Account -  [Sign up here](https://github.com/)
5. Visual Studio Code

The Alexa Skills Kit Command Line Interface (ASK CLI) is a tool for you to manage your Alexa skills and related resources, such as AWS Lambda functions.
With ASK CLI, you have access to the Skill Management API, which allows you to manage Alexa skills programmatically from the command line.
If you want how to create your Skill with the ASK CLI, please follow the first step explained in my [Node.js Skill sample](https://github.com/xavidop/alexa-nodejs-lambda-helloworld). 
We are going to use this powerful tool to do some steps in our pipeline. Let's DevOps!


####  Pipeline

![image](https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2/raw/master/img/pipeline.png)

Let's explain job by job what is happening in our powerful pipeline. 
First of all, each box on the left represented in the image above is a job and they will be defined below the `jobs` node in the GitHub Actions Workflow configuration file:

##### Checkout

The checkout job will execute the following tasks:
1. Checkout the code 
2. Bring execution permission to be able to execute all the tests

```yaml
  checkout:
    runs-on: ubuntu-latest
    name: Checkout
    steps:
      # To use this repository's private action,
      # you must check out the repository
      - name: Checkout
        uses: actions/checkout@v2
      - run: |
          chmod +x -R ./test;
          ls -la
```

##### Build

The build job will execute the following tasks:
1. Checkout the code.
2. Run `npm install` in order to download all the Node.js dependencies, including dev dependencies.

```yaml
  build:
    runs-on: ubuntu-latest
    name: Build
    needs: checkout
    steps:
      # To use this repository's private action,
      # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        cd lambda;
        npm install

```

##### Pretests

The pretest job will execute the static code quality check. Check the full explanation [here](https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2/blob/master/docs/ESLINT.md).

##### Test

The test job will execute the unit tests. Check the full explanation [here](https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2/blob/master/docs/UNITTESTS.md).

##### Code Coverage

The codecov job will execute the code coverage report. Check the full explanation [here](https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2/blob/master/docs/CODECOV.md).

##### Deploy

The deploy job will deploy the Alexa Skill to the Alexa cloud in the development stage. Check the full explanation [here](https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2/blob/master/docs/DEPLOY.md).

##### Testing the Voice User Interface

These jobs will check our interaction model. Check the full explanation [here](https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2/blob/master/docs/VUITESTS.md).

##### Integration tests

These jobs will check the interaction model and our backend as well. Check the full explanation [here](https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2/blob/master/docs/INTEGRATIONTESTS.md).

##### End to end tests

These jobs will check the full system using the voice as input. Check the full explanation [here](https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2/blob/master/docs/ENDTOENDTESTS.md).

##### Validation tests

These jobs will validate your Alexa Skill before submitting it to certification. Check the full explanation [here](https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2/blob/master/docs/VALIDATIONTESTS.md).

##### Submit

These jobs will submit your Alexa Skill to certification. Check the full explanation [here](https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2/blob/master/docs/SUBMIT.md).

##### Store-artifacts

The store-artifacts job will execute the following tasks:
1. Restore the code that we have used in the previous step in `/home/node/project` folder
2. Clean `node_modules` folder
3. Store the entire code of our Alexa Skill as an artifact. It will be accessible in GitHub Actions whenever we want to check it out.

```yaml

  store-artifacts:
    runs-on: ubuntu-latest
    name: Submit
    needs: submit
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2}
    - name: Upload code
      uses: actions/upload-artifact@v2
      with:
        name: code
        path: ${{ github.workspace }}

```

##### Workflow

The GitHub Actions Workflow which will execute the jobs explained above configuration file is located in `.github/workflows/main.yml`:

```yaml

on: [push]

jobs:
  checkout:
    runs-on: ubuntu-latest
    name: Checkout
    steps:
      # To use this repository's private action,
      # you must check out the repository
      - name: Checkout
        uses: actions/checkout@v2
      - run: |
          chmod +x -R ./test;
          ls -la
  build:
    runs-on: ubuntu-latest
    name: Build
    needs: checkout
    steps:
      # To use this repository's private action,
      # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        cd lambda;
        npm install
  pretest:
    runs-on: ubuntu-latest
    name: Pre-test
    needs: build
    steps:
    # To use this repository's private action,
    # you must check out the repository
      # To use this repository's private action,
      # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        cd lambda;
        npm install;
        npm run lint;
        npm run lint-html
    - name: Upload results
      uses: actions/upload-artifact@v2
      with:
        name: eslint-report
        path: lambda/reports/eslint/

  test:
    runs-on: ubuntu-latest
    name: Test
    needs: pretest
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        cd lambda;
        npm install;
        npm run test
    - name: Upload results
      uses: actions/upload-artifact@v2
      with:
        name: unit-tests-report-html
        path: lambda/mochawesome-report/
    - name: Upload results
      uses: actions/upload-artifact@v2
      with:
        name: unit-tests-report-xml
        path: lambda/reports/mocha/
    
  codecov:
    runs-on: ubuntu-latest
    name: Code Coverage
    needs: test
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        cd lambda;
        npm install;
        npm run codecov
      env: # Or as an environment variable
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
  deploy:
    runs-on: ubuntu-latest
    name: Deploy
    needs: codecov
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        sudo npm install -g ask-cli;
        sudo apt-get install -y jq
        cd lambda;
        npm install;
        npm run copy-package;
        cd src;
        npm run build-production
    - run: ls -la && ask deploy --ignore-hash  
      env: # Or as an environment variable
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
        ASK_ACCESS_TOKEN: ${{ secrets.ASK_ACCESS_TOKEN }}
        ASK_REFRESH_TOKEN: ${{ secrets.ASK_REFRESH_TOKEN }}
        ASK_VENDOR_ID: ${{ secrets.ASK_VENDOR_ID }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        SKILL_ID: ${{ secrets.SKILL_ID }}

  check-utterance-conflicts:
    runs-on: ubuntu-latest
    name: Check Utterance Conflicts
    needs: deploy
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        sudo npm install -g ask-cli;
        chmod +x -R ./test;
        cd test/vui-test/;
        ./interaction_model_checker.sh $SKILL_ID v2
      env: # Or as an environment variable
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
        ASK_ACCESS_TOKEN: ${{ secrets.ASK_ACCESS_TOKEN }}
        ASK_REFRESH_TOKEN: ${{ secrets.ASK_REFRESH_TOKEN }}
        ASK_VENDOR_ID: ${{ secrets.ASK_VENDOR_ID }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        SKILL_ID: ${{ secrets.SKILL_ID }}
  check-utterance-resolution:
    runs-on: ubuntu-latest
    name: Check Utterance Resolution
    needs: deploy
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        sudo npm install -g ask-cli;
        chmod +x -R ./test;
        cd test/vui-test/;
        ./utterance_resolution_checker.sh $SKILL_ID v2
      env: # Or as an environment variable
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
        ASK_ACCESS_TOKEN: ${{ secrets.ASK_ACCESS_TOKEN }}
        ASK_REFRESH_TOKEN: ${{ secrets.ASK_REFRESH_TOKEN }}
        ASK_VENDOR_ID: ${{ secrets.ASK_VENDOR_ID }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        SKILL_ID: ${{ secrets.SKILL_ID }}
  check-utterance-evaluation:
    runs-on: ubuntu-latest
    name: Check Utterance Evaluation
    needs: deploy
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        sudo npm install -g ask-cli;
        chmod +x -R ./test;
        cd test/vui-test/;
        ./utterance_evaluation_checker.sh $SKILL_ID v2
      env: # Or as an environment variable
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
        ASK_ACCESS_TOKEN: ${{ secrets.ASK_ACCESS_TOKEN }}
        ASK_REFRESH_TOKEN: ${{ secrets.ASK_REFRESH_TOKEN }}
        ASK_VENDOR_ID: ${{ secrets.ASK_VENDOR_ID }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        SKILL_ID: ${{ secrets.SKILL_ID }}
  integration-test:
    runs-on: ubuntu-latest
    name: Integration test
    needs: check-utterance-evaluation
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        sudo npm install -g ask-cli;
        chmod +x -R ./test;
        sudo apt-get install -y expect
        cd test/integration-test/;
        ./simple-dialog-checker.sh $SKILL_ID
      env: # Or as an environment variable
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
        ASK_ACCESS_TOKEN: ${{ secrets.ASK_ACCESS_TOKEN }}
        ASK_REFRESH_TOKEN: ${{ secrets.ASK_REFRESH_TOKEN }}
        ASK_VENDOR_ID: ${{ secrets.ASK_VENDOR_ID }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        SKILL_ID: ${{ secrets.SKILL_ID }}
  end-to-test:
    runs-on: ubuntu-latest
    name: End-to-end test
    needs: integration-test
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        sudo npm install -g ask-cli;
        sudo npm install -g bespoken-tools;
        chmod +x -R ./test;
        bst test --config test/e2e-bespoken-test/testing.json
      env: # Or as an environment variable
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
        ASK_ACCESS_TOKEN: ${{ secrets.ASK_ACCESS_TOKEN }}
        ASK_REFRESH_TOKEN: ${{ secrets.ASK_REFRESH_TOKEN }}
        ASK_VENDOR_ID: ${{ secrets.ASK_VENDOR_ID }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        SKILL_ID: ${{ secrets.SKILL_ID }}
    - name: Upload code
      uses: actions/upload-artifact@v2
      with:
        name: bespoken-report
        path: test_output/
  
  validation-test:
    runs-on: ubuntu-latest
    name: Validation test
    needs: end-to-test
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        sudo npm install -g ask-cli;
        chmod +x -R ./test;
        cd test/validation-test/;
        ./skill_validation_checker.sh $SKILL_ID v2
      env: # Or as an environment variable
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
        ASK_ACCESS_TOKEN: ${{ secrets.ASK_ACCESS_TOKEN }}
        ASK_REFRESH_TOKEN: ${{ secrets.ASK_REFRESH_TOKEN }}
        ASK_VENDOR_ID: ${{ secrets.ASK_VENDOR_ID }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        SKILL_ID: ${{ secrets.SKILL_ID }}
    
  submit:
    runs-on: ubuntu-latest
    name: Submit
    needs: validation-test
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - run: |
        sudo npm install -g ask-cli;
        chmod +x -R ./test;
        cd test/submit/;
        ./submit.sh $SKILL_ID v2
      env: # Or as an environment variable
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
        ASK_ACCESS_TOKEN: ${{ secrets.ASK_ACCESS_TOKEN }}
        ASK_REFRESH_TOKEN: ${{ secrets.ASK_REFRESH_TOKEN }}
        ASK_VENDOR_ID: ${{ secrets.ASK_VENDOR_ID }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        SKILL_ID: ${{ secrets.SKILL_ID }}
  store-artifacts:
    runs-on: ubuntu-latest
    name: Store Artifacts
    needs: submit
    steps:
    # To use this repository's private action,
    # you must check out the repository
    - name: Checkout
      uses: actions/checkout@v2
    - name: Upload code
      uses: actions/upload-artifact@v2
      with:
        name: code
        path: ${{ github.workspace }}

```

#### GitHub Action

After explain the pipeline, it is important to explain the GitHub Action which are using the Docker image that you can use in your pipelines. 
With the above Docker image a GitHub Action has been created in order to run ASK CLI Commands:

This GitHub Action is available in the gitHub Actions Marketplace](https://github.com/marketplace/actions/alexa-ask-aws-cli-action)

You can use the following example as a way to start:
```yaml

  - name: Alexa ASK AWS CLI Action
    uses: xavidop/alexa-ask-aws-cli-docker@v1.0.6
    id: command
    with:
      command: 'ask --version'
    env: # Or as an environment variable
      ASK_ACCESS_TOKEN: ${{ secrets.ASK_ACCESS_TOKEN }}
      ASK_REFRESH_TOKEN: ${{ secrets.ASK_REFRESH_TOKEN }}
      ASK_VENDOR_ID: ${{ secrets.ASK_VENDOR_ID }}
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      SKILL_ID: ${{ secrets.SKILL_ID }}
  # Use the output from the `hello` step
  - name: Get the output
    run: echo "The result was ${{ steps.command.outputs.result }}"

```

Or for example using it in a workflow:

```yaml
  on: [push]

  jobs:
    test-action:
      runs-on: ubuntu-latest
      name: Test Action
      steps:
        # To use this repository's private action,
        # you must check out the repository
        - name: Checkout
          uses: actions/checkout@v2
        - name: Test action step
          uses: xavidop/alexa-ask-aws-cli-docker@v1.0.6
          id: ask
          with:
            command: 'ask --version'
          env: # Or as an environment variable
            ASK_ACCESS_TOKEN: ${{ secrets.ASK_ACCESS_TOKEN }}
            ASK_REFRESH_TOKEN: ${{ secrets.ASK_REFRESH_TOKEN }}
            ASK_VENDOR_ID: ${{ secrets.ASK_VENDOR_ID }}
            AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
            AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
            SKILL_ID: ${{ secrets.SKILL_ID }}
        # Use the output from the `hello` step
        - name: Get the output
          run: echo "The result was ${{ steps.ask.outputs.result }}"

```

It is important to add that the GiHub Action are using the latest version of the ASK CLI.
You can find all the explanation in this repo.

{% github https://github.com/xavidop/alexa-ask-aws-cli-docker %}


#### Conclusion 

This is the first step to know how to DevOps your Alexa Skills using GitHub Actions.
As you have seen in this example, the Alexa Tools like ASK CLI can help us a lot. We will update this readme while we are updating the pipeline.
I hope this example project is useful to you.

That's all folks!

Happy coding!


### Submission Category: 

DIY Deployments

### Yaml File or Link to Code

Here you have the link to the GitHub Repository:

{% github https://github.com/xavidop/alexa-nodejs-lambda-helloworld-v2 %}


### Additional Resources / Info

* [DevOps Wikipedia](https://en.wikipedia.org/wiki/DevOps) - Wikipedia reference
* [Official Alexa Skills Kit Node.js SDK](https://www.npmjs.com/package/ask-sdk) - The Official Node.js SDK Documentation
* [Official Alexa Skills Kit Documentation](https://developer.amazon.com/docs/ask-overviews/build-skills-with-the-alexa-skills-kit.html) - Official Alexa Skills Kit Documentation
* [Official GitHub Actions Documentation](https://docs.github.com/) - Official GitHub Actions Documentation