1818 required : false
1919 type : string
2020 default : " true"
21+ tooling_changed :
22+ description : " Whether repository tooling, docs, or instruction files changed"
23+ required : false
24+ type : string
25+ default : " true"
26+ postgres_image_changed :
27+ description : " Whether the PostgreSQL image inputs changed"
28+ required : false
29+ type : string
30+ default : " false"
31+ contracts_changed :
32+ description : " Whether server contracts or their PostgreSQL image changed"
33+ required : false
34+ type : string
35+ default : " true"
2136 pmd_canary :
2237 description : " Whether PMD wiring inputs changed"
2338 required : false
3954 include :
4055 - check : application-server-quality
4156 display-name : " App Server"
57+ - check : tooling-quality
58+ display-name : " Tooling and Docs"
4259 - check : webapp-quality
4360 display-name : " Webapp"
4461 - check : server-contracts
5168 "webapp-quality")
5269 echo "run=${{ inputs.webapp_changed }}" >> $GITHUB_OUTPUT
5370 ;;
54- "application-server-quality"|"server-contracts" )
71+ "application-server-quality")
5572 echo "run=${{ inputs.application_server_changed }}" >> $GITHUB_OUTPUT
5673 ;;
74+ "server-contracts")
75+ echo "run=${{ inputs.contracts_changed }}" >> $GITHUB_OUTPUT
76+ ;;
77+ "tooling-quality")
78+ echo "run=${{ inputs.tooling_changed }}" >> $GITHUB_OUTPUT
79+ ;;
5780 *)
5881 echo "::error::Unknown check type '${{ matrix.check }}' in ci-quality-gates.yml matrix."
5982 echo "::error::Please add a case for this check in the 'Determine if check should run' step."
@@ -93,15 +116,12 @@ jobs:
93116 cache-type : server-contracts
94117 os : ${{ runner.os }}
95118
96- - name : Application-server formatting + agent runtime + contracts
119+ - name : Application-server quality
97120 if : steps.should_run.outputs.run == 'true' && matrix.check == 'application-server-quality'
98121 run : |
99122 bun install --frozen-lockfile
100- bun run check:package-manager
101- bun run check:agent-runtime-pins
102-
103123 ISSUES_FOUND=()
104- SERVER_OK=true; PMD_CANARY_OK=true; NULLNESS_OK=true; TOOLING_OK=true; TESTS_OK=true; CONTRACTS_OK=true; ENV_OK=true; DOCS_OK=true; DIAGRAMS_OK=true; INSTRUCTIONS_OK =true
124+ SERVER_OK=true; PMD_CANARY_OK=true; NULLNESS_OK=true; CONTRACTS_OK=true; ENV_OK=true
105125
106126 bun run check:server || { SERVER_OK=false; ISSUES_FOUND+=("Server formatting or PMD failed. Run: bun run check:server"); }
107127 bun run check:java-nullness \
@@ -118,26 +138,8 @@ jobs:
118138 cp "$RUNNER_TEMP/Application.java" "$PMD_CANARY"
119139 trap - EXIT
120140 fi
121- bun run check:agents \
122- || { TOOLING_OK=false; ISSUES_FOUND+=("Repository tooling checks failed. Run: bun run check:agents"); }
123- bun run test:agents \
124- || { TESTS_OK=false; ISSUES_FOUND+=("Agent runtime test(s) failed. Run: bun run test:agents"); }
125141 bun run check:contracts || { CONTRACTS_OK=false; ISSUES_FOUND+=("Artifact-source contract validation failed. Run: bun run check:contracts"); }
126- # Reads server/application.yml against docker/compose.{app,core}.yaml — the deployment that
127- # has to deliver each setting. Both sides are behind this job's path filter.
128142 bun run check:env || { ENV_OK=false; ISSUES_FOUND+=("A setting does not reach a container that can read it. Run: bun run check:env"); }
129- # An AGENTS.md no CLAUDE.md imports is loaded by every agent except Claude Code, and nothing
130- # about the file says so — this is the only place that reads the wiring end to end.
131- bun run check:instructions \
132- || { INSTRUCTIONS_OK=false; ISSUES_FOUND+=("An agent instruction file reaches no agent, or exists in two copies. Run: bun run check:instructions"); }
133- # docs/decisions/ and docs/runbooks/ are mounted by no Docusaurus plugin, so the site build
134- # never compiles or link-checks them. Markdown lint is the only gate they have.
135- bun run docs:lint || { DOCS_OK=false; ISSUES_FOUND+=("docs/ markdown or typecheck failed. Run: bun run docs:lint"); }
136- # Docusaurus renders mermaid in the browser, so a diagram it cannot parse builds green and
137- # publishes as an error box — the docs deployment can never be the gate for it. This leg
138- # owns the check because docs/** is behind this job's path filter and no other job's.
139- bun run check:diagrams \
140- || { DIAGRAMS_OK=false; ISSUES_FOUND+=("A committed Mermaid diagram does not parse. Run: bun run check:diagrams"); }
141143
142144 if [ ${#ISSUES_FOUND[@]} -gt 0 ]; then
143145 echo "### App Server Quality" >> $GITHUB_STEP_SUMMARY
@@ -146,17 +148,24 @@ jobs:
146148 [[ "$SERVER_OK" == "false" ]] && echo "| Server formatting and PMD | :x: Failed | \`bun run check:server\` |" >> $GITHUB_STEP_SUMMARY
147149 [[ "$PMD_CANARY_OK" == "false" ]] && echo "| PMD canary | :x: Failed | Inspect the planted-violation check |" >> $GITHUB_STEP_SUMMARY
148150 [[ "$NULLNESS_OK" == "false" ]] && echo "| Java nullness policy | :x: Failed | \`bun run check:java-nullness\` |" >> $GITHUB_STEP_SUMMARY
149- [[ "$TOOLING_OK" == "false" ]] && echo "| Repository tooling | :x: Failed | \`bun run check:agents\` |" >> $GITHUB_STEP_SUMMARY
150- [[ "$TESTS_OK" == "false" ]] && echo "| Agent runtime tests | :x: Failed | \`bun run test:agents\` |" >> $GITHUB_STEP_SUMMARY
151151 [[ "$CONTRACTS_OK" == "false" ]] && echo "| Artifact-source contracts | :x: Failed | \`bun run check:contracts\` |" >> $GITHUB_STEP_SUMMARY
152152 [[ "$ENV_OK" == "false" ]] && echo "| Env delivery by runtime role | :x: Failed | \`bun run check:env\` |" >> $GITHUB_STEP_SUMMARY
153- [[ "$INSTRUCTIONS_OK" == "false" ]] && echo "| Agent instruction wiring | :x: Failed | \`bun run check:instructions\` |" >> $GITHUB_STEP_SUMMARY
154- [[ "$DOCS_OK" == "false" ]] && echo "| Docs lint + typecheck | :x: Failed | \`bun run docs:lint\` |" >> $GITHUB_STEP_SUMMARY
155- [[ "$DIAGRAMS_OK" == "false" ]] && echo "| Mermaid diagrams | :x: Failed | \`bun run check:diagrams\` |" >> $GITHUB_STEP_SUMMARY
156153 for issue in "${ISSUES_FOUND[@]}"; do echo "::error::$issue"; done
157154 exit 1
158155 fi
159156
157+ - name : Tooling and docs quality
158+ if : steps.should_run.outputs.run == 'true' && matrix.check == 'tooling-quality'
159+ run : |
160+ bun install --frozen-lockfile
161+ bun run check:package-manager
162+ bun run check:agent-runtime-pins
163+ bun run check:agents
164+ bun run test:agents
165+ bun run check:instructions
166+ bun run docs:lint
167+ bun run check:diagrams
168+
160169 - name : Webapp quality
161170 if : steps.should_run.outputs.run == 'true' && matrix.check == 'webapp-quality'
162171 working-directory : ./webapp
@@ -257,10 +266,12 @@ jobs:
257266 continue-on-error : true
258267 if : steps.should_run.outputs.run == 'true' && matrix.check == 'server-contracts' && always()
259268 run : |
260- # The pg_partman image, not stock Postgres: the auth_event changeset that calls
261- # partman.create_parent is preconditioned onFail="MARK_RAN" on the extension being
262- # available, so on a stock image the chain replays with that changeset never executed.
263- docker build -t hephaestus-postgres:ci docker/postgres
269+ if [[ "${{ inputs.postgres_image_changed }}" == "true" ]]; then
270+ docker build -t hephaestus-postgres:ci docker/postgres
271+ else
272+ docker pull ghcr.io/ls1intum/hephaestus/postgres:${{ github.event.pull_request.base.sha || github.sha }}
273+ docker tag ghcr.io/ls1intum/hephaestus/postgres:${{ github.event.pull_request.base.sha || github.sha }} hephaestus-postgres:ci
274+ fi
264275 docker run -d --name postgres-db \
265276 -e POSTGRES_DB=hephaestus -e POSTGRES_PASSWORD=root -e POSTGRES_USER=root \
266277 -p 5432:5432 hephaestus-postgres:ci
0 commit comments