Skip to content

Commit e27acaf

Browse files
committed
add: deploy scripts
1 parent 71d8cfe commit e27acaf

18 files changed

Lines changed: 2956 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master, main, develop]
6+
pull_request:
7+
branches: [master, main, develop]
8+
9+
env:
10+
GO_VERSION: '1.23'
11+
NODE_VERSION: '20'
12+
13+
jobs:
14+
lint-backend:
15+
name: Lint Backend
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
21+
- name: Set up Go
22+
uses: actions/setup-go@v5
23+
with:
24+
go-version: ${{ env.GO_VERSION }}
25+
26+
- name: Run go fmt
27+
run: |
28+
if [ -n "$(gofmt -l .)" ]; then
29+
echo "Code is not formatted. Run 'go fmt ./...'"
30+
gofmt -d .
31+
exit 1
32+
fi
33+
34+
- name: Run go vet
35+
run: go vet ./...
36+
37+
test-backend:
38+
name: Test Backend
39+
runs-on: ubuntu-latest
40+
steps:
41+
- name: Checkout code
42+
uses: actions/checkout@v4
43+
44+
- name: Set up Go
45+
uses: actions/setup-go@v5
46+
with:
47+
go-version: ${{ env.GO_VERSION }}
48+
49+
- name: Run tests
50+
run: go test -v -race -coverprofile=coverage.out ./internal/...
51+
52+
- name: Upload coverage
53+
uses: actions/upload-artifact@v4
54+
with:
55+
name: coverage
56+
path: coverage.out
57+
58+
build-backend:
59+
name: Build Backend
60+
runs-on: ubuntu-latest
61+
needs: [lint-backend, test-backend]
62+
steps:
63+
- name: Checkout code
64+
uses: actions/checkout@v4
65+
66+
- name: Set up Go
67+
uses: actions/setup-go@v5
68+
with:
69+
go-version: ${{ env.GO_VERSION }}
70+
71+
- name: Build
72+
run: go build -v ./cmd/server
73+
74+
lint-frontend:
75+
name: Lint Frontend
76+
runs-on: ubuntu-latest
77+
steps:
78+
- name: Checkout code
79+
uses: actions/checkout@v4
80+
81+
- name: Set up Node.js
82+
uses: actions/setup-node@v4
83+
with:
84+
node-version: ${{ env.NODE_VERSION }}
85+
cache: 'npm'
86+
cache-dependency-path: web/package-lock.json
87+
88+
- name: Install dependencies
89+
working-directory: web
90+
run: npm ci
91+
92+
- name: Run ESLint
93+
working-directory: web
94+
run: npm run lint --if-present
95+
96+
build-frontend:
97+
name: Build Frontend
98+
runs-on: ubuntu-latest
99+
needs: [lint-frontend]
100+
steps:
101+
- name: Checkout code
102+
uses: actions/checkout@v4
103+
104+
- name: Set up Node.js
105+
uses: actions/setup-node@v4
106+
with:
107+
node-version: ${{ env.NODE_VERSION }}
108+
cache: 'npm'
109+
cache-dependency-path: web/package-lock.json
110+
111+
- name: Install dependencies
112+
working-directory: web
113+
run: npm ci
114+
115+
- name: Build
116+
working-directory: web
117+
run: npm run build
118+
119+
security-scan:
120+
name: Security Scan
121+
runs-on: ubuntu-latest
122+
steps:
123+
- name: Checkout code
124+
uses: actions/checkout@v4
125+
126+
- name: Set up Go
127+
uses: actions/setup-go@v5
128+
with:
129+
go-version: ${{ env.GO_VERSION }}
130+
131+
- name: Run govulncheck
132+
run: |
133+
go install golang.org/x/vuln/cmd/govulncheck@latest
134+
govulncheck ./... || true

