✨ preface

Since the blog uses Gatsbyjs to build, Markdown articles will be packaged into static HTML files after they are written. The articles are stored in the project file instead of the database, so every time the blog post is updated, it needs to be re-packaged and built. After git push, I need to connect to the cloud server, then go to the project directory and run git pull/NPM run clean/NPM run build etc.

To simplify this, automate build deployment by using Github’s Webhooks service that listens for Git push events on the server and then automatically executes the script you’ve written. After Git push, there is no need for subsequent operations, which are completed by scripts.

Jenkins is a continuous integration management platform that provides over 1000 plug-ins to support build, deploy, automate, and meet the needs of any project. But because Jenkins is Java based and too powerful, it’s a bit overkill for a personal project and adds to the strain on personal server resources. Therefore, Jenkins was not used for automatic construction and deployment. Instead, Koa2 service written by myself was used to receive Github Webhook to realize simple automatic construction.

🔧 configuration Webhooks

  1. Go to the Github repository where you need to listen for Push requests and click Settings => Webhooks => Add Webhooks

  1. Fill in your server request address and configure Secret(for laterSha1Decode validation), and select the event to listen on, this time only listening on push

  1. Go to the corresponding Webhooks details, see each request record below, and click Redeliver to resend the request.

🏳️🌈 Back-end Koa2 service

The Koa2 service on the back end is the most important part of this functionality. Its processing process:

  1. Receive a Post request from Github Webhooks
  2. Extract the request header and request Body information, and verify that necessary parameters are missing
  3. HMACSHA1 algorithm of Crypto is used to hash encode the key set by the server on the request Body, and then judge whether the decoded key matches the X-Hub-signature in the request header, so as to prevent others from sending forged illegal requests to their server or tampering with the original Github request.
  4. Use Nodejs child_process to execute different script files for different Git events and Git repositories
const Router = require('koa-router')
const crypto = require('crypto')
const { exec } = require('child_process')

const logger = require('.. /utils/log')
const Response = require('.. /utils/response')
const { webhookSecret } = require('.. /config/config')

const r = new Response()
const router = new Router()

// The router routing path is configured when Webhook is configured on Github. Webhook sends requests to this path
router.post('/ * * * *'.async ctx => {
  const requestData = ctx.request.body
  const sig = ctx.headers['x-hub-signature']
  const event = ctx.headers['x-github-event']
  const id = ctx.headers['x-github-delivery']
  if(! sig || ! event || ! id) { ctx.body = r.error(310.'No Github hook headers')
    return
  }
  if(! ['ping'.'push'].includes(event)) {
    ctx.body = r.error(311.'Gihub Hook events not allow')
    return
  }
  const { repository, sender } = requestData
  if(! repository || ! sender) { ctx.body = r.error(312.'Missing essential parameters')
    return
  }
  const { name: repositoryName } = repository
  logger('Receive Webhook'.1.`event:${event}, respository: ${repositoryName}`)
  const clientSig = `sha1=${crypto.createHmac('sha1', webhookSecret).update(JSON.stringify(requestData)).digest('hex')}`
  if(sig ! == clientSig) { logger('Webhook X-Hub-signature Decoding '.0.'Decoding mismatch')
    ctx.body = r.error(313.'X-Hub-Signature does not match')
    return
  }
  if (event === 'ping') {
    ctx.body = {
      errCode: 200.errMsg: 'Success'}}else if (event === 'push') {
    ctx.body = {
      errCode: 200.errMsg: 'Success'
    }
    if (repositoryName === '* * * *') {
      updateBlog()
    }
  }
})

// updateBlog is the action to be performed when a hook is received
const updateBlog = () = > {
  exec('****.bat'.(err) = > {
    if (err) {
      logger('execution of * * * *. Bat'.0, err)
      return
    }
    logger('execution of * * * *. Bat'.1)})}module.exports = {
  githubWebhookRouter: router
}
Copy the code

After creating Webhooks, Github sends a ping event to the target server to verify that it works, so there is an additional ping event handling (return 200).

If you set Webhooks to listen for other events, such as release, issues, star, etc., you can extend the corresponding functions.

⚡ Other Instructions

  1. The backend can be directly built using native Nodejs and quickly built using github-webhook-Hanlder package.
  2. You are advised to set the Secert key to prevent forged requests.
  3. This method is suitable for simple automatic deployment and construction of front-end resources, and is recommended for large projectsJenkinsContinuous integration tools for automated deployment.
  4. Github Webhooks monitor other events, issues, start, etc., and implement Git repository robots via Github API.
  5. Github Webhooks requests have a lot of useful information, such as multiplayer projects where you can keep track of who pushed them, or which branch they are working on, that can be extracted for different purposes.
  6. Scripts can be written using a Shell and executed by Nodejs’s child_process, or Nodejs commands can be written directly to perform file operations. The community offers much of the sameshelljs,exec-shNPM packages allow scripting commands to be written more gracefully.
  7. This is a good way to automatically deploy your website to your own personal server if no server is availableGithub PageMode deployment, this time can be usedGithub ActionTo implement, more detailed in a later article.