summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--mioproxy.prod.hcl10
-rw-r--r--services/repos/.dockerignore1
-rw-r--r--services/repos/Dockerfile51
-rw-r--r--services/repos/Makefile30
-rw-r--r--services/repos/cgit.conf2
-rw-r--r--services/repos/cgitrc17
-rw-r--r--services/repos/compose.yaml13
-rw-r--r--services/repos/httpd-cgit.conf17
-rw-r--r--services/repos/repos.cgitrc441
-rw-r--r--services/repos/repos/.gitignore2
-rwxr-xr-xservices/repos/scripts/clone-repos.sh16
-rwxr-xr-xservices/repos/scripts/fetch-repos.sh12
-rwxr-xr-xservices/repos/scripts/make-repo-list.sh16
14 files changed, 631 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 95779cb9..9c0759a3 100644
--- a/Makefile
+++ b/Makefile
@@ -11,13 +11,16 @@ provision:
.PHONY: build
build:
cd services/blog; make build
+ cd services/repos; make build
.PHONY: serve
serve:
sudo systemctl start mioproxy
cd services/blog; make serve
+ cd services/repos; make serve
.PHONY: clean
clean:
+ cd services/repos; make clean
cd services/blog; make clean
sudo systemctl stop mioproxy
diff --git a/mioproxy.prod.hcl b/mioproxy.prod.hcl
index a9e99051..f3a90622 100644
--- a/mioproxy.prod.hcl
+++ b/mioproxy.prod.hcl
@@ -26,4 +26,14 @@ server https {
port = 8001
}
}
+
+ proxy repos {
+ from {
+ host = "repos.nsfisis.dev"
+ }
+ to {
+ host = "127.0.0.1"
+ port = 8002
+ }
+ }
}
diff --git a/services/repos/.dockerignore b/services/repos/.dockerignore
new file mode 100644
index 00000000..cc2bbd24
--- /dev/null
+++ b/services/repos/.dockerignore
@@ -0,0 +1 @@
+/repos
diff --git a/services/repos/Dockerfile b/services/repos/Dockerfile
new file mode 100644
index 00000000..2734a1ee
--- /dev/null
+++ b/services/repos/Dockerfile
@@ -0,0 +1,51 @@
+ARG BASE_DEBIAN_VERSION=trixie
+ARG APACHE_HTTPD_VERSION=2.4.65
+# NOTE: Use the master branch because the latest release is 6 years ago.
+ARG CGIT_VERSION=master
+
+
+################################################
+FROM debian:$BASE_DEBIAN_VERSION-slim AS builder
+################################################
+
+ARG CGIT_VERSION
+
+RUN apt-get update && \
+ apt-get install -y \
+ build-essential \
+ curl \
+ git \
+ libssl-dev \
+ zlib1g-dev
+
+RUN git clone --branch $CGIT_VERSION https://git.zx2c4.com/cgit /cgit
+
+WORKDIR /cgit
+
+RUN --mount=type=bind,source=./cgit.conf,target=./cgit.conf \
+ make get-git && \
+ make NO_LUA=1 && \
+ make install
+
+
+#####################################################
+FROM httpd:$APACHE_HTTPD_VERSION-$BASE_DEBIAN_VERSION
+#####################################################
+
+COPY --from=builder /var/www/htdocs/cgit/ /usr/local/apache2/htdocs/cgit
+
+RUN apt-get update && \
+ apt-get install -y \
+ zstd && \
+ apt-get clean && \
+ rm -rf /var/lib/apt/lists/*
+
+RUN sed -i \
+ -e 's/^\(\s*\)#\(LoadModule .*mod_cgid.so\)/\1\2/' \
+ -e 's/^\(\s*\)#\(LoadModule .*mod_cgi.so\)/\1\2/' \
+ /usr/local/apache2/conf/httpd.conf && \
+ echo 'Include conf/extra/httpd-cgit.conf' >> /usr/local/apache2/conf/httpd.conf
+
+RUN ln -s /usr/local/apache2/conf/mime.types /etc/mime.types && \
+ mkdir -p /var/cache/cgit && \
+ chown -R www-data:www-data /var/cache/cgit
diff --git a/services/repos/Makefile b/services/repos/Makefile
new file mode 100644
index 00000000..3e684a6d
--- /dev/null
+++ b/services/repos/Makefile
@@ -0,0 +1,30 @@
+.PHONY: all
+all: deploy
+
+.PHONY: deploy
+deploy: clean build serve
+
+.PHONY: build
+build:
+ docker compose build
+ make clone-repos fetch-repos
+
+.PHONY: serve
+serve:
+ docker compose up -d
+
+.PHONY: clean
+clean:
+ docker compose down
+
+.PHONY: make-repo-list
+make-repo-list:
+ scripts/make-repo-list.sh
+
+.PHONY: clone-repos
+clone-repos:
+ scripts/clone-repos.sh
+
+.PHONY: fetch-repos
+fetch-repos:
+ scripts/fetch-repos.sh
diff --git a/services/repos/cgit.conf b/services/repos/cgit.conf
new file mode 100644
index 00000000..bf0af615
--- /dev/null
+++ b/services/repos/cgit.conf
@@ -0,0 +1,2 @@
+CGIT_SCRIPT_PATH = /var/www/htdocs/cgit/cgi
+CGIT_DATA_PATH = /var/www/htdocs/cgit/static
diff --git a/services/repos/cgitrc b/services/repos/cgitrc
new file mode 100644
index 00000000..b6cd830b
--- /dev/null
+++ b/services/repos/cgitrc
@@ -0,0 +1,17 @@
+case-sensitive-sort=0
+cache-size=1024
+clone-url=https://$HTTP_HOST/$CGIT_REPO_URL
+enable-git-config=1
+enable-index-owner=0
+mimetype-file=/etc/mime.types
+readme=:README.md
+readme=:readme.md
+readme=:README.txt
+readme=:readme.txt
+readme=:README
+readme=:readme
+root-desc=nsfisis repositories
+root-title=nsfisis repositories
+snapshots=tar.gz tar.zst zip
+
+include=/etc/repos.cgitrc
diff --git a/services/repos/compose.yaml b/services/repos/compose.yaml
new file mode 100644
index 00000000..511a5dd4
--- /dev/null
+++ b/services/repos/compose.yaml
@@ -0,0 +1,13 @@
+services:
+ cgit:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ ports:
+ - "8002:80"
+ volumes:
+ - ./cgitrc:/etc/cgitrc:ro
+ - ./repos.cgitrc:/etc/repos.cgitrc:ro
+ - ./httpd-cgit.conf:/usr/local/apache2/conf/extra/httpd-cgit.conf:ro
+ - ./repos:/src:ro
+ restart: always
diff --git a/services/repos/httpd-cgit.conf b/services/repos/httpd-cgit.conf
new file mode 100644
index 00000000..196db4d7
--- /dev/null
+++ b/services/repos/httpd-cgit.conf
@@ -0,0 +1,17 @@
+Alias /cgit.css "/usr/local/apache2/htdocs/cgit/static/cgit.css"
+Alias /cgit.js "/usr/local/apache2/htdocs/cgit/static/cgit.js"
+Alias /cgit.png "/usr/local/apache2/htdocs/cgit/static/cgit.png"
+Alias /favicon.ico "/usr/local/apache2/htdocs/cgit/static/favicon.ico"
+Alias /robots.txt "/usr/local/apache2/htdocs/cgit/static/robots.txt"
+<Directory "/usr/local/apache2/htdocs/cgit/static/">
+ AllowOverride None
+ Options None
+ Require all granted
+</Directory>
+
+ScriptAlias / "/usr/local/apache2/htdocs/cgit/cgi/cgit.cgi/"
+<Directory "/usr/local/apache2/htdocs/cgit/cgi/">
+ AllowOverride None
+ Options ExecCGI FollowSymlinks
+ Require all granted
+</Directory>
diff --git a/services/repos/repos.cgitrc b/services/repos/repos.cgitrc
new file mode 100644
index 00000000..5ce9b603
--- /dev/null
+++ b/services/repos/repos.cgitrc
@@ -0,0 +1,441 @@
+repo.url=nsfisis.dev
+repo.path=/src/nsfisis.dev.git
+repo.name=nsfisis.dev
+repo.desc=nsfisis.dev
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/nsfisis.dev
+
+repo.url=feedaka
+repo.path=/src/feedaka.git
+repo.name=feedaka
+repo.desc=feedaka
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/feedaka
+
+repo.url=dotfiles
+repo.path=/src/dotfiles.git
+repo.name=dotfiles
+repo.desc=dotfiles
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/dotfiles
+
+repo.url=phpstudy-N-slides-template
+repo.path=/src/phpstudy-N-slides-template.git
+repo.name=phpstudy-N-slides-template
+repo.desc=phpstudy-N-slides-template
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-N-slides-template
+
+repo.url=php-next-after
+repo.path=/src/php-next-after.git
+repo.name=php-next-after
+repo.desc=php-next-after
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/php-next-after
+
+repo.url=nur-packages
+repo.path=/src/nur-packages.git
+repo.name=nur-packages
+repo.desc=nur-packages
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/nur-packages
+
+repo.url=phpstudy-180-slides
+repo.path=/src/phpstudy-180-slides.git
+repo.name=phpstudy-180-slides
+repo.desc=phpstudy-180-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-180-slides
+
+repo.url=term-clock
+repo.path=/src/term-clock.git
+repo.name=term-clock
+repo.desc=term-clock
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/term-clock
+
+repo.url=php-waddiwasi
+repo.path=/src/php-waddiwasi.git
+repo.name=php-waddiwasi
+repo.desc=php-waddiwasi
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/php-waddiwasi
+
+repo.url=ducc
+repo.path=/src/ducc.git
+repo.name=ducc
+repo.desc=ducc
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/ducc
+
+repo.url=RayTracingInOneWeekend.zig
+repo.path=/src/RayTracingInOneWeekend.zig.git
+repo.name=RayTracingInOneWeekend.zig
+repo.desc=RayTracingInOneWeekend.zig
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/RayTracingInOneWeekend.zig
+
+repo.url=nil.ninja
+repo.path=/src/nil.ninja.git
+repo.name=nil.ninja
+repo.desc=nil.ninja
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/nil.ninja
+
+repo.url=iosdc-japan-2025-albatross
+repo.path=/src/iosdc-japan-2025-albatross.git
+repo.name=iosdc-japan-2025-albatross
+repo.desc=iosdc-japan-2025-albatross
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/iosdc-japan-2025-albatross
+
+repo.url=2048.c
+repo.path=/src/2048.c.git
+repo.name=2048.c
+repo.desc=2048.c
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/2048.c
+
+repo.url=regulus
+repo.path=/src/regulus.git
+repo.name=regulus
+repo.desc=regulus
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/regulus
+
+repo.url=P4Dcc
+repo.path=/src/P4Dcc.git
+repo.name=P4Dcc
+repo.desc=P4Dcc
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/P4Dcc
+
+repo.url=git-helpers
+repo.path=/src/git-helpers.git
+repo.name=git-helpers
+repo.desc=git-helpers
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/git-helpers
+
+repo.url=term-banner
+repo.path=/src/term-banner.git
+repo.name=term-banner
+repo.desc=term-banner
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/term-banner
+
+repo.url=reparojson
+repo.path=/src/reparojson.git
+repo.name=reparojson
+repo.desc=reparojson
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/reparojson
+
+repo.url=kioku
+repo.path=/src/kioku.git
+repo.name=kioku
+repo.desc=kioku
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/kioku
+
+repo.url=tiny-php.wasm
+repo.path=/src/tiny-php.wasm.git
+repo.name=tiny-php.wasm
+repo.desc=tiny-php.wasm
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/tiny-php.wasm
+
+repo.url=zgjq
+repo.path=/src/zgjq.git
+repo.name=zgjq
+repo.desc=zgjq
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/zgjq
+
+repo.url=trick-2025
+repo.path=/src/trick-2025.git
+repo.name=trick-2025
+repo.desc=trick-2025
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/trick-2025
+
+repo.url=phperkaigi-2025-albatross
+repo.path=/src/phperkaigi-2025-albatross.git
+repo.name=phperkaigi-2025-albatross
+repo.desc=phperkaigi-2025-albatross
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phperkaigi-2025-albatross
+
+repo.url=phphp
+repo.path=/src/phphp.git
+repo.name=phphp
+repo.desc=phphp
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phphp
+
+repo.url=PHPerKaigi2025-tokens
+repo.path=/src/PHPerKaigi2025-tokens.git
+repo.name=PHPerKaigi2025-tokens
+repo.desc=PHPerKaigi2025-tokens
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/PHPerKaigi2025-tokens
+
+repo.url=nsfisis.github.io
+repo.path=/src/nsfisis.github.io.git
+repo.name=nsfisis.github.io
+repo.desc=nsfisis.github.io
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/nsfisis.github.io
+
+repo.url=9-puzzle-quine.php
+repo.path=/src/9-puzzle-quine.php.git
+repo.name=9-puzzle-quine.php
+repo.desc=9-puzzle-quine.php
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/9-puzzle-quine.php
+
+repo.url=phpcon-nagoya-2025-slides
+repo.path=/src/phpcon-nagoya-2025-slides.git
+repo.name=phpcon-nagoya-2025-slides
+repo.desc=phpcon-nagoya-2025-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpcon-nagoya-2025-slides
+
+repo.url=big-clock-mode
+repo.path=/src/big-clock-mode.git
+repo.name=big-clock-mode
+repo.desc=big-clock-mode
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/big-clock-mode
+
+repo.url=turbofish-aquarium
+repo.path=/src/turbofish-aquarium.git
+repo.name=turbofish-aquarium
+repo.desc=turbofish-aquarium
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/turbofish-aquarium
+
+repo.url=cohackpp
+repo.path=/src/cohackpp.git
+repo.name=cohackpp
+repo.desc=cohackpp
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/cohackpp
+
+repo.url=phpstudy-169-slides
+repo.path=/src/phpstudy-169-slides.git
+repo.name=phpstudy-169-slides
+repo.desc=phpstudy-169-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-169-slides
+
+repo.url=justfmt.php
+repo.path=/src/justfmt.php.git
+repo.name=justfmt.php
+repo.desc=justfmt.php
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/justfmt.php
+
+repo.url=mncore-challenge
+repo.path=/src/mncore-challenge.git
+repo.name=mncore-challenge
+repo.desc=mncore-challenge
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/mncore-challenge
+
+repo.url=phperkaigi-2024-albatross
+repo.path=/src/phperkaigi-2024-albatross.git
+repo.name=phperkaigi-2024-albatross
+repo.desc=phperkaigi-2024-albatross
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phperkaigi-2024-albatross
+
+repo.url=iosdc-japan-2024-albatross
+repo.path=/src/iosdc-japan-2024-albatross.git
+repo.name=iosdc-japan-2024-albatross
+repo.desc=iosdc-japan-2024-albatross
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/iosdc-japan-2024-albatross
+
+repo.url=rand-word-gen
+repo.path=/src/rand-word-gen.git
+repo.name=rand-word-gen
+repo.desc=rand-word-gen
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/rand-word-gen
+
+repo.url=ya8-2024-slides
+repo.path=/src/ya8-2024-slides.git
+repo.name=ya8-2024-slides
+repo.desc=ya8-2024-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/ya8-2024-slides
+
+repo.url=mioproxy
+repo.path=/src/mioproxy.git
+repo.name=mioproxy
+repo.desc=mioproxy
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/mioproxy
+
+repo.url=phpcon-odawara-2024-slides
+repo.path=/src/phpcon-odawara-2024-slides.git
+repo.name=phpcon-odawara-2024-slides
+repo.desc=phpcon-odawara-2024-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpcon-odawara-2024-slides
+
+repo.url=phpstudy-166-slides
+repo.path=/src/phpstudy-166-slides.git
+repo.name=phpstudy-166-slides
+repo.desc=phpstudy-166-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-166-slides
+
+repo.url=phpstudy-163-slides
+repo.path=/src/phpstudy-163-slides.git
+repo.name=phpstudy-163-slides
+repo.desc=phpstudy-163-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-163-slides
+
+repo.url=phperkaigi-2024-slides
+repo.path=/src/phperkaigi-2024-slides.git
+repo.name=phperkaigi-2024-slides
+repo.desc=phperkaigi-2024-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phperkaigi-2024-slides
+
+repo.url=PHPerKaigi2024-tokens
+repo.path=/src/PHPerKaigi2024-tokens.git
+repo.name=PHPerKaigi2024-tokens
+repo.desc=PHPerKaigi2024-tokens
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/PHPerKaigi2024-tokens
+
+repo.url=pong-wars-quine.rb
+repo.path=/src/pong-wars-quine.rb.git
+repo.name=pong-wars-quine.rb
+repo.desc=pong-wars-quine.rb
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/pong-wars-quine.rb
+
+repo.url=phpstudy-160-slides
+repo.path=/src/phpstudy-160-slides.git
+repo.name=phpstudy-160-slides
+repo.desc=phpstudy-160-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-160-slides
+
+repo.url=phpstudy-157-slides
+repo.path=/src/phpstudy-157-slides.git
+repo.name=phpstudy-157-slides
+repo.desc=phpstudy-157-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-157-slides
+
+repo.url=nuthatch
+repo.path=/src/nuthatch.git
+repo.name=nuthatch
+repo.desc=nuthatch
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/nuthatch
+
+repo.url=nsfisis
+repo.path=/src/nsfisis.git
+repo.name=nsfisis
+repo.desc=nsfisis
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/nsfisis
+
+repo.url=blog.nsfisis.dev
+repo.path=/src/blog.nsfisis.dev.git
+repo.name=blog.nsfisis.dev
+repo.desc=blog.nsfisis.dev
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/blog.nsfisis.dev
+
+repo.url=phpstudy-155-slides
+repo.path=/src/phpstudy-155-slides.git
+repo.name=phpstudy-155-slides
+repo.desc=phpstudy-155-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-155-slides
+
+repo.url=twitter2x-quine
+repo.path=/src/twitter2x-quine.git
+repo.name=twitter2x-quine
+repo.desc=twitter2x-quine
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/twitter2x-quine
+
+repo.url=phpstudy-154-slides
+repo.path=/src/phpstudy-154-slides.git
+repo.name=phpstudy-154-slides
+repo.desc=phpstudy-154-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-154-slides
+
+repo.url=phpconfuk2023-eve-slide
+repo.path=/src/phpconfuk2023-eve-slide.git
+repo.name=phpconfuk2023-eve-slide
+repo.desc=phpconfuk2023-eve-slide
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpconfuk2023-eve-slide
+
+repo.url=phpstudy-153-slides
+repo.path=/src/phpstudy-153-slides.git
+repo.name=phpstudy-153-slides
+repo.desc=phpstudy-153-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-153-slides
+
+repo.url=phpstudy-151-slides
+repo.path=/src/phpstudy-151-slides.git
+repo.name=phpstudy-151-slides
+repo.desc=phpstudy-151-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-151-slides
+
+repo.url=phpstudy-150-slides
+repo.path=/src/phpstudy-150-slides.git
+repo.name=phpstudy-150-slides
+repo.desc=phpstudy-150-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-150-slides
+
+repo.url=PHPerKaigi2023-tokens
+repo.path=/src/PHPerKaigi2023-tokens.git
+repo.name=PHPerKaigi2023-tokens
+repo.desc=PHPerKaigi2023-tokens
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/PHPerKaigi2023-tokens
+
+repo.url=PHPerKaigi2023-slide
+repo.path=/src/PHPerKaigi2023-slide.git
+repo.name=PHPerKaigi2023-slide
+repo.desc=PHPerKaigi2023-slide
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/PHPerKaigi2023-slide
+
+repo.url=phpstudy-149-slides
+repo.path=/src/phpstudy-149-slides.git
+repo.name=phpstudy-149-slides
+repo.desc=phpstudy-149-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-149-slides
+
+repo.url=phpstudy-148-slides
+repo.path=/src/phpstudy-148-slides.git
+repo.name=phpstudy-148-slides
+repo.desc=phpstudy-148-slides
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/phpstudy-148-slides
+
+repo.url=PHPerKaigi2022-tokens
+repo.path=/src/PHPerKaigi2022-tokens.git
+repo.name=PHPerKaigi2022-tokens
+repo.desc=PHPerKaigi2022-tokens
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/PHPerKaigi2022-tokens
+
diff --git a/services/repos/repos/.gitignore b/services/repos/repos/.gitignore
new file mode 100644
index 00000000..d6b7ef32
--- /dev/null
+++ b/services/repos/repos/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/services/repos/scripts/clone-repos.sh b/services/repos/scripts/clone-repos.sh
new file mode 100755
index 00000000..e4ea7ffc
--- /dev/null
+++ b/services/repos/scripts/clone-repos.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+for url in $(grep '^repo\.homepage=' repos.cgitrc | sed 's/^repo\.homepage=//'); do
+ repo_name=$(basename "$url" .git)
+ repo_path="repos/${repo_name}.git"
+
+ if [[ -d "$repo_path" ]]; then
+ echo "Skipping $repo_name"
+ else
+ echo "Cloning $repo_name from $url"
+ git clone --bare "$url" "$repo_path"
+ sleep 5
+ fi
+done
diff --git a/services/repos/scripts/fetch-repos.sh b/services/repos/scripts/fetch-repos.sh
new file mode 100755
index 00000000..e8e9d4ea
--- /dev/null
+++ b/services/repos/scripts/fetch-repos.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+for repo_path in repos/*; do
+ if [[ -d "$repo_path" ]]; then
+ repo_name=$(basename "$repo_path" .git)
+ echo "Fetching $repo_name"
+ git -C "$repo_path" fetch --tags --prune origin
+ sleep 5
+ fi
+done
diff --git a/services/repos/scripts/make-repo-list.sh b/services/repos/scripts/make-repo-list.sh
new file mode 100755
index 00000000..73e7be68
--- /dev/null
+++ b/services/repos/scripts/make-repo-list.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+cat < /dev/null > repos.cgitrc
+for repo in $(gh repo list --limit 999 --source --visibility public --json name --jq '.[].name'); do
+ cat >> repos.cgitrc <<EOS
+repo.url=${repo}
+repo.path=/src/${repo}.git
+repo.name=${repo}
+repo.desc=${repo}
+repo.owner=nsfisis
+repo.homepage=https://github.com/nsfisis/${repo}
+
+EOS
+done