Browse Source

Merge pull request #5759 from unacms/ci/railway-port-client

CI: route Railway custom domains to port 8080; pick the client project by domain
Andrey Yasko 2 weeks ago
parent
commit
3cd630b8a3
2 changed files with 25 additions and 11 deletions
  1. 2 3
      .github/workflows/ci.yml
  2. 23 8
      scripts/railway/domains.sh

+ 2 - 3
.github/workflows/ci.yml

@@ -103,7 +103,6 @@ jobs:
       # unacms.app hosts: the backend on Railway, the NEO client (neo-ci on Vercel) in front of it
       VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
       VERCEL_TEAM: yasko
-      CLIENT_PROJECT: una-ci
       PREVIEW_API_HOST: api-pr-${{ github.event.pull_request.number }}.unacms.app
       PREVIEW_CLIENT_HOST: pr-${{ github.event.pull_request.number }}.unacms.app
       UNA_PREVIEW_API_KEY: ${{ secrets.UNA_PREVIEW_API_KEY }}
@@ -306,8 +305,9 @@ jobs:
       run: scripts/railway/domains.sh api-domain api.unacms.app "$RAILWAY_ENVIRONMENT"
 
     - name: Smoke test
+      # A fresh production install takes about 4 minutes; allow 10.
       run: |
-        for i in $(seq 1 30); do
+        for i in $(seq 1 60); do
           code=$(curl -s -o /dev/null -w '%{http_code}' https://api.unacms.app/ || true)
           [ "$code" = "200" ] && { echo "api.unacms.app is up"; exit 0; }
           # Until the certificate is issued, check the Railway hostname instead.
@@ -332,7 +332,6 @@ jobs:
       RAILWAY_PR_ENVIRONMENT: pr-${{ github.event.pull_request.number }}
       VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
       VERCEL_TEAM: yasko
-      CLIENT_PROJECT: una-ci
     steps:
     - uses: actions/checkout@v4
       with:

+ 23 - 8
scripts/railway/domains.sh

@@ -17,6 +17,8 @@ set -euo pipefail
 DNS_ZONE="${DNS_ZONE:-unacms.app}"
 CLIENT_PROJECT="${CLIENT_PROJECT:-}"
 RAILWAY_SERVICE="${RAILWAY_SERVICE:-una}"
+# Apache listens on Railway's $PORT (entrypoint.sh), which Railway sets to 8080.
+RAILWAY_TARGET_PORT="${RAILWAY_TARGET_PORT:-8080}"
 VERCEL_API=https://api.vercel.com
 
 die() { echo "domains.sh: $*" >&2; exit 1; }
@@ -98,11 +100,20 @@ api_domain() { # api_domain <host> <environment>
     label=$(label_of "$host")
     [ -n "${RAILWAY_PROJECT_ID:-}" ] || die "RAILWAY_PROJECT_ID is not set"
 
-    railway domain "$host" --service "$RAILWAY_SERVICE" --environment "$env" --port 80 --json >/dev/null 2>&1 || true
-    id=$(railway domain list --service "$RAILWAY_SERVICE" --environment "$env" --json \
-        | jq -r --arg h "$host" '.domains[] | select(.type == "custom" and .domain == $h) | .id')
+    railway domain "$host" --service "$RAILWAY_SERVICE" --environment "$env" --port "$RAILWAY_TARGET_PORT" --json >/dev/null 2>&1 || true
+    local domains env_id
+    domains=$(railway domain list --service "$RAILWAY_SERVICE" --environment "$env" --json)
+    id=$(jq -r --arg h "$host" '.domains[] | select(.type == "custom" and .domain == $h) | .id' <<< "$domains")
     [ -n "$id" ] || die "Railway did not create $host"
 
+    # Domains created earlier pointed at port 80 and answered 502; keep them on the app's port.
+    if [ "$(jq -r --arg h "$host" '.domains[] | select(.domain == $h) | .targetPort' <<< "$domains")" != "$RAILWAY_TARGET_PORT" ]; then
+        env_id=$(railway status --json | jq -r --arg e "$env" '.environments.edges[].node | select(.name == $e) | .id')
+        railway api 'mutation($id: String!, $environmentId: String!, $port: Int) { customDomainUpdate(id: $id, environmentId: $environmentId, targetPort: $port) }' \
+            --variables "$(jq -nc --arg id "$id" --arg e "$env_id" --argjson p "$RAILWAY_TARGET_PORT" '{id: $id, environmentId: $e, port: $p}')" >/dev/null
+        echo "api: $host now targets port $RAILWAY_TARGET_PORT"
+    fi
+
     status=$(railway api 'query($id: String!, $projectId: String!) { customDomain(id: $id, projectId: $projectId) { status { verificationDnsHost verificationToken dnsRecords { hostlabel recordType requiredValue } } } }' \
         --variables "$(jq -nc --arg id "$id" --arg p "$RAILWAY_PROJECT_ID" '{id: $id, projectId: $p}')")
 
@@ -116,14 +127,18 @@ api_domain() { # api_domain <host> <environment>
     echo "api: https://$host ($label)"
 }
 
-# The client project: CLIENT_PROJECT when it exists, else the project serving DNS_ZONE.
+# The client project: CLIENT_PROJECT when set, else the project that serves DNS_ZONE
+# (by attached domain, so a renamed or similarly named project can't be picked by mistake).
 client_project_id() {
     local id p
-    if [ -n "$CLIENT_PROJECT" ] && id=$(vercel GET "/v9/projects/$CLIENT_PROJECT" 2>/dev/null | jq -r '.id // empty') && [ -n "$id" ]; then
+    if [ -n "$CLIENT_PROJECT" ]; then
+        id=$(vercel GET "/v9/projects/$CLIENT_PROJECT" | jq -r '.id // empty')
+        [ -n "$id" ] || die "Vercel project $CLIENT_PROJECT not found"
         echo "$id"; return
     fi
     for p in $(vercel GET "/v9/projects?limit=100" | jq -r '.projects[].id'); do
         if vercel GET "/v9/projects/$p/domains?limit=100" | jq -e --arg z "$DNS_ZONE" '.domains[] | select(.name == $z or .name == ("www." + $z))' >/dev/null; then
+            echo "client: project $(vercel GET "/v9/projects/$p" | jq -r .name) serves $DNS_ZONE" >&2
             echo "$p"; return
         fi
     done
@@ -138,11 +153,11 @@ client_alias() { # client_alias <host> [branch]
             | jq -r --arg b "$branch" '[.deployments[] | select(.meta.githubCommitRef == $b)] | sort_by(.created) | last | .uid // empty')
     fi
     if [ -n "$uid" ]; then
-        echo "client: $CLIENT_PROJECT branch $branch"
+        echo "client: branch $branch"
     else
         uid=$(vercel GET "/v6/deployments?projectId=$project&target=production&state=READY&limit=1" | jq -r '.deployments[0].uid // empty')
-        [ -n "$uid" ] || die "no ready production deployment of $CLIENT_PROJECT"
-        echo "client: $CLIENT_PROJECT production"
+        [ -n "$uid" ] || die "no ready production deployment of the client project"
+        echo "client: production"
     fi
     vercel POST "/v2/deployments/$uid/aliases" "$(jq -nc --arg a "$host" '{alias: $a}')" >/dev/null
     echo "client: https://$host"