forked from OurHike/OurHike
-
Notifications
You must be signed in to change notification settings - Fork 0
188 lines (171 loc) · 7.44 KB
/
Copy pathcheck-deployed-app.yml
File metadata and controls
188 lines (171 loc) · 7.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# Loads the deployed app in a real browser and asks whether it draws a trail.
#
# Tier 2 of #431, tracked in #467. `check-deployment.yml` (tier 1) proves the
# bucket will answer a browser; only this proves the APP works with it.
#
# check-deployment.yml daily, no downloads can a browser REACH the data
# this daily, one page load does the APP draw a trail
# smoke-published.yml weekly, ~18 MB is what is published CORRECT
#
# WHY IT IS NOT REDUNDANT WITH TIER 1. Tier 1 cannot see a build that shipped
# without its data URL, a service worker serving a stale shell, a bundle that
# throws before its first fetch, or a CORS rule that passes a bare GET and
# fails the app's real request. Every one of those is "the map is broken" and
# none is visible to anything that is not a browser.
#
# AND WHY THE CHECK IS NOT ONLY THE TWO ASSERTIONS #431 ASKED FOR. Measured
# while building it: with the data source made unreachable, "no *No trail
# line* flag" and "no data-error notice" BOTH still passed, because the app
# raises them only once a download has failed and nothing had got far enough
# to fail. So the script also asserts the page really received the data, and
# that nothing it asked the bucket for was refused - the second is the #427
# shape seen from the app's side.
#
# IT HOLDS NO CREDENTIALS. Same posture as its two siblings: public HTTPS
# reads of the deployed site and the public bucket, nothing that could change
# what a hiker gets.
#
# IT DOES NOT FAIL THE RUN. GitHub emails on every scheduled failure, so a
# real outage would send one a day until it was filtered. The tracking issue
# is the signal - opened green->red, closed red->green.
name: Check deployed app
on:
schedule:
# 09:30 UTC daily - after tier 1 at 09:15, so if the bucket is refusing
# browsers that job says so first and this one is not a second alarm for
# the same fault.
- cron: "30 9 * * *"
workflow_dispatch:
inputs:
url:
description: "App URL to load. Defaults to the GitHub Pages deployment."
type: string
required: false
permissions:
contents: read
issues: write
concurrency:
group: check-deployed-app
cancel-in-progress: false
env:
ISSUE_TITLE: "Deployed app does not draw a trail"
ISSUE_LABEL: deployment-health
# The origin the app is actually served from since #733. Checking the old
# project-site URL instead would still pass - it 301s here - while proving
# nothing about the host a hiker is on.
DEFAULT_URL: https://ourhike.org/app/
jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 20
defaults:
run:
working-directory: client
steps:
- name: Is there a deployment to check
id: can
working-directory: .
env:
OVERRIDE: ${{ inputs.url }}
CONFIGURED: ${{ vars.DATA_BASE_URL }}
run: |
BASE="${CONFIGURED}"
if [ -z "$BASE" ]; then
echo "::warning::No DATA_BASE_URL is set, so the deployed app has no data source to load. See LAUNCH_CHECKLIST.md step 2."
echo "go=false" >> "$GITHUB_OUTPUT"
else
echo "go=true" >> "$GITHUB_OUTPUT"
echo "base=$BASE" >> "$GITHUB_OUTPUT"
echo "url=${OVERRIDE:-$DEFAULT_URL}" >> "$GITHUB_OUTPUT"
fi
- uses: actions/checkout@v4
if: steps.can.outputs.go == 'true'
- uses: actions/setup-node@v4
if: steps.can.outputs.go == 'true'
with:
node-version: "22"
cache: npm
cache-dependency-path: client/package-lock.json
- name: Install dependencies
if: steps.can.outputs.go == 'true'
run: npm ci
# Playwright pins a Chromium build per release and refuses to launch a
# different one, so the browser is installed rather than assumed. Only
# chromium: the check is about one deployment, not cross-browser
# behaviour, and the other two would triple the install for nothing.
- name: Install Chromium
if: steps.can.outputs.go == 'true'
run: npx playwright install --with-deps chromium
- name: Load the deployed app
if: steps.can.outputs.go == 'true'
env:
APP_URL: ${{ steps.can.outputs.url }}
DATA_BASE_URL: ${{ steps.can.outputs.base }}
# set +e / PIPESTATUS rather than trusting the pipe: the step's exit
# status is tee's under the default shell, so a crash of the checker
# was invisible here (#655, same fix as check-deployment.yml).
# --exit-zero reserves non-zero for exactly that crash.
run: |
set +e
node scripts/check-deployed-app.mjs \
--url "$APP_URL" \
--data-base "$DATA_BASE_URL" \
--json deployed-app.json \
--exit-zero | tee deployed-app.txt
status=${PIPESTATUS[0]}
set -e
if [ "$status" -ne 0 ]; then
echo "::error::check-deployed-app.mjs exited $status, which --exit-zero reserves for a crash."
exit "$status"
fi
- name: Write the job summary
if: always() && steps.can.outputs.go == 'true'
run: |
{
echo "## Deployed app"
echo
if [ -f deployed-app.txt ]; then
echo '```'
cat deployed-app.txt
echo '```'
else
echo "The check did not produce a report. See the step log above."
fi
} >> "$GITHUB_STEP_SUMMARY"
# Its own issue title, sharing the label with the other two health
# checks: they can be red for unrelated reasons and would otherwise
# overwrite each other's findings, while the shared label keeps all
# three findable at once.
- name: Open, update, or close the tracking issue
if: steps.can.outputs.go == 'true'
uses: actions/github-script@v7
env:
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
with:
script: |
const fs = require('fs')
const trackingIssue = require(`${process.env.GITHUB_WORKSPACE}/.github/scripts/tracking-issue.js`)
const verdict = JSON.parse(fs.readFileSync('client/deployed-app.json', 'utf8'))
const failed = verdict.failed ?? []
await trackingIssue({github, context, core}, {
label: process.env.ISSUE_LABEL,
title: process.env.ISSUE_TITLE,
checkedAt: verdict.checked_at,
keys: failed.map(f => f.check),
healthy: failed.length === 0,
allClear: `The deployed app loads its map data again, as of ${verdict.checked_at}. Closing.`,
render: (firstSeen, cell) => [
`**A browser loading ${verdict.url} does not get a working map.** ${failed.length} check(s) failed.`,
'',
'This is the app rather than the bucket. If "Check deployment" is also red, fix that one first — it is the same fault seen earlier in the chain.',
'',
'| check | first seen | detail |',
'|---|---|---|',
...failed.map(f => `| \`${f.check}\` | ${firstSeen[f.check]} | ${cell(f.detail)} |`),
'',
`Last checked ${verdict.checked_at} · [run](${process.env.RUN_URL})`,
'',
'---',
'_Generated by [Claude Code](https://claude.ai/code)_',
].join('\n'),
})