fix(ci): probe real schema in breaking-changes server readiness check (#20465)
## Summary The `GraphQL and OpenAPI Breaking Changes Detection` workflow has been posting graphql-inspector stack traces as PR comments — see [#20445 comment](https://github.com/twentyhq/twenty/pull/20445#issuecomment-4421142635) for an example. ### Root cause - The wait step probed readiness with `curl -s URL > /dev/null 2>&1`, which exits 0 for **any** HTTP response — including 5xx and GraphQL error JSON. NestJS opens the HTTP listener before the workspace schema cache is fully populated, so the wait often completed while the server still served auth/metadata error JSON. - The introspection download therefore wrote a small (~154-byte) error payload instead of the real schema. `jq empty` in the validation step only checks JSON *syntax*, so `{"errors":[...]}` passed validation. - `graphql-inspector diff` then failed with `Unable to read JSON file: ... Not valid JSON content`, the workflow swallowed the error into the diff markdown, and the bot posted that stack trace verbatim on the PR. In the failing run, the main-branch files were 154 B (GraphQL) and 112 B (REST 500); the current-branch files in the same run were 600 KB–2.8 MB. ### Fix - Wait steps now POST an authenticated introspection (`{ __schema { queryType { name } } }`) and require `.data.__schema` plus a 2xx response from `/rest/open-api/core` (`curl -f`) before declaring the server ready. - Validation step now checks for the expected shape (`.data.__schema` for GraphQL, `.openapi`/`.swagger` for OpenAPI) and includes the first 200 bytes of any bad payload in the warning, so when something genuinely goes wrong the next debugger has a real lead instead of a generic stack trace. ## Test plan - [ ] CI runs against this branch — the workflow's own readiness probes are now exercised against the real server, so a green run validates the new check. - [ ] If the readiness probe still passes but downloads regress, the strengthened validation step will surface the payload in the workflow logs instead of posting a graphql-inspector stack trace on the PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
@@ -164,9 +164,17 @@ jobs:
|
||||
interval=5
|
||||
elapsed=0
|
||||
|
||||
ADMIN_TOKEN=$(jq -r '.APPLE_JANE_ADMIN_ACCESS_TOKEN' packages/twenty-server/test/integration/constants/test-tokens.json)
|
||||
|
||||
while [ $elapsed -lt $timeout ]; do
|
||||
if curl -s "http://localhost:${{ env.CURRENT_SERVER_PORT }}/graphql" > /dev/null 2>&1 && \
|
||||
curl -s "http://localhost:${{ env.CURRENT_SERVER_PORT }}/rest/open-api/core" > /dev/null 2>&1; then
|
||||
GRAPHQL_RESPONSE=$(curl -s -X POST "http://localhost:${{ env.CURRENT_SERVER_PORT }}/graphql" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-d '{"query":"{ __schema { queryType { name } } }"}' 2>/dev/null || echo '{}')
|
||||
|
||||
if echo "$GRAPHQL_RESPONSE" | jq -e '.data.__schema' > /dev/null 2>&1 && \
|
||||
curl -fsS "http://localhost:${{ env.CURRENT_SERVER_PORT }}/rest/open-api/core" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" > /dev/null 2>&1; then
|
||||
echo "Current branch server is ready!"
|
||||
break
|
||||
fi
|
||||
@@ -177,10 +185,9 @@ jobs:
|
||||
done
|
||||
|
||||
if [ $elapsed -ge $timeout ]; then
|
||||
echo "Timeout waiting for current branch server to start"
|
||||
echo "::warning::Timed out waiting for current branch server to serve a valid schema. Validation will skip the API diff."
|
||||
echo "Current server log:"
|
||||
cat /tmp/current-server.log || echo "No current server log found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download GraphQL and REST responses from current branch
|
||||
@@ -324,9 +331,17 @@ jobs:
|
||||
interval=5
|
||||
elapsed=0
|
||||
|
||||
ADMIN_TOKEN=$(jq -r '.APPLE_JANE_ADMIN_ACCESS_TOKEN' packages/twenty-server/test/integration/constants/test-tokens.json)
|
||||
|
||||
while [ $elapsed -lt $timeout ]; do
|
||||
if curl -s "http://localhost:${{ env.MAIN_SERVER_PORT }}/graphql" > /dev/null 2>&1 && \
|
||||
curl -s "http://localhost:${{ env.MAIN_SERVER_PORT }}/rest/open-api/core" > /dev/null 2>&1; then
|
||||
GRAPHQL_RESPONSE=$(curl -s -X POST "http://localhost:${{ env.MAIN_SERVER_PORT }}/graphql" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-d '{"query":"{ __schema { queryType { name } } }"}' 2>/dev/null || echo '{}')
|
||||
|
||||
if echo "$GRAPHQL_RESPONSE" | jq -e '.data.__schema' > /dev/null 2>&1 && \
|
||||
curl -fsS "http://localhost:${{ env.MAIN_SERVER_PORT }}/rest/open-api/core" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" > /dev/null 2>&1; then
|
||||
echo "Main branch server is ready!"
|
||||
break
|
||||
fi
|
||||
@@ -337,10 +352,9 @@ jobs:
|
||||
done
|
||||
|
||||
if [ $elapsed -ge $timeout ]; then
|
||||
echo "Timeout waiting for main branch server to start"
|
||||
echo "::warning::Timed out waiting for main branch server to serve a valid schema. Validation will skip the API diff."
|
||||
echo "Main server log:"
|
||||
cat /tmp/main-server.log || echo "No main server log found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download GraphQL and REST responses from main branch
|
||||
@@ -407,11 +421,23 @@ jobs:
|
||||
valid=true
|
||||
|
||||
for file in main-schema-introspection.json current-schema-introspection.json \
|
||||
main-metadata-schema-introspection.json current-metadata-schema-introspection.json \
|
||||
main-rest-api.json current-rest-api.json \
|
||||
main-metadata-schema-introspection.json current-metadata-schema-introspection.json; do
|
||||
if [ ! -f "$file" ]; then
|
||||
echo "::warning::Missing GraphQL schema file: $file"
|
||||
valid=false
|
||||
elif ! jq -e '.data.__schema' "$file" >/dev/null 2>&1; then
|
||||
echo "::warning::File $file is not a valid GraphQL introspection result. First 200 bytes: $(head -c 200 "$file")"
|
||||
valid=false
|
||||
fi
|
||||
done
|
||||
|
||||
for file in main-rest-api.json current-rest-api.json \
|
||||
main-rest-metadata-api.json current-rest-metadata-api.json; do
|
||||
if [ ! -f "$file" ] || ! jq empty "$file" 2>/dev/null; then
|
||||
echo "::warning::Invalid or missing schema file: $file"
|
||||
if [ ! -f "$file" ]; then
|
||||
echo "::warning::Missing OpenAPI spec file: $file"
|
||||
valid=false
|
||||
elif ! jq -e '.openapi // .swagger' "$file" >/dev/null 2>&1; then
|
||||
echo "::warning::File $file is not a valid OpenAPI spec. First 200 bytes: $(head -c 200 "$file")"
|
||||
valid=false
|
||||
fi
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user