Using Github Actions for Deployments

GitHub actions are an incredible free resource provided by Github for running CI / CD pipelines. They can also be self-hosted, and are configured via simple YAML configuration files located within your repository. Previously without this feature, if you wanted to perform any sort of devops automation or pipeline with your application you had to configure your own hooks and infrastructure.

These are my Github workflow files for doing the following, all for free:

  1. Test that the Stencil web components and the Eleventy static site generator build properly on every pull request to the master branch. Also allow this to be run manually with 'workflow_dispatch' on the master branch. This is basically running a few NodeJS scripts.

  2. Automatically deploy changes to the Staging environment whenever changes are merged and pushed to the master branch via pull request or manually dispatched. Upon completion post an alert to Slack.

  3. Deploy the latest version of master to the Production environment when manually dispatched. Upon completion post an alert to Slack.

  4. Production and stage pushes share the same PR build test action. This means the static site generator and the Stencil web components are built and tested on every pull request push, merge, and manually deployment.

  5. The files are copied via SCP to the remote host after being successfully built.


# .github/workflows/pr_build_test.yml

name: Test Site Build & Compile

on:
workflow_dispatch:
branches:
- master
pull_request:

branches:
- master

jobs:
build-eleventy-and-nodesass:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build Site
uses: ./.github/actions/build_site
# .github/actions/build_site/action.yml

name: Build Eleventy Site
description: ''
runs: 
  using: composite
  steps:
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    
    - name: Install and Build Components
      run: cd components && npm install && npm run build
      shell: bash

    - name: NPM Install
      run: npm install
      shell: bash
      
    - name: Build 
      run: npm run build
      shell: bash

# .github/workflows/deploy_site_stage.yml

name: Deploy Site to Staging Environment via SCP
on: 
  workflow_dispatch:
    branches:
      - master
  push:
    branches:
      - master
jobs:
  build-and-deploy:
    name: Build & Deploy Site
    runs-on: ubuntu-latest
    steps: 
      - uses: actions/checkout@master
        with:
          fetch-depth: 0

      - name: Build Eleventy Site
        uses: ./.github/actions/build_site
      
      - name: SCP to STAGING
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USERNAME }}
          key: ${{ secrets.SSH_KEY }}
          passphrase: ${{ secrets.SSH_KEY_PASSPHRASE }}
          port: ${{ secrets.SSH_PORT }}
          source: "public_html/*"
          target: "www/SECRET_ENVIRONMENT/"
          overwrite: true

      - name: Slack Notification
        uses: rtCamp/action-slack-notify@v2
        env:
          SLACK_CHANNEL: general
          SLACK_COLOR: ${{ job.status }} # or a specific color like 'good' or '#ff00ff'
          SLACK_MESSAGE: 'Site was deployed to STAGE environment successfully! :rocket:'
          SLACK_TITLE: Deployment Completed
          SLACK_USERNAME: Deploy Bot
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

      - name: Failure Notification
        if: "${{ failure() }}"
        uses: rtCamp/action-slack-notify@v2
        env:
          SLACK_CHANNEL: general
          SLACK_COLOR: ${{ job.status }} # or a specific color like 'good' or '#ff00ff'
          SLACK_TITLE: Deployment Failed
          SLACK_USERNAME: Deploy Bot
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
# .github/workflows/deploy_site_prod.yml

name: Deploy Site to Production via SCP
on: 
  workflow_dispatch:
    branches:
      - master
jobs:
  build-and-deploy:
    name: Build & Deploy Site
    runs-on: ubuntu-latest
    steps: 
      - uses: actions/checkout@master
        with:
          fetch-depth: 0
      
      - name: Build Eleventy Site
        uses: ./.github/actions/build_site
      
      - name: SCP to Production
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USERNAME }}
          key: ${{ secrets.SSH_KEY }}
          passphrase: ${{ secrets.SSH_KEY_PASSPHRASE }}
          port: ${{ secrets.SSH_PORT }}
          source: "public_html/*"
          target: "www/shahruk.com/"
          overwrite: true
      
      - name: Slack Notification
        uses: rtCamp/action-slack-notify@v2
        env:
          SLACK_CHANNEL: general
          SLACK_COLOR: ${{ job.status }} # or a specific color like 'good' or '#ff00ff'
          SLACK_MESSAGE: 'Site was deployed to PRODUCTION environment successfully! :rocket: URL: https://shahruk.com/'
          SLACK_TITLE: Deployment Completed
          SLACK_USERNAME: Deploy Bot
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

      - name: Failure Notification
        if: "${{ failure() }}"
        uses: rtCamp/action-slack-notify@v2
        env:
          SLACK_CHANNEL: general
          SLACK_COLOR: ${{ job.status }} # or a specific color like 'good' or '#ff00ff'
          SLACK_TITLE: Deployment Failed
          SLACK_USERNAME: Deploy Bot
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

All of this, with just YAML files. And it just works, for free. 🤯