Preface
Goal: Deploy SSG in Github Workflows.
The github.io is not just for Jekyll. But also can be used for other SSG as well, such as Hugo, Hexo, Pelican and Eleventy.
Official Site
Github Actions
Each github actions has their own repository. I won’t discuss Github Actions source code in details. Github Actions deserve its own long long loong article. So here it is, this article, is about how to use it. But not a tutorial on how to make one.
1: Introducing Github Workflows
In other CI/CD, it is also called runner
.
About Workflows
In a nutshell Github Workflows is
-
Configuration
-
Reusable Script
Github Actions is a smart move from Github It has a lot of potential, because it is not just a runner configuration. But it can also be modularized using scripting language. Each modul part is called actions, that is also reusable. A complex workflows can utilize some actions, so that the workflows become simple.
If you cannot find any actions that suit your needs, you can always revert to Circle-CI like configuration, with low level pure git commands in bash, as I will show you at the end of this article.
Configuration
Just like any other CI/CD, Github Workflows relies on YAML configuration.
❯ tree .github
.github
└── workflows
└── deploy.yml
You can name it anything, and you can have more than one .
Workflow
Just like any other CI/CD, Github also support web based view, to view runner, that you can access at, for example:
Job
Each workflow (or runner) can contain jobs,
for example a deploy
job.
A job contain a few step or run
, as show below.
Run
And finally each run
is just a bunch of command,
just like any other CI/CD.
The difference is, instead of bash commands,
a run
can contain a github actions
.
2: Configuration Overview
What is it inside the configuration ?
Configuration Skeleton
All configurations has this same skeleton
name: My Cool Deploy Name
on:
push:
branches:
- master
jobs:
my_cool_build_name:
...
Start a new Job
And job for each SSG is also similar. The only thing to do is changing the language.
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout to master
uses: actions/checkout@v2
- name: Set up NodeJS 12
uses: actions/setup-node@v1
with:
node-version: 12
registry-url: https://registry.npmjs.org
For example in Python you might change to this:
jobs:
deploy:
runs-on: ubuntu-18.04
steps:
- name: Checkout to master
uses: actions/checkout@v2
- name: Set up Python 3.5
uses: actions/setup-python@v1
with:
python-version: 3.5
And in Jekyll, this might be something as below:
jobs:
deploy:
runs-on: ubuntu-18.04
steps:
- name: Checkout to master
uses: actions/checkout@master
- name: Set up Ruby 2.6
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6.x
You can find each actions in github marketplace.
Git Configuration
This is also a common requirement before using any git command.
- name: Prepare Git Initialization
run: |
git config --global user.name "someone"
git config --global user.email "someone@somewhere"
Example Configurations
I copy paste from other site, with a few adjustment.
I hope that is clear. Now consider have a look at the example configuration files. One by one, from the simplest one to complex low level command.
Most of the configuration I copy paste from other site, with a few adjustment. I respect copyright, so I put credits, by showing the original URL.
Practice
Now you can make repository, with any name, for example:
-
Hexo:
-
Eleventy:
-
Hugo:
-
Jekyll:
-
Pelican:
This is just an example, you should use your username account. and you should use your own repository.
3: Configuration: Hexo
Author
I get this configuration originally from
Secrets
You have to setup DEPLOY_KEY
in github’s secrets setting.
YAML Configuration
After a few adjustment, here is what I have got:
name: Hexo Deploy
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout to master
uses: actions/checkout@v2
- name: Set up NodeJS 12
uses: actions/setup-node@v1
with:
node-version: 12
registry-url: https://registry.npmjs.org/
- name: Setup Secret Secure Shell
run: |
mkdir -p ~/.ssh/
echo "${{secrets.DEPLOY_KEY}}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Prepare Git Initialization
run: |
git config --global user.name "someone"
git config --global user.email "someone@somewhere"
- name: Install and Configure Dependencies
run: npm install
- name: Generate Hexo Static Files
run: npm i -g hexo-cli
- name: Deploy Static Files to gh-pages Branch
run: hexo deploy -g
The hardest part of YAML configuration for SSG is the deployment part. Hexo has simplified this in only one line command.
jobs:
deploy:
...
steps:
...
run: hexo deploy -g
You should setup secure shell to use that oneline command above.
- name: Setup Secret Secure Shell
run: |
mkdir -p ~/.ssh/
echo "${{secrets.DEPLOY_KEY}}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com >> ~/.ssh/known_hosts
Do not forget to to setup in Hexo’s _config.yml
:
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
repo: git@github.com:epsi-rns/actions-hexo.git
branch: gh-pages
Preview
Please enjoy the render at
4: Configuration: Eleventy
Author
I adjust the previously made Hexo configuration, for use with Eleventy.
Secrets
You do not require to setup anything in github’s secrets setting.
Just use the GITHUB_TOKEN
.
YAML Configuration
After a few adjustment, here is what I have got:
name: Eleventy Deploy
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout to master
uses: actions/checkout@v2
- name: Set up NodeJS 12
uses: actions/setup-node@v1
with:
node-version: 12
registry-url: https://registry.npmjs.org/
- name: Install and Configure Dependencies
run: |
npm install
npm install -g @11ty/eleventy
- name: Generate Eleventy Static Files
run: |
eleventy --pathprefix="/workflows-11ty/"
- name: Deploy Static Files to gh-pages Branch
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./_site
The only different is,
I replace the hexo deploy
command, with action-gh-pages
.
- name: Deploy Static Files to gh-pages Branch
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./_site
I have got this idea of the deployment from:
No need to setup RSA key. This is very simple.
Preview
Please enjoy the render at
5: Configuration: Hugo
Author
I get this configuration originally from
Secrets
You do not require to setup anything in github’s secrets setting.
Just use the GITHUB_TOKEN
.
YAML Configuration
Almost copy paste from the link above:
name: Hugo Deploy
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-18.04
steps:
- name: Checkout to master
uses: actions/checkout@v2
- name: Set up Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: '0.62.2'
# extended: true
- name: Generate Hugo static Files
run: |
hugo
- name: Deploy Static Files to gh-pages Branch
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
It works flawlessly.
I never know that, deploying Hugo using github actions could be this easy.
Preview
Please enjoy the render at
6: Configuration: Jekyll
Author
I get this configuration originally from mas Didik
.
The article is in local language.
He did it really great.
Secrets
You do not require to setup anything in github’s secrets setting.
Just use the GITHUB_TOKEN
.
YAML Configuration
After a few trial and error, I finally manage, to get this done.
name: Jekyll Deploy
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout to master
uses: actions/checkout@master
- name: Set up Ruby 2.6
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6.x
- name: Install Gems and Configure Dependencies
run: |
gem install bundler
bundle install --jobs 4 --retry 3
- name: Deploy Static Files to gh-pages Branch
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
bundle exec rake site:publish
This is a little bit different.
Just like Hexo configuration using internal commands,
this Jekyll configuration is using oneliner rake
commands,
with GITHUB_TOKEN
as a requirement.
- name: Deploy Static Files to gh-pages Branch
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
bundle exec rake site:publish
Rakefile
What is it this rake
is all about?
Ruby use a file named Rakefile
.
I copy-paste Didik’s Rakefile
, and adjust a little.
You can get Didik’s Rakefile
from:
And I trace the source come from
After a few adjustment, my Rakefile
looks like below code:
require "rubygems"
require "tmpdir"
require "bundler/setup"
require "jekyll"
# Change your GitHub reponame
# eg. "kippt/jekyll-incorporated"
# or "id-ruby/id-ruby"
GITHUB_REPONAME = "epsi-rns/workflows-jekyll"
GITHUB_TOKEN = ENV["GITHUB_TOKEN"]
namespace :site do
desc "Generate blog files"
task :generate do
Jekyll::Site.new(Jekyll.configuration({
"source" => ".",
"destination" => "_site"
})).process
end
desc "Generate and publish blog to gh-pages"
task :publish => [:generate] do
current_directory = Dir.pwd
Dir.mktmpdir do |tmp|
cp_r "_site/.", tmp
Dir.chdir tmp
system "git init"
system "git config user.name someone"
system "git config user.email someone@somewhere"
system "git add ."
message = "Site updated at #{Time.now.utc}"
system "git commit -m #{message.inspect}"
system "git remote add origin #{git_origin}"
system "git push origin master:refs/heads/gh-pages --force"
Dir.chdir current_directory
end
end
def git_origin
if GITHUB_TOKEN
"https://x-access-token:#{GITHUB_TOKEN}@github.com/#{GITHUB_REPONAME}.git"
else
"git@github.com:#{GITHUB_REPONAME}.git"
end
end
end
Wow… I have so much to learn from this Rakefile
.
You have done great job, mr. Didik
!.
Preview
Please enjoy the render at
7: Configuration: Pelican
Author
I get this configuration originally from
But I failed miserably.
It is just me, that cannot configure publishconf.py
,
so I cannot ge make publish
to works.
I failed miserably.
Secrets
You have to setup PRIVATE_KEY
in github’s secrets setting.
Workaround
So I use my own CircleCI configuration as a based.
And combined with the RSA setup from Jim Kubicek
above.
YAML Configuration
After a few trial and error. I finally got this low level configuration as below.
name: Pelican Deploy
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout to master
uses: actions/checkout@v2
- name: Set up Python 3.5
uses: actions/setup-python@v1
with:
python-version: 3.5
- name: Setup the SSH key
env:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
run: |
mkdir $HOME/.ssh
echo "$PRIVATE_KEY" > $HOME/.ssh/id_rsa
chmod 600 $HOME/.ssh/id_rsa
ssh-keyscan -t rsa github.com >> $HOME/.ssh/known_hosts
- name: Prepare Git Initialization
run: |
git config user.email "someone@somewhere"
git config user.name "someone"
git remote -v
echo "[Checking origin/gh-pages]"
git fetch
git branch -a -l | cat
if [ $(git branch -a -l | grep gh-pages | wc -l) -eq "0" ]; then
echo "[Create gh-pages for the first time]"
git checkout -b gh-pages
git commit --allow-empty -m "Create gh-pages for the first time"
git push --set-upstream origin gh-pages
git checkout master
fi
- name: Upgrade PIP and Configure Dependencies
run: |
python3 -m venv venv
. venv/bin/activate
pip install --user --upgrade pip
pip install -r requirements.txt
- name: Generate Pelican Static Files
run: |
. venv/bin/activate
make html
- name: Precheck Output
run: |
pwd
source=$(pwd)
git worktree add -B gh-pages ~/public origin/gh-pages
git worktree list
cd ~/public
ls -lah
find . -maxdepth 1 ! -name '.git' -exec rm -rf {} \;
mv ${source}/output/* .
touch .nojekyll
ls -lah
- name: Deploy Release to GitHub
run: |
cd ~/public
git add --all
git status
git commit --allow-empty -m "$(git log master -1 --pretty=%B)"
git push --set-upstream origin gh-pages
echo "[Deployed Successfully]"
Whoaaa… this is long. But at least this works for me.
It is working
Generic Configuration
Why that long configuration? Well, as I said eralier, if you do not want to use third party github actions, you can always turn back to low level configuration with pure git.
It is generic, and hypothetically works for most traditional SSG, such as Jekyll, Hexo, Hugo, Pelican and Eleventy.
Preview
Please enjoy the render at
What is Next ?
We are almost finished. For the hunger, here is a food intellectual curiosity. Consider continue reading [ CI/CD - Git Hooks ].