Skip to content

Instantly share code, notes, and snippets.

@laneparton
Last active August 3, 2022 14:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laneparton/7a29eae1810168dfd67aecc465f6d112 to your computer and use it in GitHub Desktop.
Save laneparton/7a29eae1810168dfd67aecc465f6d112 to your computer and use it in GitHub Desktop.
A webhook that builds Gatsby via an Express endpoint with a FIFO queue.
const express = require("express");
const util = require("util");
const moment = require("moment"); // require
const exec = util.promisify(require("child_process").exec);
require("dotenv").config();
// Overall, it isn't clear what the best method of building these webhooks is.
// Is Express the answer? Is an entirely different language more efficient than Node?
// I'm leaning towards Node primarily because Gatsby builds with Node (we already need the node image)
const app = express();
let currentProcess = {
active: false,
dateTime: null,
};
let currentQueue = [];
let buildId;
const port = process.env.PORT || 8000;
app.listen(port, () => {
console.log("[Gatsby Webhook] Listening on port:", port);
});
app.get("/build_status", async (req, res) => {
if (currentProcess.active) {
res.send(`The site is building. It started at ${currentProcess.dateTime}`);
} else {
res.send("The site has built.");
}
});
app.post("/build_site", async (req, res) => {
buildId = moment().unix();
// -- Access Control --
// We can append a secret auth token
// We can also whitelist IP addresses (such as, only run from OKD IPs)
// -- Headers --
// We will change these to headers (like Gatsby Cloud) later...
// buildType = production || preview
// This can also be separated into its own webhook
const buildType = req.query.type || "production";
// Maybe with this flag, we can delete the existing .cache folder and run a cold build
// If we delete .cache, but don't delete public - what happens? We could alternatively build in a new location and copy...
const clearCache = req.query.cache || true;
// -- First Pass --
if (currentProcess.active === false) {
console.log("[Gatsby Webhook] Build Request Received: " + buildId);
res.send(`[Gatsby Webhook] Build Request Received\n`);
// Add them to the queue
currentQueue.push(buildId);
// Collect data about the current process
currentProcess = {
active: true,
dateTime: buildId,
};
build();
} else {
// -- Add to the Queue --
if ((currentQueue.length = 2)) {
// replace the second one with the current (latest) one
currentQueue[1] = buildId;
}
console.log("[Gatsby Webhook] Current Queue:");
console.info(currentQueue);
console.log("[Gatsby Webhook] A build is already in progress. This has been added to the queue.");
res.send(`[Gatsby Webhook] A build is already in progress. This has been added to the queue.\n`);
}
});
async function buildGatsbyCommand() {
try {
const { stdout, stderr } = await exec(
"node_modules/.bin/gatsby build --verbose"
);
console.log(stdout);
console.log("stderr:", stderr);
} catch (e) {
console.error(e); // should contain code (exit code) and signal (that caused the termination).
}
}
function build() {
console.log("[Gatsby Webhook] Building: " + currentQueue[0]);
buildGatsbyCommand()
.then(() => {
console.log("[Gatsby Webhook] Build " + currentQueue[0] + " has built.");
currentProcess = {
active: false,
dateTime: null,
};
currentQueue.shift();
console.log("[Gatsby Webhook] Current Queue:");
console.info(currentQueue);
})
.then(() => {
// If there are more items in the queue, keep building them.
if (currentQueue.length > 0) {
currentProcess = {
active: true,
dateTime: currentQueue[0],
};
build();
}
});
}
@laneparton
Copy link
Author

laneparton commented Aug 3, 2022

Gatsby Webhook

This is very much a WIP. It currently supports the idea of a FIFO queue of a current build and the latest build.

This is specifically built for Gatsby + Drupal, but would work with any CMS that supports the idea of a POST webhook.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment