Migration nach forgejo POC

Diese Demonstration soll beweisen, wie einfach die Migration von github nach forgejo funktioniert.

Hosten der Forgejo Instanz

Forgejo besteht aus einer einzelnen GO binary.
Wird diese gestartet erhält meinen einen Wizard, indem Alles konfiguriert werden kann.

$ ./forgejo 
2026/08/27 14:24:42 cmd/web.go:250:runWeb() [I] Starting Forgejo on PID: 10350
2026/08/27 14:24:42 cmd/web.go:114:showWebStartupMessage() [I] Forgejo version: 17.0.0-dev-388-43c7b17fb2+gitea-1.22.0 built with GNU Make 4.4.1, go1.27.0-X:nodwarf5
2026/08/27 14:24:42 cmd/web.go:115:showWebStartupMessage() [I] * RunMode: prod
2026/08/27 14:24:42 cmd/web.go:116:showWebStartupMessage() [I] * AppPath: /usr/lib/webapps/forgejo/forgejo
2026/08/27 14:24:42 cmd/web.go:117:showWebStartupMessage() [I] * WorkPath: /usr/lib/webapps/forgejo
2026/08/27 14:24:42 cmd/web.go:118:showWebStartupMessage() [I] * CustomPath: /usr/lib/webapps/forgejo/custom
2026/08/27 14:24:42 cmd/web.go:119:showWebStartupMessage() [I] * ConfigFile: /usr/lib/webapps/forgejo/custom/conf/app.ini
2026/08/27 14:24:42 cmd/web.go:120:showWebStartupMessage() [I] Prepare to run install page
2026/08/27 14:24:42 cmd/web.go:315:listen() [I] Listen: http://0.0.0.0:3000
2026/08/27 14:24:42 cmd/web.go:319:listen() [I] AppURL(ROOT_URL): http://localhost:3000/
2026/08/27 14:24:42 ...s/graceful/server.go:50:NewServer() [I] Starting new Web server: tcp:0.0.0.0:3000 on PID: 10350

wizardmain wizardmain

Die Erweiterten Einstellungen ermöglichen es uns später zB LDAP zu erfordern.
Damit könnten wir zB die Forgejo Accounts auch über die KV steuern (oder EntraID).

Repository Migration

