Compare commits

...

5 commits

Author SHA1 Message Date
1dc8c5cef4 add gitea ci section
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-07-22 04:14:26 +02:00
9732eff09a finished gitlab 2023-07-22 02:13:02 +02:00
0e45640871 OneDev hinzugefügt 2023-07-04 23:51:14 +02:00
0072d648c4 add sourcehut 2023-06-30 12:36:05 +02:00
32ae08d4e9 add sourcehut setup instructions 2023-06-14 12:12:52 +02:00
45 changed files with 2793 additions and 0 deletions

View file

@ -7,3 +7,12 @@
- [Aufgabe 3](./aufgaben/aufgabe_3.md) - [Aufgabe 3](./aufgaben/aufgabe_3.md)
- [Aufgabe 4](./aufgaben/aufgabe_4.md) - [Aufgabe 4](./aufgaben/aufgabe_4.md)
- [Aufgabe 5](./aufgaben/aufgabe_5.md) - [Aufgabe 5](./aufgaben/aufgabe_5.md)
# Selfhosting von Open-Source-Entwicklertools
- [Einleitung](./studienarbeit/1_einleitung.md)
- [GitLab](./studienarbeit/2_gitlab.md)
- [Gitea](./studienarbeit/3_gitea.md)
- [Sourcehut](./studienarbeit/4_sourcehut.md)
- [OneDev](./studienarbeit/5_onedev.md)
- [Anhang: Sourcehut-Setup](./studienarbeit/sourcehut_setup.md)

View file

