- 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