Tutorial: How to deploy an app to production with an actual button
Ready to deploy? “Ship it!” to production with the press of a button.
If you’re familiar with the deployment process, chances are you’re familiar with the set of repeated steps that have to be completed before you push to production. It’s not a process that would be described as “fun”, but it’s an important one nonetheless.
But what if we could deploy and release an application with the push of a real button? In this post, we’ll go over how to make your own “ship it” button to deploy a new release.
Prerequisites
To follow along with this tutorial, you’ll need:
- An AWS IoT Dash button: To jumpstart, we’re going to use a premade IoT button that you can purchase on Amazon.
-
An AWS account: Create an AWS account. You’ll need to create one even if you have an Amazon.com account. We’ll be using the AWS Lambda tool to call the GitHub API.
Note: This service charges you for the data you use. You can also use a virtual dash button service from your mobile phone. And the code from our guide can be connected to any application—not just AWS. - To set up your development environment: We’ll be using Node.js 6.10 when connecting with AWS Lambda. Download the latest node version—or just use Lambda for the development.
- A GitHub account: Create a GitHub account. It’s fast, easy, and of course, free.
-
A GitHub API access token: A personal access token allows you to authenticate who you are when using GitHub through the API or otherwise programmatically. To generate one:
- Navigate to https://github.com/settings/tokens
- Click Generate new token
- Select the scopes we’ll be using for the tutorial: repo_ deployment, write:packages, read:package
Once you’ve finished setting up all of the prerequisites, get started with the rest of the setup process.
Step 1: Writing the GitHub API calls
Use Node.js to call the GitHub API and the Octokit/rest.js library to wrap API calls. Octokit works like any other library and uses the GitHub REST API endpoints—but it also allows us to use await, async, promise, and callback wrappers all contained. Plus, we can authenticate at the beginning, then perform our calls.
Let’s take a look at the index.js file we’ll create.
Step 1a: Setting up Octokit
At the top of the file, we require our Octokit npm package:
const octokit = require('@octokit/rest')()
Step 1b: Authenticating
Then we authenticate with GitHub using our newly created personal access token:
octokit.authenticate({
type: 'token',
token: process.env.GH_TOKEN
})
Step 1c: Setting up the event handler
To use AWS Lambda, we need a handler to understand what to do when the button is clicked. We add the wrapper:
exports.handler = (event, context, callback) => {
console.log(`Received event: ${event}`)
let tag_name
const owner = process.env.GH_LOGIN
const repo = process.env.GH_REPO
}
Step 1d: Retrieving and creating the latest release
Inside the exports.handler
function, you’ll find releases. The GitHub Releases API is a hidden gem housed under the Repository API. You can create a draft, prerelease, set up the branch to release from, and more from one API call.
For this scenario we’ll get the latest release and increment it by one. Then we’ll publish a new release each time the button is clicked.
Both of the methods below are Promises
and will create a new release once the latest release has been retrieved. To do so, we need our GitHub username, the repo we want to release to, and a tag_name
when creating it. There are several optional details we can add, but here are the basics:
octokit.repos.getLatestRelease({
owner,
repo
}).then(result => {
tag_name = (parseInt(result.data.tag_name) + 1.0).toString() + '.0'
octokit.repos.createRelease({
owner,
repo,
tag_name
}, (error, result) => {
if (error) throw new Error()
if (result) console.log(`Created Release: ${JSON.stringify(result)}`)
})
})
Step 1e: Creating a deployment
In addition to creating a release, we’re going to start a deployment by calling upon the GitHub Deployments API. We can do this by specifying the login, repo, branch we want to deploy from, and optionally, a description:
octokit.repos.createDeployment({
owner,
repo,
ref: 'master',
description: `Deploying ${tag_name} version`
}, (error, result) => {
if (error) throw new Error()
if (result) console.log(`Created Deployment: ${JSON.stringify(result)}`)
})
Once the release and deployment methods are inside the event handler, the code is almost set. We’re using Node.js, so make sure to run npm init
and npm install @octokit/rest
to ensure the environment is setup.
A repository has been created with the entire setup process and you can find the link in Step 3 when we need to call on the code. To actually run the code, let’s first configure the new AWS IoT button.
Step 2: Configuring the AWS IoT button
To set up the button, follow the AWS quickstart guide or download the AWS IoT Button Dev app, available on iOS or Android.
Once your button is configured with WiFi, feel free to test out the example lambda functions like sending a text or email. Next we’ll create a new function.
Step 3: Setting up an AWS Lambda function
Once we set up our lambda function, we’re ready to release! Navigate to the AWS Lambda Function Console.
Step 3a: Creating the function
In orange, you’ll see a “Create Function” button, whether you’re viewing your dashboard or functions. Below are detailed steps to walk through the process. If you get stuck, try watching this video walkthrough.
- Click Create Function and Author from Scratch.
- Enter a “Name”.
- Ensure the runtime is Node.js 6.10.
- Under “Role”, select Create new role from template(s).
- Enter a “Role Name”. It can be the same as “Name”.
- Under “Policy Templates”, select AWS IoT Permissions.
Step 3b: Adding the button trigger
Once your function is created, you’ll see it has a number of different settings we can configure. We’ll edit the “Designer”, “Function Code”, and “Environment Variables” aspects of the function. Let’s begin with “Designer”.
- Add the AWS IoT Trigger in “Designer”. The “Configure Triggers” box should appear.
- Select IoT Button as the IoT Type.
- Enter the Device Serial Number located on the back of the button.
- Make sure to check Enable the Trigger, then click Add.
Step 3c: Uploading the code
Now that we have set up the button trigger, we need to make sure the code is correct. We’ll take the code from Step 2 and upload the zip file.
If you would like to use the code you wrote earlier, zip the package to the root of the folder with zip -r ShipItButton.zip ./*
or you’ll receive a cannot find /index.js error
. Otherwise, clone the contents of the repository with git clone https://github.com/ani6gup/ShipItButton.git
. Make sure the ShipItButtonLambda.zip file is cloned with the contents.
Once you have your zip file:
- Reveal the “Function Code” box by pressing the “Function Name” box in “Designer”.
- Scroll to “Function Code”.
- Under “Code Entry Type” select Upload a .zip file.
- Once you upload your file, click Save. You should now have the ability to “Edit Code Inline”.
Step 3d: Adding in the environment variables
- Scroll to “Environment Variables”.
- Create
GH_LOGIN
,GH_REPO
, andGH_TOKEN
for your environment variables and add your login, the repository you want to release to, and the personal access token you created in the prerequisites.
Step 3e: Test
Now we’re ready to test our button with the following steps:
- Click Test, a button that pops up with a “Configure Test Event”.
- Select the Hello World Event Template (Default).
- Enter in an “Event Name”.
- Click Create.
When you click Test you should be able to see new releases on your repository as they are created and the logs with Created Deployment
and Created Release
. Note: The release will only work if there is already a release present in a number format (1.0, for example).
You can check to see if your new release was created at your repositoryURL/release. Check the logs to make sure no errors were thrown. If you are seeing {message: not found}
or {message: bad credentials}
check your Personal Access Token permissions.
Step 4: Clicking the button
Now return to the “Configure Trigger Stage” and make sure your button is set. You should be able to click the button and get the same results you got when you tested it.
Next we’ll go into more detail on how to incorporate the GitHub events you just triggered within different workflows.
Step 5 (optional): Integrating within your workflow
Clicking the button will trigger a release and deployment—but what do you do with this information? At this point, you can configure it to your workflow or deployment process. The diagram below outlines how to communicate between the button or “Tooling”, GitHub, and our server.
+---------+ +--------+ +-----------+ +-------------+
| Tooling | | GitHub | | 3rd Party | | Your Server |
+---------+ +--------+ +-----------+ +-------------+
| | | |
| Create Deployment | | |
|--------------------->| | |
| | | |
| Deployment Created | | |
|<---------------------| | |
| | | |
| | Deployment Event | |
| |---------------------->| |
| | | SSH+Deploys |
| | |-------------------->|
| | | |
| | Deployment Status | |
| |<----------------------| |
| | | |
| | | Deploy Completed |
| | |<--------------------|
| | | |
| | Deployment Status | |
| |<----------------------| |
| | | |
There are several deployment services and providers to choose from. At GitHub we use Heaven to deploy directly with our chat bot, Hubot. Some companies have even adapted it into their flow. There are also applications in GitHub Marketplace that specifically help developers with fast and easy deployment.
In order to deploy an application, we use Probot, a tool for creating GitHub Apps and automating your workflow in a quick and easy way. In this case, it acts as a third party to listen for deployment events and send back deployment statuses by creating issues.
Step 5a (optional): Homemade deployment server with Probot
The application is based on the GitHub delivering deployments guide but modified to Node.js in order to use Probot.
In this scenario, the bot listens for particular GitHub events, meaning when someone presses the button to create a deployment, the application knows to create and push the new build—and provide a deployment status. The button deploys to Heroku—their Build and Release API allows us to push the GitHub release package and deploy instantly from a single POST request.
If you want to take a look or try it yourself, learn more in the Deployment Status Bot repository.
Conclusion
While you might not physically click a button to deploy your application to production regularly, you can always trigger these GitHub events to mix up a repetitive deployment process.
If you need any additional resources or help, feel free to go through the Building a GitHub App quickstart guide. Or sign up for the GitHub Developer Program, and post on the GitHub Platform Forum.
Written by
Related posts
Introducing Annotated Logger: A Python package to aid in adding metadata to logs
We’re open sourcing Annotated Logger, a Python package that helps make logs searchable with consistent metadata.
Boost your CLI skills with GitHub Copilot
Want to know how to take your terminal skills to the next level? Whether you’re starting out, or looking for more advanced commands, GitHub Copilot can help us explain and suggest the commands we are looking for.
Beginner’s guide to GitHub: Setting up and securing your profile
As part of the GitHub for Beginners guide, learn how to improve the security of your profile and create a profile README. This will let you give your GitHub account a little more personality.