.github/workflows/deploy.yml

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
name: Deploy to Ubuntu Server
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
environment:
7+
description: 'Deployment environment'
8+
required: true
9+
default: 'production'
10+
type: choice
11+
options:
12+
- production
13+
- staging
14+
push:
15+
tags:
16+
- 'deploy-*'
17+
18+
env:
19+
GO_VERSION: '1.23'
20+
NODE_VERSION: '20'
21+
BINARY_NAME: 'ocpp-emu'
22+
CONFIG_PATH: '/etc/conf/ocpp-emu.yml'
23+
WEB_PATH: '/var/www/html/ocpp-emu'
24+
SERVICE_NAME: 'ocpp-emu'
25+
26+
jobs:
27+
build:
28+
name: Build Artifacts
29+
runs-on: ubuntu-latest
30+
outputs:
31+
version: ${{ steps.version.outputs.version }}
32+
33+
steps:
34+
- name: Checkout code
35+
uses: actions/checkout@v4
36+
37+
- name: Get version
38+
id: version
39+
run: |
40+
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
41+
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
42+
else
43+
echo "version=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
44+
fi
45+
46+
- name: Set up Go
47+
uses: actions/setup-go@v5
48+
with:
49+
go-version: ${{ env.GO_VERSION }}
50+
51+
- name: Build backend (linux-amd64)
52+
env:
53+
GOOS: linux
54+
GOARCH: amd64
55+
CGO_ENABLED: 0
56+
run: |
57+
go build -ldflags="-s -w -X main.appVersion=${{ steps.version.outputs.version }}" \
58+
-o ${{ env.BINARY_NAME }} \
59+
./cmd/server
60+
61+
- name: Set up Node.js
62+
uses: actions/setup-node@v4
63+
with:
64+
node-version: ${{ env.NODE_VERSION }}
65+
cache: 'npm'
66+
cache-dependency-path: web/package-lock.json
67+
68+
- name: Build frontend
69+
working-directory: web
70+
run: |
71+
npm ci
72+
npm run build
73+
74+
- name: Upload binary artifact
75+
uses: actions/upload-artifact@v4
76+
with:
77+
name: backend-binary
78+
path: ${{ env.BINARY_NAME }}
79+
80+
- name: Upload web artifact
81+
uses: actions/upload-artifact@v4
82+
with:
83+
name: web-dist
84+
path: web/dist
85+
86+
- name: Upload config artifact
87+
uses: actions/upload-artifact@v4
88+
with:
89+
name: config
90+
path: configs/config.yaml
91+
92+
- name: Upload scripts artifact
93+
uses: actions/upload-artifact@v4
94+
with:
95+
name: scripts
96+
path: |
97+
scripts/deploy-ubuntu.sh
98+
scripts/ocpp-emu.service
99+
100+
deploy:
101+
name: Deploy to Server
102+
needs: build
103+
runs-on: ubuntu-latest
104+
environment: ${{ github.event.inputs.environment || 'production' }}
105+
106+
steps:
107+
- name: Download artifacts
108+
uses: actions/download-artifact@v4
109+
with:
110+
path: artifacts
111+
112+
- name: Setup SSH
113+
run: |
114+
mkdir -p ~/.ssh
115+
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key
116+
chmod 600 ~/.ssh/deploy_key
117+
118+
- name: Create deployment package
119+
run: |
120+
mkdir -p deploy
121+
cp artifacts/backend-binary/${{ env.BINARY_NAME }} deploy/
122+
cp -r artifacts/web-dist deploy/web
123+
cp artifacts/config/config.yaml deploy/
124+
cp artifacts/scripts/ocpp-emu.service deploy/
125+
chmod +x deploy/${{ env.BINARY_NAME }}
126+
tar -czvf deploy.tar.gz deploy
127+
128+
- name: Copy files to server
129+
run: |
130+
scp -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no \
131+
deploy.tar.gz \
132+
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/tmp/
133+
134+
- name: Deploy on server
135+
run: |
136+
ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no \
137+
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'DEPLOY_SCRIPT'
138+
139+
set -e
140+
141+
echo "=== Starting deployment ==="
142+
143+
# Extract deployment package
144+
cd /tmp
145+
rm -rf deploy
146+
tar -xzf deploy.tar.gz
147+
cd deploy
148+
149+
# Stop service if running
150+
if systemctl is-active --quiet ${{ env.SERVICE_NAME }} 2>/dev/null; then
151+
echo "Stopping existing service..."
152+
sudo systemctl stop ${{ env.SERVICE_NAME }}
153+
fi
154+
155+
# Install binary
156+
echo "Installing binary..."
157+
sudo cp ${{ env.BINARY_NAME }} /usr/local/bin/
158+
sudo chmod 755 /usr/local/bin/${{ env.BINARY_NAME }}
159+
sudo chown root:root /usr/local/bin/${{ env.BINARY_NAME }}
160+
161+
# Create service user if not exists
162+
if ! id ocpp-emu &>/dev/null; then
163+
echo "Creating service user..."
164+
sudo useradd --system --no-create-home --shell /bin/false ocpp-emu
165+
fi
166+
167+
# Create directories
168+
echo "Creating directories..."
169+
sudo mkdir -p /etc/conf
170+
sudo mkdir -p ${{ env.WEB_PATH }}
171+
sudo mkdir -p /var/log/ocpp-emu
172+
sudo chown ocpp-emu:ocpp-emu /var/log/ocpp-emu
173+
174+
# Install config (only if not exists or forced)
175+
if [ ! -f "${{ env.CONFIG_PATH }}" ]; then
176+
echo "Installing config..."
177+
sudo cp config.yaml ${{ env.CONFIG_PATH }}
178+
sudo chmod 640 ${{ env.CONFIG_PATH }}
179+
sudo chown root:ocpp-emu ${{ env.CONFIG_PATH }}
180+
else
181+
echo "Config exists, preserving existing configuration"
182+
fi
183+
184+
# Install web files
185+
echo "Installing web files..."
186+
sudo rm -rf ${{ env.WEB_PATH }}/*
187+
sudo cp -r web/* ${{ env.WEB_PATH }}/
188+
sudo chown -R www-data:www-data ${{ env.WEB_PATH }}
189+
sudo chmod -R 755 ${{ env.WEB_PATH }}
190+
191+
# Install systemd service
192+
echo "Installing systemd service..."
193+
sudo cp ocpp-emu.service /etc/systemd/system/
194+
sudo systemctl daemon-reload
195+
sudo systemctl enable ${{ env.SERVICE_NAME }}
196+
197+
# Start service
198+
echo "Starting service..."
199+
sudo systemctl start ${{ env.SERVICE_NAME }}
200+
201+
# Verify
202+
sleep 2
203+
if systemctl is-active --quiet ${{ env.SERVICE_NAME }}; then
204+
echo "=== Deployment successful ==="
205+
sudo systemctl status ${{ env.SERVICE_NAME }} --no-pager
206+
else
207+
echo "=== Deployment failed ==="
208+
sudo journalctl -u ${{ env.SERVICE_NAME }} --no-pager -n 30
209+
exit 1
210+
fi
211+
212+
# Cleanup
213+
cd /tmp
214+
rm -rf deploy deploy.tar.gz
215+
216+
echo "=== Done ==="
217+
DEPLOY_SCRIPT
218+
219+
- name: Verify deployment
220+
run: |
221+
ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no \
222+
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'EOF'
223+
224+
echo "Service status:"
225+
sudo systemctl status ${{ env.SERVICE_NAME }} --no-pager || true
226+
227+
echo ""
228+
echo "Checking API health..."
229+
curl -s http://localhost:8080/api/health || echo "API not responding on localhost:8080"
230+
231+
echo ""
232+
echo "Web files:"
233+
ls -la ${{ env.WEB_PATH }}/ | head -10
234+
EOF
235+
236+
notify:
237+
name: Notify
238+
needs: [build, deploy]
239+
runs-on: ubuntu-latest
240+
if: always()
241+
242+
steps:
243+
- name: Deployment summary
244+
run: |
245+
if [ "${{ needs.deploy.result }}" == "success" ]; then
246+
echo "## Deployment Successful" >> $GITHUB_STEP_SUMMARY
247+
echo "" >> $GITHUB_STEP_SUMMARY
248+
echo "- **Version:** ${{ needs.build.outputs.version }}" >> $GITHUB_STEP_SUMMARY
249+
echo "- **Environment:** ${{ github.event.inputs.environment || 'production' }}" >> $GITHUB_STEP_SUMMARY
250+
echo "- **Binary:** /usr/local/bin/${{ env.BINARY_NAME }}" >> $GITHUB_STEP_SUMMARY
251+
echo "- **Config:** ${{ env.CONFIG_PATH }}" >> $GITHUB_STEP_SUMMARY
252+
echo "- **Web App:** ${{ env.WEB_PATH }}" >> $GITHUB_STEP_SUMMARY
253+
else
254+
echo "## Deployment Failed" >> $GITHUB_STEP_SUMMARY
255+
echo "" >> $GITHUB_STEP_SUMMARY
256+
echo "Check the deploy job logs for details." >> $GITHUB_STEP_SUMMARY
257+
fi

0 commit comments

Comments
 (0)