Migrationen sind in Forgejo bereits mit eingebaut (https://git.cmi.ch/repo/migrate) migration

Ab dem Zeitpunkt heisst es erstmal warten, während das Repository gezügelt ist.
migrating

Die Wartezeit ist hier ausschliesslich bei Github.
Es können deshalb alle repository migrationen gleichzeitig gestartet werden und man wartet dann.
Das migrieren der Pull Requests nimmt die meiste Zeit in Anspruch.

Sobald der Prozess beendet ist steht das repo inklusive PRs bereit. migrated

Die BuildPipeline

Aus Zeitgründen setze ich für diesen POC jetzt keine CD pipeline für die windows runner Binaries auf.
Forgejo liefert diese vorkompiliert nur für Linux.

Es existiert eine Github Action, die manuell angestossen wird und die runner exe in releases bereitstellt.
Dort bediene ich mich.

Für diese demo wird eine neue Windows server 2025 vm über qemu geladen.
Installation von dotnet und msbuild:

Buildtools

$execDir = "C:\ExecStuff"
New-Item -ItemType Directory -Force -Path $execDir | Out-Null
curl.exe -Lo "$execDir\dotnet-install.ps1" "https://dot.net/v1/dotnet-install.ps1"
$dotnetPath = "C:\Program Files\dotnet"
 
& "$execDir\dotnet-install.ps1" -Channel 8.0 -InstallDir $dotnetPath
& "$execDir\dotnet-install.ps1" -Channel 10.0 -InstallDir $dotnetPath
[Environment]::SetEnvironmentVariable("DOTNET_ROOT", $dotnetPath, "Machine")
$machinePath = [Environment]::GetEnvironmentVariable("Path", "Machine")
if ($machinePath -notlike "*$dotnetPath*") {
    [Environment]::SetEnvironmentVariable("Path", "$machinePath;$dotnetPath", "Machine")
}
$extraPaths = @(
    "D:\CMI-Github\SDK\VsBuildTools\MSBuild\Current\Bin",
    $execDir
)
$machinePath = [Environment]::GetEnvironmentVariable("Path", "Machine")
foreach ($p in $extraPaths) {
    if ($machinePath -notlike "*$p*") {
        $machinePath = "$machinePath;$p"
    }
}
[Environment]::SetEnvironmentVariable("Path", $machinePath, "Machine")
 
irm -Uri "https://aka.ms/stable/vs_BuildTools.exe" -OutFile vs_BuildTools.exe
.\vs_BuildTools.exe --wait --passive --norestart --installPath "D:\CMI-Github\SDK\VsBuildTools" --add Microsoft.VisualStudio.Workload.ManagedDesktopBuildTools \ 
--add Microsoft.NetCore.Component.SDK --add Microsoft.VisualStudio.Workload.MSBuildTools \ 
--add Microsoft.VisualStudio.Workload.WebBuildTools --add Microsoft.Net.Component.4.8.TargetingPack

Runner

$ curl -Lo forgejo-runner.exe "https://github.com/Crown0815/Forgejo-runner-windows-builder/releases/download/v12.12.0/forgejo-runner-windows-amd64.exe"
  % Total    % Received % Xferd  Average Speed  Time    Time    Time   Current
                                 Dload  Upload  Total   Spent   Left   Speed
  0      0   0      0   0      0      0      0                              0
100 18.42M 100 18.42M   0      0 15.04M      0   00:01   00:01              0

Registrierung öffnen, angezeigte config kopieren, labels ergänzen und starten.

$ forgejo-runner.exe daemon --config runnerconfig.toml
time="2026-08-27T16:42:13+02:00" level=info msg="Starting runner daemon"
time="2026-08-27T16:42:13+02:00" level=info msg="runner: windows-vm, with version: v12.12.0, with labels: [windows-latest warp-windows-latest-x64-8x], ephemeral: false, declared successfully"
time="2026-08-27T16:42:13+02:00" level=info msg="[poller] launched"

runner

Anpassung der Action

Ein paar Anpassungen müssen natürlich in der Action vorgenommen werden.
Das sind zum Teil Anpassungen aus bequemlichkeit, zum anderen Teil aber ich kleine Unterschiede.
Die forgejo-cli heisst beispielsweise fj anstatt gh und hat stellenweise andere Parameter.
Dies könnte auch mit einem wrapper gelöst werden, aber diese kleine Anpassung ist kaum ein Aufwand.
Der Rest der Änderungen sind Dinge, die bereits korrekt vorkonfiguriert sind.
Der PR Kommentar wurde ersetzt, da diese Composite action eigentlich bereits in github nicht mehr genutzt werden sollte.
Da für den Test ein einzelnes Package des Monorepos genügt, wird hier nur CMI.CDWS.Interfaces hochgeladen.

diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 6944f1fd..571bcd78 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -26,32 +26,16 @@ jobs:
       version: ${{ steps.release.outputs.version }}
       docalias: ${{ steps.release.outputs.docalias }}
     steps:
-    - name: Disable autocrlf
-      run: |
-        git config --global core.autocrlf false
-
-    - uses: actions/checkout@v7
+    - uses: actions/checkout@main
       with:
         fetch-depth: 0
 
-    - name: Setup dotnet 10
-      uses: actions/setup-dotnet@v6
-      with:
-        dotnet-version: |
-            8.0.x
-            10.0.x
-
     - name: Validate CodeStyle has been applied
       shell: bash
       run: |
         dotnet tool restore
         dotnet csharpier check .
 
-    - name: Add cmi package Feeds
-      uses: CMInformatik/ci-add-nuget-feed@master
-      with:
-        github-token: ${{ secrets.CMI_GITHUB_TOKEN }}
-
     - name: Restore
       run: dotnet restore cmi-metatool-packages.sln
 
@@ -66,7 +50,8 @@ jobs:
 
     - name: Push
       run: |
-        dotnet nuget push -s cmigithub -k "${{ secrets.CMI_GITHUBTOKEN_RW }}" --skip-duplicate "out\*.nupkg"
+        dotnet nuget push -s cmigithub -k "${{ secrets.CMI_GITHUBTOKEN_RW }}" --skip-duplicate "out\CMI.CDWS.Interfaces*.nupkg"
 
     - name: Add Step Summary
       shell: bash
@@ -82,14 +67,8 @@ jobs:
 
     - name: Decorate PR
       if: ${{ steps.stepSummary.outputs.DECORATE_PR == 'true'}}
-      uses: thollander/actions-comment-pull-request@v3.0.1
-      with:
-        message: |
-          ${{ steps.stepSummary.outputs.PACKAGE_VERSION }}
-        comment-tag: cmipack_info
-        mode: recreate
-        create-if-not-exists: true
-        github-token: ${{ secrets.CMI_GITHUBTOKEN_RW }}
+      run: |
+        fj pr comment ${{ github.event.pull_request.number }} ${{ steps.stepSummary.outputs.PACKAGE_VERSION }}
 
     - name: Create release
       if: ${{ github.event_name == 'push' }}
@@ -107,13 +86,4 @@ jobs:
         [[ "${{ github.ref_name }}" == 'main' ]] && docalias='latest' || docalias='${newVersion}'
         echo "docalias=${docalias//\//_}" >> "$GITHUB_OUTPUT"
 
-        gh release create "v.${newVersion}" --title="v.${newVersion}" --notes="" --repo=${{ github.repository }} $prerelease --target=${{ github.sha }}
+        fj release create "v.${newVersion}" --branch "${{ github.sha }}" --create-tag "v.${newVersion}" --body "Neuer release: $newVersion" $prerelease
 

Action Testlauf

Auch wenn es möglich ist das Verzeichnis von .github in .forgejo umzubenennen, werden Alle actions erkannt. overview

Laufzeit

Die Testmaschine der windows VM ist hier ein 4vCPU 8G Memory runner gewesen.
Dennoch sieht man hier, dass der forgejo run 6x so schnell zuende war.
Hier muss natürlich die push Zeit abgezogen werden - 9s vs 1s -.
Gehen wir grosszügig davon aus, dass es mit einem Paket in Github auch nur 1s gedauert hätte, landen wir bei ungefähr immer noch 6x so schnell

samplerun

githubsucks

newpackage