In the last few evenings i was able to rebuild my complete workflow to publish texts in my blog with Gitea Actions. My first version was rather simple.
How I’m publishing texts to this blog
For a long time i worked with a two stage model with a third separate version for testing purposes. Since i started with git and jekyll instead of mysql and s9y, i had one main branch that contains markdown files. This markdown files result in the html pages you are seeing right now via Jekyll. So, what you are seeing here is this production branch.
Having your blog in a versioning system had so far two killer features for me: Reverting and having a history of changes. And i used both quite frequently, even when there was only this mein version.
Then there were three
Not much later there were two additional versions: There is a staging version of this website. It’s meant for testing new software versions, new layouts, changes in the templates. Staging is is public, because sometimes you want to show someone a new idea. And at the end it’s the same content as in the public website. However it may be totally broken.
And then there is draft. Despite mentioned last, the next area was the second i started to use: Draft is not public, because it’s “content in progress”. I wanted to work on blog entries in a webserver environment with the normal rendering, without having to publish the blog entries too early. There are even a few blog entries in this draft area that never saw the light of the day, because there is one or the other reason why i didn’t want to publish them.1 Draft contains the rendering of all unpublished, drafted or future blog entries.
Branches
All three stages are today represented by a branch in my Gitea. In the past i had the same construct in Github. The production website is in the main
branch, the draft area is in draft
2 branch and staging is in staging
3 branch.
Normally i just use draft
and main
. I’m writing my texts (and correct them) in the draft
branch and then - when i deem the blog entries as ready for publication - I’m triggering a pull request into the main
branch. This works reasonably well. In the past, i implemented this via some scripts running on my Mac Mini waddledee
. It had the problem i described in the last blog entry about this topic, like it was a little bit difficult to publish something on a different system than this Mac Mini.
New workflow
However, with the new fileserver, i wanted to get rid of this kludge. To implement the workflow in Gitea (that is running on my NAS) i’m using this unified workflow yaml file. It’s the same for all branches. I could use different workflow files in each branch but then i would have to put back the matching one each time i delete the branch and create it anew.
Caution: Of course this script is heavily customized for my own implementation, it has no safeguards4 and you have to adapt it your sitation and use it on your own risk. I’m running it on a gitea system that is only used by myself. The branch names are hardcoded. You should only see it as a template for your own work. I wouldn’t use it on a public or semi-public Gitea server.
In principle it’s just an expanded version of the old script. This version needs the following secrets:
BLOG_SSHPRIVATEKEY
: The private identity file for ssh. For example the content ofid_rsa
BLOG_DRAFT_HTPASSWD
: The complete content of .htpasswd file, created with thehtpassword
command
In addition you have to set the following variables:
BLOG_SSHKNOWNHOSTKEYS
: The keys of the host you want to sync the files to. I’ve created this withssh-keyscan examplewebspaceprovider.de
BLOG_REMOTEUSER
: username for ssh on your target hostBLOG_REMOTEHOST
: hostname of your target hostBLOG_HTPASSWD_DIRECTORY
: absolute path where you htpassword file will be placedBLOG_PRODUCTION_REMOTEDIR
: document root for the production webserverBLOG_STAGING_REMOTEDIR
: document root for the staging webserverBLOG_DRAFT_REMOTEDIR
: document root for the draft webserver
This is the yaml for the workflow itself:
name: Building the blog
run-name: ${{ gitea.actor }} is building the blog
on: [push]
jobs:
Buildblog:
runs-on: ubuntu-latest
container:
image: c0t0d0s0-jekyll
steps:
- name: Check out repository code
uses: actions/checkout@v4
with:
ref: ${{ gitea.ref_name }}
- name: Run Jekyll. Do not Hyde!
env:
GEM_HOME="/gems"
run: |
if [ "${{ gitea.ref_name }}" = "draft" ]; then
echo "Triggered by draft branch"
BLOG_BUILDOPTIONS="--future --unpublished --drafts --profile"
else
echo "Triggered by branch without special build options"
BLOG_BUILDOPTIONS="--profile"
fi
bundle exec jekyll build --source ${{ gitea.workspace }} $BLOG_BUILDOPTIONS --destination /site
- name: SSH stuff
env:
BLOG_SSHPRIVATEKEY: ${{ secrets.BLOG_SSHPRIVATEKEY }}
BLOG_SSHKNOWNHOSTKEYS: ${{ vars.BLOG_SSHKNOWNHOSTKEYS }}
run: |
echo "Placing identity file"
mkdir ~/.ssh
echo "$BLOG_SSHPRIVATEKEY" > ~/.ssh/id
chmod 600 ~/.ssh/id
echo "Placing known_hosts"
echo "$BLOG_SSHKNOWNHOSTKEYS" >> ~/.ssh/known_hosts
- name: preparing password protection for draft
env:
BLOG_REMOTEUSER: ${{ vars.BLOG_REMOTEUSER }}
BLOG_REMOTEHOST: ${{ vars.BLOG_REMOTEHOST }}
BLOG_DRAFT_HTPASSWD: ${{ secrets.BLOG_DRAFT_HTPASSWD }}
run: |
echo "Preparing password protection for draft"
if [ "${{ gitea.ref_name }}" = "draft" ]; then
echo "Creating htpasswd file"
echo "$BLOG_DRAFT_HTPASSWD" > ~/draft.htpasswd
echo "Transfering htpasswd file into webspace"
scp -i $HOME/.ssh/id -r ~/draft.htpasswd $BLOG_REMOTEUSER@$BLOG_REMOTEHOST:htpasswd/htpasswd
echo "Enabling password protection of draft"
echo "AuthUserFile ${{ vars.BLOG_HTPASSWD_DIRECTORY }}/draft.htpasswd" >> /site/.htaccess
echo "AuthGroupFile /dev/null" >> /site/.htaccess
echo "AuthName Draft" >> /site/.htaccess
echo "AuthType Basic" >> /site/.htaccess
echo "require valid-user" >> /site/.htaccess
fi
- name: syncing to webspace
env:
BLOG_REMOTEUSER: ${{ vars.BLOG_REMOTEUSER }}
BLOG_REMOTEHOST: ${{ vars.BLOG_REMOTEHOST }}
BLOG_DRAFT_HTPASSWD: ${{ secrets.BLOG_DRAFT_HTPASSWD }}
run: |
echo ${{ gitea.ref_name }}
if [ "${{ gitea.ref_name }}" = "main" ]; then
echo "Triggered by main branch"
BLOG_REMOTEDIR="${{ vars.BLOG_PRODUCTION_REMOTEDIR }}"
elif [ "${{ gitea.ref_name }}" = "draft" ]; then
echo "Triggered by draft branch"
BLOG_REMOTEDIR="${{ vars.BLOG_DRAFT_REMOTEDIR }}"
elif [ "${{ gitea.ref_name }}" = "staging" ]; then
echo "Triggered by draft branch"
BLOG_REMOTEDIR="${{ vars.BLOG_STAGING_REMOTEDIR }}"
else
echo "Triggered by unknown branch"
exit 1
fi
echo Syncing as $BLOG_REMOTEUSER
echo Syncing to $BLOG_REMOTEHOST
echo Syncing in $BLOG_REMOTEDIR
rsync -e "ssh -i $HOME/.ssh/id" -r /site/* $BLOG_REMOTEUSER@$BLOG_REMOTEHOST:$BLOG_REMOTEDIR
echo "Transfering final .htaccess into webspace"
scp -i $HOME/.ssh/id -r /site/.htaccess $BLOG_REMOTEUSER@$BLOG_REMOTEHOST:$BLOG_REMOTEDIR/.htaccess
-
There is even a one sentence time-bombed blog entry in the repository, publishing between thirty and sixty days after i reset the timer. If i don’t reset the publication date, an scheduled automatic build run will put this online. More or less a morbid gag. Even when i really wanted to drop this blog, i winded up this egg timer. ;) ↩
-
Big surprise! ↩
-
Yet another big surprise! ↩
-
For example it doesn’t check for spaces in the variables, doesn’t escape anything. As it said, it works in my sitation. ↩