Automating tedious GitHub tasks with Serverless (part 1)

Renan Gehan
4 min readOct 12, 2018

--

Diving head-first in the Cloud (Muzammil Soorma on Unsplash)

What is Serverless?

The Serverless framework operates as a very powerful wrapper around popular cloud providers. It allows you to quickly develop, test and deploy your product to the cloud.

I use it for most of my projects now, as it completely abstracts all the infrastructure and allows me to focus on my code.

Here are a few examples of what you can do with it:

  • Create functions that respond to REST endpoints
  • Schedule functions to run at a given time/interval
  • Run a function whenever a file is added to an S3 bucket
  • And much more

Our use case

I’ve been organizing little challenges on GitHub for Hacktoberfest, and have found myself having to label issues, and close/merge a lot of pull requests; that is why I decided to automate it as much as possible.

What we’ll try to reproduce together is the following scenario:

  • Someone wants a challenge to be assigned to him ;
  • He replies /request to the issue ;
  • Label the issue as assigned and assignee:johndoe if it wasn’t already assigned to anyone ;
  • Reply to the user indicating him whether he’s been assigned or not.

Setting up your environment

Before diving in the actual code, you’ll have to set up your Serverless environment.

You first need to install Serverless as a global dependency:

npm install -g serverless

This will install the serverless binary globally (and also create an sls alias)

Next, you’ll need to install the AWS CLI tool, that will later be used by Serverless to manage all your resources.

You could use another cloud provider, but I’ll only be covering AWS as this is the one I’m the most familiar with.

Once installed, you’ll have to create an AWS user for Serverless and generate keys for it. Please refer to this section of the official guide. I usually name this user serverless-[whatever], for this article, I’ll name it serverless-admin.

Now that you have your keys, we can configure Serverless to access AWS on your behalf:

serverless configure credentials \
--provider aws \
--key <access-key-id> \
--secret <secret-access-key> \
--profile serverless-admin

This creates an ~/.aws/credentials file containing your keys under a profile named serverless-admin.

At this point, you should have a fully-functional Serverless setup.

Initializing your project

Create an empty Serverless project named github-automation-project, using the aws-nodejs template:

serverless create \
--template aws-nodejs \
--path github-automation-project

There are quite a lot of templates available, for various languages (TypeScript, Python, Java, etc.), and various platforms.

Inside github-automation-project/ you’ll find a serverless.yml file. This file contains the whole definition of your project, what are your functions, how they can be triggered, etc.

If you’re curious, here is a reference of all the things you can set up in this file.

For now, you only have two things to change:

  • Edit the provider section so that it uses the correct AWS user
  • Add an http event to your function so that it can be triggered via a POST request on the /webhook endpoint:

Another useful file is handler.js ; it contains all the logic of your function. For now, it only returns a JSON payload containing a message and the inputevent object:

This event object will later come very handy, as it contains the request payload, the request headers, and various AWS related metadata.

Running your functions

From here, you have two options:

  • Redeploy every time you want to test a change (actually not that slow)
  • Run your functions locally (this is my favorite solution)

1. Locally

To run your functions locally, you don’t need much:

# Initialize a package.json
npm init --yes
# Install the serverless-offline plugin
npm install --save-dev serverless-offline

Once you have installed the serverless-offline plugin, add this two lines at the root of your serverless.yml file (do not nest it under any rule):

plugins:
- serverless-offline

That’s all there is to do! Let’s test it out:

serverless offline start# In another terminal
curl -X POST http://localhost:3000/webhook

This should return the JSON payload we discussed above.

2. In the Cloud

You can deploy your functions to the Cloud this way.

# Deploy all your stack
serverless deploy
# Deploy a single function (a lot faster)
serverless deploy --function hello

After a short while, it will show you a summary of what’s been deployed, including the endpoint on which you can reach your function.

It will look somewhat like this:

Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (19.45 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..............................
Serverless: Stack update finished...
Service Information
service: github-automation-project
stage: dev
region: us-east-1
stack: github-automation-project-dev
api keys:
None
endpoints:
POST - https://<random-id>.execute-api.us-east-1.amazonaws.com/dev/webhooks
functions:
hello: github-automation-project-dev-hello

Once again, that’s all there is to it! You can test it out with a little cURL:

curl -X POST https://<random-id>.execute-api.us-east-1.amazonaws.com/dev/webhook

Modifying our function’s behavior

We’ll see in part 2 how to connect our function to GitHub. For now, familiarize yourself a bit with Serverless, and look at what is available in the event object.

For example, if you wanted your function to return the sum of the two numbers a and b passed as JSON, you could modify your function that way:

curl -d '{"a":123,"b":77}' -X POST http://localhost:3000/webhook=> { "result": 200 }

There’s no error handling, no payload validation, but that’s fine, we’ll discard all of this the next part.

In the second part, we’ll implement the actual logic of the lambda, and I’ll give you a few Serverless-related tips.

--

--