Building and Releasing Using the Platform API

Last Updated: 07 April 2015

Table of Contents

This article describes how to use the build resource of the Platform API to build source code into slugs that can be run by apps on the Heroku platform.

The build resource complements the interactive git-based deployment flow but is optimized for non-interactive continuous integration setups. The outputs of using the Build resource are slugs and releases that can be downloaded, manipulated, reused, and moved around with the slug and release endpoints of the Platform API.

By combining the Build resource and the slug and release resources, developers can build flows where source code is pushed to a repository (not on Heroku), built into a slug by the Build resource and then deployed to one or more apps on the platform.

The Build resource is available on api.heroku.com along with the rest of the Platform API.

Creating builds

Need a place to upload source tarballs for use with the Build API? See the sources endpoint section below.

Creating a build from a source tarball is simple:

$ curl -n -X POST https://api.heroku.com/apps/example-app/builds \
-d '{"source_blob":{"url":"https://github.com/heroku/node-js-sample/archive/master.tar.gz", "version": "cb6999d361a0244753cf89813207ad53ad906a14"}}' \
-H 'Accept: application/vnd.heroku+json; version=3' \
-H "Content-Type: application/json"
{
  "created_at": "2014-04-23T02:47:04+00:00",
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "source_blob": {
    "url": "https://github.com/heroku/node-js-sample/archive/cb6999d361a0244753cf89813207ad53ad906a14.tar.gz",
    "version": "cb6999d361a0244753cf89813207ad53ad906a14"
  },
  "slug": {
    "id": null
  },
  "status": "pending",
  "updated_at": "2014-04-23T02:47:11+00:00",
  "user": {
    "email": "username@example.com",
    "id": "01234567-89ab-cdef-0123-456789abcdef"
  }
}

This will cause Heroku to fetch the source tarball, unpack it and start a build, just as if the source code had been pushed to Heroku using git. If the build completes successfully, the resulting slug will be deployed automatically to the app in a new release.

If for some reason you just want to create slugs that are not immediately released to a particular app, we currently recommend creating a separate app to handle builds and then use the generated slugs to create releases on the apps where you want slugs to run.

In the example above, we pass in an optional version parameter. This is a piece of metadata that you use to track what version of your source originated this build. If you are creating builds from git-versioned source code, for example, the commit hash would be a good value to use for the version parameter. The version parameter is not required and is not used when downloading and building the source code. It’s merely a piece of metadata used that you can optionally use to track what source code version went into building what slug.

Listing builds

You can list builds for a particular app:

$ curl -n https://api.heroku.com/apps/example-app/builds \
-H 'Accept: application/vnd.heroku+json; version=3'
[
  {
    "created_at": "2014-04-23T02:47:04+00:00",
    "id": "01234567-89ab-cdef-0123-456789abcdef",
    "source_blob": {
      "url": "https://github.com/heroku/node-js-sample/archive/cb6999d361a0244753cf89813207ad53ad906a14.tar.gz",
      "version": "cb6999d361a0244753cf89813207ad53ad906a14"
    },
    "slug": {
      "id": "01234567-89ab-cdef-0123-456789abcdef"
    },
    "status": "succeeded",
    "updated_at": "2014-04-23T02:47:11+00:00",
    "user": {
      "email": "username@example.com",
      "id": "01234567-89ab-cdef-0123-456789abcdef"
    }
  },
  ...
]

The sample output above show one completed build. Note that the slug id is included in the output. You can use the slug id to create new releases on the same apps or on other apps on Heroku. You can also use the slug resource to download slugs to debug builds, for example.

All builds are available in the build list, including ones created by git-pushing to the Heroku repository for the app. Builds that fail for any reason are also tracked. To get the status of a build, check the status property. Possible values are pending, successful and failed.

Build output

You can also get the output of a particular build:

$ curl -n https://api.heroku.com/apps/example-app/builds/01234567-89ab-cdef-0123-456789abcdef/result \
-H 'Accept: application/vnd.heroku+json; version=3'
{
"build": {
    "id": "01234567-89ab-cdef-0123-456789abcdef",
    "status": "succeeded"
  },
  "exit_code": 0,
  "lines": [
    {
      "stream": "STDOUT",
      "line": "\n"
    },
    {
      "stream": "STDOUT",
      "line": "-----> Fetching custom git buildpack... done\n"
    },
    ...
   ]
}

The output includes both STDOUT and STDERR and is provided in the order it was output by the build. If you combine with values of all the line elements, you will will get the same output as you would have seen when doing an interactive git push to Heroku.

