Skip to content

Automatic Deployment

WARNING

At the time of writing, Automatic Deployment workflow is still in development. We have a working workflow that will deploy update from develop to Cloudways staging via Git Pull.

This articles will be updated as soon as we updated our deployment workflow. Including deployment via FTP/SFTP

Master-copy of this workflow can be located here

More detail on Actions and Workflows

Deployment workflow

Here's the workflow for automatic deployment.

Production and Staging workflow are exactly the same process. just atarget to different branches.

yaml
name: Build and Deploy to staging
run-name: Deploy to staging (Initiated by ${{ github.actor }})
on:
  push:
    branches:
      - develop
jobs:
  deployment:
    environment: Staging
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Build Assets
        uses: ./.github/actions/build-sage
        with:
          theme-path: wp-content/themes/monsoontea
          target-branch: deploy/staging
      - name: Cloudways Git Deployment
        uses: ./.github/actions/cloudways-pull
        with:
          repository: ${{ vars.GIT_REPOSITORY }}
          api-key: ${{ secrets.STAGING_CLOUDWAYS_API_KEY }}
          api-email: ${{ secrets.STAGING_CLOUDWAYS_API_EMAIL }}
          server-id: ${{ vars.STAGING_CLOUDWAYS_SERVER_ID }}
          application-id: ${{ vars.STAGING_CLOUDWAYS_APP_ID }}
          target-branch: deploy/staging

Trigger

This workflow will be triggered when user push into branch develop as indicated in on.push.branches

Once workflow is triggered, it will start a new job

Job

Jobs named deployment will start running. GitHub will use ubuntu-latest to spin up new Docker instance to run the following steps (instructions)

Steps

This job contains three steps

  1. Checkout repository This will use a predefined action actions/checkout@v4 (by GitHub) to checkout git repositry to work with. Once checkout is done, it will proceed to next step
  2. Build Assets This step will call to an action file ./.github/actions/build-sage and pass variables along with the call via with parameter (theme-path and target-branch).
  3. Cloudways Git Deployment Once the previous step is done, it will continue to this steap and call an action file ./.github/actions/cloudways-pull as well as pass along variables via with parameter

Deployment Actions

From Steps section, we use two custom actions: ./.github/actions/build-sage and ./.github/actions/cloudways-pull.

build-sage

Action file located at .github/actions/build-sage/action.yml

yaml
name: Build and optimize assets
inputs:
  theme-path:
    required: true
    type: string
  target-branch:
    required: true
    type: string
runs:
  using: "composite"
  steps:
    - name: Checkout repository
      uses: actions/checkout@v4
    - run: git config --global user.email "git@invisibleink.asia"
      shell: bash
    - run: git config --global user.name "Invisible Ink Git Bot"
      shell: bash
    - name: Setup Node
      uses: actions/setup-node@v4
      with:
        node-version: 20
        cache: 'npm'
        cache-dependency-path: "${{ inputs.theme-path}}/package-lock.json"
    - name: Compile assets
      shell: bash
      working-directory: ${{ inputs.theme-path }}
      run: |
        npm install
        npm run build
    - name: Install PHP Dependencies
      uses: php-actions/composer@v6
      with:
        dev: no
        args: --optimize-autoloader
        php_version: 8.2
        version: 2
        working_dir: ${{ inputs.theme-path }}
    - name: Add build artifact
      shell: bash
      working-directory: ${{ inputs.theme-path }}
      run: |
        git branch ${{ inputs.target-branch }}
        git checkout ${{ inputs.target-branch }}
        git add --force ./vendor
        git add --force ./public
        git commit -m 'Build artifacts'
        git push --force --set-upstream origin ${{ inputs.target-branch }}

inputs section will indicate what variables should be passed along when call this action (using with parameter)

yaml
runs:
  using: "composite"

Indicate this action will run in composite mode, which will let you run shell script defined in steps

yaml
    - name: Checkout repository
      uses: actions/checkout@v4
    - run: git config --global user.email "git@invisibleink.asia"
      shell: bash
    - run: git config --global user.name "Invisible Ink Git Bot"
      shell: bash

This will checkout the repository, and setup basic git config.

yaml
    - name: Setup Node
      uses: actions/setup-node@v4
      with:
        node-version: 20
        cache: 'npm'
        cache-dependency-path: "${{ inputs.theme-path}}/package-lock.json"
    - name: Compile assets
      shell: bash
      working-directory: ${{ inputs.theme-path }}
      run: |
        npm install
        npm run build

This will pull NodeJS and start compiling assets using npm install and npm run build command (or any command defined in package.json)

yaml
    - name: Install PHP Dependencies
      uses: php-actions/composer@v6
      with:
        dev: no
        args: --optimize-autoloader
        php_version: 8.2
        version: 2
        working_dir: ${{ inputs.theme-path }}

Then this will pull PHP/Composer and install required package

yaml
    - name: Add build artifact
      shell: bash
      working-directory: ${{ inputs.theme-path }}
      run: |
        git branch ${{ inputs.target-branch }}
        git checkout ${{ inputs.target-branch }}
        git add --force ./vendor
        git add --force ./public
        git commit -m 'Build artifacts'
        git push --force --set-upstream origin ${{ inputs.target-branch }}

And at last step, will commit any build artifacts back into repository (on a new branch) to be deployed by next action.

cloudways-pull

Action file located at .github/actions/cloudways-pull/action.yml

yaml
name: Cloudways git deployment
inputs:
  target-branch:
    required: true
    type: string
  api-email:
    required: true
    type: string
  api-key:
    required: true
    type: string
  server-id:
    required: true
    type: string
  application-id:
    required: true
    type: string
  repository:
    required: true
    type: string
runs:
  using: composite
  steps:
    - name: Trigger Git Pull on Cloudways
      shell: bash
      run: |
        email=$( printf %s '${{ inputs.api-email }}'|jq -sRr @uri )
        api_key=$( printf %s '${{ inputs.api-key }}'|jq -sRr @uri )
        git_url=$( printf %s '${{ inputs.repository }}' | jq -sRr @uri)
        response=$(curl -X POST --header 'Content-Type: application/x-www-form-urlencoded' --header 'Accept: application/json' -d "email=$email&api_key=$api_key" 'https://api.cloudways.com/api/v1/oauth/access_token')
        is_error=$(echo $response | jq -r '.error')
        if [[ ! "$is_error" == null ]] then
            echo $response | jq -r '.error_description'
            exit 1
        fi
        access_token=$(echo $response | jq -r '.access_token')
        pull_response=$(curl -X POST --header 'Content-Type: application/x-www-form-urlencoded' --header 'Accept: application/json' --header "Authorization: Bearer $access_token" -d "server_id=${{ inputs.server-id }}&app_id=${{ inputs.application-id }}&branch_name=${{ inputs.target-branch }}&git_url=$git_url" 'https://api.cloudways.com/api/v1/git/clone' | jq)
        echo $pull_response | jq

Deployment action is pretty much how you deploy website using Terminal.

In this case, Cloudways, we use cURL to trigger Cloudways API to pull latest code and artifacts from repository on newly created branch from last step. This action could take time from 1-5 minutes depends on how resposive the server would be at the time.