Files
freeCodeCamp/.github/workflows/deploy.yml
2025-02-14 23:31:15 +05:30

139 lines
5.9 KiB
YAML

name: CD -- Deploy - API (Docker Swarm)
on:
workflow_dispatch:
jobs:
static:
runs-on: ubuntu-24.04
outputs:
site_tld: ${{ steps.static_data.outputs.site_tld }}
environment_long: ${{ steps.static_data.outputs.environment_long }}
environment_short: ${{ steps.static_data.outputs.environment_short }}
steps:
- name: Set site_tld
id: static_data
run: |
if [ "${{ github.ref }}" == "refs/heads/prod-staging" ]; then
echo "site_tld=dev" >> $GITHUB_OUTPUT
echo "environment_long=staging" >> $GITHUB_OUTPUT
echo "environment_short=stg" >> $GITHUB_OUTPUT
elif [ "${{ github.ref }}" == "refs/heads/prod-current" ]; then
echo "site_tld=org" >> $GITHUB_OUTPUT
echo "environment_long=production" >> $GITHUB_OUTPUT
echo "environment_short=prd" >> $GITHUB_OUTPUT
else
echo "site_tld=dev" >> $GITHUB_OUTPUT
echo "environment_long=staging" >> $GITHUB_OUTPUT
echo "environment_short=stg" >> $GITHUB_OUTPUT
fi
build:
name: Build & Push Docker Image
needs: static
uses: ./.github/workflows/docker-docr.yml
with:
site_tld: ${{ needs.static.outputs.site_tld }}
app: api
deploy:
runs-on: ubuntu-24.04
needs: [static, build]
permissions:
deployments: write
environment:
name: ${{ needs.static.outputs.environment_long }}
url: https://api.freecodecamp.${{ needs.static.outputs.site_tld }}/status/ping?version=${{ needs.build.outputs.tagname }}
steps:
- name: Setup and connect to Tailscale network
uses: tailscale/github-action@v3
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:ci
version: latest
- name: Configure SSH
# This is a workaround to avoid the SSH warning about known hosts & strict host key checking.
# It's not a problem for us, because we're using Tailscale to connect.
run: |
mkdir -p ~/.ssh
echo "Host *
UserKnownHostsFile=/dev/null
StrictHostKeyChecking no" > ~/.ssh/config
- name: Check connection
run: |
tailscale status | grep -q "$TS_MACHINE_NAME" || { echo "Machine not found"; exit 1; }
ssh $TS_USERNAME@$TS_MACHINE_NAME "uptime"
- name: Deploy with Docker Stack
env:
# These are set in the "Environment" secrets
API_LOCATION: ${{ secrets.API_LOCATION }}
AUTH0_CLIENT_ID: ${{ secrets.AUTH0_CLIENT_ID }}
AUTH0_CLIENT_SECRET: ${{ secrets.AUTH0_CLIENT_SECRET }}
AUTH0_DOMAIN: ${{ secrets.AUTH0_DOMAIN }}
COOKIE_DOMAIN: ${{ secrets.COOKIE_DOMAIN }}
COOKIE_SECRET: ${{ secrets.COOKIE_SECRET }}
DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
FCC_API_LOG_LEVEL: ${{ secrets.FCC_API_LOG_LEVEL }}
GROWTHBOOK_FASTIFY_API_HOST: ${{ secrets.GROWTHBOOK_FASTIFY_API_HOST }}
GROWTHBOOK_FASTIFY_CLIENT_KEY: ${{ secrets.GROWTHBOOK_FASTIFY_CLIENT_KEY }}
HOME_LOCATION: ${{ secrets.HOME_LOCATION }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
MONGOHQ_URL: ${{ secrets.MONGOHQ_URL }}
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
SES_ID: ${{ secrets.SES_ID }}
SES_SECRET: ${{ secrets.SES_SECRET }}
STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }}
# These are set in the static job above
DEPLOYMENT_ENV: ${{ needs.static.outputs.site_tld }}
DEPLOYMENT_VERSION: ${{ needs.build.outputs.tagname }}
SENTRY_ENVIRONMENT: api-${{ needs.static.outputs.site_tld }}
STACK_NAME: ${{ needs.static.outputs.environment_short }}-api
run: |
ssh $TS_USERNAME@$TS_MACHINE_NAME /bin/bash << EOF
cd /home/${TS_USERNAME}/docker-swarm-config/stacks/api || { echo "Failed to change directory"; exit 1; }
echo "Debug: Current directory: \$(pwd)"
echo "API_LOCATION=${API_LOCATION}" >> .env.tmp
echo "AUTH0_CLIENT_ID=${AUTH0_CLIENT_ID}" >> .env.tmp
echo "AUTH0_CLIENT_SECRET=${AUTH0_CLIENT_SECRET}" >> .env.tmp
echo "AUTH0_DOMAIN=${AUTH0_DOMAIN}" >> .env.tmp
echo "COOKIE_DOMAIN=${COOKIE_DOMAIN}" >> .env.tmp
echo "COOKIE_SECRET=${COOKIE_SECRET}" >> .env.tmp
echo "DOCKER_REGISTRY=${DOCKER_REGISTRY}" >> .env.tmp
echo "FCC_API_LOG_LEVEL=${FCC_API_LOG_LEVEL}" >> .env.tmp
echo "GROWTHBOOK_FASTIFY_API_HOST=${GROWTHBOOK_FASTIFY_API_HOST}" >> .env.tmp
echo "GROWTHBOOK_FASTIFY_CLIENT_KEY=${GROWTHBOOK_FASTIFY_CLIENT_KEY}" >> .env.tmp
echo "HOME_LOCATION=${HOME_LOCATION}" >> .env.tmp
echo "JWT_SECRET=${JWT_SECRET}" >> .env.tmp
echo "MONGOHQ_URL=${MONGOHQ_URL}" >> .env.tmp
echo "SENTRY_DSN=${SENTRY_DSN}" >> .env.tmp
echo "SES_ID=${SES_ID}" >> .env.tmp
echo "SES_SECRET=${SES_SECRET}" >> .env.tmp
echo "STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}" >> .env.tmp
echo "DEPLOYMENT_ENV=${DEPLOYMENT_ENV}" >> .env.tmp
echo "DEPLOYMENT_VERSION=${DEPLOYMENT_VERSION}" >> .env.tmp
echo "SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT}" >> .env.tmp
set -a
source .env.tmp || { echo "Failed to source .env.tmp"; exit 1; }
set +a
rm -f .env.tmp
echo "Debug: Sanity check variables: "
env | grep -E '^DEPLOYMENT' || { echo 'Vars not found'; exit 1; }
echo "Debug: Sanity check config: "
docker stack config -c stack-api.yml | rg 'DOMAIN' || { echo 'Invalid stack config'; exit 1; }
# Dump the stack config to a file for debugging, this will be replaced with a deploy command
docker stack config -c stack-api.yml > /tmp/stack-api-${DEPLOYMENT_VERSION}.yml
EOF
shell: bash