mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-01-19 18:01:09 -05:00
133 lines
5.1 KiB
YAML
133 lines
5.1 KiB
YAML
name: CD - Deploy - API
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
fcc_api_log_level:
|
|
description: 'Log level for the API'
|
|
type: choice
|
|
options:
|
|
- debug
|
|
- info
|
|
- warn
|
|
default: info
|
|
|
|
jobs:
|
|
static:
|
|
name: Set Static Data
|
|
runs-on: ubuntu-22.04
|
|
outputs:
|
|
site_tld: ${{ steps.static_data.outputs.site_tld }}
|
|
environment: ${{ steps.static_data.outputs.environment }}
|
|
fcc_api_log_level: ${{ steps.static_data.outputs.fcc_api_log_level }}
|
|
steps:
|
|
- name: Set Static Data
|
|
id: static_data
|
|
run: |
|
|
if [ "${{ github.ref }}" == "refs/heads/prod-staging" ]; then
|
|
echo "site_tld=dev" >> $GITHUB_OUTPUT
|
|
echo "environment=stg" >> $GITHUB_OUTPUT
|
|
echo "fcc_api_log_level=${{ inputs.fcc_api_log_level || 'info' }}" >> $GITHUB_OUTPUT
|
|
elif [ "${{ github.ref }}" == "refs/heads/prod-current" ]; then
|
|
echo "site_tld=org" >> $GITHUB_OUTPUT
|
|
echo "environment=prd" >> $GITHUB_OUTPUT
|
|
echo "fcc_api_log_level=${{ inputs.fcc_api_log_level || 'info' }}" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "site_tld=dev" >> $GITHUB_OUTPUT
|
|
echo "environment=stg" >> $GITHUB_OUTPUT
|
|
echo "fcc_api_log_level=${{ inputs.fcc_api_log_level || 'info' }}" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
build:
|
|
name: Build & Push
|
|
needs: static
|
|
uses: ./.github/workflows/docker-docr.yml
|
|
with:
|
|
site_tld: ${{ needs.static.outputs.site_tld }}
|
|
app: api
|
|
secrets: inherit
|
|
|
|
deploy:
|
|
name: Deploy to Docker Swarm -- ${{ needs.static.outputs.environment }}
|
|
runs-on: ubuntu-22.04
|
|
needs: [static, build]
|
|
env:
|
|
TS_USERNAME: ${{ secrets.TS_USERNAME }}
|
|
TS_MACHINE_NAME: ${{ secrets.TS_MACHINE_NAME }}
|
|
permissions:
|
|
deployments: write
|
|
environment:
|
|
name: ${{ needs.static.outputs.environment }}
|
|
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 }}
|
|
hostname: gha-${{needs.static.outputs.environment}}-api-ci-${{ github.run_id }}
|
|
tags: tag:ci
|
|
version: latest
|
|
|
|
- name: Configure SSH & Check Connection
|
|
run: |
|
|
mkdir -p ~/.ssh
|
|
echo "Host *
|
|
UserKnownHostsFile=/dev/null
|
|
StrictHostKeyChecking no" > ~/.ssh/config
|
|
chmod 644 ~/.ssh/config
|
|
sleep 10
|
|
tailscale status | grep -q "$TS_MACHINE_NAME" || { echo "Error: Machine not found"; exit 1; }
|
|
sleep 1
|
|
MACHINE_IP=$(tailscale ip -4 $TS_MACHINE_NAME)
|
|
echo -e "\nLOG:Checking connection to $TS_MACHINE_NAME..."
|
|
ssh $TS_USERNAME@$MACHINE_IP "uptime"
|
|
|
|
- name: Deploy with Docker Stack
|
|
env:
|
|
# These are set in the "Environment" specifc secrets
|
|
AGE_ENCRYPTED_ASC_SECRETS: ${{ secrets.AGE_ENCRYPTED_ASC_SECRETS }}
|
|
AGE_SECRET_KEY: ${{ secrets.AGE_SECRET_KEY }}
|
|
# These are set in the static job above
|
|
STACK_NAME: ${{ needs.static.outputs.environment }}-api
|
|
DEPLOYMENT_VERSION: ${{ needs.build.outputs.tagname }}
|
|
FCC_API_LOG_LEVEL: ${{ needs.static.outputs.fcc_api_log_level }}
|
|
run: |
|
|
REMOTE_SCRIPT="
|
|
set -e
|
|
echo -e '\nLOG:Deploying API to \$TS_MACHINE_NAME...'
|
|
cd /home/\${TS_USERNAME}/docker-swarm-config/stacks/api || { echo \"Error: Failed to change directory\"; exit 1; }
|
|
which age > /dev/null || { echo \"Error: age not installed\"; exit 1; }
|
|
|
|
echo -e '\nLOG:Decrypting secrets...'
|
|
echo \"\${AGE_ENCRYPTED_ASC_SECRETS}\" > secrets.age.asc
|
|
echo \"\${AGE_SECRET_KEY}\" > age.key && chmod 600 age.key
|
|
age --identity age.key --decrypt secrets.age.asc > .env
|
|
rm -f age.key secrets.age.asc
|
|
|
|
echo -e '\nLOG:Adding deployment variables...'
|
|
{
|
|
echo \"DEPLOYMENT_VERSION=\${DEPLOYMENT_VERSION}\"
|
|
echo \"FCC_API_LOG_LEVEL=\${FCC_API_LOG_LEVEL}\"
|
|
} >> .env
|
|
|
|
echo -e '\nLOG:Exporting environment variables...'
|
|
while IFS='=' read -r key value; do
|
|
if [[ -n \$key && ! \$key =~ ^# ]]; then
|
|
export \"\${key}=\${value}\"
|
|
fi
|
|
done < .env
|
|
rm -f .env
|
|
|
|
echo -e '\nLOG:Validating environment and config...'
|
|
env | grep -E 'DOMAIN|DEPLOYMENT' || { echo \"Error: Required environment variables not found\"; exit 1; }
|
|
docker stack config -c stack-api.yml > /dev/null || { echo \"Error: Invalid stack configuration\"; exit 1; }
|
|
|
|
echo -e '\nLOG:Deploying stack...'
|
|
docker stack deploy -c stack-api.yml --prune --with-registry-auth --detach=false \${STACK_NAME}
|
|
echo -e '\nLOG:Finished deployment.'
|
|
"
|
|
MACHINE_IP=$(tailscale ip -4 $TS_MACHINE_NAME)
|
|
ssh $TS_USERNAME@$MACHINE_IP "$REMOTE_SCRIPT"
|