Дублирует пайплайны для Gitea Actions (.gitea/workflows/)
Build & Push Image / Build and push to GHCR (push) Failing after 3m1s
Build & Push Image / Build and push Caddy (Cloudflare DNS) image (push) Failing after 11s
CI / fmt + clippy + test (push) Failing after 21m4s

Копии .github/workflows/{ci,build,deploy}.yml — Gitea Actions синтаксически
совместим с GitHub Actions, поэтому большая часть 1:1. Отличие: логин на
ghcr.io в build.yml теперь через secrets.GHCR_TOKEN (настоящий GitHub PAT),
не secrets.GITHUB_TOKEN — автотокен Gitea валиден только для самого Gitea,
на ghcr.io им не залогиниться. deploy.yml уже использовал GHCR_TOKEN,
не тронут в этой части.

Нужно завести в Gitea: секрет GHCR_TOKEN (write:packages), плюс все
остальные секреты, что уже есть в GitHub Actions (отдельное хранилище,
не шарится автоматически). Триггер workflow_run в deploy.yml поддержан не
во всех версиях Gitea Actions — см. комментарий в файле.
This commit is contained in:
2026-07-09 14:28:05 +07:00
parent 7290f9483b
commit e6c81bf8fd
3 changed files with 250 additions and 0 deletions
+98
View File
@@ -0,0 +1,98 @@
# Копия .github/workflows/build.yml для Gitea Actions. Отличие от оригинала:
# логин на ghcr.io использует secrets.GHCR_TOKEN (настоящий GitHub PAT с
# правами write:packages), а не secrets.GITHUB_TOKEN — автотокен Gitea валиден
# только для самого Gitea (API/пакеты этого инстанса), на ghcr.io им не
# залогиниться. Секрет GHCR_TOKEN нужно завести отдельно в настройках этого
# репозитория/организации в Gitea.
name: Build & Push Image
on:
push:
branches: [main]
tags: ["v*"]
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/netrunner-control-plane
jobs:
build:
name: Build and push to GHCR
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha,format=long
type=ref,event=tag
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# Кеш слоёв между прогонами — повторные сборки в разы быстрее.
cache-from: type=gha
cache-to: type=gha,mode=max
# Кастомная сборка Caddy (модуль caddy-dns/cloudflare, нужен для TLS на
# dev-стенде — см. Caddyfile.dev). Компилировать xcaddy'ем прямо на VPS
# оказалось слишком долго и один раз реально уронило SSH-деплой по таймауту
# (компиляция go-модулей на слабой машине не укладывалась в command_timeout
# appleboy/ssh-action) — та же причина, по которой Rust вообще не собирается
# на VPS. Собираем здесь и просто тянем готовый образ, как и основной.
build-caddy:
name: Build and push Caddy (Cloudflare DNS) image
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile.caddy
push: true
# Захардкожено, не ${{ github.repository_owner }}: он резолвится в
# "nineAp" (смешанный регистр), Docker такие теги отклоняет — та же
# причина, по которой deploy.yml тоже хардкодит "nineap" для
# основного образа вместо репозиторного контекста.
tags: ${{ env.REGISTRY }}/nineap/netrunner-caddy-cloudflare:latest
cache-from: type=gha,scope=caddy
cache-to: type=gha,mode=max,scope=caddy
+54
View File
@@ -0,0 +1,54 @@
name: CI
on:
pull_request:
push:
branches: [main]
env:
CARGO_TERM_COLOR: always
SQLX_OFFLINE: "true"
jobs:
check:
name: fmt + clippy + test
runs-on: ubuntu-24.04
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
# sqlx::test сам создаёт временные БД и накатывает ./migrations.
DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache cargo
uses: Swatinem/rust-cache@v2
- name: Format check
run: cargo fmt --all -- --check
- name: Clippy
run: cargo clippy --all-targets -- -D warnings
- name: Tests
run: cargo test --all-targets
+98
View File
@@ -0,0 +1,98 @@
# Копия .github/workflows/deploy.yml для Gitea Actions. secrets.GHCR_TOKEN
# здесь уже был настоящим PAT (не автотокеном), менять не пришлось.
# Триггер workflow_run (авто-деплой после успешной сборки) поддерживается не
# во всех версиях Gitea Actions — если deploy-dev не срабатывает автоматически
# после build, проверить версию Gitea или временно дергать деплой вручную
# через workflow_dispatch.
name: Deploy
# Один пайплайн, две джобы:
# - deploy-dev: авто, срабатывает после успешного "Build & Push Image" на main.
# - deploy-prod: вручную из вкладки Actions ("Run workflow"), как и раньше.
on:
workflow_run:
workflows: ["Build & Push Image"]
types: [completed]
branches: [main]
workflow_dispatch:
inputs:
image_tag:
description: "Тег образа в GHCR для прод-деплоя"
required: true
default: "latest"
jobs:
deploy-dev:
name: Auto-deploy to Dev VPS
if: github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
# Копируем compose-файл + Caddyfile (примонтированный конфиг, не образ —
# сам Caddy-образ, как и образ бэкенда, дев-сервер тянет из GHCR, собран
# в build.yml::build-caddy. Собирать xcaddy прямо на VPS один раз уже не
# уложилось в таймаут SSH-деплоя и уронило весь прогон).
- name: Sync compose file to Dev VPS
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.DEV_VPS_IP }}
username: root
key: ${{ secrets.DEV_SSH_PRIVATE_KEY }}
source: "docker-compose.dev-remote.yml,Caddyfile.dev"
target: "/root/netrunner-core"
strip_components: 0
- name: Remote deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.DEV_VPS_IP }}
username: root
key: ${{ secrets.DEV_SSH_PRIVATE_KEY }}
script: |
set -e
cd /root/netrunner-core
export IMAGE="ghcr.io/nineap/netrunner-control-plane:latest"
export CADDY_IMAGE="ghcr.io/nineap/netrunner-caddy-cloudflare:latest"
echo "🚀 Deploying ${IMAGE} to DEV"
echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
docker compose -f docker-compose.dev-remote.yml pull
docker compose -f docker-compose.dev-remote.yml up -d --remove-orphans
docker image prune -f
echo "✅ Dev synchronized."
deploy-prod:
name: Pull & restart on Prod VPS
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-24.04
steps:
- name: Remote deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.VPS_IP }}
username: root
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
set -e
cd /root/netrunner-core
export IMAGE="ghcr.io/nineap/netrunner-control-plane:${{ github.event.inputs.image_tag }}"
echo "🚀 Deploying ${IMAGE}"
echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
# Тянем свежий образ, прогоняем миграции (one-shot) и поднимаем сервисы.
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d --remove-orphans
# Чистим старые слои.
docker image prune -f
echo "✅ Uplink synchronized."