Arc 4 Quest 19

The Other Forges

GitLab CI, Bitbucket Pipelines, Jenkins and portability

The Master Archivist leads you to the top of the tallest tower of the Forge. From there, you discover a breathtaking panorama: beyond the lands of GitHub, other forges glow on the horizon. Columns of smoke and light rise from distant cities, each with its own towers, its own fires, its own construction philosophies.

"You thought GitHub's Forge was the only one? No, young Master. Across the kingdom, other forges operate with different philosophies. GitLab, Bitbucket, Jenkins, and many more. A true Master Archivist knows them all, for each forge possesses unique strengths. Today, you will discover these distant lands and learn to forge in each of them."

Why learn multiple platforms?

You might wonder: "If I know GitHub Actions, why learn anything else?" Excellent question. Here's the answer:

  • The job market: some companies use GitLab, others Bitbucket, others still Jenkins. Knowing multiple platforms makes you much more employable.
  • Needs vary: an open source project will naturally go to GitHub, but a company with internal servers may prefer self-hosted GitLab.
  • Portability: understanding the common concepts lets you switch from one platform to another in hours, not weeks.
  • Critical thinking: knowing the alternatives lets you choose the right tool rather than being stuck with a default choice.

"A blacksmith who knows only one type of forge is prisoner of his forge. One who knows them all is free to choose."

GitLab CI/CD - The Imperial Forge

GitLab is often considered GitHub's most complete competitor. Its main strength: everything is integrated. CI/CD, container registry, project management, security - all in a single platform.

The .gitlab-ci.yml file

Like GitHub Actions uses files in .github/workflows/, GitLab uses a single file at the repository root: .gitlab-ci.yml.

stages:
  - test
  - deploy

test:
  stage: test
  script:
    - echo "Running tests..."

deploy:
  stage: deploy
  script:
    - echo "Deploying..."
  only:
    - main

Key concepts of GitLab CI

Concept Description
Stages The pipeline steps, executed in order
Jobs Individual tasks, attached to a stage
Script Commands to execute in a job
Runners Machines that execute jobs (shared or private)
Artifacts Files produced by a job, passed to subsequent ones

A more complete example

stages:
  - build
  - test
  - deploy

variables:
  APP_NAME: "my-application"