Beta streaming build output

Realtime vuild output is available using the 3.streaming-build-output version of the Platform API.

Here’s how to use streaming build output with curl (note that we’re sending 3.streaming-build-output instead of just 3 for the version value in the Accept header):

$ curl -n -X POST https://api.heroku.com/apps/example-app/builds \
-d '{"source_blob":{"url":"https://github.com/heroku/node-js-sample/archive/master.tar.gz", "version": "cb6999d361a0244753cf89813207ad53ad906a14"}}' \
-H 'Accept: application/vnd.heroku+json; version=3.streaming-build-output' \
-H "Content-Type: application/json"
{
  "created_at": "2014-07-25T21:46:02+00:00",
  "id": "4dff04cd-08ae-4a73-b4c1-12b84170a30f",
  "output_stream_url": "https://build-output.heroku.com/streams/1b/1be0f203-4d00-4948-9c7f-769067c99843/logs/cc/cce90488-d545-4cc8-a5f2-de10f0802d5d.log",
  "slug": {
    "id": null
  },
  "source_blob": {
    "url": "https://github.com/heroku/node-js-sample/archive/cb6999d361a0244753cf89813207ad53ad906a14.tar.gz",
    "version": "cb6999d361a0244753cf89813207ad53ad906a14",
    "version_description": null
  },
  "status": "pending",
  "updated_at": "2014-07-25T21:46:02+00:00",
  "user": {
    "email": "username@example.com",
    "id": "01234567-89ab-cdef-0123-456789abcdef"
  }
}

Make a GET request to the URL in output_stream_url.

$ curl "https://build-output.heroku.com/streams/1b/1be0f203-4d00-4948-9c7f-769067c99843"

-----> Node.js app detected
-----> Requested node range:  0.10.x
...

The output_stream_url url is also available if you GET an existing build with the 3.streaming-build-output version value in the Accept header.

The build output is sent via chunked encoding and the connection is closed when the build completes. If a client connects after data is sent for a given build, the data is buffered from the start of the build. Output can be streamed while the build is on progress, and at any time after the build has completed (in the latter case, all output will be sent immediately).

A null character chunk may be sent as a heartbeat while receiving data. This is not build output. It is a signal the build is still running but has not output any data recently.

Sources endpoint

The Build API requires that input source tarball are available for download. As a convenience, we provide a sources endpoint that accepts tarball uploads and provides an expiring url to the uploaded tarball. Use the sources endpoint if you want to use the build API with source code that is not otherwise available for public download.

Create a Source

The first API call creates a PUT and a GET URL. Use the PUT url to upload your source tar.gz file and then pass the GET URL to build API when creating the build. The URLs are only available for 1 hour, after which they both expire.

$ curl -n -X POST https://api.heroku.com/apps/example-app/sources \
-H 'Accept: application/vnd.heroku+json; version=3' \
{
 "source_blob": {
   "get_url":"https://s3-external-1.amazonaws.com/herokusources/...",
   "put_url":"https://s3-external-1.amazonaws.com/herokusources/..."
 }
}

Use the source_blob:put_url to Upload Data

Next, upload the source tarball to the source_blob:put_url you received in the previous step with a HTTP PUT:

$ curl "https://s3-external-1.amazonaws.com/herokusources/..." \
  -X PUT -H 'Content-Type:' --data-binary @source.tgz
...

Note: when using curl, it’s important to set -H 'Content-type:' to avoid sending a Content-Type header.

Create a Build Using source_blob:get_url

Finally, use the source_blob:get_url from the first API call to create a new build:

 curl -n -X POST https://api.heroku.com/apps/example-app/builds \
-d '{"source_blob":{"url":"https://s3-external-1.amazonaws.com/herokusources/...", "version": "cb6999d361a0244753cf89813207ad53ad906a14"}}' \
-H 'Accept: application/vnd.heroku+json; version=3' \
-H "Content-Type: application/json"
{
  "created_at": "2014-04-23T02:47:04+00:00",
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "source_blob": {
    "url": "https://s3-external-1.amazonaws.com/herokusources/...",
    "version": "cb6999d361a0244753cf89813207ad53ad906a14"
  },
  "slug": {
    "id": null
  },
  "status": "pending",
  "updated_at": "2014-04-23T02:47:11+00:00",
  "user": {
    "email": "username@example.com",
    "id": "01234567-89ab-cdef-0123-456789abcdef"
  }
}