ci.yml 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. name: UNA CI
  2. on:
  3. push:
  4. branches: [ "master" ]
  5. pull_request:
  6. branches: [ "master" ]
  7. types: [opened, synchronize, reopened, closed]
  8. permissions:
  9. contents: read
  10. pull-requests: write
  11. # A newer push to a PR, or closing it, cancels that PR's run in progress, so the teardown can't
  12. # race a preview deploy that is still creating the environment. Master pushes never cancel.
  13. concurrency:
  14. group: ci-${{ github.event.pull_request.number && format('pr-{0}', github.event.pull_request.number) || github.sha }}
  15. cancel-in-progress: ${{ github.event_name == 'pull_request' }}
  16. jobs:
  17. test:
  18. if: github.event_name == 'push' || github.event.action != 'closed'
  19. runs-on: ubuntu-latest
  20. services:
  21. mysql:
  22. image: mariadb:11
  23. env:
  24. MYSQL_ROOT_PASSWORD: root
  25. MYSQL_DATABASE: una
  26. MYSQL_USER: una
  27. MYSQL_PASSWORD: una
  28. ports:
  29. - 3306:3306
  30. options: >-
  31. --health-cmd="healthcheck.sh --connect --innodb_initialized"
  32. --health-interval=10s
  33. --health-timeout=5s
  34. --health-retries=10
  35. steps:
  36. - uses: actions/checkout@v4
  37. - name: Setup PHP
  38. uses: shivammathur/setup-php@v2
  39. with:
  40. php-version: '8.3'
  41. extensions: intl, curl, gd, mbstring, zip, exif, pdo_mysql
  42. ini-values: short_open_tag=On, memory_limit=256M
  43. tools: composer, phing, phpunit:12
  44. - name: Setup Node
  45. uses: actions/setup-node@v4
  46. with:
  47. node-version: '24'
  48. cache: yarn
  49. - name: Install PHP dependencies
  50. run: composer install --prefer-dist --no-progress --no-dev
  51. - name: Install JS dependencies
  52. run: yarn install --frozen-lockfile
  53. - name: Prepare writable paths
  54. run: |
  55. mkdir -p cache cache_public logs tmp storage
  56. chmod a+rwX inc cache cache_public logs tmp storage
  57. test -f plugins/ffmpeg/ffmpeg.exe && chmod 0755 plugins/ffmpeg/ffmpeg.exe
  58. - name: Install UNA
  59. working-directory: install
  60. run: >
  61. php cmd.php
  62. -m bx_antispam
  63. --db_host=127.0.0.1
  64. --db_name=una
  65. --db_user=una
  66. --db_password=una
  67. --server_http_host=localhost
  68. --server_php_self=/install/index.php
  69. - name: Run PHPUnit
  70. run: phpunit -c tests/phpunit.xml
  71. - name: Build package
  72. run: phing package -Dbuild=${{ github.run_number }}
  73. - name: Upload package artifact
  74. uses: actions/upload-artifact@v4
  75. with:
  76. name: una-package
  77. path: packages/*.zip
  78. if-no-files-found: error
  79. preview-env:
  80. # Same-repo PRs only: forks and Dependabot get no secrets, and Dependabot PRs need no preview.
  81. name: Prepare PR environment
  82. if: >-
  83. github.event_name == 'pull_request' && github.event.action != 'closed'
  84. && github.event.pull_request.head.repo.full_name == github.repository
  85. && github.event.pull_request.user.login != 'dependabot[bot]'
  86. runs-on: ubuntu-latest
  87. env:
  88. RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
  89. RAILWAY_PROJECT_ID: ${{ secrets.RAILWAY_PROJECT_ID }}
  90. RAILWAY_BASE_ENVIRONMENT: ${{ secrets.RAILWAY_ENVIRONMENT }}
  91. RAILWAY_TEMPLATE_ENVIRONMENT: pr-template
  92. RAILWAY_PR_ENVIRONMENT: pr-${{ github.event.pull_request.number }}
  93. # unacms.app hosts: UNA (service una) and the NEO web client (service neo), both on Railway
  94. VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
  95. VERCEL_TEAM: yasko
  96. PREVIEW_API_HOST: api-pr-${{ github.event.pull_request.number }}.unacms.app
  97. PREVIEW_CLIENT_HOST: pr-${{ github.event.pull_request.number }}.unacms.app
  98. UNA_PREVIEW_API_KEY: ${{ secrets.UNA_PREVIEW_API_KEY }}
  99. outputs:
  100. domains: ${{ steps.domains.outputs.ok }}
  101. steps:
  102. - uses: actions/checkout@v4
  103. with:
  104. sparse-checkout: |
  105. .github/actions
  106. scripts/railway
  107. - uses: ./.github/actions/railway-cli
  108. - name: Provision PR environment
  109. run: |
  110. if [ -z "$RAILWAY_API_TOKEN" ] || [ -z "$RAILWAY_PROJECT_ID" ]; then
  111. echo "Set secrets RAILWAY_API_TOKEN (account token) and RAILWAY_PROJECT_ID" >&2
  112. exit 1
  113. fi
  114. base="${RAILWAY_BASE_ENVIRONMENT:-production}"
  115. template="${RAILWAY_TEMPLATE_ENVIRONMENT:-pr-template}"
  116. railway link --project "$RAILWAY_PROJECT_ID" --environment "$base" --json
  117. # Railway services are project-scoped: mariadb, una and neo already exist, so `railway add`
  118. # cannot create them again and a plain new environment holds no instances of them
  119. # (every preview after the first failed this way). A PR environment therefore gets
  120. # its instances by duplicating the template environment. An environment left over
  121. # from a failed run has no una instance; recreate it.
  122. if ! railway service status --service una --environment "$RAILWAY_PR_ENVIRONMENT" >/dev/null 2>&1; then
  123. railway environment delete "$RAILWAY_PR_ENVIRONMENT" -y >/dev/null 2>&1 || true
  124. railway environment new "$RAILWAY_PR_ENVIRONMENT" --duplicate "$template" --json
  125. # a duplicate may carry the template's deployments; the builds below replace them
  126. railway down --service una --environment "$RAILWAY_PR_ENVIRONMENT" -y >/dev/null 2>&1 || true
  127. railway down --service neo --environment "$RAILWAY_PR_ENVIRONMENT" -y >/dev/null 2>&1 || true
  128. fi
  129. railway link --project "$RAILWAY_PROJECT_ID" --environment "$RAILWAY_PR_ENVIRONMENT" --json
  130. # An environment duplicated before the neo service existed lacks it.
  131. scripts/railway/neo.sh instance "$RAILWAY_PR_ENVIRONMENT"
  132. # The duplicated una instance is what `railway up` deploys into. Setting its variables
  133. # doubles as the readiness check: it fails with "ServiceInstance not found" until it exists.
  134. for i in $(seq 1 12); do
  135. railway variable set --service una --environment "$RAILWAY_PR_ENVIRONMENT" --skip-deploys \
  136. MYSQLHOST=mariadb.railway.internal \
  137. MYSQLPORT=3306 \
  138. MYSQLDATABASE=una \
  139. MYSQLUSER=una \
  140. MYSQLPASSWORD=una \
  141. UNA_DEMO_SEED=1 \
  142. UNA_CLIENT_URL="https://$PREVIEW_CLIENT_HOST" \
  143. ${UNA_PREVIEW_API_KEY:+UNA_API_KEY="$UNA_PREVIEW_API_KEY"} \
  144. && break
  145. sleep 5
  146. done
  147. railway domain --service una --environment "$RAILWAY_PR_ENVIRONMENT" || true
  148. railway domain --service neo --environment "$RAILWAY_PR_ENVIRONMENT" || true
  149. # NEO talks to this PR's UNA through its Railway domain, which has a certificate from
  150. # the start (the api-pr host gets one minutes later). UNA_AUTO_HOSTNAME makes UNA build
  151. # its URLs from that host.
  152. una_host=$(railway domain list --service una --environment "$RAILWAY_PR_ENVIRONMENT" --json | jq -r '.domains[] | select(.type == "service") | .domain' | head -n1)
  153. [ -n "$una_host" ] || { echo "No Railway domain for una" >&2; exit 1; }
  154. scripts/railway/neo.sh vars "$RAILWAY_PR_ENVIRONMENT" "https://${una_host#https://}" "https://$PREVIEW_CLIENT_HOST"
  155. - name: Preview domains on unacms.app
  156. id: domains
  157. if: env.VERCEL_TOKEN != ''
  158. run: |
  159. scripts/railway/domains.sh railway-domain "$PREVIEW_API_HOST" "$RAILWAY_PR_ENVIRONMENT" una
  160. # Until 2026-10 the client host was a Vercel alias of the neo-ci build; drop it if present.
  161. scripts/railway/domains.sh client-unalias "$PREVIEW_CLIENT_HOST"
  162. scripts/railway/domains.sh railway-domain "$PREVIEW_CLIENT_HOST" "$RAILWAY_PR_ENVIRONMENT" neo
  163. echo "ok=1" >> "$GITHUB_OUTPUT"
  164. deploy:
  165. name: Deploy PR to Railway (una)
  166. needs: [test, preview-env]
  167. runs-on: ubuntu-latest
  168. env:
  169. RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
  170. RAILWAY_PROJECT_ID: ${{ secrets.RAILWAY_PROJECT_ID }}
  171. RAILWAY_PR_ENVIRONMENT: pr-${{ github.event.pull_request.number }}
  172. steps:
  173. - uses: actions/checkout@v4
  174. - uses: actions/download-artifact@v4
  175. with:
  176. name: una-package
  177. path: packages
  178. - name: Prepare artefact
  179. run: |
  180. mkdir -p deploy
  181. unzip -q packages/*.zip -d /tmp/una-pkg
  182. pkg_dir=$(find /tmp/una-pkg -mindepth 1 -maxdepth 1 -type d | head -n 1)
  183. cp -a "$pkg_dir"/. deploy/
  184. cp scripts/railway/Dockerfile scripts/railway/entrypoint.sh scripts/railway/railway.toml scripts/railway/.railwayignore \
  185. scripts/railway/configure.php scripts/railway/seed.php deploy/
  186. chmod +x deploy/entrypoint.sh
  187. - uses: ./.github/actions/railway-cli
  188. - name: Deploy artefact
  189. run: railway up ./deploy --path-as-root --no-gitignore --verbose --ci --service una --environment "$RAILWAY_PR_ENVIRONMENT" --project "$RAILWAY_PROJECT_ID"
  190. deploy-neo:
  191. # NEO isn't covered by `test`, so it builds alongside it.
  192. name: Deploy PR to Railway (neo)
  193. needs: preview-env
  194. runs-on: ubuntu-latest
  195. env:
  196. RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
  197. RAILWAY_PROJECT_ID: ${{ secrets.RAILWAY_PROJECT_ID }}
  198. RAILWAY_PR_ENVIRONMENT: pr-${{ github.event.pull_request.number }}
  199. steps:
  200. - uses: actions/checkout@v4
  201. - uses: ./.github/actions/railway-cli
  202. - name: Deploy NEO
  203. run: |
  204. scripts/railway/neo.sh stage /tmp/deploy-neo
  205. railway up /tmp/deploy-neo --path-as-root --no-gitignore --verbose --ci --service neo --environment "$RAILWAY_PR_ENVIRONMENT" --project "$RAILWAY_PROJECT_ID"
  206. preview-comment:
  207. name: Comment preview URLs
  208. needs: [preview-env, deploy, deploy-neo]
  209. if: always() && needs.preview-env.result == 'success'
  210. runs-on: ubuntu-latest
  211. env:
  212. RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
  213. RAILWAY_PROJECT_ID: ${{ secrets.RAILWAY_PROJECT_ID }}
  214. RAILWAY_PR_ENVIRONMENT: pr-${{ github.event.pull_request.number }}
  215. PREVIEW_API_HOST: api-pr-${{ github.event.pull_request.number }}.unacms.app
  216. PREVIEW_CLIENT_HOST: pr-${{ github.event.pull_request.number }}.unacms.app
  217. DOMAINS_OK: ${{ needs.preview-env.outputs.domains }}
  218. UNA_RESULT: ${{ needs.deploy.result }}
  219. NEO_RESULT: ${{ needs.deploy-neo.result }}
  220. GH_TOKEN: ${{ github.token }}
  221. PR_NUMBER: ${{ github.event.pull_request.number }}
  222. steps:
  223. - uses: actions/checkout@v4
  224. with:
  225. sparse-checkout: .github/actions
  226. - uses: ./.github/actions/railway-cli
  227. - name: Comment preview URLs on PR
  228. run: |
  229. railway link --project "$RAILWAY_PROJECT_ID" --environment "$RAILWAY_PR_ENVIRONMENT" --json >/dev/null
  230. service_url() {
  231. local host
  232. host=$(railway domain list --service "$1" --environment "$RAILWAY_PR_ENVIRONMENT" --json | jq -r '.domains[] | select(.type == "service") | .domain' | head -n1)
  233. [ -n "$host" ] && echo "https://${host#https://}"
  234. }
  235. una_url=$(service_url una || true)
  236. neo_url=$(service_url neo || true)
  237. state() { [ "$1" = success ] && echo "" || echo " (deploy: $1)"; }
  238. marker="<!-- railway-preview -->"
  239. if [ "$DOMAINS_OK" = "1" ]; then
  240. body=$(printf '%s\n**Preview**: https://%s (NEO web client%s, also %s)\n**API**: https://%s (UNA%s, also %s)\n\nRailway environment: `%s`. A new custom domain needs a few minutes for its certificate, and a fresh UNA install about 10.' \
  241. "$marker" "$PREVIEW_CLIENT_HOST" "$(state "$NEO_RESULT")" "$neo_url" "$PREVIEW_API_HOST" "$(state "$UNA_RESULT")" "$una_url" "$RAILWAY_PR_ENVIRONMENT")
  242. else
  243. body=$(printf '%s\n**Preview**: %s (NEO web client%s)\n**API**: %s (UNA%s)\n\nRailway environment: `%s`' \
  244. "$marker" "$neo_url" "$(state "$NEO_RESULT")" "$una_url" "$(state "$UNA_RESULT")" "$RAILWAY_PR_ENVIRONMENT")
  245. fi
  246. comment_id=$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" --paginate \
  247. --jq ".[] | select(.user.login == \"github-actions[bot]\" and (.body | contains(\"${marker}\"))) | .id" \
  248. | head -n1)
  249. if [ -n "$comment_id" ]; then
  250. gh api --method PATCH "repos/${GITHUB_REPOSITORY}/issues/comments/${comment_id}" -f body="$body"
  251. else
  252. gh pr comment "$PR_NUMBER" --body "$body"
  253. fi
  254. deploy-production:
  255. # Runs next to the Jenkins deploy to ci.una.io, which is unchanged.
  256. name: Deploy master to Railway (api.unacms.app)
  257. needs: test
  258. if: github.event_name == 'push' && github.ref == 'refs/heads/master'
  259. runs-on: ubuntu-latest
  260. concurrency:
  261. group: railway-production
  262. cancel-in-progress: false
  263. environment:
  264. name: production
  265. url: https://api.unacms.app
  266. env:
  267. RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
  268. RAILWAY_PROJECT_ID: ${{ secrets.RAILWAY_PROJECT_ID }}
  269. RAILWAY_ENVIRONMENT: production
  270. VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
  271. VERCEL_TEAM: yasko
  272. UNA_API_KEY: ${{ secrets.UNA_API_KEY }}
  273. steps:
  274. - uses: actions/checkout@v4
  275. - uses: actions/download-artifact@v4
  276. with:
  277. name: una-package
  278. path: packages
  279. - name: Prepare artefact
  280. run: |
  281. mkdir -p deploy
  282. unzip -q packages/*.zip -d /tmp/una-pkg
  283. pkg_dir=$(find /tmp/una-pkg -mindepth 1 -maxdepth 1 -type d | head -n 1)
  284. cp -a "$pkg_dir"/. deploy/
  285. cp scripts/railway/Dockerfile scripts/railway/entrypoint.sh scripts/railway/railway.toml scripts/railway/.railwayignore \
  286. scripts/railway/configure.php scripts/railway/seed.php deploy/
  287. chmod +x deploy/entrypoint.sh
  288. - uses: ./.github/actions/railway-cli
  289. - name: Configure production
  290. run: |
  291. if [ -z "$RAILWAY_API_TOKEN" ] || [ -z "$RAILWAY_PROJECT_ID" ]; then
  292. echo "Set secrets RAILWAY_API_TOKEN (account token) and RAILWAY_PROJECT_ID" >&2
  293. exit 1
  294. fi
  295. railway link --project "$RAILWAY_PROJECT_ID" --environment "$RAILWAY_ENVIRONMENT" --json
  296. # Database credentials and UNA_HASH_SECRET live in the Railway environment, not here.
  297. railway variable set --service una --environment "$RAILWAY_ENVIRONMENT" --skip-deploys \
  298. UNA_CLIENT_URL=https://unacms.app \
  299. ${UNA_API_KEY:+UNA_API_KEY="$UNA_API_KEY"}
  300. - name: Deploy artefact
  301. run: railway up ./deploy --path-as-root --no-gitignore --verbose --ci --service una --environment "$RAILWAY_ENVIRONMENT" --project "$RAILWAY_PROJECT_ID"
  302. - name: api.unacms.app DNS
  303. if: env.VERCEL_TOKEN != ''
  304. run: scripts/railway/domains.sh railway-domain api.unacms.app "$RAILWAY_ENVIRONMENT" una
  305. - name: Smoke test
  306. # A fresh production install takes about 4 minutes; allow 10.
  307. run: |
  308. for i in $(seq 1 60); do
  309. code=$(curl -s -o /dev/null -w '%{http_code}' https://api.unacms.app/ || true)
  310. [ "$code" = "200" ] && { echo "api.unacms.app is up"; exit 0; }
  311. # Until the certificate is issued, check the Railway hostname instead.
  312. host=$(railway domain list --service una --environment "$RAILWAY_ENVIRONMENT" --json | jq -r '.domains[] | select(.type == "service") | .domain' | head -n1)
  313. if [ -n "$host" ] && [ "$(curl -s -o /dev/null -w '%{http_code}' "https://${host#https://}/" || true)" = "200" ]; then
  314. echo "up at https://$host (api.unacms.app answered $code; certificate may still be pending)"
  315. exit 0
  316. fi
  317. sleep 10
  318. done
  319. echo "UNA did not come up" >&2
  320. exit 1
  321. deploy-production-neo:
  322. # The NEO web client for unacms.app. NEO_PRODUCTION_HOST (a repository variable) is the
  323. # public host; until it is set, the client is only on its Railway domain.
  324. name: Deploy master to Railway (neo)
  325. if: github.event_name == 'push' && github.ref == 'refs/heads/master'
  326. runs-on: ubuntu-latest
  327. concurrency:
  328. group: railway-production-neo
  329. cancel-in-progress: false
  330. environment:
  331. name: production-neo
  332. url: ${{ steps.urls.outputs.app_url }}
  333. env:
  334. RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
  335. RAILWAY_PROJECT_ID: ${{ secrets.RAILWAY_PROJECT_ID }}
  336. RAILWAY_ENVIRONMENT: production
  337. VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
  338. VERCEL_TEAM: yasko
  339. NEO_PRODUCTION_HOST: ${{ vars.NEO_PRODUCTION_HOST }}
  340. steps:
  341. - uses: actions/checkout@v4
  342. - uses: ./.github/actions/railway-cli
  343. - name: Configure neo
  344. id: urls
  345. run: |
  346. railway link --project "$RAILWAY_PROJECT_ID" --environment "$RAILWAY_ENVIRONMENT" --json
  347. railway domain --service neo --environment "$RAILWAY_ENVIRONMENT" || true
  348. neo_host=$(railway domain list --service neo --environment "$RAILWAY_ENVIRONMENT" --json | jq -r '.domains[] | select(.type == "service") | .domain' | head -n1)
  349. neo_host=${neo_host#https://}
  350. [ -n "$neo_host" ] || { echo "No Railway domain for neo" >&2; exit 1; }
  351. app_url="https://${NEO_PRODUCTION_HOST:-$neo_host}"
  352. scripts/railway/neo.sh vars "$RAILWAY_ENVIRONMENT" https://api.unacms.app "$app_url"
  353. echo "app_url=$app_url" >> "$GITHUB_OUTPUT"
  354. echo "neo_url=https://$neo_host" >> "$GITHUB_OUTPUT"
  355. - name: Deploy NEO
  356. run: |
  357. scripts/railway/neo.sh stage /tmp/deploy-neo
  358. railway up /tmp/deploy-neo --path-as-root --no-gitignore --verbose --ci --service neo --environment "$RAILWAY_ENVIRONMENT" --project "$RAILWAY_PROJECT_ID"
  359. - name: Production host DNS
  360. if: env.NEO_PRODUCTION_HOST != '' && env.VERCEL_TOKEN != ''
  361. run: scripts/railway/domains.sh railway-domain "$NEO_PRODUCTION_HOST" "$RAILWAY_ENVIRONMENT" neo
  362. - name: Smoke test
  363. env:
  364. NEO_URL: ${{ steps.urls.outputs.neo_url }}
  365. run: |
  366. for i in $(seq 1 30); do
  367. code=$(curl -s -o /dev/null -w '%{http_code}' "$NEO_URL/" || true)
  368. [ "$code" = "200" ] && { echo "NEO is up at $NEO_URL"; exit 0; }
  369. sleep 10
  370. done
  371. echo "NEO did not answer 200 at $NEO_URL (last: $code)" >&2
  372. exit 1
  373. teardown:
  374. name: Remove PR Railway environment
  375. if: >-
  376. github.event_name == 'pull_request' && github.event.action == 'closed'
  377. && github.event.pull_request.head.repo.full_name == github.repository
  378. && github.event.pull_request.user.login != 'dependabot[bot]'
  379. runs-on: ubuntu-latest
  380. env:
  381. RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
  382. RAILWAY_PROJECT_ID: ${{ secrets.RAILWAY_PROJECT_ID }}
  383. RAILWAY_BASE_ENVIRONMENT: ${{ secrets.RAILWAY_ENVIRONMENT }}
  384. RAILWAY_PR_ENVIRONMENT: pr-${{ github.event.pull_request.number }}
  385. VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
  386. VERCEL_TEAM: yasko
  387. PREVIEW_API_HOST: api-pr-${{ github.event.pull_request.number }}.unacms.app
  388. PREVIEW_CLIENT_HOST: pr-${{ github.event.pull_request.number }}.unacms.app
  389. steps:
  390. - uses: actions/checkout@v4
  391. with:
  392. sparse-checkout: |
  393. .github/actions
  394. scripts/railway
  395. - name: Remove preview domains
  396. if: env.VERCEL_TOKEN != ''
  397. continue-on-error: true
  398. run: |
  399. scripts/railway/domains.sh client-unalias "$PREVIEW_CLIENT_HOST"
  400. scripts/railway/domains.sh dns-remove "$PREVIEW_CLIENT_HOST"
  401. scripts/railway/domains.sh dns-remove "$PREVIEW_API_HOST"
  402. - uses: ./.github/actions/railway-cli
  403. - name: Delete PR environment
  404. run: |
  405. if [ -z "$RAILWAY_API_TOKEN" ] || [ -z "$RAILWAY_PROJECT_ID" ]; then
  406. echo "Set secrets RAILWAY_API_TOKEN (account token) and RAILWAY_PROJECT_ID" >&2
  407. exit 1
  408. fi
  409. base="${RAILWAY_BASE_ENVIRONMENT:-production}"
  410. railway link --project "$RAILWAY_PROJECT_ID" --environment "$base" --json
  411. # The run for the PR's last push is cancelled above (workflow concurrency), so nothing
  412. # can create the environment after this. A PR closed before its first deploy has none.
  413. if railway environment delete "$RAILWAY_PR_ENVIRONMENT" -y; then
  414. echo "Deleted $RAILWAY_PR_ENVIRONMENT"
  415. else
  416. echo "No environment $RAILWAY_PR_ENVIRONMENT to delete"
  417. fi