-
Notifications
You must be signed in to change notification settings - Fork 0
133 lines (122 loc) · 4.91 KB
/
Copy pathdeploy.yml
File metadata and controls
133 lines (122 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# =============================================================================
# Deploy to a Linux cloud host over SSH, then: docker compose up -d --build
#
# Prerequisites (SSH user in secrets.SSH_USER)
# * Docker + docker compose v2; that user in the `docker` group
# * A writable app directory — default is **$HOME/kb** on the server
# * The public key half of the deploy key in that user's ~/.ssh/authorized_keys
#
# ------------------------------------------------------------------------------
# GITHUB REPOSITORY SECRETS
# ------------------------------------------------------------------------------
# Required: SERVER_HOST, SSH_USER, SSH_PRIVATE_KEY
# Optional: KNOWN_HOSTS, SSH_PORT (default 22)
# DEPLOY_PATH — Absolute path on the server, e.g. /home/devops/kb. If **unset**,
# the job uses $(ssh 'printf %s $HOME')/kb so the path always matches the
# *actual* home of the login user (avoids "Permission denied" when $HOME
# is not /home/<name> or DEPLOY_PATH was a mistaken placeholder).
# NOT in GitHub: .env (stays on the host; rsync excludes it)
# =============================================================================
name: Deploy to cloud server
on:
workflow_dispatch:
push:
branches: [main]
paths:
- "kb/**"
- "pyproject.toml"
- "Dockerfile"
- "docker-compose.yml"
- ".github/workflows/deploy.yml"
concurrency:
group: deploy-${{ github.ref_name }}
cancel-in-progress: true
# Quieter until checkout/ssh-agent publish Node-24–native major versions
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Check required secrets
run: |
if [ -z "$SERVER_HOST" ] || [ -z "$SSH_USER" ]; then
echo "Set repository secrets SERVER_HOST, SSH_USER, and SSH_PRIVATE_KEY" >&2
exit 1
fi
env:
SERVER_HOST: ${{ secrets.SERVER_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
- name: Checkout
uses: actions/checkout@v4
- name: Start ssh-agent
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Configure known_hosts
run: |
set -euo pipefail
mkdir -p ~/.ssh
chmod 700 ~/.ssh
if [ -n "$KNOWN_BLOB" ]; then
echo "$KNOWN_BLOB" > ~/.ssh/known_hosts
else
PORT="${PORT:-22}"
ssh-keyscan -p "$PORT" -H "$H" >> ~/.ssh/known_hosts 2>/dev/null || { echo "ssh-keyscan failed"; exit 1; }
fi
chmod 600 ~/.ssh/known_hosts
env:
KNOWN_BLOB: ${{ secrets.KNOWN_HOSTS }}
H: ${{ secrets.SERVER_HOST }}
PORT: ${{ secrets.SSH_PORT }}
- name: Resolve remote deploy path
id: rpath
run: |
set -euo pipefail
PORT="${PORT:-22}"
if [ -z "$H" ] || [ -z "$SSH_USER" ]; then echo "Missing H or SSH_USER" >&2; exit 1; fi
RSH="ssh -o BatchMode=yes -o StrictHostKeyChecking=yes -p $PORT"
if [ -n "$DEPLOY_PATH" ]; then
RP="$DEPLOY_PATH"
else
# One SSH as the key user: use real $HOME (avoids wrong /home/<name> and "Permission denied")
RP=$($RSH "$SSH_USER@$H" 'printf %s "$HOME/kb"')
fi
{
echo "remote_path<<__KB_PATH__"
printf '%s\n' "$RP"
echo "__KB_PATH__"
} >> "$GITHUB_OUTPUT"
env:
H: ${{ secrets.SERVER_HOST }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
PORT: ${{ secrets.SSH_PORT }}
SSH_USER: ${{ secrets.SSH_USER }}
- name: Ensure directory, sync, and restart
env:
H: ${{ secrets.SERVER_HOST }}
PORT: ${{ secrets.SSH_PORT }}
SSH_USER: ${{ secrets.SSH_USER }}
REMOTE_PATH: ${{ steps.rpath.outputs.remote_path }}
run: |
set -euo pipefail
PORT="${PORT:-22}"
RP="${REMOTE_PATH:-}"
RSH="ssh -o BatchMode=yes -o StrictHostKeyChecking=yes -p $PORT"
if [ -z "$SSH_USER" ] || [ -z "$H" ] || [ -z "$RP" ]; then
echo "Missing SSH_USER, SERVER_HOST, or resolved path" >&2
exit 1
fi
$RSH "$SSH_USER@$H" "mkdir -p -- \"$RP\""
export RSYNC_RSH="ssh -o BatchMode=yes -o StrictHostKeyChecking=yes -p $PORT"
# rsync: "user@host:/abs/path/"
rsync -avz --delete --checksum \
--filter='P .env' --filter='P .env.*' --filter='P .venv' --filter='P venv' \
--exclude='.git/' \
--exclude='.env' --exclude='.env.*' \
--exclude='.pytest_cache' --exclude='.ruff_cache' --exclude='.mypy_cache' --exclude='__pycache__' \
--exclude='.cursor' --exclude='*.pyc' \
./ "$SSH_USER@$H:$RP/"
$RSH "$SSH_USER@$H" "set -euo pipefail; cd -- \"$RP\" && docker compose up -d --build --wait"