Feat/analytics #27
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| 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 |