An improved GitHub deployment workflow
A couple of days ago I blogged about how to deploy SvelteKit websites to a digital ocean droplet. Near the end of that post I offered a github workflow file but noted that it was basic and could be improved. Well here it is...
name: Build & Deploy
on:
push:
branches:
- main
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout main branch
uses: actions/checkout@v4
- name: Install SSH Key
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.SSH_KEY }}
known_hosts: "unnecessary"
- name: Adding Known Hosts
run: ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Deploy with rsync
run: rsync -avz --delete . ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:website/${GITHUB_SHA}
- name: Build site
uses: appleboy/ssh-action@master
env:
GITHUB_SHA: ${GITHUB_SHA}
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }}
envs: GITHUB_SHA
script: |
cd ~/website/${GITHUB_SHA}
nvm use || nvm install $(cat .nvmrc)
npm install
npm run build
cd ~/website
rm ~/website/current 2> /dev/null
ln -s ~/website/${GITHUB_SHA} ~/website/current
cd ~/website/current
pm2 reload website || pm2 start server.js --name website
cd ~/website
ls -dt */ | tail -n +3 | xargs rm -rf
The improvements come as follows:
Line 30: Instead of copying the files dfirectly into the "website" folder, we now copy them into a folder inside of the website folder that is named with the commit hash id e.g. "website/9087191712783b40dc975c2f646d7c377ca98b51"
Lines 34, 35, and 40: We pass the GITHUB_SHA
environment variable down through the action so that we can use it in our script on the server.
Lines 42 - 45: we move into this new "website/9087191712783b40dc975c2f646d7c377ca98b51" folder and do our build inside there instead of directly inside the website folder.
Line 47: we remove the "current" symbolic link and fail silently if it couldn't be removed due to it not existing (which, will be the case the first time).
Line 48: we create a symbolic link from the "website/9087191712783b40dc975c2f646d7c377ca98b51" folder to "website/current".
Lines 49 and 50: we then move into the "current" folder (which is really just the "website/9087191712783b40dc975c2f646d7c377ca98b51" folder) and then reload pm2
so that it will pick up the new files.
Lines 51-52: We then finish off by moving into the "website" directory, listing the files in time order and removing anything that is not in the most recent "3" files. This should leave behind the "current" symbolic link, the folder that has the latest files in it and a folder with the previous version in, just in case you need to rollback quickly by deleting the symbolic link and adding a new one to the old folder.
You might be wondering why I deleted the symbolic link and then made a new one instead of just using ln -sf
to overwrite the existing one. I did it this way to ensure the created at timestamp is "now" otherwise the "current" folder might end up being deleted by that final line which would result in the website going offline.