@ -0,0 +1,161 @@
# Selfhosting von Open-Source-Entwicklertools
Um effizient mit anderen Entwicklern an Open-Source-Projekten arbeiten zu können, muss
man den Quellcode seines Projekts veröffentlichen, Aufgaben koordinieren und neue
Codebeiträge entgegen nehmen.
Hierbei kommt fast immer eine Git-Hosting-Plattform zum Einsatz. Diese erlaubt es einem,
sein Repository zu veröffentlichen und mit anderen Personen über das Internet
zusammenzuarbeiten. Andere Nutzer und Entwickler können Softwarefehler melden,
Vorschläge für neue Features machen und neuen Code zum Projekt beitragen.
Der meistgenutzte Git-Hosting-Anbieter ist GitHub. Die Plattform wurde von Tom
Preston-Werner, Chris Wanstrath, P. J. Hyett and Scott Chacon gegründet und ging 2008
ans Netz. 2018 wurde die Firma von Microsoft übernommen.
Der große Vorteil von GitHub ist, dass der Dienst für öffentliche Projekte vollkommen
kostenlos ist. Zudem hat der Dienst mit 100 Millionen Nutzern die mit Abstand größte
Community an potenziellen Beitragenden.
GitHub bietet auch einen Continuous-Integration-Dienst namens GitHub Actions an, mit dem
man sein Projekt automatisch testen und veröffentlichen lassen kann. Im Gegensatz zu
vielen Konkurrenzanbietern setzt GitHub hierbei kein Nutzungslimit bei öffentlichen
Repositories.
Allerdings hat die Nutzung von GitHub auch seine Nachteile. Zum einen ist man bei der
Nutzung eines fremden Webdiensts, insbesondere wenn dieser kostenlos ist und man
deswegen keinen Vertrag mit dem Anbieter abgeschlossen hat, komplett von dessen
Entscheidungen und Nutzungsbedingungen abhängig. Der Anbieter kann den Dienst
einstellen, kostenpflichtig machen, Features entfernen oder bestimmte Nutzer
ausschließen.
Beispielsweise wurde der russische Webentwickler Nikolay Kuchumov wegen eines einzigen
beleidigenden Issues
[2020 auf GitHub gesperrt](https://medium.com/@catamphetamine/how-github-blocked-me-and-all-my-libraries-c32c61f061d3).
Dabei wurden alle seine Repositories von der Plattform entfernt. Noch absurder: GitHub
verlangte eine Kopie seines Personalausweis um die Sperre wieder aufzuheben.
Es gibt auch einige Fälle von Open Source-Projekten, die von GitHub wegen angeblichen
Verstößen gegen das amerikanische Urheberrecht (DMCA) gesperrt wurden. Das prominenteste
Beispiel hierfür ist der Video-Downloader
[youtube-dl](github.blog/2020-11-16-standing-up-for-developers-youtube-dl-is-back/).
Auch das Repository der alternativen Smartwatch-App
[Gadgetbridge](https://www.heise.de/news/Pebble-Gadgetbridge-unter-Beschuss-3740625.html)
wurde zeitweise von GitHub gesperrt. Eine selbstgehostete Plattform ist dagegen viel
schwieriger zu sperren.
Ein weiterer Grund für einige Entwickler, die GitHub-Plattform zu verlassen, ist die
Einführung von GitHub Copilot. Hierbei handelt es sich um ein künstliche Intelligenz,
die einem Programmierer automatisch Code-Vorschläge geben kann. Dessen Sprachmodell
wurde mit dem Code aus öffentlichen GitHub-Repositories trainiert. Kritiker sehen
hierbei eine Urheberrechtsverletzung, da der AI-generierte Code Schnipsel aus den
Trainingsdaten enthalten kann, die dann ohne Erwähnung des Urhebers in andere Projekte
eingefügt werden.
Insbesondere bei privaten oder firmeninternen Projekten kann auch der Datenschutz ein
Grund sein, auf Webanwendungen von Fremdanbietern zu verzichten und die Daten auf
eigenen Servern zu speichern. Da GitHub nicht quelloffen ist und nur mit einer
kostspieligen Enterprise-Lizenz selbst gehostet werden kann, ist is für solche Fälle
attraktiv, eine Open-Source-Anwendung einzusetzen.
Mittlerweile gibt es mehrere Open-Source-Projekte, die Alternativen zu GitHub entwickelt
hat. Im Gegensatz zu proprietären Webdiensten lassen sich diese Anwendungen auf eigenen
Servern installieren, sodass man die volle Autonomie über sein System behält.
In dieser Arbeit werde ich vier von ihnen testen und vergleichen.
## Testkriterien
Ich habe jede Plattform auf meinem Rechner installiert und nach folgenden Kritierien
getestet:
### 0\. Über das Projekt
Zuerst werde ich einige grundlegende Informationen über die entsprechende Anwendung
präsentieren.
- In welcher Programmiersprache ist die Anwendung geschrieben?
- Wie lange existiert das Projekt bereits? Ist es eine Abspaltung eines anderen
Projekts?
- Wie viele Beitragende hat das Projekt?
- Wie sieht die Architektur der Anwendung aus? Welche Dienste werden benötigt?
### 1\. Installation und Einrichtung
Hier gebe ich eine kurze Anleitung zur Installation und Einrichtung der Anwendung. Ich
werde hierbei bewerten, wie einfach die Installation vonstatten geht.
Monolithisch (d.h. aus einem Dienst) aufgebaute Anwendungen sind in der Regel einfacher
einzurichten, bieten aber weniger Flexibilität bei der Skalierung für viele User.
### 2\. Systemanforderungen
Hierbei geht es nicht nur um die unterstützten Betriebssysteme und CPU-Architekturen,
sondern auch um den Bedarf an Rechenleistung und Arbeitsspeicher. Im Idealfall soll die
Software auch auf preisgünstigen Single Board-Computern und virtualisierten Servern
lauffähig sein, sodass sich jeder ein selbst gehostetes Setup leisten kann und nicht aus
Kostengründen auf proprietäre Anbieter angewiesen ist.
Getestet wurden CPU-Auslastung und Arbeitsspeicherverbrauch auf einem Rechner mit einem
Ryzen 5700G-Prozessor (16 Threads) und 32GB RAM. Die angegebene CPU-Auslastung bezieht
sich auf die ausgelasteten Threads (wie in htop angezeigt), d.h. 100% entspricht einem
voll ausgelastetem Thread, 16.000% einem voll ausgelasteten Prozessor.
Neben dem Ressourcenverbrauch im Leerlauf habe ich auch die CPU-Auslastung unter Last
gemessen. Hierfür habe ich das Repository des Linux-Kernels importiert und mir die
Versionsgeschichte und die Blame-Ansicht der Makefile im Stammverzeichnis anzeigen
lassen.
### 3\. Bedienung
Wie einfach ist die Weboberfläche zu bedienen? Ist es möglich, schnell durch
Repositories zu navigieren? Gibt es eine Suchfunktion, um beispielsweise eine bestimmte
Funktion im Code zu finden?
Zudem habe ich dir Unterstützung für verschiedene Dateiformate getestet. Alle
Plattformen können Code, Markdown und Textdateien darstellen. Binärdateien können auf
diese Weise natürlich nicht dargestellt werden, weswegen einige Plattformen spezielle
Viewer für bestimmte Dateitypen mitbringen. Um dies zu testen, habe ich ein Repository
mit Dateien in folgenden Formaten angelegt.
- Bilder (\*.jpg, \*.svg)
- Tabellen (\*.csv, \*.xlsx, \*.ods)
- Text (\*.rst, \*.tex, \*.docx, \*.odt)
- PDF-Dokumente
- 3D-Modelle (\*.stl)
- Jupyter-Notebooks (\*.ipynb)
Zum Vergleich: GitHub unterstützt alle diese Dateitypen mit Ausnahme von LaTEX- und
MS/Open Office-Dokumenten.
### 4\. Import bestehender Projekte
Eine gute GitHub-Alternative sollte es dem Entwickler ermöglichen, bestehende Projekte
von anderen Providern zu importieren. Hierbei soll nicht nur das Repository, sondern
auch z.B. Issues übertragen werden können.
### 5\. Zusatzfeatures
Bietet die Anwendung zusätzlich zu Git-Repositories, Issues und Pull-Requests noch
weitere Features an?
Beispiele hierfür wären das Hosting von statischen Websites direkt aus Repositories
heraus, ein Repository für Softwarepakete verschiedener Programmiersprachen oder
Projektmanagement-Tools.
### 6\. Continuous Integration
Continuous Integration (CI), also das automatische Testen von neuem Code ist ein fester
Teil des Worflows vieler Entwickler. Hat die Plattform einen CI-Dienst eingebaut oder
lässt sie sich mit anderen CI-Diensten integrieren?
### 7\. Öffentliche Instanzen
Nicht jeder möchte den Aufwand betreiben, seine Git-Hosting-Plattform selbst zu hosten.
Deswegen ist es vom Vorteil, wenn es die Möglichkeit gibt, anstelle dessen einer
öffentlichen Instanz beizutreten.
## Quellen
- [Software Freedom Conservancy](https://sfconservancy.org/GiveUpGitHub/): Give up
GitHub

View file

@ -0,0 +1,278 @@
# GitLab
2011, drei Jahre nach dem Start von GitHub veröffentlichten Dmytro Zaporozhets und Sytse
Sijbrandij die erste Version von GitLab. Damit ist GitLab die erste und bekannteste
Open-Source-Alternative zu GitHub.
GitLab Community Edition ist unter der MIT-Lizenz veröffentlicht. Die Firma hinter
GitLab verfolgt ein "Open Core"-Geschäftsmodell, d.h. einige fortgeschrittene Features
sind nicht in der Community Edition enthalten und erfordern die proprietären Versionen
"Premium" bzw. "Ultimate". Diese sind nur in Form eines Abonnements zum Preis von 29
(Premium) bzw. 99USD (Ultimate) pro Nutzer und Monat erhältlich. Open-Source-Projekte
und Bildungseinrichtungen können die Ultimate-Version kostenfrei nutzen.
Im Kern ist GitLab eine Ruby-on-Rails-Webanwendung. Allerdings sind einige Funktionen
der Plattform (bspw. SSH oder Git-Operationen) an zusätzliche Services ausgelagert. Die
meisten dieser Services sind in Go implementiert. Das Webfrontend wurde mit Vue.js
implementiert.
<img src="./assets/gitlab/architecture.png" alt="GitLab Architektur" width="500"/>
- **Workhorse** Reverse Proxy, der HTTP-Anfragen an Git oder die Hauptanwendung
weiterleitet
- **Gitaly** Microservice zur Speicherung der Git-Repositories und Verarbeitung von
Git-Anfragen
- **GitLab Shell** SSH-Server
- **Sidekiq** Task Queue zur Ausführung von Aufgaben im Hintergrund
GitLab verwendet eine PostgreSQL-Datenbank zur Speicherung seiner Daten. Zudem kommt
eine Redis-Instanz als Cache und Event Queue zum Einsatz.
Getestet wurde GitLab in der Version 16.1.1.
## Installation
Um die Installation der Anwendung trotz ihres Aufbaus aus verschiedenen Services zu
vereinfachen, stellt GitLab ein Omnibus-Paket zur verfügung. Hierbei handelt es sich um
ein Linux-Softwarepaket, das die gesamte GitLab-Anwendung mit allen Services (inklusive
NGINX, Redis und Postgres) beinhalten. Die Pakete sind für die meisten
Linux-Distributionen (Ubuntu, Debian, Alma Linux, CentOS, OpenSUSE, Raspberry Pi OS)
verfügbar.
Um Gitlab als Omnibus-Paket zu installieren, muss man zuerst das Gitlab-Repository zu
seinem System hinzufügen. Hierfür kann man dieses Skript verwenden:
<https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh>.
Danach kann man GitLab mit diesem Befehl installieren und starten:
```
GITLAB_ROOT_PASSWORD="<strongpassword>" EXTERNAL_URL="http://gitlab.example.com" apt install gitlab-ce
```
Der Konfigurationsprozess dauert mehrere Minuten. Wenn der Webserver gestartet ist, kann
man die Weboberfläche aufrufen und sich anmelden (Benutzername: `root`).
GitLab stellt auch ein Docker-Image (`gitlab/gitlab-ce`) zur Verfügung, welches das
Omnibus-Paket beinhaltet. Der Einrichtungsprozess ist der gleiche wie bei einer bare
metal-Installation, mit dem Unterschied dass die Konfiguration durch die
Umgebungsvariable `GITLAB_OMNIBUS_CONFIG` erfolgt.
[Hier](./assets/gitlab/docker-compose.yml) ist die Docker-Compose-Datei, die ich für
meine Testinstallation verwendet habe.
Für Unternehmen und große Organisationen mit Tausenden Nutzern bietet GitLab in ihrer
Dokumentation auch Referenzarchitekturen für hochverfügbare Systemen mit mehreren
Servern.
## Systemanforderungen
GitLab bietet Pakete für eine
[Vielzahl von Linux-Distributionen](https://docs.gitlab.com/ee/administration/package_information/supported_os.html),
sowohl für Intel/AMD als auch für ARM-Prozessoren. Das offizielle Docker-Image ist
jedoch nur für die arm64-Architektur verfügbar.
GitLab hat unter allen getesteten Plattformen den höchsten Ressourcenverbrauch.
Im Leerlauf bewegt sich die CPU-Last auf meinem Testsystem zwischen 3 und 30 Prozent.
Der Arbeitsspeicherverbrauch beträgt ganze 6GB.
Aufwändige Git-Operationen können Lastspitzen über 100% für eine Dauer von bis zu 5
Sekunden pro Anfrage verursachen.
GitLab erwähnt in ihrer Dokumentation, dass man die Konfiguration anpassen kann, um den
Ressourcenverbrauch etwas zu senken. Nachdem ich diese Zeilen zur Konfigurationsdatei
hinzugefügt habe, sank der Speicherbedarf auf 2.8GB und die CPU-Auslastung auf 1-12%.
```
# Reduce the number of running workers to the minimum in order to reduce memory usage
puma['worker_processes'] = 2
sidekiq['max_concurrency'] = 9
# Turn off monitoring to reduce idle cpu and disk usage
prometheus_monitoring['enable'] = false
```
Für eine Installation auf Single Board-Computern und kleinen V-Servern ist der
Speicherverbrauch jedoch weiterhin zu hoch. GitLab gibt als Mindestanforderung 4
CPU-Kerne und 4GB RAM an.
## Bedienung
Gitlab's Weboberfläche wurde mit dem VueJS-Framework realisiert. Die gesamte
Weboberfläche wird somit clientseitig mittels JavaScript gerendert. Dies erlaubt eine
äußerst flüssige Navigation durch die Webseite, da die Seite nicht bei jedem
Navigationsschritt neu geladen wird. Der Nachteil dieser Lösung: Javascript ist für die
Darstellung der Webseite zwingend erforderlich.
GitLab bietet die Möglichkeit, den Code eines Repositories zu durchsuchen. Die
Verwendung einer externen Elasticsearch-Instanz für die Suche und die Möglichkeit, die
gesamte Gitlab-Instanz zu durchsuchen, ist allerdings den kostenpflichtigen Versionen
vorbehalten.
GitLab unterstützt in der Standardkonfiguration die meisten Dateiformate unter den
getesteten Plattformen. Auf der Weboberfläche können Bilder, CSV-Tabellen, PDF-Dokumente
und stl-Modelle betrachtet werden, alternative Markupsprachen wie Restructured Text
werden ebenfalls unterstützt. Es gibt sogar die Möglichkeit, GeoJSON-Dateien (Listen von
GPS-Standorten) auf einer OpenStreetMap-Karte darzustellen.
Eine Besonderheit der Gitea-Weboberfläche stellt die Web-IDE dar. GitLab verfügt über
eine modifizierte Version von Visual Studio Code, mit der man direkt im Browser an
seinen Projekten arbeiten kann.
![GitLab-Web-IDE](./assets/gitlab/web_ide.png)
## Import bestehender Projekte
GitLab erlaubt den Projektimport von GitHub, Bitbucket, FogBugz, Gitea sowie von anderen
GitLab-Instanzen.
Die Importfunktion ist standardmäßig deaktiviert und muss erst in der _Admin Area_
aktiviert werden (_Settings_ \> _General_ \> _Visibility and access controls_ \> _Import
sources_).
Für den Import von GitHub-Projekten muss man sich mit einem Access Token anmelden und
bekommt anschließend eine Übersicht aller Repositories angezeigt. Hier kann man
auswählen, welche Repositories übertragen werden sollten. Der Import umfasst auch
Issues, Pull Requests und Releases.
![GitLab-Import](./assets/gitlab/import.png)
Als einzige Plattform im Test bietet GitLab die Möglichkeit, ein Repository mit
sämtlichen gespeicherten Daten als zip-Datei zu exportieren. Dies erlaubt nicht nur den
Import auf anderen Instanzen sondern bietet dem Nutzer auch eine Backup-Option.
## Zusatzfeatures
GitLab hat von allen getesteten Plattformen die meisten Features. Einige Features sind
jedoch der proprietären Premium/Ultimate Edition vorbehalten, die ich nicht getestet
habe.
Die Projektmanagement-Features von GitLab sind die besten im Test. GitLab erlaubt das
Erstellen von Issues mit Labels, Verantwortlichen, Fälligkeitsterminen und geleisteter
Arbeitszeit. Zudem können Issues zu Meilensteinen hinzugefügt werden.
Issue Boards erlauben einen schnellen Überblick über den alle gerade bearbeiteten
Issues. Es lassen sich Spalten erstellen, die Issues mit einem bestimmten Tag auflisten.
Erstellt man also z.B. zwei Tags: "Implementierung" und "Review" und legt in seinem
Board zwei Spalten hierfür an, erhält man eine Übersicht über den Fortschritt aller
Issues. Issues lassen sich zwischen Spalten verschieben, wodurch sich auch die Tags des
Issues ändern.
![GitLab Kanban](./assets/gitlab/kanban.png)
Ein interessantes Feature ist die Möglichkeit, zu einem Issue mehrere Tasks
hinzuzufügen. Tasks sind Sub-Issues, die ihre eigene Beschreibung und Diskussion haben,
aber unter einem Issue zusammengefasst sind. Auf diese Weise lassen sich große Features
in kleinere Arbeitsschritte aufteilen, die von verschiedenen Teammitgliedern erledigt
werden können.
![GitLab Issue mit Task](./assets/gitlab/issue.png)
Viele fortgeschrittene Projektmanagement-Features sind allerdings der Enterprise Edition
vorbehalten. Hierzu gehört z.B. das Anlegen von Boards mit Filtern (z.B. für einen
bestimmten Meilenstein) oder Aufwandsschätzungen.
Um Projekte zu dokumentieren bietet GitLab ein auf Git und Markdown basierendes Wiki.
Zudem gibt es mit "Snippets" einen Pastebin, der ebenfalls Git zur Speicherung der
Codeschnipsel verwendet.
Es gibt auch die Möglichkeit, mit GitLab statische Webseiten zu hosten. Die Seiten
können mit GitLab CI gebaut und unter einer persönlichen Subdomain veröffentlicht
werden.
GitLab bietet auch eine Paketregistry für Bibliotheken verschiedener Programmiersprachen
(z.B. Maven, npm, Python) an. Die Unterstützung für einige Programmiersprachen wie Ruby
ist allerdings noch experimentell. \*.deb-Pakete sowie Docker-Images können ebenfalls
mit GitLab gehostet werden.
Zur einfachen Bedienung mit der Kommandozeile bietet GitLab das Tool `glab` an. Damit
lassen sich beispielsweise Issues und Pull Requests erstellen und bearbeiten, Snippets
hochladen und CI-Build starten. Es gibt auch ein offizielles VS-Code-Plugin, das
Pull-Requests, Issues und CI-Builds in den Texteditor integriert.
## Continous Integration
Gitlab verfügt über ein eingebautes CI-System, um Software automatisiert zu testen und
zu veröffentlichen. Das System kann Builds in Docker-Containern, auf einem
Kubernetes-Cluster, in einer VirtualBox-Maschine oder ohne Virtualisierung ausführen.
Hierfür verwendet Gitlab ein verteiltes System aus Runnern. Die Runner kommunizieren
über das Internet mit der Gitlab-Instanz und können so neue Buildaufträge
entgegennehmen.
Um einen Runner einzurichten, muss man zuerst die erforderliche Konfigurationsdatei
erstellen. Hierfür startet man den Runner mit dem Befehl `register`:
```
docker run --rm -it -v $(pwd)/runner-config:/etc/gitlab-runner gitlab/gitlab-runner register
```
Daraufhin fragt der Runner nach der URL der Gitlab-Instanz und einem
Registrierungstoken. Den Token kann man sich entweder in den Repository-Einstellungen
oder in der Admin-Oberfläche generieren lassen (je nachdem, ob man den Runner nur zu
einem Projekt oder der gesamten Instanz hinzufügen möchte). Anschließend muss man
festlegen, wie der Runner die Builds ausführen sollte. In meinem Test habe ich den
`docker`-Executor gewählt.
Wenn die Konfiguration abgeschlossen ist, kann man den Runner mit diesem Befehl starten
```
docker run --rm -it -v $(pwd)/runner-config:/etc/gitlab-runner gitlab/gitlab-runner
```
![Runner](./assets/gitlab/runners.png)
Anschließend kann man für sein Repository einen Build definieren. Hierfür muss man eine
Datei mit dem Namen `.gitlab-ci.yml` im Wurzelverzeichnes des Repositories erstellen, in
der die einzelnen Schritte des Builds beschrieben werden. GitLab stellt ein Repository
mit Beispielen für verschiedene Programmiersprachen und Frameworks zur Verfügung, um den
Einstieg zu erleichtern.
```yml
image: "rust:latest"
test:cargo:
script:
- rustc --version && cargo --version # Print version info for debugging
- rustup component add rustfmt clippy
- cargo fmt --all --check
- cargo clippy --all --features=rss -- -D warnings
- cargo test --features=rss --workspace
```
## Öffentliche Instanzen
Gitlab betreibt selbst eine öffentliche Instanz der proprietären Ultimate-Version unter
[gitlab.com](https://gitlab.com/explore/).
Daneben gibt es eine Vielzahl von communitybetriebenen GitLab-Instanzen, die die freie
Community Edition verwenden. Viele große Open-Source-Projekte und Organisationen hosten
eine eigene GitLab-Instanz, wie zum Beispiel [Debian](https://salsa.debian.org),
[Framasoft](https://framagit.org/public/projects/) oder [KDE](https://invent.kde.org).
## Fazit
GitLab ist zu Recht seit mehr als zehn Jahren die führende quelloffene
GitHub-Alternative. Mittlerweile bietet GitLab mehr Features als die Konkurrenz von
Microsoft.
Trotz seiner komplexen Architektur lässt sich GitLab relativ einfach und schnell
installieren, da das Omnibus-Paket die einzelnen Dienste automatisch konfiguriert.
Insbesondere Unternehmen und große Organisationen werden die professionellen Features
und den kommerziellen Support zu schätzen wissen.
Darüber hinaus bietet Gitlab selbst in der Open-Source-Version die besten
Projektmanagement-Features im Test. Wer also keine separate Projektmanagement-Anwendung
einsetzen möchte, ist mit Gitlab ebenfalls gut beraten.
Wer seine Plattform allerdings auf einem kleinen Single Board Computer oder V-Server
betreiben möchte, sollte sich dagegen nach einer leichtgewichtigeren Alternative
umsehen.
## Quellen
- Dokumentation <https://docs.gitlab.com/>
- Repository <https://gitlab.com/gitlab-org/gitlab-foss/>
- Architekturübersicht
<https://docs.gitlab.com/ee/development/architecture.html#gitlab-architecture-overview>
- Liste von öffentlichen GitLab-Instanzen
<https://wiki.p2pfoundation.net/List_of_Community-Hosted_GitLab_Instances>

View file

@ -0,0 +1,327 @@
# Gitea
Das Gitea-Projekt begann 2016 als Fork der Git-Hosting-Plattform Gogs. Lunny Xiao, einer
der Beitragenden von Gogs, war damit unzufrieden, dass der Gründer des Projekts, Joe
Chen, das Projekt alleine betreuen und keine weiteren Maintainer ernennen wollte.
2022 gründete Lunny Xiao die Firma Gitea Limited. Die Firma bietet Unternehmen Hosting-
und Supportdienstleistungen für Gitea an. Da einige Mitglieder der Community einem
kommerziell geleiteten Open-Source-Projekt misstrauen, entstand ein neuer Fork names
Forgejo. Forgejo steht unter der Leitung von Codeberg, einem Berliner Verein, der seit
2018 eine öffentliche Gitea-Instanz betreibt. Abgesehen von Design- und Namensänderungen
unterscheidet sich Forgejo von Gitea momentan kaum.
Gitea ist in Go geschrieben und besteht aus einer einzigen ausführbaren Datei.
Standardmäßig verwendet Gitea eine interne SQLite-Datenbank, alternativ werden auch
externe Datenbanken (MySQL, MariaDB, Postgres, MS SQL) unterstützt.
Die Weboberfläche wied serverseitig mit Templates gerendert. Einige Websitekomponenten
wie z.B. Drop-Down-Menüs erfordern JavaScript.
Getestet wurde die Version 1.20.0-rc2.
## Installation
Gitea stellt kompilierte Binaries für alle gängigen Betriebssysteme unter
<https://dl.gitea.com/gitea/> zur Verfügung. Von dort aus lässt sich die Anwendung
einfach herunterladen und starten.
Alternativ gibt es auch [offizielle](https://pkgs.org/download/gitea) und
[inoffizielle](https://gitea.com/gitea/awesome-gitea/src/branch/main/README.md#user-content-packages)
Pakete für die meisten Linux-Distributionen.
Darüber hinaus stellt Gitea auch ein Docker-Image (`gitea/gitea`) zur Verfügung.
Die Einrichtung ist extrem simpel. Beim ersten Start wird diese Konfigurationsseite
angezeigt, auf der man die grundlegenden Einstellungen (z.B. Datenbank-URL,
Admin-Passwort) vornehmen kann. Nach der Bestätigung ist Gitea in wenigen Sekunden
bereit zur Verwendung.
![Gitea-Konfiguration](./assets/gitea/setup.png)
Dieser Konfigurationsassistent wird jedoch nur beim ersten Start angezeigt. Alle
weiteren Konfigurationsänderungen müssen durch die
`app.ini`-[Konfigurationsdatei](https://docs.gitea.com/1.20/administration/config-cheat-sheet)
erfolgen. Gitea verfügt zwar über eine Admin-Oberfläche, diese dient allerdings
hauptsächlich der Nutzerverwaltung und erlaubt keine Konfigurationsänderungen.
## Systemanforderungen
Gitea ist auf jedem Betriebssystem und jeder CPU-Architektur lauffähig, die von der
Programmiersprache Go unterstützt wird. Binaries für MacOS (amd64/aarch64), FreeBSD
(amd64), Windows (i386/amd64) und Linux (i386/amd64/arm5/arm6/aarch64) werden offiziell
zum Download angeboten. Das offizielle Docker-Image ist für die amd64- und
aarch64-Architektur verfügbar.
Im Leerlauf benötigt der Server ca. 150MB Arbeitsspeicher und verursacht unter 0.1%
CPU-Auslastung. Damit ist Gitea die mit Abstand leichtgewichtigste Plattform in Test und
eignet sich perfekt für den Einsatz auf schwächerer Hardware.
## Bedienung
Die Weboberfläche von Gitea wird serverseitig mit Hilfe von Templates gerendert
(klassische Multi-Page-Anwendung). Dies hat den Vorteil, dass die Seite auch ohne
JavaScript dargestellt werden kann (wenn auch mit eingeschränkter Bedienbarkeit).
Obwohl bei jedem Navigationsschritt durch ein Repository die gesamte Seite neu geladen
wird, läuft die Navigation durch Ordner sehr flüssig.
Optisch und funktional ist die Benutzerschnittstelle stark an GitHub angelehnt. Wer also
vorher GitHub verwendet hat, findet sich auf Gitea schnell zurecht
Der Code in Gitea-Repositories kann durchsucht werden, allerdings ist diese Funktion
standardmäßig deaktiviert. Um sie zu aktivieren, müssen diese Zeilen zur
Konfigurationsdatei hinzugefügt werden:
```
[indexer]
REPO_INDEXER_ENABLED=true
```
Standardmäßig verwendet Gitea die Bibliothek [Bleve](https://blevesearch.com/) für die
Suche, es kann jedoch auch eine externe Elasticsearch-Instanz verwendet werden.
![Gitea-Suche](./assets/gitea/search.png)
Gitea kann standardmäßig Bilder, CSV-Dateien, PDFs und Markdown-Dateien auf der
Weboberfläche darstellen. Andere Markupsprachen wie ReStructured Text werden
standardmäßig nicht unterstützt. Allerdings bietet Gitea als einzige getestete Plattform
die Möglichkeit, zusätzliche Renderer in der Konfigurationsdatei zu definieren.
Beispielsweise kann Gitea Pandoc verwenden, um RST, LaTEX oder Word-Dokumente in HTML zu
konvertieren und anzuzigen. Es ist auch möglich, mit etwas Bastelei einen Viewer für STL
oder Excel-Dateien zu installieren.
## Import bestehender Projekte
Gitea bietet die Möglichkeit, Projekte von GitHub, Gitlab, Gogs, OneDev, GitBucket und
Codebase zu importieren. Neben den Repositories können auch Issues, Pull-Requests und
Releases importiert werden.
Der Versuch, zwei meiner GitHub-Projekte mit Issues und Pull-Requests zu übertragen,
scheiterte jedoch mit einer Fehlermeldung.
## Zusatzfeatures
Gitea bietet grundlegende Features zum Projektmanagement. Issues können erstellt, mit
Labels versehen und bestimmten Entwicklern zugewiesen werden. Es können
Fälligkeitstermine für Issues festgelegt und die Arbeitszeit hinterlegt werden.
Dazu kommt die Möglichkeit, Issues zu Meilensteinen hinzuzufügen und somit
beispielsweise den Arbeitsfortschritt für eine neue Version zu verfolgen.
Darüber hinaus können in Gitea Kanbanboards erstellt werden. Allerdings sind diese
Boards nicht in das restliche Issue-System integriert und deswegen umständlich zu
nutzen. Issues müssen beispielsweise manuell den Boards hinzugefügt werden. Während
GitLab Labels verwendet, um die Issues den Spalten zuzuordnen ist in Gitea außerhalb des
Boards nicht ersichtlich, welchen Status ein Issue hat. Ein Issue, das in die
Done-Spalte verschoben wird, wird nicht automatisch geschlossen. Umgekehrt führt das
Schließen eines Issues nicht zu einer Platzierung in der Done-Spalte.
Dokumentation für Gitea-Repositories kann in einem simplen, auf Markdown basierenden
Wiki veröffentlicht werden.
Das Hosting statischer Webseiten unterstützt Gitea nicht, weswegen das Team von Codeberg
hierfür eine [eigene Lösung](https://codeberg.org/Codeberg/pages-server) entwickelt hat.
Gitea bietet eine integrierte Registry für Pakete aller gängigen Programiersprachen
(z.B. Python, npm, Rust). Wer eine Softwarebibliothek entwickelt, kann diese auf seiner
Gitea-Instanz veröffentlichen, sodass andere Entwickler sie nutzen können. Zudem
unterstützt die Gitea-Registry Linux-Pakete (.deb und .rpm) sowie Docker-Images.
Gitea unterstützt als einzige getestete Plattform agit. Dies ist ein alternativer
Git-Workflow, der von Alibaba entwickelt wurde. Agit erlaubt es Entwicklern, Pull
Requests zu erstellen ohne zuvor einen Fork des Projekts anzulegen. Hierbei wird die
Änderung mit diesem Befehl in einen versteckten Branch des Reposiories gepusht, worauf
Gitea automatisch eine PR erstellt.
Dieser Befehl erfordert im Gegensatz zum normalen push keine Schreibrechte im
entsprechenden Repository.
```
git push origin HEAD:refs/for/main -o topic="feat/user-search" -o title="Add user search"
```
Es existiert auch ein Git-Plugin für agit namens
[`git-repo`](https://git-repo.info/en/2020/03/agit-flow-and-git-repo/), damit man nicht
jedes Mal diesen langen Befehl eintippen muss, sondern den Beschreibungstext direkt in
die Kommandozeile tippen kann.
Gitea lässt sich auch mit dem Tool [`tea`](https://gitea.com/gitea/tea) auf der
Kommandozeile bedienen. Auf diese Weise lassen sich Issues erstellen und lesen oder Pull
Requests erstellen und abrufen.
Gitea bietet dem Administrator vollen Zugriff auf seinen Webserver und das
Templatesystem. Dadurch kann man Templates und Stylesheets durch eigens angepasste
Versionen ersetzen und die Weboberfläche nach seinen Bedürfnissen anpassen. Dies ist
insbesondere für große Organisationen und Firmen interessant, die ihre
Git-Hosting-Plattform nach ihrem Corporate Design gestalten möchten.
Ein Beispiel für eine stark angepasste Gitea-Oberfläche ist die Instanz des
[Blender-Projekts](https://projects.blender.org/), die sich nahtlos in die restliche
Projektseite einfügt.
## Continous Integration
### Woodpecker
Gitea verfügte lange nicht über einen eingebauten CI-Server. Allerdings gibt es eine
Schnittstelle, um externe CI-Systeme anzubinden.
Ich habe einige CI-Systeme getestet, die mit Gitea kompatibel sind.
[Woodpecker](https://woodpecker-ci.org/) ist meiner Meinung nach eines der besten
Systeme. Bei Woodpecker handelt es sich um einen Fork des Drone CI-Projekts nach deren
Wechsel von der Apache License zu einer nichtkommerziellen Lizent.
Woodpecker erlaubt den Login mit seinem Gitea-Account und zeigt dem Entwickler auf der
Startseite eine Liste aller Repositories an. Von dort aus lässt sich die CI für
bestimmte Repositories aktivieren. Daraufhin konfiguriert Woodpecker die Webhooks des
Repositories, sodass die Builds automatisch bei Aktualisierungen gestartet werden.
Woodpecker verwendet sogenannte Agents, die mittels GRPC mit dem zentralen Server
kommunizieren und Buildaufträge empfangen. Die Agents verwenden Docker, um die Builds in
Containern auszuführen.
![Woodpecker CI](./assets/gitea/woodpecker.png)
Die Builds werden in einer yml-Datei mit dem Namen `.woodpecker.yml` im
Wurzelverzeichnes des Repositories definiert. Jeder Buildschritt wird in einem eigenen
Docker-Container ausgeführt.
```yaml
pipeline:
test:
image: rust:latest
commands:
- rustup component add rustfmt clippy
- cargo fmt --all --check
- cargo clippy --all --features=rss -- -D warnings
- cargo test --features=rss --workspace
```
Die Installation von Woodpecker ist etwas komplizierter, da Woodpecker sowohl einen
HTTP-Server als auch einen GRPC-Server bereitstellt. Möchte man Agents auf anderen
Servern betreiben, sollte auch der GRPC-Server mit TLS gesichert sein. Hierfür kann man
einen Reverse Proxy (z.B Traefik) verwenden. Allerdings beinhaltet die offizielle
Dokumentation keine Anleitung hierfür.
[Hier](./assets/woodpecker/docker-compose.yml) ist die Docker-Compose-Datei, die ich für
meine Setup (mit Traefik) verwendet habe. Vor der Verwendung müssen noch die folgenden
Konfigurationsvariablen bearbeitet werden:
- `WOODPECKER_HOST` URL der Woodpecker-Instanz
- `WOODPECKER_GITEA_URL` URL der Gitea-Instanz
- `WOODPECKER_GITEA_CLIENT` / `WOODPECKER_GITEA_SECRET` OAuth-Zugangsdaten (in Gitea das
Einstellungsmenü aufrufen und unter _Create a new OAuth2 Application_ einen neuen
Client erstellen. Redirect URI: `<WOODPECKER_URL>/authorize`)
- `WOODPECKER_AGENT_SECRET` ist das Passwort für alle mit der Instanz verbundenen
Agents. Hierfür sollte man sich einfach einen langen Zufallsstring erzeugen,
beispielsweise mit `openssl rand -hex 32`.
### Gitea Actions
Mit dem vorletzten Release 1.19 bekam Gitea jedoch ein eigenes CI-System: Gitea Actions.
Hierbei wurde nicht nur der Name an die Konkurrenz von Microsoft angelehnt. Das System
basiert auf [act](https://github.com/nektos/act), einer freien Implementation von GitHub
Actions. Ursprünglich wurde act zum lokalen Testen von GitHub Actions entwickelt. Gitea
hat die Anwendung stattdessen als Basis für ihr CI-System verwendet.
Standardmäßig sind Gitea Actions in den Einstellungen deaktiviert. Um sie verwenden zu
können, muss man diese Zeilen zur Konfigurationsdatei hinzufügen:
```
[actions]
ENABLED=true
```
Anschließend muss man wie bei Gitlab und Woodpecker einen Runner einrichten, der die
Builds mittels Docker ausführt. Der Runner kann als Binary von der
[Gitea-Download-Seite](https://dl.gitea.com/act_runner/) heruntergeladen werden. Es ist
auch möglich, den Runner in einem Docker-Container zu betreiben.
Nachdem man den Runner heruntergeladen hat, muss man ihn konfigurieren. Dafür führt man
den Befehl `act-runner register` auf. Anschließend muss man die Adresse der Instanz und
einen Registrierungstoken, den man in der Admin-Oberfläche unter _Actions / Runners_
erzeugen kann.
Anschließend muss man noch die Actions im gewünschten Repository aktivieren, in dem man
in den Einstellungen den Haken bei _Enable Repository Actions_ setzt.
Die Builds werden als yaml-Dateien im Verzeichnis `.gitea/workflows` definiert. Obwohl
Gitea die gleiche Syntax wie Github Actions verwendet, sind die Workflows nicht 1:1
kompatibel. Beispielsweise lädt Gitea vordefinierte Actions wie `actions/checkout` nicht
von [github.com/actions](https://github.com/actions) sondern von
[gitea.com/actions](https://gitea.com/actions) herunter, sodass einige Actions nicht
verfügbar sind.
Außerdem führt GitHub seine Builds in einer virtuellen Maschine mit einer Vielzahl an
vorinstallierten Programmiersprachen und Entwicklertools aus. Da das Image dieser
Maschine sehr groß ist, benutzt Gitea stattdessen standardmäßig den
Debian+NodeJS-Container `node:16-bullseye`. Das Image enthält neben Node.js auch Python,
gcc, make und curl. Wer andere Programmiersprachen benutzt, muss jedoch Anwendungen
nachinstallieren (wie beispielsweise Rust im unteren Beispiel). Es ist jedoch möglich,
andere Docker-Images zu verwenden.
```yaml
name: Test
on: [push]
jobs:
Test:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Setup Rust
run: |
curl https://sh.rustup.rs -sSf | sh -s -- -y
source "$HOME/.cargo/env"
- name: Test
run: |
cargo clippy
cargo test
```
![Gitea Actions](./assets/gitea/actions.png)
Ein wichtiges Feature, das Gitea Actions momentan noch fehlt ist die Möglichkeit,
Workflows manuell zu starten. Da Gitea Actions noch relativ neu ist, gehe ich jedoch
davon aus, dass dieses Feature in Zukunft implementiert wird.
## Öffentliche Instanzen
Die von den Maintainern des Projekts betriebene Instanz unter
[gitea.com](https://gitea.com/explore/repos) verfügt über 5600 Repositories.
Eine noch größere Instanz betreibt der Berliner Verein Codeberg e.V. Auf
[codeberg.org](https://codeberg.org) werden 30900 öffentliche Repositories gehostet.
Zusätzlich zu ihrer Gitea-Instanz bietet Codeberg auch einen Webhosting-Dienst unter
[\*.codeberg.page](codeberg.page) an. Codeberg betreibt auch einen Woodpecker-CI-Server,
für dessen Verwendung die Nutzer allerdings manuell freigeschaltet werden müssen.
Da Gitea sehr einfach und günstig zu hosten ist, wird es von einigen Open
Source-Projekten auch als sekundäre Plattform zusätzlich zu GitHub verwendet.
Beispielsweise betreibt das Team hinter dem alternativen YouTube-Frontend Invidious eine
[Gitea-Instanz](https://gitea.invidious.io/iv-org), um vor eventuellen Takedowns des
Repositories auf GitHub sicher zu sein
## Fazit
Während GitLab meiner Meinung nach die beste Lösung für große Organisationen und
Unternehmen darstellt, ist Gitea das perfekte System für einzelne Entwickler, kleine
Teams und Hobbybastler. Durch seinen sparsamen Ressourcenverbrauch ist Gitea auf fast
jeder Hardware lauffähig und die Einrichtung funktioniert einfach und schnell.
Darüber hinaus lässt sich Gitea mit eigenen Themes und Templates individuell anpassen
und zu seiner persönlichen Website machen.
Die Projektmanagement-Features von Gitea sind allerdings eher rudimentär. Wer
Kanbanboards benötigt, sollte Gitlab oder OneDev in Betracht ziehen oder hierfür eine
externe Software verwenden.
## Quellen
- Projektseite <https://gitea.com>
- Repository <https://github.com/go-gitea/gitea/>
- Start von Codeberg (damals TeaHub)
<https://www.heise.de/news/Neue-Entwickler-Plattform-TeaHub-will-Github-beerben-4078811.html>,
<https://blog.codeberg.org/codebergorg-launched.html>

View file

@ -0,0 +1,292 @@
# Sourcehut
Eine Git-Hosting-Plattform ohne Pull-Requests, einer spartanischen Weboberfläche und
einem mächtigen Buildsystem - so lässt sich Sourcehut am besten zusammenfassen.
![SourceHut homepage](./assets/sourcehut/homepage.png)
SourceHut begann im
[Oktober 2016](https://git.sr.ht/~sircmpwn/meta.sr.ht/commit/40dcb38349af3f67845857c4ac9003911a653624)
als Hobbyprojekt von Drew DeVault. Drew wollte eine alternative zu den etablierten
Git-Hosting-Diensten entwickeln, die den klassischen E-Mail-basierten Git-Workflow
unterstützt anstatt das Funktionsprinzip von GitHub zu kopieren.
[2018](https://drewdevault.com/2018/11/15/sr.ht-general-availability.html) war die
Alpha-Version der Software öffentlich unter <https://sr.ht> verfügbar.
Die Plattform besteht aus einzelnen Komponenten für die verschiedenen Features:
- meta.sr.ht (Login und Benutzerverwaltung)
- hub.sr.ht (Projektverwaltung)
- git.sr.ht / hg.sr.ht (Git/Mercurial Hosting)
- todo.sr.ht (Issues)
- lists.sr.ht (Mailinglisten)
- man.sr.ht (Wiki)
- paste.sr.ht (Pastebin)
- builds.sr.ht (Continuous Integration)
- pages.sr.ht (Statisches Webhosting)
Jede dieser Komponentent besteht wiederum aus 2-3 Diensten: dem in Python/Flask
implementierten Webfrontend, einem in Go geschriebenen API-Server und eventuell noch
zusätzliche Dienste wie eine Task Queue.
Jede Komponente legt ihre Daten in einer eigenen PostgreSQL-Datenbank ab. Zusätzlich
wird noch eine gemeinsame Redis-Instanz als Cache und Event Queue verwendet.
Hier ist eine Übersicht über die einzelnen Dienste:
![SourceHut architecture](./assets/sourcehut/sourcehut_arch.svg)
## Installation
Da Sourcehut aus mehreren Services für die einzelnen Features besteht, ist die
Einrichtung mit deutlich mehr Aufwand verbunden. Die Anleitung zur Installation findet
sich auf der [Dokumentationsseite](https://man.sr.ht/installation.md) des Projekts.
Allerdings ist diese Anleitung nicht vollständig und ich musste an einigen Stellen im
Quellcode der Software nachschlagen, wie bestimmte Features zu konfigurieren sind.
Erschwerend kommt hinzu, dass Sourcehut an vielen Stellen keine aussagekräftigen
Fehlermeldungen liefert. Beispielsweise hatte ich das Problem, dass builds.sr.ht keine
VMs starten konnte, da diese standardmäßig mit 4GB RAM konfiguriert sind - zu viel für
meine Test-VM. Der einzige Fehler, der in diesem Fall auf der Webseite angezeigt wird,
ist der, dass das Build-System innerhalb einer bestimmten Zeit keine Verbindung zur VM
aufbauen konnte. Der OOM-Fehler beim Start wurde weder geloggt noch an den Nutzer
weitergegeben.
Auf der Dokumentationsseite wird erwähnt, dass sich das Projekt noch im Alpha-Stadium
befindet, es ist also zu hoffen, dass die Dokumentation in Zukunft verbessert wird.
Ich habe sämtliche Schritte, die zur Installation meiner Testinstanz erforderlich waren,
im [Anhang](sourcehut_setup.md) aufgelistet.
## Systemanforderungen
Sourcehut ist auf jedem System lauffähig, das Python 3.10 und Go unterstützt. Allerdings
sind die Pakete momentan nur für die amd64-Architektur verfügbar. Wer Sourcehut also auf
einem Raspberry Pi oder ARM-Server installieren will, muss die Pakete selbst
kompilieren.
Die CPU-Auslastung im Leerlauf ist gering (ca. 1%). Bei aufwändigen Git-Operationen
sieht die Sache jedoch anders aus. Wenn man sich z.B. die Änderungshistorie der Makefile
des Linux-Kernels anzeigen lässt, läuft git.sr.ht 30 Sekunden lang mit 100%
CPU-Auslastung, bis Nginx die Anfrage wegen Zeitüberschreitung abbricht. Dieses Problem
lässt sich auch auf der offiziellen Instanz reproduzieren
([Link zum Testen](https://git.sr.ht/~gregkh/linux-stable/log/master/item/Makefile)).
Zum Vergleich: Die Ausführung des Befehls `git --no-pager log Makefile | head -n 1000`
benötigte auf meinem Testsystem nur 100ms.
Beim Arbeitsspeicherverbrauch macht sich die Microservice-Architektur negativ bemerkbar:
jeder Python-Dienst reserviert 90-100MB, die in Go geschriebenen API-Server kommen mit
20-30MB RAM aus. Da die gesamte Sourcehut-Installation aus 14 Python- und 8 Go-Services
besteht, summiert sich der Arbeitsspeicherbedarf auf ca. 1,5GB.
## Bedienung
Sourcehut's Weboberfläche ist spartanisch designt und kommt fast ohne JavaScript aus.
Dadurch ist die Webseite ohne Probleme in alten Geräten und Browsern benutzbar.
Die Repository-Ansicht ist klar an GitWeb angelehnt und zeigt die Dateien ähnlich wie
der `ls -l`-Befehl zusammen mit Größe und Berechtigungen an.
Genau wie GitWeb (und ls) platziert Sourcehut Ordner nicht vor Dateien, was das
Auffinden bestimmter Ordner unter vielen Dateien erschwert.
Eine Suchfunktion gibt es nicht, dadurch ist es schwierig, auf der Webseite durch große
Projekte zu navigieren.
Hinzu kommt, dass die Webseite nur Code und Markdown-Dokumente darstellen kann. Bilder,
PDF-Dokumente oder andere Markupsprachen wie RST werden nicht unterstützt.
![Repository](./assets/sourcehut/repo.png)
Die einzelnen Komponenten von Sourcehut sind eigenständige Webanwendungen. Dies hat den
Vorteil, dass man nur einen Teil von Sourcehut installieren kann, wenn man
beispielsweise den Build-Service oder die Mailinglisten nicht benötigt. Allerdings macht
diese Aufteilung die Bedienung an vielen Stellen hakelig. Es gibt zwar eine zentrale
Projektverwaltung (hub.sr.ht), die Repositories, Issue-Tracker und Mailinglisten zu
bestimmten Projekten zuordnet. Allerdings ist diese Verlinkung eine Einbahnstraße: von
der Projekseite auf dem Hub kann man alle zugehörigen Repositories, Issue-Tracker und
Mailinglisten aufrufen, befindet man sich aber bspw. in einem Repository, kann man das
zugehörige Projekt nicht ohne weiteres ermitteln.
![SourceHut Hub](./assets/sourcehut/hub.png) Projektansicht im SourceHut Hub
Sourcehut unterscheidet sich von GitHub und anderen Code-Hosting-Plattformen vor allem
dadurch, dass es zur Kollaboration zwischen Entwicklern keine Pull-Requests verwendet.
Stattdessen basiert das System auf den "klassischen" Git-Workflow, also dem Austausch
von Patches via E-Mail. Projekteigentümer können Mailinglisten einrichten und darüber
Patches empfangen.
Dies hat den Vorteil, dass außenstehende Entwickler sich nicht auf der Plattform
registrieren müssen und ausschließlich via E-Mail mit den Maintainern des Projekts
kommunizieren können.
Sourcehut bietet Entwicklern auch die Möglichkeit, über die Weboberfläche Patches zu
erstellen und zu versenden. Dazu muss man das Repository zuerst auf der Plattform
klonen, die eigenen Commits hochladen und diese anschießend in der Weboberfläche
auswählen.
![Send patchset](./assets/sourcehut/send_patchset.png)
Auch wenn dieser Workflow sicherlich Vorteile mit sich bringt, muss man feststellen,
dass dies für die meisten Entwickler ungewohnt und umständlich ist. Entwickler, die
bisher nur mit GitHub und ähnlichen Plattformen gearbeitet haben, werden beim Versuch,
zu einem Projekt beizutragen, eventuell auf Hindernisse stoßen.
Es gibt auch ein CLI-Tool namens [hut](https://git.sr.ht/~emersion/hut), um die
verschiedenen Sourcehut-Dienste mit der Kommandozeile zu bedienen. Das Tool erlaubt das
Erstellen von Issues, Hochladen von Releases, Starten von Builds, Veröffentlichen von
Webseiten, Hinzufügen von SSH-Keys und einiges mehr.
## Import bestehender Projekte
Die Sourcehut-Weboberfläche erlaubt auf lediglich den Import von öffentlichen
Git-Repositories per clone. Es gibt keine Möglichkeit zum Import von Issues und
Pull-Requests werden wie oben erwähnt nicht unterstützt.
## Zusatzfeatures
Wie bereits beschrieben besteht Sourcehut aus einer Vielzahl von Diensten, den
Entwicklern neben Git-Hosting und Issue Tracking diverse Zusatzfeatures bieten.
man.sr.ht ist ein auf Git basierendes Wiki, das in Markdown geschriebene
Dokumentationstexte darstellen kann. Allerdings bietet es kaum Features: der einzige
Unterschied zum Betrachten von Markdown-Dateien in git.sr.ht ist das
Seiteninhaltsverzeichnis, das man.sr.ht oben anfügt. Es gibt kein Inhaltsverzeichnis
über die gesamte Dokumentation, genauso wenig wie eine Suchfunktion.
paste.sr.ht ist ein Pastebin zum Speichern und Veröffentlichen von kleineren Texten,
Skripten und Codeausschnitten. Man kann Pastes öffentlich oder privat speichern und es
gibt auch die Möglichkeit, Textdateien mit dem `hut`-CLI-Tool hochzuladen.
pages.sr.ht ist ein Webhosting-Dienst, der es einem erlaubt, statische Webseiten unter
einer persönlichen Subdomain zu veröffentlichen. Hierfür muss man sämtliche Dateien als
`tar.gz`-Archiv komprimieren und anschließend mit dem `hut`-Tool hochladen.
Das Issue-System von Sourcehut (todo.sr.ht) ist jedoch sehr rudimentär. Es gibt außer
Labels und der Möglichkeit, verantwortliche Personen zuzuweisen keine Zusatzfunktionen,
die das Projektmanagement erleichtern. Für größere Projekte ist daher die Verwendung
einer zusätzlichen Projektmanagement-Software wie Redmine nötig.
## Continous Integration
builds.sr.ht ist ein sehr leistungsfähiges und einfach zu verwendender CI-System.
Builds können über die Weboberfläche, eine API oder durch Git-Pushes und auf der
Mailigliste eingegangene Patches initiiert werden. Zum Ausführen der Builds werden
virtuelle Maschinen (mit QEMU/KVM) gestartet, wodurch die Build-Umgebung vom Server
isoliert ist.
QEMU erlaubt es auch, andere CPU-Architekturen zu emulieren und so beispielsweise
Embedded Linux-Anwendungen zu testen.
![Erfolgreicher Build](./assets/sourcehut/successful_build.png)
Sourcehut Builds werden durch
[yaml-Manifests](https://man.sr.ht/builds.sr.ht/manifest.md) beschrieben. Die Syntax ist
sehr simpel gehalten. Manifests bestehen aus dem Namen des VM-Images, den benötigten
Paketen und Repositories und einem oder mehreren Shell-Skripten.
```yaml
image: alpine/latest
packages:
- cargo
sources:
- https://code.thetadev.de/ThetaDev/short-uuid.git
tasks:
- test: |
cd short-uuid
cargo test
```
Es gibt auch die Möglichkeit, für den Build benötige Secrets wie API-Keys und
SSH-Schlüssel zu hinterlegen. Die Secrets werden auf der Build-VM in Dateien abgelegt,
von wo aus sie in Buildskripten verwendet werden können (z.B.
`cargo publish --token "$(<~/.cargo-token)"`). Zudem gibt es die Möglichkeit, SSH- und
GPG-Schlüssel automatisch zu importieren.
Ein besonderes Feature von builds.sr.ht ist die Möglichkeit, fehlgeschlagene Builds zu
analysieren. Schlägt ein Build fehl, läuft die entsprechende VM noch 10 Minuten weiter.
In dieser Zeit kann man sich per SSH mit dem Build-Server verbinden und kann Befehle in
der entsprechenden Build-VM ausführen. Auf diese Weise kann man Logdateien inspizieren
oder den Build mit Konfigurationsänderungen neu starten, ohne jedes Mal das
Buildmanifest zu ändern und neu zu übermitteln.
![Fehlgeschlagener Build](./assets/sourcehut/failed_build.png)
Allerdings bietet Sourcehut Builds nicht die Möglichkeit, zu spezifizieren, wann ein
Build ausgeführt werden soll. Builds werden immer dann gestartet, wenn ein Branch in
einem Repository aktualisiert wird, in dem sich eine `.builds.yml`-Datei befindet.
Eingehende Patches in der Mailingliste können ebenfalls einen Build startet.
Es gibt jedoch keine Möglichkeit, Builds nur dann zu starten, wenn ein bestimmter Branch
oder bestimmte Dateien aktualisiert wurden. Dies kann beispielsweise in Monorepos
(Repositories mit mehreren Projekten) zu unnötig lange dauernden Builds führen.
## Öffentliche Instanzen
Die öffentliche Sourcehut-Instanz, die von Drew DeVault und seiner Firma betrieben wird,
befindet sich unter <https://sr.ht>.
sr.ht ist der einige mir bekannte Git-Hosting-Anbieter, der ein kostenpflichtiges
Abonnement für das Erstellen eigener Projekte erfordert. Solange sich Sourcehut im
Alpha-Stadium befindet, ist das Abo allerdings optional (außer für die Nutzung des
Build-Service). Das Abonnement kostet 20€ im Jahr, man kann auch auf freiwilliger Basis
bis zum 100€ bezahlen, um das Projekt zu unterstützen.
Die kostenpflichtigen Mitgliedschaften erlauben Sourcehut, finanziell unabhängig zu sein
und nicht den Entscheidungen von Investoren unterworfen zu sein. Sourcehut
veröffentlicht seine jährlichen Einnahmen und Ausgaben auf ihrem Blog und gibt an, seit
2019 Profit zu erwirtschaften.
Bekannte Projekte, die auf sr.ht gehostet werden sind das alternative Instagram-Frontend
[Bibliogram](https://sr.ht/~cadence/bibliogram/),
[microblog.pub](https://sr.ht/~tsileo/microblog.pub/), eine persönliche
Microblogging-Anwendung mit ActivityPub-Unterstützung und natürlich
[Sourcehut](https://sr.ht/~sircmpwn/sourcehut/) selbst. Insgesamt hostet sr.ht ca. 7100
Projekte.
Es gibt auch Open-Source-Projekte, die ihren Code auf anderen Plattformen hosten und nur
das Build-System von Sourcehut nutzen. Beispielsweise benutzt die Linux-Distribution
postmarketOS [Sourcehut Builds](https://build.postmarketos.org/) zum Bau ihrer Pakete.
Wichtig ist noch zu erwähnen, dass die offizielle Sourcehut-Instanz keine Projekte
erlaubt, die mit
[Blockchain oder Kryptowährungen](https://sourcehut.org/blog/2022-10-31-tos-update-cryptocurrency/)
zu tun haben. Sourcehut begründet dies damit, dass Kryptowährungen häufig für Betrug und
andere Verbrechen eingesetzt werden und große Mengen an Ressourcen verschwenden.
Abgesehen von der offiziellen Instanz gibt es sehr wenige weiterem öffentlichen
Sourcehut-Instanzen, was wohl auch dem komplizierten Einrichtungsprozess geschuldet ist.
Es existiert eine Instanz unter [gnu.org](https://sourcehut.gnu.org), die sich
allerdings im Entwicklermodus befindet und über keine öffentlichen Projekte verfügt. Die
größte alternative Sourcehut-Instanz, die ich gefunden habe, ist
<https://code.netlandish.com/>. Die Instanz wird von einer Webentwicklungsfirma
betrieben, beherbergt 9 öffentliche Projekte und erlaubt keine Registrierung von
Außenstehenden.
## Fazit
Das Highlight von sr.ht ist meiner Meinung nach der CI-Dienst. Während die meisten
anderen CI-Dienste an Repositories gekoppelt sind, erlaubt es Sourcehut, einfach ein
Build-Manifest mit dem CLI-Tool oder dem Formular auf der Website abzuschicken und
ausführen zu lassen. Die Möglichkeit fehlgeschlagene Builds zu analysieren ist ebenfalls
einzigartig.
Allerdings ist die Einrichtung von Sourcehut sehr aufwändig und einige grundlegende
Features wie eine Suchfunktion fehlen weswegen ich das System in seinem momentanen
Zustand nicht empfehlen kann.
Hinzu kommt, dass Sourcehut trotz seiner spartanischen Weboberfläche und seinem
reduziertem Funktionsumfang das System mit dem zweithöchsten Ressourcenverbrauch im Test
war.
Da sich Sourcehut wie gesagt noch im Alpha-Stadium befindet, lohnt es sich jedoch das
Projekt weiter zu verfolgen.
## Quellen
- Projektseite <https://sr.ht/~sircmpwn/sourcehut/>
- Sourcehut Blog <https://sourcehut.org/blog/>

View file

@ -0,0 +1,232 @@
# OneDev
Abschließen möchte ich meinen Test mit einer weitgehend unbekannten Plattform, die erst
2019 als Hobbyprojekt von zwei Entwicklern veröffentlicht wurde, sich aber in Sachen
Funktionalität nicht vor den anderen Plattformen verstecken muss: OneDev.
![OneDev homepage](./assets/onedev/homepage.png)
OneDev ist in Java geschrieben und verwendet das Webframework Apache Wicket. Das Projekt
wird hauptächlich von Robin Shen und Steve Luo entwickelt, insgesamt gibt es ca. 30
Beitragende. Das Projekt ist unter der MIT-Lizenz veröffentlicht.
Der
[erste Commit](https://code.onedev.io/onedev/server/~commits/6be8e3f97c97e44cf6b5a9b8360c299cc55388f6)
erfolgte im April 2012, die erste in Git getaggte Version (2.0.0) wurde 2019
veröffentlicht. Rechnet man mit dem Datum des ersten Release, ist OneDev die jüngste der
vier Plattformen, die ich getestet habe.
OneDev besteht aus einer einzigen Java-Anwendung und erfordert bei Verwendung der
eingebetteten HSQL-Datenbank keine zusätzlichen Dienste zum Betrieb. Es werden auch
externe Datenbanken (MySQL, MariaDB, Postgres, MS SQL, Oracle) unterstützt.
Getestet wurde die Version 8.5.2.
## Installation
Die OneDev-Entwickler stellen Container-Images für OneDev zur Verfügung
(`docker.io/1dev/server`), mit denen sich OneDev einfach mittels Docker installieren
lässt. Alternativ gibt es auch die Möglichkeit, die Java-Anwendung direkt auf seinem
System zu installieren oder OneDev in einem Kubernetes-Cluster zu betreiben.
Für den Installationsprozess gibt es eine Schritt-für-Schritt-Anleitung auf der
Dokumentationsseite des Projekts. Allerdings bin ich hiervon abgewichen, da in der
Installationsanleitung empfohlen wird, den Docker-Socket (`/var/run/docker.sock`) im
OneDev-Container als Volume einzubinden.
Dies ist nur dann erforderlich, wenn der eingebaute _Server Docker Executor_ anstelle
eines externen Agents für CI-Jobs verwendet wird.
Da Container mit Docker-Zugriff effektiv über Root-Rechte auf dem Hostsystem verfügen,
ist dies jedoch mit einem Sicherheitsrisiko verbunden. Deswegen empfehle ich, den
eingebauten Agent nicht zu nutzen und stattdessen den seperaten Agent-Container
(`docker.io/1dev/agent`) zu verwenden. Der CI-Agent sollte bei einem Produktionssetup
auf einem anderen Server bzw. einer anderen VM laufen, auf der sich keine wertvollen
oder sensiblen Daten befinden - insbesondere wenn nicht vertrauenswürdige Nutzer Zugriff
auf das CI-System haben.
[Hier](./assets/onedev/docker-compose.yml) ist die Docker-Compose-Datei, die ich für
meine Testinstallation verwendet habe.
Nach dem Start des Servers kann man auf der Weboberfläche den ersten Benutzeraccount
anlegen und die URL des Servers konfigurieren.
Anschließend muss noch das CI-System eingerichtet werden. Hierzu öffnet man den
Menüpunkt _Administration_ \> _Agents_, klickt auf _Tokens_ und generiert sich einen
neuen Agent Token. Dieser Token muss dem Agent als Umgebungsvariable übergeben werden
(also z.B. in die Docker-Compose-Datei eintragen). Nach dem Start des Agents muss dieser
in der Tabelle sichtbar sein.
![Agent setup](./assets/onedev/add_agent.png)
Danach öffnet man den Menüpunkt _Job Executors_ und erstellt einen _Remote Docker
Executor_. Damit ist die Einrichtung des CI-Systems abgeschlossen und man kann den
ersten Build starten (siehe im Abschnitt
[Continuous Integration](#continous-integration)).
Standardmäßig erlaubt OneDev nur angemeldeten Benutzern den Zugriff auf die Instanz. Um
seine Projekte öffentlich verfügbar zu machen, muss noch die Option _Security Settings_
\> _Enable Anonymous Access_ aktiviert werden.
## Systemanforderungen
OneDev ist auf jedem System mit Java-Unterstützung lauffähig. Das offizielle
Docker-Image wird für die 64bit Interl/AMD und ARM-Architektur angeboten.
Der Server benötigte auf meinem System ca. 1.2GB Arbeitsspeicher, der CI-Agent ca.
180MB. Die CPU-Auslastung im Leerlauf beträgt auf meinem System (AMD Ryzen 5700G) ca.
1%, mit gelegentlichen Spitzen auf 5-10%.
Aufwändige Git-Operationen (History/Blame in großen Repositories) können Lastspitzen von
bis zu 100% mit einer Dauer von max. 2 Sekunden verursachen. Bei Nutzung der
Suchfunktion habe ich bis zu 50% Auslastung gemessen.
## Bedienung
OneDev verfügt über eine modern gestaltete Weboberfläche, die mit dem Webframework
Apache Wicket realisiert wurde. Das Framework lädt beim Navigieren nur die Teile der
Website vom Server, die sich durch den entsprechenden Navigationsschritt geändert haben
(also z.B. die Dateiliste).
Dadurch geht das Navigieren durch die Repositories sehr flüssig vonstatten, ohne dass
die gesamte Seite neu geladen werden muss.
Ein Alleinstellungsmerkmal von OneDev ist die Suchfunktion. OneDev verwendet nicht nur
eine Textsuchmaschine, sondern analysiert den Code im Repository und bietet so die
Möglichkeit, nach Klassen und Funktionen zu suchen. Die Suchergebnisse werden während
dem Tippen angezeigt. Auf diese Weise kann man schnell durch komplexe Softwareprojekte
navigieren.
![Suche](./assets/onedev/search.png)
Die Suche kann auch über ein Kontextmenü in der Code-Ansicht aufgrufen werden. Auf diese
Weise kann man nach Definitionen oder Verwendungen von Funktionen suchen. Es gibt auch
eine Übersicht aller Klassen und Funktionen einer Datei auf der rechten Seite.
Die Code-Analyse ist für die Sprachen Java, JavaScript, C, C++, CSharp, Go, PHP, Python,
CSS, SCSS, LESS und R verfügbar. Rust wird leider nicht unterstützt.
![Code-Navigation](./assets/onedev/code_navigation.png)
OneDev kann auf der Weboberfläche Code, Markdown-Dokumente und Bilder darstellen. Es
gibt keine Unterstützung für alternative Markupsprachen wie RST.
## Import bestehender Projekte
OneDev bietet einen Import-Assistenten mit Unterstützung für GitHub, Gitlab, BitBucket,
und Gitea. Neben dem Git-Repository werden auch Metadaten und Issues übertragen.
Der Importer erlaubt es auch, nach einer Authentifizierung per API-Key sämtliche
Projekte eines Nutzers oder einer Organisation zu übertragen, was beim Umstieg viel Zeit
sparen kann.
Es gibt jedoch nicht die Möglichkeit, Projekte aus anderen OneDev-Instanzen zu
übertragen.
## Zusatzfeatures
OneDev verfügt über umfangreiche Tools zum Projektmanagement. Es gibt die Möglichkeit,
Issues zu Meilensteinen zuzuordnen (z.B. _Sprint 14_ oder _Version 2.0_). Zudem verfügt
OneDev über Issue Boards, um Issues je nach Status in mehreren Spalten anzuzeigen.
![OneDev Issue Board](./assets/onedev/kanban.png)
Issues können bestimmten Entwicklern zugewiesen werden und es gibt die Möglichkeit,
Abhängigkeiten zwischen Issues zu definieren (z.B. Issue A muss vor Issue B erledigt
werden). Was allerdings fehlt ist die Möglichkeit, einem Issue mehrere Labels
zuzuordnen.
OneDev bietet auch die Möglichkeit, statische Webseiten zu hosten. Hierfür ist im
Gegensatz zu Gitlab Pages keine separate Domain nötig. Stattdessen wird die Webseite im
Unterverzeichnis `~site` des Repositorys (z.B. `https://example.com/user/repo/~site`)
veröffentlicht.
Als einzige getestete Plattform verfügt OneDev über ein Plugin-System. Auf diese Weise
lassen sich neue Features implementieren, ohne die Software verändern zu müssen.
Beispielsweise gibt es ein Plugin zum
[Import von Issues](https://github.com/DevCharly/onedev-plugin-import-redmine/) aus der
Projektmanagement-Anwendung Redmine.
Weitere Zusatzfeatures wie Paketmanagement bietet OneDev nicht. Darüber hinaus fehlt die
Möglichkeit, Releases seiner Software hochzuladen und mit Git-Tags zu verknüpfen. Dieses
Feature beherrschen ansonsten alle getesteten Plattformen.
## Continous Integration
OneDev bietet ein eingebautes CI-System um Projekte zu kompilieren und zu testen. Die
Jobs können in Docker-Containern, Kubernetes-Pods oder bare metal ausgeführt werden.
Jobs werden in einer yml-Datei definiert, die als `.onedev-buildspec.yml` im
Wurzelverzeichnis des Repositories abgelegt werden muss.
OneDev bietet jedoch auch eine Weboberfläche, um Builds zu erstellen und zu bearbeiten.
Auf diese Weise muss man nicht zuerst die yaml-Syntax erlernen, um das CI-System zu
nutzen. Über die Weboberfläche lassen sich bestimmte Aktionen (z.B. "Befehle ausführen",
"Docker Image bauen", "Webseite veröffentlichen") auswählen und konfigurieren.
![CI-Editor](./assets/onedev/ci_editor.png)
```yml
version: 23
jobs:
- name: test
steps:
- !CheckoutStep
name: checkout
cloneCredential: !DefaultCredential {}
withLfs: false
withSubmodules: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
- !CommandStep
name: build
runInContainer: true
image: rust:latest
interpreter: !DefaultInterpreter
commands:
- rustup component add rustfmt clippy
- cargo fmt --all --check
- cargo clippy --all --features=rss -- -D warnings
- cargo test --features=rss --workspace
useTTY: false
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
triggers:
- !BranchUpdateTrigger {}
- !PullRequestUpdateTrigger {}
retryCondition: never
maxRetries: 3
retryDelay: 30
timeout: 3600
```
Die Builds können durch Branch Updates oder neue Pull Requests ausgelöst werden. Es gibt
auch die Möglichkeit, Builds zeitgesteuert oder manuell zu starten.
## Öffentliche Instanzen
Das OneDev-Team betreibt ihre eigene Instanz unter
[code.onedev.io](https://code.onedev.io). Allerdings verbietet diese Instanz das
erstellen eigener Projekte und dient nur der Entwicklung und Demonstration der
Plattform.
Darüber hinaus habe ich außer einer kleinen privaten Instanz names
["Winux Projects"](https://projects.winux.it/) keine öffentlichen Instanzen gefunden,
was sicher auch daran liegt, dass das Projekt momentan noch relativ unbekannt ist.
## Fazit
Obwohl OneDev noch relativ jung und weitgehend unbekannt ist, kann es funktional
durchaus mit den Konkurrenten mithalten. Insbesondere die intelligente Suchfunktion und
das einfach zu bedienende CI-System haben mir im Test sehr gut gefallen.
Allerdings ist OneDev immer noch ein Hobbyprojekt von 2 Entwicklern und hat keine Firma
oder größere Organisation hinter sich. Wer OneDev beispielsweise in einem Unternehmen
einsetzen möchte, muss die Einrichtung und den Support selbst übernehmen, da es im
Gegensatz zu GitLab und Gitea keine öffentlichen Instanzen oder SaaS-Angebote gibt.
Wer sich hieran nicht stört, erhält mit OneDev eine leichtgewichtige, einfach zu
installierende und moderne Git-Hosting-Plattform.
## Quellen
- Projektseite <https://onedev.io/>
- Repository <https://code.onedev.io/onedev/server>

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View file

@ -0,0 +1,21 @@
version: "3.6"
services:
web:
image: "gitlab/gitlab-ce:latest"
restart: unless-stopped
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://localhost:8001'
nginx['listen_https'] = false
nginx['listen_port'] = 80
nginx['redirect_http_to_https'] = false
letsencrypt['enable'] = false
GITLAB_ROOT_PASSWORD: secret1234
ports:
- "8001:80"
- "2222:22"
volumes:
- "./config:/etc/gitlab"
- "./logs:/var/log/gitlab"
- "./data:/var/opt/gitlab"
shm_size: "256m"

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

View file

@ -0,0 +1,19 @@
version: "3"
services:
onedev:
image: 1dev/server:latest
ports:
- 6610:6610
- 6611:6611
volumes:
- ./data:/opt/onedev
agent:
image: 1dev/agent:latest
environment:
- "serverUrl=http://onedev:6610"
- "agentToken=3922e711-8a7f-4dd0-8b68-fd3ca891ffff"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./work:/agent/work
depends_on:
- onedev

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View file

@ -0,0 +1,109 @@
<mxfile host="65bd71144e">
<diagram id="oiookRJMGbAoKEPYmeVH" name="Page-1">
<mxGraphModel dx="741" dy="808" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" background="#ffffff" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="3" value="Frontend&lt;br&gt;:5000" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="40" y="80" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="4" value="API&lt;br&gt;:5100" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="120" y="80" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="5" value="meta.sr.ht&lt;br&gt;(Nutzerverwaltung)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#141414;" parent="1" vertex="1">
<mxGeometry x="140" y="50" width="60" height="10" as="geometry"/>
</mxCell>
<mxCell id="6" value="Webhooks&lt;br&gt;(Queue)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="200" y="80" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="8" value="Frontend&lt;br&gt;:5014" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="360" y="80" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="9" value="API&lt;br&gt;:5114" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="440" y="80" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="10" value="hub.sr.ht&lt;br&gt;(Startseite)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#141414;" parent="1" vertex="1">
<mxGeometry x="410" y="50" width="60" height="20" as="geometry"/>
</mxCell>
<mxCell id="11" value="Frontend&lt;br&gt;:5001" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="40" y="200" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="12" value="API&lt;br&gt;:5101" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="120" y="200" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="13" value="git.sr.ht&lt;br&gt;(Nutzerverwaltung)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#141414;" parent="1" vertex="1">
<mxGeometry x="140" y="170" width="60" height="10" as="geometry"/>
</mxCell>
<mxCell id="14" value="Webhooks&lt;br&gt;(Queue)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="200" y="200" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="15" value="Frontend&lt;br&gt;:5004" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="360" y="200" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="16" value="API&lt;br&gt;:5104" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="440" y="200" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="17" value="man.sr.ht&lt;br&gt;(Wiki)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#141414;" parent="1" vertex="1">
<mxGeometry x="410" y="170" width="60" height="20" as="geometry"/>
</mxCell>
<mxCell id="18" value="Frontend&lt;br&gt;:5002" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="40" y="320" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="19" value="API&lt;br&gt;:5102" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="120" y="320" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="20" value="builds.sr.ht&lt;br&gt;(CI)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#141414;" parent="1" vertex="1">
<mxGeometry x="140" y="290" width="60" height="10" as="geometry"/>
</mxCell>
<mxCell id="21" value="Worker" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="200" y="320" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="22" value="Worker" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="210" y="330" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="23" value="Frontend&lt;br&gt;:5011" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="360" y="320" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="24" value="API&lt;br&gt;:5111" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="440" y="320" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="25" value="paste.sr.ht&lt;br&gt;(Wiki)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#141414;" parent="1" vertex="1">
<mxGeometry x="410" y="290" width="60" height="20" as="geometry"/>
</mxCell>
<mxCell id="26" value="Frontend&lt;br&gt;:5006" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="360" y="440" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="27" value="API&lt;br&gt;:5106" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="440" y="440" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="28" value="lists.sr.ht&lt;br&gt;(Mailinglisten)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#141414;" parent="1" vertex="1">
<mxGeometry x="478" y="410" width="60" height="20" as="geometry"/>
</mxCell>
<mxCell id="29" value="Process&lt;br&gt;(Queue)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="560" y="440" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="30" value="LMTP" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="520" y="440" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="31" value="Frontend&lt;br&gt;:5003" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="40" y="440" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="32" value="API&lt;br&gt;:5103" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="120" y="440" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="33" value="todo.sr.ht&lt;br&gt;(Issues)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#141414;" parent="1" vertex="1">
<mxGeometry x="158" y="410" width="60" height="20" as="geometry"/>
</mxCell>
<mxCell id="34" value="Webhooks&lt;br&gt;(Queue)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="240" y="440" width="80" height="40" as="geometry"/>
</mxCell>
<mxCell id="35" value="LMTP" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="200" y="440" width="40" height="40" as="geometry"/>
</mxCell>
<mxCell id="36" value="Webhooks&lt;br&gt;(Queue)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="640" y="440" width="80" height="40" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

View file

@ -0,0 +1,523 @@
[sr.ht]
# The name of your network of sr.ht-based sites
site-name=sourcehut
#
# The top-level info page for your site
site-info=https://sourcehut.org
#
# {{ site-name }}, {{ site-blurb }}
site-blurb=the hacker's forge
#
# If this != production, we add a banner to each page
environment=production
#
# Contact information for the site owners
owner-name=Drew DeVault
owner-email=sir@cmpwn.com
#
# The source code for your fork of sr.ht
source-url=https://git.sr.ht/~sircmpwn/srht
#
# Link to your instance's privacy policy. Uses the sr.ht privacy policy as the
# default, which describes the information collected by the upstream SourceHut
# code.
privacy-policy=
#
# A key used for encrypting session cookies. Use `srht-keygen service` to
# generate the service key. This must be shared between each node of the same
# service (e.g. git1.sr.ht and git2.sr.ht), but different services may use
# different keys. If you configure all of your services with the same
# config.ini, you may use the same service-key for all of them.
service-key=9654c9ec7bedab6321a7f29f8b1b607ba023ddb9e248a67e10c49122e59a335f
#
# A secret key to encrypt internal messages with. Use `srht-keygen network` to
# generate this key. It must be consistent between all services and nodes.
network-key=iZnfEOgNVuCw6uGPQx1LE6eKVd20GXnd9IgCD3wxKJA=
#
# The redis host URL. This is used for caching and temporary storage, and must
# be shared between nodes (e.g. git1.sr.ht and git2.sr.ht), but need not be
# shared between services. It may be shared between services, however, with no
# ill effect, if this better suits your infrastructure.
redis-host=redis://localhost:6379
#
# Optional email address for reporting security-related issues.
security-address=
#
# The global domain of the site. If unset, the global domain will be determined
# from the service URL: each service is assumed to be a sub-domain of the global
# domain, i.e. of the form `meta.globaldomain.com`.
global-domain=codeforge.int
[mail]
# Outgoing SMTP settings
smtp-host=
smtp-port=
smtp-from=user@example.org
#
# Default: starttls
# Options: starttls, tls, insecure
smtp-encryption=tls
#
# Default: plain
# Options: plain, none
smtp-auth=plain
# user / password are required if smtp-auth is plain
smtp-user=user@example.org
smtp-password=pass
pgp-privkey=/etc/sr.ht/gpg/privkey.gpg
pgp-pubkey=/etc/sr.ht/gpg/pubkey.gpg
pgp-key-id=E77640E3C9BA474C9C0791547298D360EE7DB9B4
[webhooks]
#
# base64-encoded Ed25519 key for signing webhook payloads. This should be
# consistent between all services.
#
# Use the `srht-keygen webhook` command to generate this key. Put the private
# key here and distribute the public key to anyone who would want to verify
# webhook payloads from your service.
private-key=FMCFMBL9HX3OHkYFoDUetJzxNfHw0vwWgLFKACXdoCY=
[meta.sr.ht]
#
# URL meta.sr.ht is being served at (protocol://domain)
origin=http://meta.codeforge.int
# Address and port to bind the debug server to
# debug-host=127.0.0.1
# debug-port=5000
#
# Configures the SQLAlchemy connection string for the database.
connection-string=postgresql://meta:1234@localhost/meta.sr.ht?sslmode=disable
#
# Set to "yes" to automatically run migrations on package upgrade.
migrate-on-upgrade=yes
#
# The redis connection used for the webhooks worker
webhooks=redis://localhost:6379/1
#
# If "yes", the user will be sent the stock sourcehut welcome emails after
# signup (requires cron to be configured properly). These are specific to the
# sr.ht instance so you probably want to patch these before enabling this.
welcome-emails=no
#
# Origin URL for the API
# By default, the API port is 100 more than the web port
api-origin=http://localhost:5100
[meta.sr.ht::api]
#
# Maximum complexity of GraphQL queries. The higher this number, the more work
# that API clients can burden the API backend with. Complexity is equal to the
# number of discrete fields which would be returned to the user. 200 is a good
# default.
max-complexity=200
#
# The maximum time the API backend will spend processing a single API request.
#
# See https://golang.org/pkg/time/#ParseDuration
max-duration=3s
#
# Set of IP subnets which are permitted to utilize internal API
# authentication. This should be limited to the subnets from which your
# *.sr.ht services are running.
#
# Comma-separated, CIDR notation.
internal-ipnet=127.0.0.0/8,::1/128,192.168.0.0/16,10.0.0.0/8
[meta.sr.ht::settings]
#
# If "no", public registration will not be permitted.
registration=yes
#
# Where to redirect new users upon registration
onboarding-redirect=http://codeforge.int
[meta.sr.ht::aliases]
#
# You can add aliases for the client IDs of commonly used OAuth clients here.
#
# Example:
# git.sr.ht=12345
[meta.sr.ht::billing]
#
# "yes" to enable the billing system
enabled=no
#
# Get your keys at https://dashboard.stripe.com/account/apikeys
stripe-public-key=
stripe-secret-key=
[meta.sr.ht::auth]
#
# What authentication method to use.
# builtin: use sr.ht builtin authentication
# unix-pam: use Unix PAM authentication
auth-method=builtin
[hub.sr.ht]
#
# URL hub.sr.ht is being served at (protocol://domain)
origin=http://codeforge.int
#
# Address and port to bind the debug server to
# debug-host=127.0.0.1
# debug-port=5014
#
# Configures the SQLAlchemy connection string for the database.
connection-string=postgresql://hub:1234@localhost/hub.sr.ht?sslmode=disable
#
# Set to "yes" to automatically run migrations on package upgrade.
migrate-on-upgrade=yes
#
# hub.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
oauth-client-id=712f709b315e4441
oauth-client-secret=a186072ee9900662841188857777f44f
[git.sr.ht]
#
# URL git.sr.ht is being served at (protocol://domain)
origin=http://git.codeforge.int
#
# Address and port to bind the debug server to
#debug-host=0.0.0.0
#debug-port=5001
#
# Configures the SQLAlchemy connection string for the database.
connection-string=postgresql://git:1234@localhost/git.sr.ht?sslmode=disable
#
# Set to "yes" to automatically run migrations on package upgrade.
migrate-on-upgrade=yes
#
# The redis connection used for the webhooks worker
webhooks=redis://localhost:6379/1
#
# A post-update script which is installed in every git repo.
post-update-script=/usr/bin/gitsrht-update-hook
#
# git.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
oauth-client-id=33e27e614a5a6c99
oauth-client-secret=e128d76adb42d64290381facab1a9db1
#
# Path to git repositories on disk
repos=/var/lib/git/
#
# Configure the S3 bucket and prefix for object storage. Leave empty to disable
# object storage. Bucket is required to enable object storage; prefix is
# optional.
#s3-bucket=
#s3-prefix=
#
# Required for preparing and sending patchsets from git.sr.ht
outgoing-domain=
#
# Origin URL for the API
# Only needed if not run behind a reverse proxy, e.g. for local development.
# By default, the API port is 100 more than the web port
#api-origin=http://localhost:5101
[git.sr.ht::api]
#
# Maximum complexity of GraphQL queries. The higher this number, the more work
# that API clients can burden the API backend with. Complexity is equal to the
# number of discrete fields which would be returned to the user. 200 is a good
# default.
max-complexity=200
#
# The maximum time the API backend will spend processing a single API request.
#
# See https://golang.org/pkg/time/#ParseDuration
max-duration=3s
#
# Set of IP subnets which are permitted to utilize internal API
# authentication. This should be limited to the subnets from which your
# *.sr.ht services are running.
#
# Comma-separated, CIDR notation.
internal-ipnet=127.0.0.0/8,::1/128,192.168.0.0/16,10.0.0.0/8
[git.sr.ht::dispatch]
#
# The authorized keys hook uses this to dispatch to various handlers
# The format is a program to exec into as the key, and the user to match as the
# value. When someone tries to log in as this user, this program is executed
# and is expected to omit an AuthorizedKeys file.
#
# Uncomment the relevant lines to enable the various sr.ht dispatchers.
/usr/bin/gitsrht-keys=git:git
/usr/bin/buildsrht-keys=builds:builds
[todo.sr.ht]
#
# URL todo.sr.ht is being served at (protocol://domain)
origin=http://todo.codeforge.int
#
# Address and port to bind the debug server to
#debug-host=0.0.0.0
#debug-port=5003
#
# Configures the SQLAlchemy connection string for the database.
connection-string=postgresql://todo:1234@localhost/todo.sr.ht?sslmode=disable
#
# Set to "yes" to automatically run migrations on package upgrade.
migrate-on-upgrade=yes
#
# todo.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
oauth-client-id=215b592aa1e401b6
oauth-client-secret=05f0d7ba973c6e4f2e0b5c95f00510f4
#
# Outgoing email for notifications generated by users
notify-from=user@example.org
#
# The redis connection used for the webhooks worker
webhooks=redis://localhost:6379/1
#
# Origin URL for the API
# Only needed if not run behind a reverse proxy, e.g. for local development.
# By default, the API port is 100 more than the web port
#api-origin=http://localhost:5103
[todo.sr.ht::mail]
#
# Path for the lmtp daemon's unix socket. Direct incoming mail to this socket.
# Alternatively, specify IP:PORT and an SMTP server will be run instead.
sock=/tmp/todo.sr.ht-lmtp.sock
#
# The lmtp daemon will make the unix socket group-read/write for users in this
# group.
sock-group=postfix
#
# Fill this in with the name of the domain to which emails should be sent.
# Leave blank to disable email submission.
posting-domain=
[lists.sr.ht]
#
# URL lists.sr.ht is being served at (protocol://domain)
origin=http://lists.codeforge.int
#
# Address and port to bind the debug server to
#debug-host=0.0.0.0
#debug-port=5006
#
# Configures the SQLAlchemy connection string for the database.
connection-string=postgresql://lists:1234@localhost/lists.sr.ht?sslmode=disable
#
# Set to "yes" to automatically run migrations on package upgrade.
migrate-on-upgrade=yes
#
# The redis connection used for the webhooks worker
webhooks=redis://localhost:6379/1
#
# The redis connection used for the Celery worker (configure this on both the
# master and workers)
redis=redis://localhost:6379/0
#
# The domain that incoming email should be sent to. Forward mail sent here to
# the LTMP socket.
posting-domain=lists.codeforge.int
#
# lists.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
oauth-client-id=95b6e656251e01f9
oauth-client-secret=c6a53f7ac6e242dcbae198b738ce9c9a
#
# Trusted upstream SMTP server generating Authentication-Results header fields
msgauth-server=mail.sr.ht.local
#
# If "no", prevents non-admins from creating new lists
allow-new-lists=yes
#
# Origin URL for the API
# Only needed if not run behind a reverse proxy, e.g. for local development.
# By default, the API port is 100 more than the web port
#api-origin=http://localhost:5106
[lists.sr.ht::worker]
# Protocol used by the daemon. Either lmtp or smtp. By default ltmp if using
# unix socket and smtp if using tcp socket.
protocol=lmtp
#
# Path for the lmtp daemon's unix socket. Direct incoming mail to this socket.
# Alternatively, specify IP:PORT will run the server using tcp.
sock=/tmp/lists.sr.ht-lmtp.sock
#
# The lmtp daemon will make the unix socket group-read/write for users in this
# group.
sock-group=postfix
#
# Comma-delimited list of Content-Types to reject. Messages with Content-Types
# included in this list are rejected. Multipart messages are always supported,
# and each part is checked against this list.
#
# Uses fnmatch for wildcard expansion.
reject-mimetypes=
#
# Link to include in the rejection message where senders can get help
# correcting their email.
reject-url=https://man.sr.ht/lists.sr.ht/etiquette.md
[lists.sr.ht::api]
#
# Maximum complexity of GraphQL queries. The higher this number, the more work
# that API clients can burden the API backend with. Complexity is equal to the
# number of discrete fields which would be returned to the user. 200 is a good
# default.
max-complexity=200
#
# The maximum time the API backend will spend processing a single API request.
#
# See https://golang.org/pkg/time/#ParseDuration
max-duration=90s
#
# Set of IP subnets which are permitted to utilize internal API
# authentication. This should be limited to the subnets from which your
# *.sr.ht services are running.
#
# Comma-separated, CIDR notation.
internal-ipnet=127.0.0.0/8,::1/128,192.168.0.0/16,10.0.0.0/8
[lists.sr.ht::redirects]
#
# Redirects for migrating old mailing lists to new ones. This just sets up the
# redirect for incoming emails.
#
# old-address=~example/new-name
[man.sr.ht]
#
# URL man.sr.ht is being served at (protocol://domain)
origin=http://man.codeforge.int
#
# Address and port to bind the debug server to
#debug-host=0.0.0.0
#debug-port=5004
#
# Configures the SQLAlchemy connection string for the database.
connection-string=postgresql://man:1234@localhost/man.sr.ht?sslmode=disable
#
# Set to "yes" to automatically run migrations on package upgrade.
migrate-on-upgrade=yes
#
# man.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
oauth-client-id=96319d48a50cdfe5
oauth-client-secret=e405e716b052402c88035c6ab429e6d3
[builds.sr.ht]
#
# URL builds.sr.ht is being served at (protocol://domain)
origin=http://builds.codeforge.int
#
# Address and port to bind the debug server to
#debug-host=0.0.0.0
#debug-port=5002
#
# Configures the SQLAlchemy connection string for the database.
connection-string=postgresql://builds:1234@localhost/builds.sr.ht?sslmode=disable
#
# Set to "yes" to automatically run migrations on package upgrade.
migrate-on-upgrade=yes
#
# The redis connection used for the Celery worker (configure this on both the
# master and workers)
redis=redis://localhost:6379/0
#
# builds.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
oauth-client-id=ecfda530d17ae5c3
oauth-client-secret=68176355b4de8865163748e0a1ec1551
#
# Script used to launch on ssh connnection. /usr/bin/master-shell on master,
# /usr/bin/runner-shell for workers.
# If master and worker are on the same system set to /usr/bin/runner-shell
shell=/usr/bin/runner-shell
#
# Set to "yes" to allow nonpaying users to submit builds
allow-free=yes
#
# Origin URL for the API
# Only needed if not run behind a reverse proxy, e.g. for local development.
# By default, the API port is 100 more than the web port
#api-origin=http://localhost:5102
#
# These config options are only necessary for systems running a build runner
[builds.sr.ht::worker]
#
# Name of this build runner (with HTTP port if not 80)
name=runner.codeforge.int
#
# Path to write build logs
buildlogs=/var/log/builds
#
# Path to the build images
images=/var/lib/images
#
# In production you should NOT put the build user in the docker group. Instead,
# make a scratch user who is and write a sudoers or doas.conf file that allows
# them to execute just the control command, then update this config option. For
# example:
#
# doas -u docker /var/lib/images/control
#
# Assuming doas.conf looks something like this:
#
# permit nopass builds as docker cmd /var/lib/images/control
#
# For more information about the security model of builds.sr.ht, visit the wiki:
#
# https://man.sr.ht/builds.sr.ht/installation.md
controlcmd=sudo -u docker /var/lib/images/control
#
# Max build duration. See https://golang.org/pkg/time/#ParseDuration
timeout=45m
#
# Http bind address for serving local build information/monitoring
bind-address=127.0.0.1:8080
#
# Build trigger email
trigger-from=user@example.org
#
# Configure the S3 bucket and prefix for object storage. Leave empty to disable
# object storage. Bucket is required to enable object storage; prefix is
# optional.
s3-bucket=
s3-prefix=
[paste.sr.ht]
#
# URL paste.sr.ht is being served at (protocol://domain)
origin=http://paste.codeforge.int
#
# Address and port to bind the debug server to
#debug-host=0.0.0.0
#debug-port=5011
#
# Configures the SQLAlchemy connection string for the database.
connection-string=postgresql://paste:1234@localhost/paste.sr.ht?sslmode=disable
#
# Set to "yes" to automatically run migrations on package upgrade.
migrate-on-upgrade=yes
#
# paste.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
oauth-client-id=b930097f0d5666fb
oauth-client-secret=ee749b58b1ff808f3bc095a7e5ea4f9a
#
# Origin URL for the API
# Only needed if not run behind a reverse proxy, e.g. for local development.
# By default, the API port is 100 more than the web port
#api-origin=http://localhost:5111

View file

@ -0,0 +1,20 @@
real_ip_header X-Forwarded-For;
real_ip_recursive on;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';

View file

@ -0,0 +1,223 @@
# Meta
server {
include sourcehut.conf;
include port80.conf;
server_name meta.codeforge.int;
location / {
proxy_pass http://127.0.0.1:5000;
include web.conf;
}
location /.well-known/oauth-authorization-server {
proxy_pass http://127.0.0.1:5000;
}
location /query {
proxy_pass http://127.0.0.1:5100;
include graphql.conf;
}
location /static {
root /usr/lib/$python/site-packages/metasrht;
expires 30d;
}
}
# Hub
server {
include sourcehut.conf;
include port80.conf;
server_name codeforge.int;
location / {
proxy_pass http://127.0.0.1:5014;
include web.conf;
}
location /query {
proxy_pass http://127.0.0.1:5114;
include graphql.conf;
}
location /static {
root /usr/lib/$python/site-packages/hubsrht;
expires 30d;
}
}
# Git
server {
include sourcehut.conf;
include port80.conf;
server_name git.codeforge.int;
location / {
proxy_pass http://127.0.0.1:5001;
include web.conf;
}
location /query {
proxy_pass http://127.0.0.1:5101;
include graphql.conf;
}
location /static {
root /usr/lib/$python/site-packages/gitsrht;
expires 30d;
}
location = /authorize {
proxy_pass http://127.0.0.1:5001;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
location ~ ^/([^/]+)/([^/]+)/(HEAD|info/refs|objects/info/.*|git-upload-pack).*$ {
auth_request /authorize;
root /var/lib/git;
fastcgi_pass unix:/run/fcgiwrap/fcgiwrap.sock;
fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend;
fastcgi_param PATH_INFO $uri;
fastcgi_param GIT_PROJECT_ROOT $document_root;
fastcgi_read_timeout 500s;
include fastcgi_params;
gzip off;
}
}
# Man
server {
include sourcehut.conf;
include port80.conf;
server_name man.codeforge.int;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:5004;
include web.conf;
}
location /query {
proxy_pass http://127.0.0.1:5104;
include graphql.conf;
}
location /static {
root /usr/lib/$python/site-packages/mansrht;
expires 30d;
}
}
# Todo
server {
include sourcehut.conf;
include port80.conf;
server_name todo.codeforge.int;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:5003;
include web.conf;
}
location /query {
proxy_pass http://127.0.0.1:5103;
include graphql.conf;
}
location /static {
root /usr/lib/$python/site-packages/todosrht;
expires 30d;
}
}
# Lists
server {
include sourcehut.conf;
include port80.conf;
server_name lists.codeforge.int;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:5006;
include web.conf;
}
location /query {
proxy_pass http://127.0.0.1:5106;
include graphql.conf;
}
location /static {
root /usr/lib/$python/site-packages/listssrht;
expires 30d;
}
}
# Paste
server {
include sourcehut.conf;
include port80.conf;
server_name paste.codeforge.int;
client_max_body_size 10M;
location / {
proxy_pass http://127.0.0.1:5011;
include web.conf;
}
location /query {
proxy_pass http://127.0.0.1:5111;
include graphql.conf;
}
location /static {
root /usr/lib/$python/site-packages/pastesrht;
expires 30d;
}
}
# Builds
server {
include sourcehut.conf;
include port80.conf;
server_name builds.codeforge.int;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:5002;
include web.conf;
}
location /query {
proxy_pass http://127.0.0.1:5102;
include graphql.conf;
}
location /static {
root /usr/lib/$python/site-packages/buildsrht;
expires 30d;
}
}
# Runner (proxy only local requests)
server {
include sourcehut.conf;
include port80.conf;
server_name runner.codeforge.int;
location / {
proxy_pass http://127.0.0.1:8080;
include web.conf;
allow 127.0.0.1;
deny all;
}
}

View file

@ -0,0 +1,10 @@
listen 80;
listen [::]:80;
location ^~ /.well-known {
root /var/www;
}
location = /robots.txt {
root /var/www;
}

View file

@ -0,0 +1,3 @@
set $python "python3.10";
set_real_ip_from 127.0.0.0/16;
set_real_ip_from 173.195.146.128/25;

View file

@ -0,0 +1,5 @@
real_ip_header X-Forwarded-For;
real_ip_recursive on;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

View file

@ -0,0 +1,48 @@
version: "3"
services:
woodpecker-server:
image: woodpeckerci/woodpecker-server:next
restart: unless-stopped
networks:
- proxy
environment:
- WOODPECKER_OPEN=true
- WOODPECKER_HOST=https://ci.thetadev.de
- WOODPECKER_GITEA=true
- WOODPECKER_GITEA_URL=https://code.thetadev.de
- WOODPECKER_GITEA_CLIENT=48060801-dc04-4361-b0a9-eefbfc6f29d0
- WOODPECKER_GITEA_SECRET=gto_wefjljwg4ouio34goi4ui34ui34uighjrfvnerrejrekwhgui34g4
- WOODPECKER_AGENT_SECRET=f81909f8e70371af65a6e1c6e77d35d4677c3ed242dcadde032fb27a9c5f9c35
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.woodpecker.entrypoints=websecure"
- "traefik.http.routers.woodpecker.rule=Host(`ci.thetadev.de`)"
- "traefik.http.routers.woodpecker.service=woodpecker"
- "traefik.http.services.woodpecker.loadbalancer.server.port=8000"
# gRPC service
- "traefik.http.routers.woodpecker-grpc.entrypoints=websecure"
- "traefik.http.routers.woodpecker-grpc.rule=Host(`ci-grpc.thetadev.de`)"
- "traefik.http.routers.woodpecker-grpc.service=woodpecker-grpc"
- "traefik.http.services.woodpecker-grpc.loadbalancer.server.port=9000"
- "traefik.http.services.woodpecker-grpc.loadbalancer.server.scheme=h2c"
woodpecker-agent:
image: woodpeckerci/woodpecker-agent:next
command: agent
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /etc/localtime:/etc/localtime:ro
environment:
- "WOODPECKER_SERVER=ci-grpc.thetadev.de:443"
- "WOODPECKER_AGENT_SECRET=f81909f8e70371af65a6e1c6e77d35d4677c3ed242dcadde032fb27a9c5f9c35"
- "WOODPECKER_MAX_PROCS=2"
- "WOODPECKER_HOSTNAME=ocloud"
- WOODPECKER_GRPC_SECURE=true
- WOODPECKER_GRPC_VERIFY=true
networks:
proxy:
external: true

View file

@ -0,0 +1,512 @@
# Anhang: Installation von Sourcehut
Da ich im Internet keine vollständige Installationsanleitung für Sourcehut gefunden
habe, beschreibe ich hier den vollständigen Installationsvorgang für meine Testinstanz.
Ich habe Sourcehut wie vom Entwickler empfohlen auf einer Alpine-Linux-VM installiert.
Die Sourcehut-Pakete werden auch für Arch und Debian (Sid) angeboten.
Alle aufgelisteten Befehle müssen als Root-User ausgeführt werden, sofern es nicht
anders beschrieben ist.
## Sourcehut-Repo
Zuerst muss das Sourcehut-Repository zum Paketmanager des Systems hinzugefügt werden.
Die URLs für verschiedene Distributionen sind in der Dokumentation des Projekts
angegeben.
<https://man.sr.ht/packages.md>
```
echo "https://mirror.sr.ht/alpine/v3.17/sr.ht" > /etc/apk/repositories
wget -q -O /etc/apk/keys/alpine@sr.ht.rsa.pub https://mirror.sr.ht/alpine/alpine@sr.ht.rsa.pub
apk update
```
## Grundlegende Dienste
Zu Beginn müssen die grundlegenden Dienste eingerichtet werden: die Postgres-Datenbank,
Redis und ein Nginx-Webserver, der als Reverse Proxy zwischen dem Nutzer und den
einzelnen Diensten steht.
Beim Einrichten der Dienste ist zu beachten, dass Alpine Linux OpenRC anstelle des
systemd-Init-Systems verwendet und alle neu installierten Dienste manuell aktiviert und
gestartet werden müssen.
```
apk add postgresql redis nginx
rc-service postgresql setup
rc-update add postgresql
rc-service postgresql start
rc-update add nginx
rc-update add redis
rc-service nginx start
rc-service redis start
```
Wenn Postgres läuft, kann man die Datenbanken und Nutzer für die einzelnen Dienste
erstellen.
```
su postgres
psql
CREATE USER meta WITH PASSWORD '1234';
CREATE DATABASE "meta.sr.ht";
ALTER DATABASE "meta.sr.ht" OWNER TO meta;
GRANT ALL PRIVILEGES ON DATABASE "meta.sr.ht" TO meta;
CREATE USER hub WITH PASSWORD '1234';
CREATE DATABASE "hub.sr.ht";
ALTER DATABASE "hub.sr.ht" OWNER TO hub;
GRANT ALL PRIVILEGES ON DATABASE "hub.sr.ht" TO hub;
CREATE USER git WITH PASSWORD '1234';
CREATE DATABASE "git.sr.ht";
ALTER DATABASE "git.sr.ht" OWNER TO git;
GRANT ALL PRIVILEGES ON DATABASE "git.sr.ht" TO git;
CREATE USER man WITH PASSWORD '1234';
CREATE DATABASE "man.sr.ht";
ALTER DATABASE "man.sr.ht" OWNER TO man;
GRANT ALL PRIVILEGES ON DATABASE "man.sr.ht" TO man;
CREATE USER todo WITH PASSWORD '1234';
CREATE DATABASE "todo.sr.ht";
ALTER DATABASE "todo.sr.ht" OWNER TO todo;
GRANT ALL PRIVILEGES ON DATABASE "todo.sr.ht" TO todo;
CREATE USER lists WITH PASSWORD '1234';
CREATE DATABASE "lists.sr.ht";
ALTER DATABASE "lists.sr.ht" OWNER TO lists;
GRANT ALL PRIVILEGES ON DATABASE "lists.sr.ht" TO lists;
CREATE USER paste WITH PASSWORD '1234';
CREATE DATABASE "paste.sr.ht";
ALTER DATABASE "paste.sr.ht" OWNER TO paste;
GRANT ALL PRIVILEGES ON DATABASE "paste.sr.ht" TO paste;
CREATE USER builds WITH PASSWORD '1234';
CREATE DATABASE "builds.sr.ht";
ALTER DATABASE "builds.sr.ht" OWNER TO builds;
GRANT ALL PRIVILEGES ON DATABASE "builds.sr.ht" TO builds;
```
Alle Sourcehut-Dienste werden über eine einzige Datei unter `/etc/sr.ht/config.ini`
konfiguriert. Sourcehut stellte jedoch keine vollständige Beispielkonfiguration bereit,
weswegen ich meine Konfiguration aus den einzelnen Repositories zusammenkopieren musste.
- <https://git.sr.ht/~sircmpwn/meta.sr.ht/tree/master/item/config.example.ini>
- <https://git.sr.ht/~sircmpwn/hub.sr.ht/tree/master/item/config.example.ini>
- <https://git.sr.ht/~sircmpwn/git.sr.ht/tree/master/item/config.example.ini>
- <https://git.sr.ht/~sircmpwn/man.sr.ht/tree/master/item/config.example.ini>
- <https://git.sr.ht/~sircmpwn/paste.sr.ht/tree/master/item/config.example.ini>
- <https://git.sr.ht/~sircmpwn/builds.sr.ht/tree/master/item/config.example.ini>
- <https://git.sr.ht/~sircmpwn/todo.sr.ht/tree/master/item/config.example.ini>
- <https://git.sr.ht/~sircmpwn/lists.sr.ht/tree/master/item/config.example.ini>
[Beispielkonfiguration](./assets/sourcehut_setup/config.ini)
Folgende Optionen müssen angepasst werden:
- Die Domains/URLs der Webseiten (in meiner Beispielkonfiguration `*.codeforge.int`).
- Datenbank-URLs/Passwörter (Option: `connection-string`)
- GPG-Keys (ein GPG-Schlüsselpaar ohne Passwort erstellen und unter `mail/pgp-privkey`,
`mail/pgp-pubkey` und `mail/pgp-key-id` angeben)
- `service-key`, `network-key`, `webhooks/private-key` (siehe meta.sr.ht)
- OAuth-Client-IDs/Secrets (siehe meta.sr.ht)
Anschließend kann man Nginx so konfigurieren, dass Web-Anfragen an die einzelnen Dienste
weitergeleitet werden können. Eine Nginx-Beispielkonfiguration findet sich in
[diesem Repository](https://git.sr.ht/~sircmpwn/sr.ht-nginx/tree) auf Sourcehut.
[Hier](./assets/sourcehut_setup/nginx/nginx_services.conf) befindet sich die angepasste
Version (ohne HTTPS), die ich für meine Testinstallation verwendet habe.
Noch ein Hinweis für Testinstallationen mit internen Domains: Die konfigurierten
Domains/URL müssen auf der Maschine, auf der Sourcehut läuft, erreichbar sein. Eventuell
müssen diese Domains also in die /etc/hosts-Datei eingetragen werden. Ansonsten
funktioniert die OAuth-Authentifizierung sowie das CI-System nicht.
## Sourcehut-Dienste
Jede einzelne Sourcehut-Anwendung (git.sr.ht, builds.sr.ht, todo.sr.ht, etc) besteht aus
mehreren Diensten. Dazu zählen das Python-Webfrontend, ein in Go geschriebener
API-Server und eventuell noch zusätzliche Dienste wie eine Task Queue.
Die Einrichtung einer Sourcehut-Anwendung erfordert folgende Schritte
1. Installation des Pakets
2. Initialisierung der Datenbank mit dem Skript `<service>-initdb`
3. Starten der Dienste
Bei einigen Diensten sind noch zusätzliche Konfigurationsanpassungen notwendig.
### meta.sr.ht
- Web-UI: Port 5000
- API: Port 5100
meta.sr.ht ist der Dienst zur Nutzerverwaltung und Authentisierung und muss deswegen
zuerst installiert werden.
```
# Paket installieren
apk add meta.sr.ht
# Datenbank initialisieren
metasrht-initdb
# Schlüssel erzeugen und in die Konfigurationsdatei eintragen
# [sr.ht] > service-key
srht-keygen service
# [sr.ht] > network-key
srht-keygen network
# [webhooks] > private-key
srht-keygen webhook
# Dienste starten
rc-update add meta.sr.ht
rc-update add meta.sr.ht-api
rc-update add meta.sr.ht-webhooks
rc-service meta.sr.ht start
rc-service meta.sr.ht-api start
rc-service meta.sr.ht-webhooks start
# Admin-Benutzer erstellen
metasrht-manageuser -t admin -e thetadev@example.com thetadev
# Cronjob hinzufügen
crontab -e
0 0 * * * metasrht-daily
```
Die einzelnen Sourcehut-Dienste verwenden OAuth zur Authentifizierung der Nutzer. Jeder
Dienst muss hierfür über eine eigene Client-Konfiguration verfügen. Diese lässt sich
über das (Legacy) OAuth-Dashboard unter `meta.<Sourcehut-Domain>/oauth` erstellen.
![OAuth-Setup](./assets/sourcehut/oauth.png)
Als _Base Redirect URI_ trägt man die URL des Dienstes mit dem Pfad `oauth/callback`
ein. Beispiel: `https://git.codeforge.int/oauth/callback`.
![OAuth-Registrierung](./assets/sourcehut/oauth_new_client.png)
Die Client-ID und das Client-Secret, das auf der nächsten Seite angezeigt wird, können
nun in die Konfigurationsdatei unter `[<service>.sr.ht]/oauth-client-id` und
`[<service>.sr.ht]/oauth-client-secret` eingetragen werden.
Standardmäßig verlangt Sourcehut nach einer manuellen Einwilligung für die Nutzung eines
OAuth-Diensts. Um die internen Sourcehut-Dienste als vertrauenswürdig zu markieren und
den Einwilligungsbildschirm für neue Nutzer zu deaktivieren, muss man eine manuelle
Änderung an der Datenbank vornehmen und das Feld `preauthorized` für die entsprechenden
OAuth-Clients auf `true` setzen.
```
su postgres
psql
\c "meta.sr.ht"
UPDATE oauthclient SET preauthorized=true;
```
### hub.sr.ht
hub.sr.ht fungiert als Startseite für Sourcehut. Hier kann man Projekte erstellen,
suchen und aufrufen.
- Web-UI: Port 5014
- API: Port 5114
```
# hub.src.ht (Port: 5014, API-Port: 5114)
apk add hub.sr.ht
hubsrht-initdb
rc-update add hub.sr.ht
rc-update add hub.sr.ht-api
rc-service hub.sr.ht-api start
rc-service hub.sr.ht start
```
### git.sr.ht
git.sr.ht ist der eigentliche Git-Hosting-Dienst. Sourcehut bietet auch einen Dienst für
das Versionskontrollsystem Mercurial an, diesen habe ich jedoch nicht getestet.
- Web-UI: Port 5001
- API: Port 5101
```
# Abhängigkeiten für git-http server installieren
apk add git-sr.ht fcgiwrap git-daemon
gitsrht-initdb
```
Diese Zeilen müssen zur `/etc/ssh/sshd_config` hinzugrfügt werden. Dadurch kann der
SSH-Server Nutzer anhand der auf Sourcehut hinterlegten SSH-Zugangsdaten
authentifizieren.
```
AuthorizedKeysCommand=/usr/bin/gitsrht-dispatch "%u" "%h" "%t" "%k"
AuthorizedKeysCommandUser=root
PermitUserEnvironment SRHT_*
```
Da SSH den Login von Nutzern mit nicht gesetztem Passwort verbietet, muss der Account
`git` mit einem beliebigen Passwort versehen werden.
Anschließend muss noch eine Logdatei für das Skript `gitsrht-shell`, dass bei einer
SSH-Verbindung aufgerufen wird, erstellt werden.
```
touch /var/log/gitsrht-shell
chown git:git /var/log/gitsrht-shell
```
Nachdem alles konfiguriert wurde, kann man den Dienst starten und das Skript
`gitsrht-periodic` in den crontab eintragen.
```
rc-update add fcgiwrap
rc-update add git.sr.ht
rc-update add git.sr.ht-api
rc-update add git.sr.ht-webhooks
rc-service fcgiwrap start
rc-service git.sr.ht-webhooks start
rc-service git.sr.ht-api start
rc-service git.sr.ht start
# Cronjob hinzufügen:
*/20 * * * * gitsrht-periodic
```
### man.sr.ht
- Web-UI: Port 5004
- API: Port 5104
man.sr.ht ist ein Git-gestütztes Wiki. Der Dienst hängt von git.sr.ht zur Verwaltung der
Repositories ab.
```
apk add man.sr.ht
mansrht-initdb
rc-update add man.sr.ht
rc-update add man.sr.ht-api
rc-service man.sr.ht-api start
rc-service man.sr.ht start
```
### paste.sr.ht
- Web-UI: Port 5011
- API: Port 5111
paste.sr.ht ist ein simpler Pastebin, mit dem man Codeschnipsel speichern und
veröffentlichen kann.
```
apk add paste.sr.ht
pastesrht-initdb
rc-update add paste.sr.ht
rc-update add paste.sr.ht-api
rc-service paste.sr.ht-api start
rc-service paste.sr.ht start
```
### builds.sr.ht
- Web-UI: Port 5002
- API: Port 5102
builds.sr.ht ist der Continuous-Integration-Dienst von Sourcehut.
Da der Dienst KVM zur Virtualisierung verwendet, muss auf dem Hostsystem _Nested
virtualization_ aktiviert werden, sollte der Dienst selbst in einer KVM-gestützten
virtuellen Maschine installiert werden:
<https://docs.fedoraproject.org/en-US/quick-docs/using-nested-virtualization-in-kvm/>
builds.sr.ht besteht aus zwei Komponenten: dem Master-Server und dem Worker. Der
Master-Server verwaltet die Builds, die Worker führen sie aus. Aus Sicherheitsgründen
wird empfohlen, die Worker auf einem seperaten System zu installieren. Bei meiner
Testinstallation habe ich jedoch beide Komponenten auf dem selben System installiert.
Zuerst installiert man die erforderlichen Pakete und initialisiert die Datenbank:
```
# Master-Server
apk add builds.sr.ht
# Worker-Server
builds.sr.ht-worker builds.sr.ht-images
buildsrht-initdb
```
Der Nutzer `builds` muss genauso wie der git-Nutzer mit einem beliebigen Password
versehen werden, um den SSH-Zugriff auf fehlgeschlagene Builds zu ermöglichen.
Anschließend kann man den Master-Server starten
```
rc-update add builds.sr.ht
rc-update add builds.sr.ht-api
rc-service builds.sr.ht-api start
rc-service builds.sr.ht start
```
Der Worker benutzt standardmäßig eine QEMU-Installation in einem Docker-Container, um
die Build-VMs zu betreiben. Deswegen muss man zuerst Docker installieren und starten.
Zusätzlich sollte man einen neuen Benutzer mit dem Namen `docker` anlegen und der
Docker-Gruppe hinzufügen. Dann konfiguriert man sudo so, dass der `builds`-Nutzer das
`/var/lib/images/control`-Skript zum Start der Buildmaschinen als `docker`-Nutzer
aufrufen kann. Auf diese Weise muss man dem Build-Nutzer keine vollen Root- oder
Docker-Rechte geben.
```
apk add docker
rc-update add docker
rc-service docker start
sudo adduser -SDH docker docker
visudo
# Diese Zeile in die sudoers-Datei eintragen
builds ALL=(docker) NOPASSWD: /var/lib/images/control
```
```
cd /var/lib/images
docker build -t qemu qemu/Dockerfile .
```
Als nächstes muss man die VM-Images bauen. Im Ordner `/var/lib/images` befinden sich
Skripte für eine Vielzahl von Betriebssystemen und CPU-Architekturen.
Ich habe zum Testen das Alpine 3.17-Image in einem Docker-Container gebaut. Dazu musste
ich zunächst eine kleine Annpassung am Buildskript vornehmen. Das Skript unter
`/var/lib/images/alpine/genimg` enthält den Befehl `modprobe nbd max_part=16`, der in
einem Docker-Container nicht ausgeführt werden kann. Dieser Befehl muss deshalb
auskommentiert werden und stattdessen vorher auf dem Hostsystem ausgeführt werden.
Anschließend kann man das Image bauen:
```
modprobe nbd max_part=16
docker run -it --rm --privileged -v /var/lib/images:/images alpine:3.17
# Im Docker-Container
cd /images/alpine/3.17
apk add qemu-img sfdisk syslinux e2fsprogs
./genimg
```
Mit der Datei `/etc/image-control.conf` kann der Worker konfiguriert werden
(zugewiesener Arbeitsspeicher, Methode der Virtualisierung).
```
MEMORY=4096
default_means=docker
```
Nachdem der Worker konfiguriert wurde, kann man ihn mit dem Skript
`/var/lib/images/control` testen.
Hinweis: wenn der Container nicht startet, sollte man prüfen, ob das System genug RAM
zum Start der VM zur Verfügung hat.
```
./control alpine/latest boot x86_64 12345
docker ps # Prüfen, ob der Container gestartet wurde
# Über die SSH-Verbindung kann man nun Befehle auf der Build-VM ausführen
ssh -p 12345 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no build@localhost
./control alpine/latest cleanup 12345
```
Jetzt kann der Worker gestartet werden:
```
# Start worker
rc-update add builds.sr.ht-worker
rc-service builds.sr.ht-worker start
```
### todo.sr.ht
- Web-UI: Port 5003
- API: Port 5103
```
apk add todo.sr.ht
```
Im Gegensatz zu den anderen Diensten konnte ich die Datenbank für den todo-Dienst nicht
mit `todosrht-initdb` erfolgreich initialisieren. Offenbar fehlten in diesem Skript
bestimmte Datenbankobjekte, sodass die Anwendung Fehler lieferte. Stattdessen habe ich
die `schema.sql`-Datei aus dem sourcehut-Repository verwendet.
```
wget "https://git.sr.ht/~sircmpwn/todo.sr.ht/blob/master/schema.sql"
psql -U todo -d todo.sr.ht -f schema.sql
todo-migrate stamp head
```
Anschließend können die Dienste gestartet werden.
Hinweis: Der LMTP-Dienst ist dafür da, E-Mails zu empfangen, sodass man auf Issues per
Mail antworten kann. Hierfür ist ein Mailserver nötig, weswegen ich diesen Dienst in
meiner Testinstallation nicht vollständig konfigurieren konnte.
```
rc-update add todo.sr.ht
rc-update add todo.sr.ht-api
rc-update add todo.sr.ht-lmtp
rc-update add todo.sr.ht-webhooks
rc-service todo.sr.ht-webhooks start
rc-service todo.sr.ht-lmtp start
rc-service todo.sr.ht-api start
rc-service todo.sr.ht start
```
### lists.sr.ht
- Web-UI: Port 5006
- API: Port 5106
lists.sr.ht ist der Mailingslisten-Dienst für Sourcehut. Mangels eines eigenen
Mailservers konnte ich diesen Dienst in meiner Test-VM nicht einrichten.
Eine Anleitung für die Mail-Konfiguration findet sich hier:
<https://man.sr.ht/lists.sr.ht/configuration.md>
```
listssrht-initdb
rc-update add lists.sr.ht
rc-update add lists.sr.ht-api
rc-update add lists.sr.ht-lmtp
rc-update add lists.sr.ht-process
rc-update add lists.sr.ht-webhooks
rc-service lists.sr.ht-webhooks start
rc-service lists.sr.ht-process start
rc-service lists.sr.ht-lmtp start
rc-service lists.sr.ht-api start
rc-service lists.sr.ht start
```