Update .github/workflows/test-deploy.yaml #107
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: 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 |