Skip to content

Feat/analytics

Feat/analytics #27

---
name: Production Deploy
on:
pull_request:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
packages: write
concurrency:
group: production-deploy-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
name: Build And Publish Production Image
runs-on: ubuntu-latest
outputs:
image_name: ${{ steps.image.outputs.image_name }}
steps:
- name: Check Out Repository
uses: actions/checkout@v4
- name: Derive Image Name
id: image
run: |
echo "image_name=ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/monsterindex" >> "$GITHUB_OUTPUT"
- name: Prepare Runtime Environment File
env:
APP_KEY: ${{ secrets.APP_KEY }}
GOOGLE_CLIENT_ID: ${{ vars.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
WEBPUSH_VAPID_PRIVATE_KEY: ${{ secrets.WEBPUSH_VAPID_PRIVATE_KEY }}
WEBPUSH_VAPID_PUBLIC_KEY: ${{ vars.WEBPUSH_VAPID_PUBLIC_KEY }}
run: |
set -euo pipefail
runtime_env="/tmp/monsterindex.runtime.env"
cp codebase/.env.production "$runtime_env"
upsert_env() {
local key="$1"
local value="$2"
local file="$3"
local escaped_value
escaped_value="$(printf '%s' "$value" | sed -e 's/[\/&]/\\&/g')"
if grep -q "^${key}=" "$file"; then
sed -i "s|^${key}=.*|${key}=${escaped_value}|" "$file"
else
printf '%s=%s\n' "$key" "$value" >> "$file"
fi
}
app_key="${APP_KEY:-}"
if [ "${GITHUB_EVENT_NAME}" = "push" ] && [ "${GITHUB_REF}" = "refs/heads/main" ] && [ -z "$app_key" ]; then
echo "APP_KEY secret is required for main image builds" >&2
exit 1
fi
: "${app_key:=base64:0/86JhZpPi2WqyHvw6vKbLW17gSmHrxP/mw26Pjvc0M=}"
upsert_env "APP_KEY" "$app_key" "$runtime_env"
upsert_env "GOOGLE_CLIENT_ID" "${GOOGLE_CLIENT_ID:-}" "$runtime_env"
upsert_env "GOOGLE_CLIENT_SECRET" "${GOOGLE_CLIENT_SECRET:-}" "$runtime_env"
upsert_env "WEBPUSH_VAPID_PUBLIC_KEY" "${WEBPUSH_VAPID_PUBLIC_KEY:-}" "$runtime_env"
upsert_env "WEBPUSH_VAPID_PRIVATE_KEY" "${WEBPUSH_VAPID_PRIVATE_KEY:-}" "$runtime_env"
chmod 0600 "$runtime_env"
- name: Set Up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log In To GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate Docker Metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ steps.image.outputs.image_name }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=sha,prefix=sha-
- name: Build Docker Image
uses: docker/build-push-action@v6
with:
context: .
file: ./.docker/production/images/Dockerfile
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
secret-files: |
runtime_env=/tmp/monsterindex.runtime.env
deploy:
name: Deploy To Production
runs-on: ubuntu-latest
needs: build
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && vars.OPS_REPO_DIR != ''
environment:
name: production
url: https://monster.cheapest.promo
steps:
- name: Validate Deploy Configuration
env:
PRODUCTION_HOST: ${{ secrets.PRODUCTION_HOST }}
PRODUCTION_USER: ${{ secrets.PRODUCTION_USER }}
PRODUCTION_SSH_KEY: ${{ secrets.PRODUCTION_SSH_KEY }}
run: |
set -euo pipefail
test -n "${PRODUCTION_HOST:-}" || { echo "PRODUCTION_HOST secret is required"; exit 1; }
test -n "${PRODUCTION_USER:-}" || { echo "PRODUCTION_USER secret is required"; exit 1; }
test -n "${PRODUCTION_SSH_KEY:-}" || { echo "PRODUCTION_SSH_KEY secret is required"; exit 1; }
- name: Deploy Production On VPS
uses: appleboy/ssh-action@v1.2.0
env:
MONSTER_INDEX_IMAGE: ${{ needs.build.outputs.image_name }}:latest
OPS_REPO_DIR: ${{ vars.OPS_REPO_DIR }}
OPS_REPO_REF: ${{ vars.OPS_REPO_REF }}
GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }}
GHCR_PAT: ${{ secrets.GHCR_PAT }}
with:
host: ${{ secrets.PRODUCTION_HOST }}
username: ${{ secrets.PRODUCTION_USER }}
key: ${{ secrets.PRODUCTION_SSH_KEY }}
envs: GHCR_PAT,GHCR_USERNAME,MONSTER_INDEX_IMAGE,OPS_REPO_DIR,OPS_REPO_REF
script: |
set -euo pipefail
cd "${OPS_REPO_DIR}"
git fetch origin
git checkout "${OPS_REPO_REF:-main}"
git pull --ff-only origin "${OPS_REPO_REF:-main}"
if [ -n "${GHCR_USERNAME:-}" ] && [ -n "${GHCR_PAT:-}" ]; then
echo "${GHCR_PAT}" | docker login ghcr.io -u "${GHCR_USERNAME}" --password-stdin
fi
export MONSTER_INDEX_IMAGE
cd monster-index
./deploy.sh