build:
  stage: build
  script:
    - echo "Building $APP_NAME..."
    - mkdir -p build
    - cp src/*.py build/
  artifacts:
    paths:
      - build/

unit-test:
  stage: test
  script:
    - echo "Running unit tests..."
    - python -m pytest tests/

lint-test:
  stage: test
  script:
    - echo "Checking style..."
    - python -m flake8 src/

deploy:
  stage: deploy
  script:
    - echo "Deploying $APP_NAME..."
  only:
    - main
  when: manual

GitLab's strengths

  • All-in-one: CI/CD, Docker container registry, project management, wiki, static pages - everything is natively integrated.
  • Self-hosting: you can install GitLab on your own servers. This is a huge advantage for companies that want to keep control of their data.
  • Built-in container registry: every GitLab project has its own Docker registry, ready to use.
  • Deployment environments: GitLab lets you define environments (staging, production) and visualize deployments directly in the interface.

"The Imperial Forge of GitLab is an autonomous kingdom. It needs no other city to function. Everything is under one roof. That is its greatest strength - and sometimes its weakness, for this power can be intimidating for beginners."

Bitbucket Pipelines - The Merchant Guilds' Forge

Bitbucket is the forge of the Atlassian ecosystem - the same family as Jira (project management) and Confluence (documentation). If your company uses Jira, Bitbucket integrates naturally.

The bitbucket-pipelines.yml file

Bitbucket also uses a YAML file at the repository root:

pipelines:
  default:
    - step:
        name: Tests
        script:
          - echo "Running tests..."

  branches:
    main:
      - step:
          name: Tests
          script:
            - echo "Running tests..."
      - step:
          name: Deployment
          script:
            - echo "Deploying..."

Key concepts of Bitbucket Pipelines

Concept Description
Pipelines The global configuration container
Steps Individual stages (equivalent to jobs)
Script Commands to execute in a step
Pipes Pre-built integrations (deploy to AWS, Slack, etc.)
Caches Dependency caching between runs

Example with Pipes

Pipes are a Bitbucket specialty - they are ready-to-use integrations:

pipelines:
  default:
    - step:
        name: Tests
        caches:
          - node
        script:
          - npm install
          - npm test
    - step:
        name: Slack Notification
        script:
          - pipe: atlassian/slack-notify:2.0.0
            variables:
              WEBHOOK_URL: $SLACK_WEBHOOK
              MESSAGE: "Build completed successfully!"

Bitbucket's strengths

  • Jira integration: commits and branches are automatically linked to Jira tickets. You create a branch from a ticket, and everything is tracked.
  • Pipes: pre-built integrations that simplify common tasks (AWS deployment, notifications, etc.).
  • Free private repos: historically, Bitbucket offered free private repos before GitHub.
  • Confluence integration: documentation is directly linked to the code.

"The Merchant Guilds' Forge of Bitbucket is woven into a commercial network. Every Jira ticket, every Confluence page, every commit - all are connected. For large organized guilds, it's a considerable advantage."

Other notable forges

The world of forges is not limited to these three giants. Here are other important players:

Jenkins - The Veteran

Jenkins is one of the oldest CI/CD tools. It is entirely self-hosted and extremely flexible.

  • Strengths: infinite customization, immense plugin ecosystem (over 1800), free and open source.
  • Weaknesses: aging interface, complex configuration, maintenance required.
  • Config file: Jenkinsfile (Groovy syntax)
pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                sh 'echo "Running tests..."'
            }
        }
    }
}

Jenkins remains widely used in large companies that have invested heavily in their infrastructure.

CircleCI - The Cloud Sprinter

CircleCI is a cloud-native CI/CD platform, known for its speed and efficiency.

  • Strengths: very fast, excellent Docker support, good interface.
  • Weaknesses: cost increases quickly with usage, fewer auxiliary features.
  • Config file: .circleci/config.yml

Travis CI - The Open Source Pioneer

Travis CI was historically the favorite CI/CD platform for open source projects. It popularized the concept of CI/CD integrated with forges.

  • Strengths: simple to configure, pioneer of GitHub integration.
  • Weaknesses: lost popularity after its acquisition, reduced free tier.
  • Config file: .travis.yml

Forgejo/Gitea Actions - The Free Alternative

Forgejo and Gitea are self-hosted, lightweight, open source forges. Their Actions system is compatible with GitHub Actions - you can often reuse your workflows directly!

  • Strengths: lightweight, self-hosted, GitHub Actions compatible, privacy-respecting.
  • Weaknesses: smaller community, fewer third-party actions available.
  • Config file: .forgejo/workflows/ or .gitea/workflows/ (same syntax as GitHub Actions)

"Each forge was built by different artisans, with different philosophies. Jenkins is the indestructible veteran, CircleCI the sprinter, Travis the pioneer, and Forgejo the free path. None is perfect, but each excels in its domain."

Comparison table

Here is a summary to help you understand the differences:

Criterion GitHub Actions GitLab CI Bitbucket Pipelines
Config file .github/workflows/*.yml .gitlab-ci.yml bitbucket-pipelines.yml
Self-hosting No (except runners) Yes (GitLab CE/EE) No
Docker registry GitHub Packages Natively integrated Not integrated
Marketplace/Plugins GitHub Marketplace CI/CD Catalogue Atlassian Pipes
Project integration Issues, Projects Boards, Epics, Milestones Jira, Confluence
Free (CI) 2000 min/month 400 min/month 50 min/month
Main strength Community, Actions All-in-one Atlassian ecosystem
Ideal for Open source, startups Enterprises, DevOps Teams on Jira

How to choose the right platform?

The choice depends on your context. Here's a simple guide:

  • Doing open source? - GitHub. The community is there, contributors know the platform.
  • Your company wants full internal control? - Self-hosted GitLab. Data on your servers, total customization.
  • Your team already uses Jira? - Bitbucket. The native integration with the Atlassian ecosystem saves a lot of time.
  • You want a lightweight, free solution? - Forgejo/Gitea. Perfect for a personal server or a small team.
  • You have an existing complex system? - Jenkins. Its flexibility is unmatched for special cases.

Choosing a forge is not a question of best or worst. It's a question of context. The best hammer is the one that fits the nail you need to drive.

Portability - The art of not being trapped

A common trap: putting all your CI/CD logic in your platform's YAML file. If you change forges one day, you have to rewrite everything.

The solution? Keep the logic in scripts, not in the YAML.

Bad approach (everything in the YAML)

# .github/workflows/ci.yml - Hard to port
name: CI
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install -r requirements.txt
      - run: python -m pytest tests/ --cov=src
      - run: python -m flake8 src/ --max-line-length=120
      - run: echo "All tests pass!"

Good approach (logic in a script)

First, create a scripts/test.sh script:

#!/bin/bash
# scripts/test.sh - The logic is here, not in the YAML
echo "Installing dependencies..."
pip install -r requirements.txt

echo "Running tests..."
python -m pytest tests/ --cov=src

echo "Checking style..."
python -m flake8 src/ --max-line-length=120

echo "All tests pass!"

Then, each YAML file simply calls this script:

# GitHub Actions
- run: bash scripts/test.sh

# GitLab CI
script:
  - bash scripts/test.sh

# Bitbucket Pipelines
script:
  - bash scripts/test.sh

Result: if you change platforms, you only need to rewrite the minimal YAML file. All your logic stays intact.

This approach is called "shell-first CI". It's a good practice adopted by experienced DevOps teams. As a bonus, you can test your scripts locally before pushing!

"The wisest Master Archivists never chain themselves to a single forge. They write their scrolls so they can be carried anywhere. That's portability - and it's a skill worth its weight in gold."

Hands-on exercise - Forge on three anvils

Prove your mastery of the Forges by writing the same pipeline on three platforms:

  1. Create a multi-forge repository with a test script
  2. Write the GitHub Actions pipeline in .github/workflows/ci.yml
  3. Write the GitLab CI pipeline in .gitlab-ci.yml
  4. Write the Bitbucket Pipelines pipeline in bitbucket-pipelines.yml
  5. All three pipelines must call the same test script
  6. Commit everything and run the verification

Step 1 - Create the repository

mkdir multi-forge
cd multi-forge
git init -b main

Step 2 - Create the test script

Create a scripts/ folder and a scripts/test.sh file:

mkdir scripts

Write the content of scripts/test.sh:

#!/bin/bash
# scripts/test.sh - Portable test script

echo "=== Running tests ==="

# Test 1: verify the README file exists
if [ -f "README.md" ]; then
    echo "PASS: README.md exists"
else
    echo "FAIL: README.md missing"
    exit 1
fi

# Test 2: verify the scripts folder exists
if [ -d "scripts" ]; then
    echo "PASS: scripts/ folder exists"
else
    echo "FAIL: scripts/ folder missing"
    exit 1
fi

echo "=== All tests pass ==="

Make it executable:

chmod +x scripts/test.sh

Step 3 - Create a README

echo "# Multi-Forge" > README.md
echo "Multi-platform CI/CD demonstration project." >> README.md

Step 4 - Write the GitHub Actions pipeline

mkdir -p .github/workflows

Content of .github/workflows/ci.yml:

name: CI
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: bash scripts/test.sh

Step 5 - Write the GitLab CI pipeline

Content of .gitlab-ci.yml (at the root):

stages:
  - test

test:
  stage: test
  script:
    - bash scripts/test.sh

Step 6 - Write the Bitbucket Pipelines pipeline

Content of bitbucket-pipelines.yml (at the root):

pipelines:
  default:
    - step:
        name: Tests
        script:
          - bash scripts/test.sh

Step 7 - Commit everything

git add .
git commit -m "Add CI pipelines for GitHub, GitLab and Bitbucket"

Step 8 - Run the verification

bash verifier.sh
.\verifier.ps1

Concept summary

Concept Description
GitLab CI/CD CI/CD platform integrated into GitLab, file .gitlab-ci.yml
Bitbucket Pipelines CI/CD integrated into Bitbucket, file bitbucket-pipelines.yml
Jenkins Self-hosted CI/CD tool, very flexible, file Jenkinsfile
CircleCI Fast cloud-native CI/CD platform
Travis CI CI/CD pioneer for open source
Forgejo/Gitea Self-hosted forges compatible with GitHub Actions
Portability Keep the logic in scripts, not in the YAML

Configuration files summary

Platform File Location
GitHub Actions *.yml .github/workflows/
GitLab CI .gitlab-ci.yml Repository root
Bitbucket Pipelines bitbucket-pipelines.yml Repository root
Jenkins Jenkinsfile Repository root
CircleCI config.yml .circleci/
Travis CI .travis.yml Repository root
Forgejo/Gitea *.yml .forgejo/workflows/ or .gitea/workflows/

The Master Archivist contemplates the three anvils before you - each bears a different pipeline, but all forge the same result. He slowly nods his head, visibly satisfied.

"You have forged on three different anvils with equal mastery. GitHub, GitLab, Bitbucket - you now know the philosophies of each forge and you know how to adapt your work to each one. And above all, you understood the most important secret: portability. Your scripts are free, chained to no forge."

He strikes three blows on the largest anvil. The flames of the Automated Forges rise one last time, casting monumental shadows on the walls.

"The Arc of the Automated Forges is complete. You have mastered the eternal forges, the kingdom's actions, the automated trials, and the alternative forges. You are an Accomplished Blacksmith."

The Master Archivist hands you a golden badge - a hammer crossed with a quill, the symbol of those who master both writing and forging.

"But the world evolves, Blacksmith. Beyond the guilds and forges you know, new paths open. Rebel archivists are experimenting with decentralized versioning - no central server, no dominant forge. Radicle, the peer-to-peer protocol for code... This is Arc 5: Beyond the Guilds. And it will change your vision of everything you have learned."