- Add automated deployment workflow configuration - Configure CI/CD pipeline for bc-netts-energy 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
169
.github/workflows/deploy.yaml
vendored
Normal file
169
.github/workflows/deploy.yaml
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
name: Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
APP_NAME: bc-netts-energy
|
||||
BINARY_NAME: netts-energy
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SERVICE_PORT: ${{ secrets.SERVICE_PORT }}
|
||||
NETTS_API_KEY: ${{ secrets.NETTS_API_KEY }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.24"
|
||||
|
||||
- name: Go module cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Run unit tests
|
||||
run: go test ./...
|
||||
|
||||
- name: Build binary
|
||||
run: |
|
||||
mkdir -p build
|
||||
go build -o build/${{ env.BINARY_NAME }} ./cmd/server
|
||||
|
||||
- name: Upload binary to server
|
||||
uses: appleboy/scp-action@v0.1.7
|
||||
with:
|
||||
host: ${{ secrets.SSH_HOST }}
|
||||
port: ${{ secrets.SSH_PORT }}
|
||||
username: ${{ secrets.SSH_USER }}
|
||||
password: ${{ secrets.SSH_PASSWORD }}
|
||||
source: build/${{ env.BINARY_NAME }}
|
||||
target: /tmp
|
||||
|
||||
- name: Deploy on remote host
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: ${{ secrets.SSH_HOST }}
|
||||
port: ${{ secrets.SSH_PORT }}
|
||||
username: ${{ secrets.SSH_USER }}
|
||||
password: ${{ secrets.SSH_PASSWORD }}
|
||||
script_stop: true
|
||||
command_timeout: 30m
|
||||
envs: APP_NAME,BINARY_NAME,SERVICE_PORT,GITHUB_SHA,NETTS_API_KEY
|
||||
script: |
|
||||
set -euo pipefail
|
||||
|
||||
APP_DIR="/opt/${APP_NAME}"
|
||||
RELEASE_ROOT="${APP_DIR}/releases"
|
||||
RELEASE_PATH="${RELEASE_ROOT}/${GITHUB_SHA}"
|
||||
CURRENT_LINK="${APP_DIR}/current"
|
||||
SHARED_DIR="${APP_DIR}/shared"
|
||||
BINARY_PATH="${RELEASE_PATH}/${BINARY_NAME}"
|
||||
REMOTE_TMP="/tmp/${BINARY_NAME}"
|
||||
|
||||
mkdir -p "${RELEASE_ROOT}" "${SHARED_DIR}"
|
||||
|
||||
if [ ! -f "${REMOTE_TMP}" ]; then
|
||||
echo "Binary ${REMOTE_TMP} not found on remote host." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${RELEASE_PATH}"
|
||||
mv "${REMOTE_TMP}" "${BINARY_PATH}"
|
||||
chmod +x "${BINARY_PATH}"
|
||||
|
||||
SERVICE_NAME="${APP_NAME}.service"
|
||||
SERVICE_EXISTS=0
|
||||
if systemctl list-unit-files "${SERVICE_NAME}" >/dev/null 2>&1; then
|
||||
SERVICE_EXISTS=1
|
||||
if systemctl is-active --quiet "${SERVICE_NAME}"; then
|
||||
systemctl stop "${SERVICE_NAME}"
|
||||
fi
|
||||
fi
|
||||
|
||||
TARGET_PORT="${SERVICE_PORT:-8080}"
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
LISTEN_CMD="ss -ltn"
|
||||
elif command -v netstat >/dev/null 2>&1; then
|
||||
LISTEN_CMD="netstat -ltn"
|
||||
else
|
||||
echo "Neither ss nor netstat is available to check port usage." >&2
|
||||
rm -rf "${RELEASE_PATH}"
|
||||
if [ "${SERVICE_EXISTS}" = "1" ]; then
|
||||
systemctl start "${SERVICE_NAME}"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ${LISTEN_CMD} | awk '{print $4}' | grep -q ":${TARGET_PORT}$"; then
|
||||
echo "Port ${TARGET_PORT} is already in use. Deployment aborted." >&2
|
||||
rm -rf "${RELEASE_PATH}"
|
||||
if [ "${SERVICE_EXISTS}" = "1" ]; then
|
||||
systemctl start "${SERVICE_NAME}"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${SHARED_DIR}/config.yaml" ]; then
|
||||
echo "Missing config at ${SHARED_DIR}/config.yaml. Deployment aborted." >&2
|
||||
rm -rf "${RELEASE_PATH}"
|
||||
if [ "${SERVICE_EXISTS}" = "1" ]; then
|
||||
systemctl start "${SERVICE_NAME}"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${NETTS_API_KEY:-}" ]; then
|
||||
echo "NETTS_API_KEY is not provided. Deployment aborted." >&2
|
||||
rm -rf "${RELEASE_PATH}"
|
||||
if [ "${SERVICE_EXISTS}" = "1" ]; then
|
||||
systemctl start "${SERVICE_NAME}"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "/etc/systemd/system/${SERVICE_NAME}" ]; then
|
||||
cat <<EOF > "/etc/systemd/system/${SERVICE_NAME}"
|
||||
[Unit]
|
||||
Description=BC Netts Energy Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${APP_DIR}/current
|
||||
ExecStart=${APP_DIR}/current/${BINARY_NAME} -config ${SHARED_DIR}/config.yaml
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
EnvironmentFile=-/opt/${APP_NAME}/shared/.env
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl enable "${SERVICE_NAME}"
|
||||
else
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
ln -sfn "${RELEASE_PATH}" "${CURRENT_LINK}"
|
||||
|
||||
ENV_FILE="${SHARED_DIR}/.env"
|
||||
cat <<EOF > "${ENV_FILE}"
|
||||
NETTS_API_KEY=${NETTS_API_KEY}
|
||||
EOF
|
||||
chmod 600 "${ENV_FILE}"
|
||||
|
||||
systemctl restart "${SERVICE_NAME}"
|
||||
systemctl --no-pager status "${SERVICE_NAME}"
|
||||
Reference in New Issue
Block a user