Hey Siri, Deploy My Elixir App
Just for the heck of it, I decided to attempt to build a GitHub Actions workflow that would allow me to deploy an Elixir app using Siri on my iPhone. In this post, I’m going to demonstrate how I deploy the app to the Heroku Container Runtime using Actions, as well as how I can trigger deploying the app using Siri.
I’m not sure I recommend what I’m doing in this post for a real-world production app, but it’s a fun example of what can be done with GitHub Actions.
Building the Elixir App
The app that we’re going to be deploying is a simple server built with Plug that sends “pong $app_version” in response to a GET request to the “/ping” route. You can view the source code for this app before I added any of the workflow- or container-related code here (the code that returns the app version was added later, but it’s not particularly interesting).
After I built the basic app, I used Distillery to generate a release configuration file. It’s pretty straightforward—the only change from the default generated release configuration is that it grabs the Erlang cookie from an environment variable.
I’m not going to get into much more detail on the app itself, but feel free to poke around in the code, if you’re interested.
A Dockerfile for the App
In order to run the app on the Heroku Container Runtime, the app needs a Dockerfile that copies the built release, and then runs it in the foreground. You can see the app’s Dockerfile here.
The Dockerfile is based on Alpine Linux. It copies the built release file from
the “_build” directory, and then calls ./bin/ping foreground
. Running the app
in the foreground is necessary to get log output from the heroku logs -t
command.
Building the Workflow
The workflow file is a little more complicated. We need to ensure that the environment in which the release is compiled is identical to the environment of the app’s Dockerfile. Since the Dockerfile is based on Alpine Linux, the command that compiles the release as a part of our Actions workflow also needs to be Alpine Linux.
I’m going to step through the actions one-by-one that the workflow uses.
The Workflow
In order to use Siri to deploy this app, we’re going to tell the workflow to trigger on the “repository_dispatch” event.
Triggering the workflow on this event will allow us to use Siri shortcuts to make a POST request to the GitHub API in order to deploy our app. I’ll go into more detail on that later.
Create Release
The first thing that the workflow does is creating the release. This is the self-contained archive with everything necessary in order to run the app. If you’re unfamiliar with OTP releases, you can read more about them (and Distillery) on ElixirSchool.
You’ll notice that this action uses a repo-relative action at ”./.github/mix”. The reason for this is what I stated earlier—I need to ensure that the action I use to run my Mix commands is based on Alpine Linux. I do have a Mix action that I use in some other workflows, but it’s not based on Alpine Linux.
The Dockerfile for this action installs rebar and hex, and
then sets mix
as the entrypoint for the container by using an entrypoint shell
script.
Registry Login
After we’ve created the release, we need to log in to the Heroku container registry.
This action also uses a custom repository-relative action. For the Heroku
container registry commands to work, we need both Docker and the Heroku command
line interface tool to be available in our container. This action is built based
on the “docker” image, and then installs Node and the Heroku CLI with NPM. It
sets heroku
as the container entrypoint.
Notice that we are also providing a “HEROKU_API_KEY” secret that I’ve configured on the repository. The Heroku CLI tool picks up this environment variable and uses it for authentication.
Container Push
Now that we’re logged into the Heroku container registry, we need to push our app to the registry.
The “args” value here calls heroku container:push web --app ping-ex
, which
tells the Heroku CLI to build the app using the Dockerfile in the project, and
then push it to the container registry for the “ping-ex” app’s “web” dyno.
Container Release
Once the container is pushed, we want to actually release it so that it becomes the “active” container running for our app.
This action calls heroku container:release web --app ping-ex
, which takes the
most recently-pushed image and releases it to the “web” dyno. Heroku will start
routing requests to this dyno once the container starts.
Building the Siri Shortcut
Now that we’ve built the workflow, we need to build a Siri Shortcut to deploy the app. You can get the shortcut that I built for this here.
The shortcut makes a POST request to the repository dispatch endpoint that looks like this:
For this to work, you need a personal access token with “repo” scope in order to make a request to the repository dispatches endpoint.
Once the shortcut is added to your Shortcuts app, you can add it to Siri. Apple has a helpful article explaining how to do this.
Now, you can simply say “Hey Siri, deploy my app” in order to push the latest code on GitHub to Heroku!