Migrating from GitLab to Forgejo

speckx1 pts0 comments

Migrating From Gitlab to Forgejo | www.bentasker.co.uk

Skip to main content

About five years ago, I migrated my project management from JIRA to Gitlab.

There were some initial teething problems but, over the last half decade, Gitlab has served my needs pretty well.

The urge to replace it, though, has been growing.

Gitlab is pretty resource heavy and I've previously had to migrate other workloads off the host because they were impacted by Gitlab's RAM gobbling ways.

Last year, I upgraded Gitlab and found that the behaviour of the UI had changed: the issue listing page opened issues in a drawer, with no way to set the default back to the original behaviour. That eventually became possible in a later release but, still, the experience rankled.

This week, I decided that it was time to finally do something about my Gitlab install and so set about migrating to Forgejo.

This post talks about some of that experience - it's not a walkthrough guide on migrating, and instead addresses some sticking points that I ran into along with some tooling I created along the way.

Deployment

I won't go into too much depth here because Forgejo has excellent docs but, essentially I deployed the docker image by adding the following to the service section of my docker-compose:

forgejo:<br>image: codeberg.org/forgejo/forgejo:15<br>container_name: forgejo<br>environment:<br>- USER_UID=1000<br>- USER_GID=1000<br># Required because my gitlab hostname<br># will resolve to a RFC1918 address<br>- FORGEJO__migrations__ALLOW_LOCALNETWORKS=true<br>restart: always<br>volumes:<br>- /home/ben/docker_files/files/forgejo/data:/data<br>- /etc/localtime:/etc/localtime:ro<br>ports:<br>- '1200:3000'<br>- '1022:22'

I chose to use Forgejo's sqlite3 support for the database - I like not having another external $thing to maintain.

After starting the container, the web interface (on port 1200 in my case) provided an installation wizard which allowed me to set things like my custom SSH port (1022).

Data Migration

Forgejo has migration tools built into it, including one for Gitlab:

As well as the repo itself, the tooling is able to import issues, wiki pages etc.

Unfortunately, though, it's designed to migrate a repository... singular. I had over 200 repos in my Gitlab instance and didn't really want to go through 200 sets of clickops.

Searching around, I found a third-party migration script, so decided to give that a try:

git clone https://git.autonomic.zone/kawaiipunk/gitlab-to-gitea.git<br>cd gitlab-to-gitea/<br>python3 -m pip install -r requirements.txt<br>nano migrate.py # provide tokens etc<br>python3 migrate.py

This almost did what I wanted, but had a couple of problems:

It copied issues over but not comments (which to be fair, the README is clear about)

Issue creation dates were set to now rather than the original

Projects without a repository enabled in Gitlab get created but don't work (Forgejo just shows a migrating gif1)

The issue with repo-less projects was annoying, but also quite easily addressed - I used a script to enable repo on any Gitlab project that had it disabled:

#!/usr/bin/env python3<br>import gitlab<br>import os<br>import sys

GITLAB_URL = os.environ.get("GITLAB_URL", "https://gitlab.home")<br>GITLAB_TOKEN = os.environ.get("GITLAB_TOKEN", "")

gl = gitlab.Gitlab(GITLAB_URL, private_token=GITLAB_TOKEN)

updated = 0<br>ok = 0

for project in gl.projects.list(iterator=True):<br>if project.repository_access_level == "disabled":<br>print(f"Enabling repository: {project.path_with_namespace}")<br>project.repository_access_level = "enabled"<br>project.save()<br>updated += 1<br>else:<br>print(f"OK: {project.path_with_namespace} ({project.repository_access_level})")<br>ok += 1

print(f"\nDone — {ok} already enabled, {updated} updated")

Given the lack of ability to move and correctly date comments, I decided that migrating all issues had probably been the wrong choice - I have static HTML exports of Gitlab issues, so would still be able to refer to anything historic if a need arose.

The migration script didn't have a toggle to disable issue migration, so I modified it:

diff --git a/migrate.py b/migrate.py<br>index f910f90..ff23e4c 100644<br>--- a/migrate.py<br>+++ b/migrate.py<br>@@ -553,7 +553,7 @@ def import_projects(gitlab_api: gitlab.Gitlab, gitea_api: pygitea):<br>collaborators: [gitlab.v4.objects.ProjectMember] = project.members.list(all=True)<br>labels: [gitlab.v4.objects.ProjectLabel] = project.labels.list(all=True)<br>milestones: [gitlab.v4.objects.ProjectMilestone] = project.milestones.list(all=True)<br>- issues: [gitlab.v4.objects.ProjectIssue] = project.issues.list(all=True)<br>+ issues: [gitlab.v4.objects.ProjectIssue] = []

print("Importing project " + name_clean(project.name) + " from owner " + project.namespace['name'])<br>print("Found " + str(len(collaborators)) + " collaborators for project " + name_clean(project.name))

I stopped the container, deleted the data directory from disk and started again.

This time, the migration worked, but further review highlighted an important shortcoming that I'd missed: the script...

gitlab project forgejo migrate issues migrating

Related Articles