71cddd6a91
Manage Telegram instances through Kubernetes with legacy adoption for forust and anna. Build and deploy the panel image alongside the runtime.
359 lines
11 KiB
YAML
359 lines
11 KiB
YAML
name: ci
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- "**"
|
|
pull_request:
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
REGISTRY: gcr.forust.xyz
|
|
|
|
jobs:
|
|
lint-prettier:
|
|
runs-on: [self-hosted, linux, arch, homelab]
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Check formatting with Prettier
|
|
shell: bash
|
|
run: |
|
|
mapfile -t prettier_files < <(
|
|
git ls-files \
|
|
| grep -E '\.(md|json|ya?ml|html|css)$' \
|
|
| grep -Ev '^(\.docs/|\.zed/|errorpages/html/|homepages/(forust_files|xdfnx_files)/)'
|
|
)
|
|
|
|
if [ "${#prettier_files[@]}" -eq 0 ]; then
|
|
echo "No Prettier-managed files found."
|
|
exit 0
|
|
fi
|
|
|
|
docker run --rm \
|
|
-v "$PWD:/work" \
|
|
-w /work \
|
|
node:22-alpine \
|
|
sh -lc 'npx --yes prettier@3 --check --ignore-unknown "$@"' sh "${prettier_files[@]}"
|
|
|
|
lint-ruff:
|
|
runs-on: [self-hosted, linux, arch, homelab]
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Lint Python with Ruff
|
|
shell: bash
|
|
run: |
|
|
docker run --rm \
|
|
-v "$PWD:/work" \
|
|
-w /work \
|
|
ghcr.io/astral-sh/ruff:latest \
|
|
check .
|
|
|
|
lint-yaml:
|
|
runs-on: [self-hosted, linux, arch, homelab]
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Lint YAML syntax
|
|
shell: bash
|
|
run: |
|
|
docker run --rm \
|
|
-v "$PWD:/work" \
|
|
-w /work \
|
|
cytopia/yamllint:latest \
|
|
-c .yamllint .
|
|
|
|
lint-dockerfiles:
|
|
runs-on: [self-hosted, linux, arch, homelab]
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Lint Dockerfiles
|
|
shell: bash
|
|
run: |
|
|
mapfile -t dockerfiles < <(
|
|
git ls-files ':(glob)**/Dockerfile' ':(glob)**/Dockerfile.*'
|
|
)
|
|
|
|
if [ "${#dockerfiles[@]}" -eq 0 ]; then
|
|
echo "No Dockerfiles found."
|
|
exit 0
|
|
fi
|
|
|
|
docker run --rm \
|
|
-v "$PWD:/work" \
|
|
-w /work \
|
|
--entrypoint hadolint \
|
|
hadolint/hadolint:latest-debian \
|
|
-c .hadolint.yaml "${dockerfiles[@]}"
|
|
|
|
validate:
|
|
runs-on: [self-hosted, linux, arch, homelab]
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Validate Kubernetes manifests
|
|
shell: bash
|
|
run: |
|
|
mapfile -t manifests < <(
|
|
git ls-files ':(glob)**/k8s/**/*.yaml' ':(glob)**/k8s/**/*.yml' \
|
|
| grep -Ev '(^|/)(kustomization\.ya?ml|.*\.example\.ya?ml|.*values\.ya?ml|patch-.*\.ya?ml)$'
|
|
)
|
|
|
|
if [ "${#manifests[@]}" -eq 0 ]; then
|
|
echo "No Kubernetes manifests found."
|
|
exit 0
|
|
fi
|
|
|
|
docker run --rm \
|
|
-v "$PWD:/work" \
|
|
-w /work \
|
|
ghcr.io/yannh/kubeconform:latest \
|
|
-strict \
|
|
-ignore-missing-schemas \
|
|
-summary \
|
|
"${manifests[@]}"
|
|
|
|
build:
|
|
needs: [lint-prettier, lint-ruff, lint-yaml, lint-dockerfiles, validate]
|
|
if: github.event_name != 'pull_request' && (github.ref_name == 'main' || github.ref_name == 'dev')
|
|
runs-on: [self-hosted, linux, arch, homelab]
|
|
outputs:
|
|
services: ${{ steps.services.outputs.services }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Detect changed docker-built services
|
|
id: services
|
|
shell: bash
|
|
run: |
|
|
base="${{ github.event.before }}"
|
|
if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ]; then
|
|
base="$(git rev-list --max-parents=0 HEAD)"
|
|
fi
|
|
|
|
mapfile -t changed_files < <(git diff --name-only "$base" "${GITHUB_SHA}")
|
|
|
|
services=()
|
|
|
|
add_service() {
|
|
local name="$1"
|
|
local seen=0
|
|
for existing in "${services[@]}"; do
|
|
if [ "$existing" = "$name" ]; then
|
|
seen=1
|
|
break
|
|
fi
|
|
done
|
|
if [ "$seen" -eq 0 ]; then
|
|
services+=("$name")
|
|
fi
|
|
}
|
|
|
|
for file in "${changed_files[@]}"; do
|
|
case "$file" in
|
|
dtek_notif/*)
|
|
add_service dtek_notif
|
|
;;
|
|
errorpages/*)
|
|
add_service errorpages
|
|
;;
|
|
userbot/*)
|
|
add_service userbot
|
|
;;
|
|
homepages/*)
|
|
add_service homepages
|
|
;;
|
|
edu_master/phpsessid-bot/*|edu_master/webinar-checker/*|edu_master/compose.yaml)
|
|
add_service edu_master
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ "${#services[@]}" -eq 0 ]; then
|
|
echo "No docker-built services changed."
|
|
echo "services=" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
printf '%s\n' "${services[@]}" | tee /tmp/services.txt
|
|
echo "services=$(paste -sd, /tmp/services.txt)" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Log in to registry
|
|
if: steps.services.outputs.services != ''
|
|
shell: bash
|
|
run: |
|
|
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login "${REGISTRY}" \
|
|
-u "${{ secrets.REGISTRY_USERNAME }}" \
|
|
--password-stdin
|
|
|
|
- name: Build and push changed images
|
|
if: steps.services.outputs.services != ''
|
|
shell: bash
|
|
run: |
|
|
IFS=, read -r -a services <<< "${{ steps.services.outputs.services }}"
|
|
|
|
for service in "${services[@]}"; do
|
|
case "$service" in
|
|
dtek_notif)
|
|
image="${REGISTRY}/forust/dtek-notif"
|
|
tags=("latest")
|
|
case "${GITHUB_REF_NAME}" in
|
|
main)
|
|
tags+=("main" "prod")
|
|
;;
|
|
dev)
|
|
tags+=("dev")
|
|
;;
|
|
esac
|
|
build_args=()
|
|
for tag in "${tags[@]}"; do
|
|
build_args+=(-t "${image}:${tag}")
|
|
done
|
|
docker build "${build_args[@]}" dtek_notif
|
|
for tag in "${tags[@]}"; do
|
|
docker push "${image}:${tag}"
|
|
done
|
|
;;
|
|
errorpages)
|
|
image="${REGISTRY}/forust/error-pages"
|
|
tags=("latest")
|
|
case "${GITHUB_REF_NAME}" in
|
|
main)
|
|
tags+=("main" "prod")
|
|
;;
|
|
dev)
|
|
tags+=("dev")
|
|
;;
|
|
esac
|
|
build_args=()
|
|
for tag in "${tags[@]}"; do
|
|
build_args+=(-t "${image}:${tag}")
|
|
done
|
|
docker build "${build_args[@]}" errorpages
|
|
for tag in "${tags[@]}"; do
|
|
docker push "${image}:${tag}"
|
|
done
|
|
;;
|
|
userbot)
|
|
tags=("latest")
|
|
case "${GITHUB_REF_NAME}" in
|
|
main)
|
|
tags+=("main" "prod")
|
|
;;
|
|
dev)
|
|
tags+=("dev")
|
|
;;
|
|
esac
|
|
for target in runtime panel; do
|
|
case "$target" in
|
|
runtime)
|
|
context="userbot"
|
|
image="${REGISTRY}/forust/userbot"
|
|
;;
|
|
panel)
|
|
context="userbot/panel"
|
|
image="${REGISTRY}/forust/userbot-panel"
|
|
;;
|
|
esac
|
|
build_args=()
|
|
for tag in "${tags[@]}"; do
|
|
build_args+=(-t "${image}:${tag}")
|
|
done
|
|
docker build "${build_args[@]}" "$context"
|
|
for tag in "${tags[@]}"; do
|
|
docker push "${image}:${tag}"
|
|
done
|
|
done
|
|
;;
|
|
homepages)
|
|
for service in forust xdfnx; do
|
|
case "$service" in
|
|
forust)
|
|
image="${REGISTRY}/forust/forust-homepage"
|
|
;;
|
|
xdfnx)
|
|
image="${REGISTRY}/forust/xdfnx-homepage"
|
|
;;
|
|
esac
|
|
tags=("latest")
|
|
case "${GITHUB_REF_NAME}" in
|
|
main)
|
|
tags+=("main" "prod")
|
|
;;
|
|
dev)
|
|
tags+=("dev")
|
|
;;
|
|
esac
|
|
build_args=()
|
|
for tag in "${tags[@]}"; do
|
|
build_args+=(-t "${image}:${tag}")
|
|
done
|
|
docker build "${build_args[@]}" -f "homepages/Dockerfile.${service}" homepages
|
|
for tag in "${tags[@]}"; do
|
|
docker push "${image}:${tag}"
|
|
done
|
|
done
|
|
;;
|
|
edu_master)
|
|
for service in session-keeper webinar-checker; do
|
|
case "$service" in
|
|
session-keeper)
|
|
context="edu_master/phpsessid-bot"
|
|
image="${REGISTRY}/forust/session-keeper"
|
|
;;
|
|
webinar-checker)
|
|
context="edu_master/webinar-checker"
|
|
image="${REGISTRY}/forust/webinar-checker"
|
|
;;
|
|
esac
|
|
tags=("latest")
|
|
case "${GITHUB_REF_NAME}" in
|
|
main)
|
|
tags+=("main" "prod")
|
|
;;
|
|
dev)
|
|
tags+=("dev")
|
|
;;
|
|
esac
|
|
build_args=()
|
|
for tag in "${tags[@]}"; do
|
|
build_args+=(-t "${image}:${tag}")
|
|
done
|
|
docker build "${build_args[@]}" "$context"
|
|
for tag in "${tags[@]}"; do
|
|
docker push "${image}:${tag}"
|
|
done
|
|
done
|
|
;;
|
|
esac
|
|
done
|
|
|
|
deploy-userbot-panel:
|
|
needs: build
|
|
if: github.ref_name == 'main' && contains(needs.build.outputs.services, 'userbot')
|
|
runs-on: [self-hosted, linux, arch, homelab, prod]
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Apply and roll out userbot panel
|
|
shell: bash
|
|
run: |
|
|
kubectl apply -f userbot/k8s/base/panel.yaml
|
|
kubectl get secret userbot-common-secrets -n default -o json \
|
|
| jq 'del(.metadata.annotations,.metadata.creationTimestamp,.metadata.resourceVersion,.metadata.uid,.metadata.managedFields) | .metadata.namespace = "userbot"' \
|
|
| kubectl apply -f -
|
|
kubectl apply -f userbot/k8s/base/userbots.yaml
|
|
kubectl rollout restart deployment/userbot-panel -n userbot
|
|
kubectl rollout status deployment/userbot-panel -n userbot --timeout=180s
|