Hosting a Hugo Site Using Codeberg Pages with One-Click Deployment

How to host a Hugo site using Codeberg Pages with one-click deployment?

Yesterday I made a few changes to my site, namely I decided to merge my Persian and English blog into one, and write more blog posts.

To write more, it is necessary for the act of publishing a blog post to be easy. It would be easy on Github, which has its own CI, but I don’t want to host my blog there (they’re not a big help to libre software). Not using Github means I lose access to a nice CI. I could request one from Codeberg but seeing that it’d take their resources I decided against that as well.

Using Bash for Automatic Deployment

To automate a series of repetitive shell commands, the ever-present bash is the first option to consider. So that’s what I went with.

My blog is on a single repo, but has two different branches. This meant that I had to go through some extra loops (git switch, git clean, …) to publish my blog. Wouldn’t it be nice if I could have both my branches, my source directory and its build results in separate directories? A simple yet stupid approach is to clone the repo twice and use each branch in a different folder. However the best practice is to use git worktrees. And that’s what I went with.

First we need to create one directory for each of the branches. You can learn this trick from here. Note that you may have to also allow for relative paths (git config status.relativePaths true) if you’re moving the base folder around, or use the same folder on multiple devices (for example by using Syncthing).

After being done with the process, you will have this directory structure:

.
├── deploy.sh
├── main
└── src

Make sure to go inside each worktree and do a git pull. You may need to set up upstream branches as well.

Then you can run the following deployment code for deploy.sh when you’re in the parent directory:

set -eu

if [ -z "$1" ]; then
    echo "usage: bash deploy.sh commit message."
    echo "currently commit message is not set."
    exit 1
fi

BOLD="\e[1m"
RED="\e[31m"
RESET="\e[0m"

echo -e "${BOLD}${RED}Make sure to push to src, as it does not happen automatically${RESET}"


echo "Currently at $PWD"
cd src
echo "Building..."
hugo
cd ..
cd main
echo "Removing all files in main"
rm -rf *
if [ ! -f .domains ]; then
    echo "Error: File '.domains' does not exist."
    exit 1
fi
echo "Restoring main"
cp -r ../src/public/* .
echo "Git add"
git add .
echo "Git diff, do you verify?"
git diff HEAD
read -p "Do you want to continue? (y/n): " answer

if [[ "$answer" == "n" ]]; then
    echo "You said no. Exiting..."
    exit 0
elif [[ "$answer" == "y" ]]; then
    echo "Continuing..."
else
    echo "Invalid input. Please enter 'y' or 'n'."
    exit 1
fi
echo "Git commit..."
git commit -m "$1"
echo "Git push..."
git push

With this setup, I push to the src branch manually, but I can then easily deploy the static build results locally without using any CI tooling.

Have thoughts or questions? I'd love to hear them:

hossein.01 (Signal)
me@hossein.me

Want more articles like this one? Get notified of new posts by subscribing to the RSS feed or the email newsletter. I won't share your email or send spam, only blog posts.

Want more content now? This blog's archive has 28 ready-to-read articles. I also curate a list of cool URLs I find on the internet.

Find a mistake? This blog is open source, you can always open an issue.

Thanks for reading! ♡ All content on this blog is licensed under CC BY-SA 4.0, except where noted otherwise, or for third-party materials.