My brief journey of moving from GitHub to GitLab

Why GitLab?

I have always used GitHub for my code. So for no reason except curiosity I decided to migrate to GitLab. I had to start somewhere, so I started with this blog!

How was it?

Pretty easy and straightforward. But of course, what would you expect? They are both git online repo serivices. Yes I know that they have some big differences, but I'll discover/learn them later on.

The main differences that I encountered:

  • The GitLab UI; I still need to familiarize with it 😂.
  • The CI/CD features.

GitLab CI/CD

GitHub Actions and GitLab CI/CD have some important differences. First of all, the configuration file. While the GitHub Actions' file is easy to read for a newcomer, I actually prefer the GitLab one: you need to write/specify more configuration. But in the end, it make much more sense.

After going through the CI/CD docs and understanding some basic concepts (such as stages and rules), I was able to port my GitHub Action to GitLab. This is now my CI script, you can find the old one here:

stages:
  - build
  - deploy
  - clean

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "prod"'
    - if: '$CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_BRANCH == "prod"'

variables:
  PROJECT_NAME: "jeks"
  #CLOUDFLARE_API_TOKEN: # Secret
  #CLOUDFLARE_ACCOUNT_ID: # Secret

patch-and-build:
  stage: build
  image: alpine:3.23
  variables:
    GIT_SUBMODULE_STRATEGY: recursive
  artifacts:
    paths:
      - ./blog/public
    expire_in: 1 day
  before_script:
    - apk add --no-cache git
    - apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/community/ zola
  script:
    - echo "Applying Git patches"
    - |
      for patch in patches/*.patch.diff; do
        if [ -f "$patch" ]; then
          echo "Applying patch $patch"
          git apply "$patch" || { echo "Failed to apply patch $patch"; exit 1; }
        else
          echo "No patch file found: $patch"
          exit 1
        fi
      done

    - echo "Running zola build"
    - cd ./blog/
    - zola build

publish:
  image: node:alpine3.23
  stage: deploy
  script:
    - npm install wrangler --location=global
    - wrangler pages deploy ./blog/public --project-name "${PROJECT_NAME}" --branch "main"

remove-older:
  stage: clean
  image: debian:12-slim
  before_script:
    - apt-get update
    - apt-get install -y jq curl
  script:
    - echo "Cleaning up old deployments"
    - |
      DEPLOYMENTS=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/${PROJECT_NAME}/deployments" \
      -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
      | jq -r '.result | reverse | .[].id')

      if [ -z "$DEPLOYMENTS" ]; then
        echo "No deployments found."
        exit 0
      fi

      readarray -t DEPLOYMENT_ARRAY <<< "$DEPLOYMENTS"

      if [ ${#DEPLOYMENT_ARRAY[@]} -gt 2 ]; then
        NUM_DEPLOYMENTS_TO_DELETE=$(( ${#DEPLOYMENT_ARRAY[@]} - 2 ))
        for (( i=0; i<$NUM_DEPLOYMENTS_TO_DELETE; i++ )); do
          DEPLOYMENT_ID="${DEPLOYMENT_ARRAY[$i]}"
          echo "Deleting deployment $DEPLOYMENT_ID"
          curl -s -X DELETE "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/${PROJECT_NAME}/deployments/$DEPLOYMENT_ID" \
          -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}"
        done
      else
        echo "No old deployments to delete."
      fi

One key difference I want to point out is that GitLab has no out-of-the-box way of managing secrets, unlike GitHub. You can create environment variables per Project. And declare them masked ([Masked] will be displayed in the logs instead of the value), hidden (can not be revealed, neither in settings) and protected (can be used only on protected branches). Or you can also configure external secret management serivices, like HashiCorp Vault.

What else has changed? Introducing Umami

When I wrote about analytics I ended up having both Counter and Rybbit. Now, after some months, I can definitely tell that Counter doesn't work for me: it has recorded only 11 users compared to Rybbit's 72.

I recently heard about Umami, and given that it meets my requirements, I decided to give it a try. Now I'll see how it performs compared to Rybbit. And, as always, I'll come back with updates.