Skip to content

Update .github/workflows/test-deploy.yaml #107

Update .github/workflows/test-deploy.yaml

Update .github/workflows/test-deploy.yaml #107

Workflow file for this run

name: Test Wasp Deploy
on:
push:
paths:
- "waspc/**"
- ".github/**"
branches:
- main
# TODO: remove before merging this PR
- miho-railway-deployment-test-ci
tags:
- v*
workflow_dispatch:
env:
# We use run_id because it's shorter than commit SHA since
# the max length for project name in Railway is 25 characters.
APP_PREFIX: ci-${{ github.run_id }}
FLY_API_TOKEN: ${{ secrets.FLY_GITHUB_TESTING_TOKEN }}
FLY_REGION: mia
FLY_ORG: wasp-testing
RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_GITHUB_TESTING_TOKEN }}
RAILWAY_WASP_WORKSPACE_ID: eb1f9060-40c8-4be0-a372-3a8c9b8bdcf2
APP_TO_DEPLOY: waspc/examples/todoApp
DEPLOY_INFO_DIR: /tmp/deploy-info
CACHE_KEY_PREFIX: deploy-info
jobs:
deploy_app:
name: Deploy app (${{ matrix.provider }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
provider: [fly, railway]
environment:
name: ${{ matrix.provider }}-deploy-test
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-haskell
- uses: actions/setup-node@v4
with:
cache: "npm"
node-version: "22"
- name: Install Wasp CLI
working-directory: waspc
run: ./run install
- name: Install Fly CLI
if: matrix.provider == 'fly'
uses: superfly/flyctl-actions/setup-flyctl@v1
- name: Install Railway CLI
if: matrix.provider == 'railway'
run: npm install -g @railway/cli
- name: Prepare env variables
working-directory: ${{ env.APP_TO_DEPLOY }}
run: |
set -e
# NOTE: This assumes env var values don't contain:
# - The character `#`.
# - An empty line (i.e., there are no multiline env values).
mapfile -t ENV_VAR_ARGUMENTS < <(
cat .env.server.example |
sed -E 's/#.*//' |
awk 'NF {$1=$1;print}' |
sed -E 's/^/--server-secret\n/'
)
# Save into a file so that subsequent steps can use it.
printf '%s\n' "${ENV_VAR_ARGUMENTS[@]}" > .env-args.txt
- name: Deploy app to Fly
if: matrix.provider == 'fly'
working-directory: ${{ env.APP_TO_DEPLOY }}
run: |
set -e
echo "Deploying with prefix: $APP_PREFIX (provider: fly)"
mapfile -t ENV_VAR_ARGUMENTS < .env-args.txt
yes | wasp-cli deploy fly launch "$APP_PREFIX" "$FLY_REGION" --org "$FLY_ORG" "${ENV_VAR_ARGUMENTS[@]}"
- name: Deploy app to Railway
if: matrix.provider == 'railway'
working-directory: ${{ env.APP_TO_DEPLOY }}
run: |
set -e
echo "Deploying with prefix: $APP_PREFIX (provider: railway)"
mapfile -t ENV_VAR_ARGUMENTS < .env-args.txt
wasp-cli deploy railway launch "$APP_PREFIX" --workspace $RAILWAY_WASP_WORKSPACE_ID "${ENV_VAR_ARGUMENTS[@]}"
- name: Get deployed app hostnames (Fly)
if: matrix.provider == 'fly'
working-directory: ${{ env.APP_TO_DEPLOY }}
run: |
set -e
function get_fly_app_hostname() {
config_file="$1"
flyctl status -j -c "$config_file" | jq -r '.Hostname'
}
echo "SERVER_HOSTNAME=$(get_fly_app_hostname fly-server.toml)" >> "$GITHUB_ENV"
echo "CLIENT_HOSTNAME=$(get_fly_app_hostname fly-client.toml)" >> "$GITHUB_ENV"
- name: Get deployed app hostnames (Railway)
if: matrix.provider == 'railway'
working-directory: ${{ env.APP_TO_DEPLOY }}
run: |
set -e
function get_railway_service_hostname() {
service_name="$1"
railway status --json | jq -r --arg NAME "$service_name" '.services.edges[] | select(.node.name == $NAME) | .node.serviceInstances.edges[0].node.domains.serviceDomains[0].domain'
}
server_service_name="${APP_PREFIX}-server"
client_service_name="${APP_PREFIX}-client"
echo "SERVER_HOSTNAME=$(get_railway_service_hostname "$server_service_name")" >> "$GITHUB_ENV"
echo "CLIENT_HOSTNAME=$(get_railway_service_hostname "$client_service_name")" >> "$GITHUB_ENV"
- name: Save deployment info to cache
run: |
set -e
mkdir -p "$DEPLOY_INFO_DIR"
echo "$SERVER_HOSTNAME" > "$DEPLOY_INFO_DIR/server-hostname"
echo "$CLIENT_HOSTNAME" > "$DEPLOY_INFO_DIR/client-hostname"
- name: Cache deployment info
uses: actions/cache/save@v4
with:
path: ${{ env.DEPLOY_INFO_DIR }}
key: ${{ env.CACHE_KEY_PREFIX }}-${{ matrix.provider }}-${{ github.run_id }}
smoke_test_app:
name: Smoke test app (${{ matrix.provider }})
runs-on: ubuntu-latest
needs: deploy_app
strategy:
fail-fast: false
matrix:
provider: [fly, railway]
steps:
- uses: actions/checkout@v4
- name: Restore deployment info
uses: actions/cache/restore@v4
with:
path: ${{ env.DEPLOY_INFO_DIR }}
key: ${{ env.CACHE_KEY_PREFIX }}-${{ matrix.provider }}-${{ github.run_id }}
- name: Load hostnames from cache
run: |
set -e
echo "SERVER_HOSTNAME=$(cat "$DEPLOY_INFO_DIR/server-hostname")" >> "$GITHUB_ENV"
echo "CLIENT_HOSTNAME=$(cat "$DEPLOY_INFO_DIR/client-hostname")" >> "$GITHUB_ENV"
- name: Smoke test deployed app
run: ./scripts/smoke-test-deployed-test-app.sh "$SERVER_HOSTNAME" "$CLIENT_HOSTNAME"
cleanup:
name: Cleanup app (${{ matrix.provider }})
runs-on: ubuntu-latest
if: always()
needs: [deploy_app, smoke_test_app]
strategy:
fail-fast: false
matrix:
provider: [fly, railway]
steps:
- uses: actions/checkout@v4
- name: Prepare Fly CLI for cleanup
if: matrix.provider == 'fly'
uses: superfly/flyctl-actions/setup-flyctl@v1
with:
# NOTE: We pinned the Fly because we don't want the changes in the
# Fly CLI to affect our cleanup procedure. `fly destroy` isn't a part
# of Wasp, we're just incidentally using the same tool Wasp uses.
version: v0.3.164
- name: Clean up testing app from Fly.io
if: matrix.provider == 'fly'
run: |
# NOTE: We are relying on Wasp's naming conventions here
flyctl apps destroy -y $APP_PREFIX-server || true
flyctl apps destroy -y $APP_PREFIX-client || true
flyctl apps destroy -y $APP_PREFIX-db || true
- name: Clean up testing app from Railway
if: matrix.provider == 'railway'
run: |
set -e
function get_railway_project_id() {
local project_name="$1"
curl --silent --request POST \
--url https://backboard.railway.com/graphql/v2 \
--header "Authorization: Bearer $RAILWAY_API_TOKEN" \
--header 'Content-Type: application/json' \
--data "{\"query\":\"query { workspace(workspaceId: \\\"$RAILWAY_WASP_WORKSPACE_ID\\\") { projects { edges { node { id name } } } } }\"}" | \
jq -r --arg PROJECT_NAME "$project_name" '.data.workspace.projects.edges[] | select(.node.name == $PROJECT_NAME) | .node.id'
}
function delete_railway_project() {
local project_id="$1"
curl --request POST \
--url https://backboard.railway.com/graphql/v2 \
--header "Authorization: Bearer $RAILWAY_API_TOKEN" \
--header 'Content-Type: application/json' \
--data "{\"query\":\"mutation { projectDelete(id: \\\"$project_id\\\") }\"}"
}
project_id=$(get_railway_project_id "$APP_PREFIX")
if [ -n "$project_id" ] && [ "$project_id" != "null" ]; then
echo "Found project $APP_PREFIX with ID: $project_id"
delete_railway_project "$project_id"
else
echo "Project $APP_PREFIX not found, skipping cleanup"
fi