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

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)

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

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.

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.TargetingPackRunner
$ 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 0Registrierung ö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"
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.

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


