Building & Publishing this blog
2022, May, 23
UPDATE 2 : Now using Nuxt 3
This blog uses Gridsome framework based on the concept of JAMstack (Javascript-API-Markup).
Content for the blog is written in Markdown files. All the markdown files and web UI code are in separate private Github repos.
Goal was to create a simple, lightweight, DIY approach to automatically build and deployed this blog on server.
Advantages of using Github:
- No need of dedicated Content Management System (CMS) : Markdown files can be created in any editor and pushed to Github.
- Webhooks : Github provides webhooks for all repo.
UPDATE : now using Github Actions to build and deploy this blog. Following steps are no longer used.
nodejs app to receive push webhook request
Webhook request is POST call.
Github webhook request example can be found here.
const express = require('express');const { exec } = require("child_process");const app = express();app.use(express.json());app.use(express.urlencoded({ extended: true }));const port = process.env.PORTapp.post('/pushed', (req, res) => { if(req && req.body && req.body.repository) { console.log('webhook request for ' + req.body.repository.full_name); exec("python3 <SCRIPT_NAME>.py", (error, stdout, stderr) => { if (error) { console.log(`error: ${error.message}`); return; } if (stderr) { console.log(`stderr: ${stderr}`); return; } console.log(`stdout: ${stdout}`); }); res.send(JSON.stringify({repo: req.body.repository.full_name})); } else { res.send(JSON.stringify({})); }})app.listen(port, () => { console.log(`listening on port ${port}`)})
python script to pull content & code from github, build and deploy
from datetime import datetime as dtimport subprocessimport osimport logginglogging.basicConfig(filename='<LOG_FILE_NAME>', level=logging.DEBUG)PUSH_SERVER = os.getenv('PUSH_SERVER')PUSH_TOKEN = os.getenv('PUSH_TOKEN')GH_TOKEN = os.getenv('GH_TOKEN')def push_msg(build_id, msg): data = { 'title': 'blog-cd : {}'.format(build_id), 'message': msg, 'priority': 5 } requests.post('{}/message?token={}'.format(PUSH_SERVER, PUSH_TOKEN), data=data)def build_and_publish(): build_id = str(round(dt.utcnow().timestamp())) START = dt.now() push_msg(build_id, 'Started') logging.info(build_id +': Build start') subprocess.run(['mkdir', build_id]) os.chdir(build_id) logging.info(build_id +': Cloning') subprocess.run(['git', 'clone', 'https://<USERNAME>:{}@github.com/<USERNAME>/<REPO>.git'.format(GH_TOKEN)]) os.chdir('<REPO>') logging.info(build_id +': Starting npm install') subprocess.run(['npm', 'install']) logging.info(build_id +': Starting build') subprocess.run(['gridsome', 'build']) logging.info(build_id +': Copying') os.chdir('dist') subprocess.run(['cp', '-r', '.', '<DESTINATION>']) logging.info(build_id + ': clean up') os.chdir('../..') subprocess.run(['rm', '-rf', build_id]) END = dt.now() duration = str(END - START) push_msg(build_id, 'Done in ' + duration) logging.info(build_id + ': DONE in ' + duration)if __name__ == '__main__': build_and_publish()
This could have been also written purely as a shell script, but I decided to go with python3.
Ensure that environment variables are added permanently. export from terminal only sets them for current session.
$ export KEY="value"
To permanently set them, added them to ~/.bashrc file.
Push notification on deployment (Optional)
Using Gotify to send push message on phone whenever the build is complete and site is deployed. Push messages are sent to Gotify server by push_msg function as REST call.