From 1b3b29f5565d92f575b4b9fba4a5f343234af7ad Mon Sep 17 00:00:00 2001 From: samuel Date: Sun, 15 Mar 2026 19:08:39 +0100 Subject: [PATCH] feat: go back to gitea --- .gitea/workflows/cd.yaml | 20 ++--- .gitea/workflows/ci.yaml | 1 - Makefile | 80 ++++++++++++----- README.md | 84 +++++++++++++++++- .../{forgejo/netoik_app.ini => gitea/app.ini} | 26 ++++-- files/img/favicon.png | Bin 0 -> 5644 bytes files/img/favicon.svg | 1 + files/img/logo.png | Bin 0 -> 20079 bytes files/img/logo.svg | 1 + files/systemd/forgejo.conf | 3 - files/systemd/gitea.service | 15 ++++ netoik-git.spec | 77 +++++++++++----- 12 files changed, 238 insertions(+), 70 deletions(-) rename files/{forgejo/netoik_app.ini => gitea/app.ini} (55%) create mode 100644 files/img/favicon.png create mode 100644 files/img/favicon.svg create mode 100644 files/img/logo.png create mode 100644 files/img/logo.svg delete mode 100644 files/systemd/forgejo.conf create mode 100644 files/systemd/gitea.service 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 0000000000000000000000000000000000000000..10121547551d6a7b1c10c2730b899ea2d92a6b85 GIT binary patch literal 5644 zcmd^Cc{J4D-~W)xlI5F1N+!OVkQrlaGYr|cNR~*VVP+UHGiEWvSSm|NX+vLSNs<;( zNwPl@$};xs*$v4=vJA;{hJJnPcfQX#&pE&I{Po;(?z#8rp|Y5W6sCF z2>|Z=@Wa&A`R;5muB`z8|D6p+p6X4%%y})~4;4oM0E9@E$0-0H_J-H_5>>@^1HfiI zypt={)%Gybn-~B=V~Ac@2qS>B9;R=|AfdfaW2qo7tPh@m0)H;40E6%t6xc<}R^66l zg7w8)hLEw2A$CsQA*a0&7_gy%us#FH2p|Pusb~-*z@I=tGEm@kUL=8n17UqK z28VPoHU9x2V{j<2FO^C{LZNgz9YTjgh-4oq41qvE)it0R8fs(=PK^>wprRRS1d1Zq zKv)>G&S8qBc$4uYDxOFH@i@_5L>d(Z1`C6JP#aOHWW3i;b^-;0UiZ*=ArNn302Ga( zKw%Jdo-7bZe*=#+!cchT#wL!~z;$E8^2e|5L_(7(Sf^kT76o>|QiwFNH+G$Y7xaU~ zgp5T~u^0mlbq#Gbb-0?ku0HhNmUw&o9bk&4q79h)18GF69){?>F+pw&rbd>gu0|Gk zV>`-*5xz^HxLX>cZ798VI;H42FQK!(cyIHbQ=>rNxgGnFy%O?N9p-8{f9j`Lh z%b!;hBn%D;gTQ~Bh{QVsjp|Dz8`$HqWHMHt2l$su_&-s=2q68u*WVN{(4=3gk`X}K zs3s!WiAeM}FhLW7&>#%a8}&nV@=CC&Ar|IYM}>Nl>`!PMM9SReZH zduAZ~_ZJaMz@Wfnu%Q8dQ%jIQ+&C&hZYg0LQFEB#OyB?IggAg(! zzAkPFLzYYQ-QpMW=YmFr8>tm(`L_%^o{WFitZ&)Yd;7f_T_jO>^;-&|c&#IVSoyTn zB-?F*_}#Iv|77vBzSRJ+RSimXZ9GqFTZz{0T}nHO2%TPjL}__r8rJd5?jp3N;dY87 zWA|&h@EpOECksvQlFFKH+%Z%z0#n;yqP=04t%;95NZ(!*Ifv*QWE95_ClhX zTYjLu*a>OlI3D8l2=b=EZcTUhL;oI|+7F-Q;hq5^+xy`M7mpVM_a}#oZ-kdC`&<~}JP;DUACn2Qc$`x-gQyDP+&{sET+b{F%#-Kd zD}CA78H(0(P}zP7@9bd<6-QGJ&r7AMd zL!Im*CkSon8F7i>i(AGHA4S_+mnx^l7lOPhr%^Tp!Y-2VLHKW7p%X<%72ZlpZh zb`IG;b^hpOMe-Mg`1=BM>E!#P$~tVlmiADWW|_+Or#XxR`G;%c>&njZZ_AcGZIf5( z2`^hA?`%R}Q&w4d7zGU+eqQZiNocH)oX0;^&U|?+=&^ZsiMDSE%=9$&4ogP%)77_y z4&d_F3XazM^c>3cbt~Uai)%8c=nKl7oQt3QO>_>kjR|^5vTy|G8-PG%wto7O6MuBpBTKKVF;ZJi!L7FOX@matCKtE!4B6A_sY#`p_yeIs zj)eY^Ls!*w?#n-~X1=n8RZA-lfyN6@Ec;wD#m)A|F%(8PT z56FmPSOlW`q2K|r_yc`HZxe6k&iLDByq`SMp_iI786MZW`&x)V6n=}=(pGZf`|xC_ zP4bPKgVVB(8u}8pcd{;8AOAHflZ@)a)t+tHb;i7-L{BE#WSo)3sRN6% zOIG%FfBC{Jf<9d$Uysu8v1Kn$%8~ibu>X?$JUVu4sav|}i(ldWSB5j6YON&9`O;br zu;^*&w>}FU{OeB@+D-O~Xno1$mCX-pg#a4| zdGMQ{N`-~h$S&@Lvcr`T3A@4FK~qw!?omgyF!fJskmgwHH-2Jy&xieb+wip~Bs9f{ zpNvIc-tf_uNbOJ!PvFG57tEP)pr(^L`!2D#)>HTA_4egIie}&EwnQ2~DLK0$5?M83 z|JT%a8V=kl8f}waNFS6I_!2ZF%z-!9%A0k8iu*loJl15!iQWulXY9#eic>q@R&;(v zR2(X2)&;sX-G3#Rt+}HR?4y@6E^>Qn_#j8`-rjviCOZOV?dqD+(uZTL$NDHwVV7y= zl(L#AbA$G|l1|9Z`tMbP%|48M(Rs^G{>#I}{%Yxyy)$(6yGR|g+*ah!>ow>rP)N+! zTA8MM^ALP5*Kb9xLb2YcBkiJH=WLD* zI=5|cAZd0_{{n7uD(u$SH_&PAyiQe)^HkmCE9{_y?rBdTIq?n`JI4L`gWezRIiJ^( zQ`1Q07-o-*(%OOpAAQ(as=Q6EBzyd1ePX_x{)MKd0>kRn3*GTR7^@^fwr0e3tLSFE zEA&l?M{dvVmAcQgc=^#?vu>Odczle@p-ol6(` zEWdp9&A`=`sXC;M8yXOnU)~iGwNO&c zeOZ5`_My3caCxy1*U}bxO2o6M5s@c-rSVy; zHo3!3zE-7|XKGGH3T-G3q263$mm~@A&9*uIayn z9hH9kP1~Nrk+#df;o9}kiC4>l;+%XSh$fc(mVI{R8u?_CH*9sF79=i`z_DNO*(~n(}t9z?KQ*o?zK*HY22m zv)}f;2uKi*NSMlYcp*d_YdiF$rR8p)9A8wA-q>IlAxAuyqj6uu5FOomMDaIcf| z|Hknp57n-Xc11-m#JSrX@ZKaFuN~ot?PluAhniM~k^-4%n`g=UJTBZ~U%4Ih6oDM` z_&C~JS*6`>^du*EqRQPcD@x3B|I5Cu2_Yrt4I6H_K&NX8i^A)dt70tEP}V}W2+i15 zx6^8&QB&D>n`0(FeXemk3@B)pRk zo5z+TUjMyD4SH6{BaiCPd4|^%zt({Ud#J00xos>ltkQwjUhUt1Wx7LnkFP}tf7lr%Kb>8E*cY7yUsct>4SQKA-9%eCJM^&290BP5W|o4d&)+PMQ0iZ5E3y}=z1i|tK(d!><{ z0Xk&L@bH~KYRy{^U=w8tCC{n;f?z`nQ?01+@)3h}RgSHD#mwsye(_yl?F;QaVeQ+3 zBXq(l$l)k7V5)hz$SJ?M~Rs!x4U_coE+7vpWNS%Lq|2ZoS61< z&KY06{4rO%OWrNzh!J}}^hu*M?YZ%dLUP1}TkU}Sa?AAA&K>NY0Kco{P%Vp(OCkg1 zl%081(l-f(<;t5?;`g_v=!c(=zY>=i?Ut=D<%dvv6rqz5G$otV8Tx70z6aC7&tnwD zfVg040c~+)>k^AoFdxP8gr`C}Ob&PSPWyLr8@!bA^I76PK?~J2sJl&E&4Kb^$hYKO z)X--H=17_@avUR+=@}G+)}oEuT)AM{v#!6oP{rs;yP;mDG*K)%k?U#F!)YlO2r z|Gf4x_O4?87pCLfY#KArHS5$n?#^1=Bgj?->U6Ye|?kdB^R4U}pm z)7t`d{1T&gk4z>wDkk)(r;5;exdjB~vA%$D>85*vVV#F004h!OeQqU_Lt#5&!Tf_ \ No newline at end of file diff --git a/files/img/logo.png b/files/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..892f1a6b7f151e37b532ab4b095a9b5cc6431694 GIT binary patch literal 20079 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 literal 0 HcmV?d00001 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