DEV Community

Cover image for How to trigger a manual redeploy on Heroku from code - A killer feature to update your Gatsby setup that isn't documented
Matteus Deloge
Matteus Deloge

Posted on • Edited on

5 2

How to trigger a manual redeploy on Heroku from code - A killer feature to update your Gatsby setup that isn't documented

TL;DR: You can easily retrigger an Heroku build for your Gatsby service to ingest Strapi CMS data, you only need to execute a POST request on an undocumented weird subdomain from Heroku called **kolkrabbi.heroku.com. See further down for API call details and Strapi CMS example implementation.

So I got a request from Conversation Starter, a customer from one of my freelance assignments (I'm a tech lead at Craftworkz by day and an IT freelancer by night), that they wanted to setup a headless CMS system to manage and host their blog posts for their existing website, built with the amazing Gatsby framework.

The choice was immediately made to use Strapi as the CMS system, mainly because of the great reviews it gets in the community and the many tutorials that are available.

Development went smoothly but then, deployment time had arrived. Both Strapi and the Gatsby website run happily on Heroku dynos, but due to the nature of Gatsby (static hosting of content) we need to rebuild the website on each change to the published blog post articles in the CMS.

One would think that a simple rebuild of an existing deployment on Heroku is a simple and well documented thing, right?

Well, it's not.

After a long search, even considering pushing empty git commits from the Strapi CMS to the Gatsby repository to trigger a new build, I found a breadcrumb that would lead me to the solution for my problem: a manual redeploy button on Heroku itself.

Alt Text

Well isn't this nice! That's exactly the feature I needed. However, this is documented nowhere in the official Heroku docs (send me the link if you would find it).

Using my trusted Chrome dev tools I luckily was able to document the API call myself, and again lucky: it was very easy to replicate without doing too much weird stuff. The only weird thing here is that you need to call an unknown Heroku subdomain, called kolkrabbi.heroku.com

The API call looks like this:

POST https://kolkrabbi.heroku.com/apps/<HEROKU_APP_ID>/github/push

Headers: {
    "Authorization": "Bearer <USER_AUTH_TOKEN>"
}

Body: {
    "branch": "master"
}
Enter fullscreen mode Exit fullscreen mode

Where:

  • HEROKU_APP_ID = your app's UUID which you can fetch using the heroku apps:info --json command
  • USER_AUTH_TOKEN = your own user's access token. Go to https://dashboard.heroku.com/account and navigate to the API Key section
  • Within the body of your call you can then choose which branch to build.

Please note that if you have multiple instances of your application (such as development and production), you will have a different App ID.

And as a cherry on the cake, I'll post my Strapi config here as well. The idea is that every time an Article model instance is being created, updated or deleted, the Heroku build function is being triggered so that Gatsby can ingest the new changes.

./api/articles/models/article.js

'use strict';

const axios = require('axios');

/**
 * Lifecycle callbacks for the `Article` model.
 */

var deployUrl = `https://kolkrabbi.heroku.com/apps/${process.env.HEROKU_APP_ID}/github/push`

var axiosConfig = {
    headers: {
        "Authorization": `Bearer ${process.env.CS_HEROKU_BUILD_TOKEN}`,
        "Content-Type": "application/json"
    }
}

async function callDeployEndpoint(deployUrl, branch) {
    await axios
        .post(deployUrl, {
            "branch": branch
        }, axiosConfig)
        .then((res) => {
            strapi.log.debug(`Executed build trigger for branch ${branch} `);
        })
        .catch((error) => {
            strapi.log.error(`Caught error for branch ${branch}: `, error);
        });
}

async function triggerDeploy() {
    strapi.log.debug('Triggered redeploy');
    strapi.log.debug('axiosConfig: ', axiosConfig);
    await callDeployEndpoint(deployUrl, "master");

}

module.exports = {
    lifecycles: {
        async afterCreate(data) {
            await triggerDeploy();
        },
        async afterUpdate(data) {
            await triggerDeploy();
        },
        async afterDestroy(data) {
            await triggerDeploy();
        },
    }
};
Enter fullscreen mode Exit fullscreen mode

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay