diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 217d4de..94f76f7 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -7,21 +7,15 @@ on: jobs: build_n_upload: - runs-on: linux + runs-on: self-hosted steps: - - name: Git checkout - uses: actions/checkout@v6 + - uses: actions/checkout@v6 with: + fetch-depth: 0 fetch-tags: true - - name: Build tarball - run: make tarball + - run: make tarball + - run: rpmbuild -ba "$(make name).spec" + - run: make upload env: - GIT_REFERENCE: ${{ github.ref }} - - name: Build rpm package - run: rpmbuild -ba "$(make name).spec" - - name: Upload rpm package - run: make upload - env: - GIT_PACKAGES_USERNAME: ${{ vars.GIT_PACKAGES_USERNAME }} - GIT_PACKAGES_TOKEN: ${{ secrets.GIT_PACKAGES_TOKEN }} + PKG_TOKEN: ${{ secrets.PKG_TOKEN }} diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 71184a5..fc23cbd 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -18,4 +18,3 @@ jobs: run: make tarball - name: Build rpm file run: rpmbuild -ba "$(make name).spec" - diff --git a/Makefile b/Makefile index b145d94..1acb383 100644 --- a/Makefile +++ b/Makefile @@ -1,57 +1,89 @@ NAME = netoik-git VERSION = $(shell git describe --abbrev=0) RELEASE = $(shell git rev-parse --short HEAD) -REFERENCE = $(if $(GIT_REFERENCE),$(GIT_REFERENCE),$(shell git branch --show-current)) ARCH = noarch OWNER = samuel +SUMMARY = "Netoïk Git server" +LICENSE = "MIT" +URL = "https://git.netoik.io/$(OWNER)/$(NAME)" +SOURCE0 = "$(NAME)-$(VERSION)-$(RELEASE).tar.gz" RPM_RPMDIR = $(shell rpm --eval '%{_rpmdir}') RPM_SBINDIR = $(shell rpm --eval '%{_sbindir}') RPM_SOURCEDIR = $(shell rpm --eval '%{_sourcedir}') -RPM_SHAREDSTATEDIR = $(shell rpm --eval '%{_sharedstatedir}') RPM_SYSCONFDIR = $(shell rpm --eval '%{_sysconfdir}') +RPM_TMPPATH = $(shell rpm --eval '%{_tmppath}') RPM_UNITDIR = $(shell rpm --eval '%{_unitdir}') -RPM_TARBALL_PATH = $(RPM_SOURCEDIR)/$(NAME)-$(VERSION)-$(RELEASE).tar.gz -RPM_BUILD_PATH = $(RPM_RPMDIR)/$(BUILD_ARCH)/$(NAME)-$(VERSION)-$(RELEASE).$(BUILD_ARCH).rpm +RPM_TARBALL_PATH = $(RPM_SOURCEDIR)/$(SOURCE0) +RPM_BUILD_PATH = $(RPM_RPMDIR)/$(ARCH)/$(NAME)-$(VERSION)-$(RELEASE).$(ARCH).rpm + +.PHONY: help +help: + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: name -name: - @echo $(NAME) +name: ## Show project name + @echo "$(NAME)" .PHONY: version -version: - @echo $(VERSION) +version: ## Show current project version + @echo "$(VERSION)" .PHONY: release -release: - @echo $(RELEASE) +release: ## Show current project release + @echo "$(RELEASE)" .PHONY: arch -arch: - @echo $(ARCH) +arch: ## Show rpm arch target + @echo "$(ARCH)" .PHONY: owner -owner: - @echo $(OWNER) +owner: ## Show project owner name + @echo "$(OWNER)" -.PHONY: install -install: - install --mode=755 --directory $(DESTDIR)$(RPM_SYSCONFDIR)/nginx/conf.d $(DESTDIR)$(RPM_SYSCONFDIR)/forgejo/conf $(DESTDIR)$(RPM_UNITDIR)/forgejo.service.d - install --mode=644 --target-directory=$(DESTDIR)$(RPM_SYSCONFDIR)/nginx/conf.d/ files/nginx/git.netoik.io.conf - install --mode=660 --target-directory=$(DESTDIR)$(RPM_SYSCONFDIR)/forgejo/conf files/forgejo/netoik_app.ini - install --mode=644 --target-directory=$(DESTDIR)$(RPM_UNITDIR)/forgejo.service.d files/systemd/forgejo.conf +.PHONY: summary +summary: ## Show project summary + @echo "$(SUMMARY)" + +.PHONY: license +license: ## Show project license + @echo "$(LICENSE)" + +.PHONY: url +url: ## Show project homepage URL + @echo "$(URL)" + +.PHONY: source0 +source0: ## Show rpm source0 file name + @echo "$(SOURCE0)" $(RPM_TARBALL_PATH): * git archive --format=tar.gz \ --output="$@" \ --prefix="$(NAME)-$(VERSION)/" \ --verbose \ - "$(REFERENCE)" + HEAD .PHONY: tarball -tarball: $(RPM_TARBALL_PATH) +tarball: $(RPM_TARBALL_PATH) ## Build rpm tarball + +.PHONY: install +install: ## Install files into rpm dest (requires env var DESTDIR) + @if [ -z "$(DESTDIR)" ]; then \ + printf "[CRITICAL] Missing env var DESTDIR\n[CRITICAL] This command is designed to be called by rpmbuild only!\n" 1>&2; \ + exit 1; \ + fi + install --mode=755 --directory $(DESTDIR)$(RPM_SYSCONFDIR)/nginx/conf.d $(DESTDIR)$(RPM_SYSCONFDIR)/gitea $(DESTDIR)$(RPM_UNITDIR) $(DESTDIR)$(RPM_TMPPATH)/gitea_images + install --mode=644 --target-directory=$(DESTDIR)$(RPM_SYSCONFDIR)/nginx/conf.d files/nginx/git.netoik.io.conf + install --mode=640 --target-directory=$(DESTDIR)$(RPM_SYSCONFDIR)/gitea files/gitea/app.ini + install --mode=644 --target-directory=$(DESTDIR)$(RPM_UNITDIR) files/systemd/gitea.service + install --mode=644 --target-directory=$(DESTDIR)$(RPM_TMPPATH)/gitea_images files/img/* .PHONY: upload -upload: - curl --fail-with-body --upload-file "$(RPM_BUILD_PATH)" --user "$(OWNER):$(GIT_PACKAGES_TOKEN)" https://git.netoik.io/api/packages/$(OWNER)/rpm/upload +upload: ## Upload rpm package to Gitea repository (requires env var PKG_TOKEN) + @if [ -z "$(PKG_TOKEN)" ]; then \ + printf "[CRITICAL] Missing env var PKG_TOKEN\n[CRITICAL] This command is designed to be called by Gitea Actions only!\n" 1>&2; \ + exit 1; \ + fi + curl --fail-with-body --upload-file "$(RPM_BUILD_PATH)" --user "$(OWNER):$(PKG_TOKEN)" https://git.netoik.io/api/packages/$(OWNER)/rpm/upload diff --git a/README.md b/README.md index 44519ba..3f9148a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,83 @@ -# Netoïk Git ![badge](https://git.netoik.io/samuel/netoik-git/actions/workflows/ci.yaml/badge.svg) +# Netoïk Git Server ![badge](https://git.netoik.io/samuel/netoik-git/actions/workflows/ci.yaml/badge.svg) + +Build an RPM package which will install the Git server called Gitea with custom configuration. + +- listen on port 3000 +- reversed by nginx +- rely on postgres for database +- rely on valkey for cache + + +# Development + +A `Makefile` is integrated to let you run some basic commands. + +- Display some information about the project + ```shell + make help + make name + make version + make release + make arch + ``` + +- Build a tarball: + ```shell + make tarball + ``` + +- Build an rpm package: + ```shell + rpmbuild -ba netoik-git.spec + ``` + +- Upload rpm package to Gitea repository (env var `PKG_TOKEN` is required): + ```shell + make upload + ``` + + +# CI / CD + +Two workflows are set up. + +- Continuous Integration: + - triggered by each push event on branch `main` + - builds tarball + - builds rpm package + +- Continuous Delivery: + - triggered by each tag push event + - builds tarball + - builds rpm package + - uploads rpm package to repository + + +# Deployment + +Some commands to deploy the RPM package on server + +- Add Gitea repo to your repo list: + ```shell + dnf config-manager --add-repo https://git.netoik.io/api/packages/samuel/rpm.repo + dnf repolist | grep gitea-samuel + ``` + +- Show available versions: + ```shell + dnf --showduplicates netoik-git + ``` + +- Install or upgrade package: + ```shell + dnf --nogpgcheck --refresh --assumeyes --best install netoik-git + ``` + + +# Security Notes + +For security reasons, act runners does not have sudo privileges and so there is: +- **no** Continuous Deployment because act runners cannot use `dnf` +- **no** GPG signing because act runners cannot use `gpg` + -Build an RPM package which will install the Git UI server called Gitea. diff --git a/files/forgejo/netoik_app.ini b/files/gitea/app.ini similarity index 55% rename from files/forgejo/netoik_app.ini rename to files/gitea/app.ini index aee2cf5..4cd3580 100644 --- a/files/forgejo/netoik_app.ini +++ b/files/gitea/app.ini @@ -1,10 +1,13 @@ # Do not edit this file unless you are aware about what you are doing! # See official doc here: https://docs.gitea.com/next/administration/config-cheat-sheet -APP_NAME = Netoïk Git Server -RUN_USER = forgejo +RUN_USER = gitea RUN_MODE = prod -WORK_PATH = /var/lib/forgejo +WORK_PATH = /var/lib/gitea + +[ui] +THEMES=dark,light,auto +DEFAULT_THEME=auto [server] DOMAIN = git.netoik.io @@ -17,11 +20,24 @@ SSH_PORT = 22222 [database] DB_TYPE = postgres HOST = /run/postgresql -NAME = forgejo -USER = forgejo +NAME = gitea +USER = gitea [security] INSTALL_LOCK = true +SECRET_KEY = $SECRET_KEY +INTERNAL_TOKEN = $INTERNAL_TOKEN [service] DISABLE_REGISTRATION = true + +[cache] +ADAPTER = redis +HOST = redis+socket:///run/valkey/valkey.sock + +[session] +PROVIDER = redis +PROVIDER_CONFIG = redis+socket:///run/valkey/valkey.sock + +[oauth2] +JWT_SECRET = $JWT_SECRET diff --git a/files/img/favicon.png b/files/img/favicon.png new file mode 100644 index 0000000..1012154 Binary files /dev/null and b/files/img/favicon.png differ diff --git a/files/img/favicon.svg b/files/img/favicon.svg new file mode 100644 index 0000000..4331246 --- /dev/null +++ b/files/img/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/files/img/logo.png b/files/img/logo.png new file mode 100644 index 0000000..892f1a6 Binary files /dev/null and b/files/img/logo.png differ diff --git a/files/img/logo.svg b/files/img/logo.svg new file mode 100644 index 0000000..b72dc59 --- /dev/null +++ b/files/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/files/systemd/forgejo.conf b/files/systemd/forgejo.conf deleted file mode 100644 index 9f2b1b7..0000000 --- a/files/systemd/forgejo.conf +++ /dev/null @@ -1,3 +0,0 @@ -[Service] -ExecStart= -ExecStart=/usr/bin/forgejo web --config /etc/forgejo/conf/netoik_app.ini diff --git a/files/systemd/gitea.service b/files/systemd/gitea.service new file mode 100644 index 0000000..2200e8f --- /dev/null +++ b/files/systemd/gitea.service @@ -0,0 +1,15 @@ +[Unit] +Description=Gitea (Git with a cup of tea) +After=network.target postgresql.service valkey.service + +[Service] +RestartSec=2s +Type=simple +User=gitea +Group=gitea +WorkingDirectory=/var/lib/gitea/ +ExecStart=/usr/sbin/gitea web +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/netoik-git.spec b/netoik-git.spec index b18aafa..05b10c3 100644 --- a/netoik-git.spec +++ b/netoik-git.spec @@ -3,17 +3,17 @@ Name: %(make name) Version: %(make version) Release: %(make release) -Summary: Netoik Reverse Proxy -License: MIT -URL: https://git.netoik.io/%(make owner)/%(make name) +Summary: %(make summary) +License: %(make license) +URL: %(make url) -Source0: %{name}-%{version}-%{release}.tar.gz +Source0: %(make source0) Buildarch: %(make arch) BuildRequires: make -Requires: netoik-rp netoik-db netoik-cache forgejo +Requires: netoik-rp netoik-db netoik-cache %description -Install the Git UI server called Forgejo (fork of Gitea). +Install the Git server called Gitea. %prep %autosetup -v @@ -22,35 +22,68 @@ Install the Git UI server called Forgejo (fork of Gitea). %make_install %post -# Change rights on config file -chgrp forgejo %{_sysconfdir}/forgejo/conf/netoik_app.ini +# Download and verify gitea binary +export ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') +wget -O %{_tmppath}/gitea https://dl.gitea.com/gitea/1.25.5/gitea-1.25.5-linux-$ARCH +wget -O %{_tmppath}/gitea.asc https://dl.gitea.com/gitea/1.25.5/gitea-1.25.5-linux-$ARCH.asc +gpg --keyserver hkps://keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2 +gpg --verify %{_tmppath}/gitea.asc %{_tmppath}/gitea +rm %{_tmppath}/gitea.asc +chmod 755 gitea +mv %{_tmppath}/gitea %{_sbindir}/gitea -# Add user forgejo to db groups -usermod --groups postgres,valkey --append forgejo +# Replace secrets in app.ini +export INTERNAL_TOKEN=$(runuser --user=gitea -- gitea generate secret INTERNAL_TOKEN) +export JWT_SECRET=$(runuser --user=gitea -- gitea generate secret JWT_SECRET) +export SECRET_KEY=$(runuser --user=gitea -- gitea generate secret SECRET_TOKEN) +envsubst < %{_sysconfdir}/gitea/app.ini > %{_sysconfdir}/gitea/.app.ini.new +mv %{_sysconfdir}/gitea/.app.ini.new %{_sysconfdir}/gitea/app.ini +chown root:gitea %{_sysconfdir}/gitea/app.ini + +# Create gitea user +useradd --base-dir %{_sharedstatedir} --create-home --shell $SHELL --system gitea +runuser --user=gitea -- mkdir --parents %{_sharedstatedir}/gitea/{custom,data,log} %{_sharedstatedir}/gitea/custom/conf +runuser --user=gitea -- ln --symbolic --force %{_sysconfdir}/gitea/app.ini %{_sharedstatedir}/gitea/custom/conf/app.ini +usermod --groups postgres,valkey --append gitea + +# Add lugit theme +wget -O %{_tmppath}/gitea-lugit-theme.tar.gz https://github.com/lucas-labs/gitea-lugit-theme/releases/download/v1.0.1/gitea-lugit-theme.tar.gz +runuser --user=gitea -- tar --extract --gzip --directory=%{_sharedstatedir}/gitea/custom --file %{_tmppath}/gitea-lugit-theme.tar.gz +runuser --user=gitea -- mv %{_tmppath}/gitea_images/* %{_sharedstatedir}/gitea/custom/public/assets/img +rm --recursive %{_tmppath}/gitea_images # Create postgres user and db -if ! runuser --user=postgres -- psql --quiet --tuples-only --command='\du' | grep --quiet forgejo; then - runuser --user=postgres -- createuser forgejo - runuser --user=postgres -- createdb --owner=forgejo forgejo +if ! runuser --user=postgres -- psql --quiet --tuples-only --command='\du' | grep --quiet gitea; then + runuser --user=postgres -- createuser gitea + runuser --user=postgres -- createdb --owner=gitea gitea fi # Create admin user -if ! runuser --user=forgejo -- forgejo --config %{_sysconfdir}/forgejo/conf/netoik_app.ini admin user list | grep samuel; then - runuser --user=forgejo -- forgejo --config %{_sysconfdir}/forgejo/conf/netoik_app.ini admin user create --username samuel --email "samuel.campos@netoik.io" --admin --random-password --random-password-length 30 --fullname "Samuel Campos" +if ! runuser --user=gitea -- gitea admin user list | grep samuel; then + runuser --user=gitea -- gitea admin user create --username samuel --email "samuel.campos@netoik.io" --admin --random-password --random-password-length 30 --fullname "Samuel Campos" + runuser --user=gitea -- gitea admin user must-change-password samuel fi -# Restart forgejo and nginx services +# Restart gitea and nginx services systemctl daemon-reload -systemctl reenable forgejo.service -systemctl restart forgejo.service -systemctl restart nginx.service +systemctl reenable gitea.service +systemctl restart gitea.service nginx.service + +%postun +if [ $1 == 0 ]; then + userdel --force --remove gitea + runuser --user=postgres -- psql --command='DROP DATABASE gitea; DROP USER gitea;' +fi %files -%attr(660, root, -) %{_sysconfdir}/forgejo/conf/netoik_app.ini +%dir %attr(755, root, root) %{_sysconfdir}/gitea +%attr(640, root, -) %{_sysconfdir}/gitea/app.ini + %attr(644, root, root) %{_sysconfdir}/nginx/conf.d/git.netoik.io.conf -%dir %attr(755, root, root) %{_unitdir}/forgejo.service.d -%attr(644, root, root) %{_unitdir}/forgejo.service.d/forgejo.conf +%attr(644, root, root) %{_unitdir}/gitea.service + +%attr(755, root, root) %{_sbindir}/gitea %changelog %autochangelog