Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/actionlint.yaml

This file was deleted.

10 changes: 10 additions & 0 deletions .github/actions/setup-caches/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ inputs:
runs:
using: "composite"
steps:
- name: Validate cache type
shell: bash
env:
CACHE_TYPE: ${{ inputs.cache-type }}
run: |
case "$CACHE_TYPE" in
application-server-quality|application-server-verification|application-server-integration|server-contracts|webapp-e2e|webapp-storybook) ;;
*) echo "::error::Unknown cache type '$CACHE_TYPE'."; exit 1 ;;
esac

- name: Compute generated-client cache identity
id: generated-clients-identity
if: startsWith(inputs.cache-type, 'application-server-') || contains(fromJSON('["webapp-e2e", "server-contracts"]'), inputs.cache-type)
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/cd-docs-teardown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ permissions:
jobs:
teardown:
name: Teardown Preview
timeout-minutes: 10
runs-on: ubuntu-latest
env:
PREVIEW_URL: ls1intum-hephaestus-docs-pr-${{ github.event.number }}.surge.sh
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/cd-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
build-preview:
name: Build (preview)
if: github.event_name == 'pull_request'
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -54,6 +55,7 @@ jobs:
build-production:
name: Build (production)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -81,6 +83,7 @@ jobs:
name: PR Preview
needs: build-preview
if: github.event_name == 'pull_request'
timeout-minutes: 10
runs-on: ubuntu-latest
env:
PREVIEW_URL: ls1intum-hephaestus-docs-pr-${{ github.event.number }}.surge.sh
Expand Down Expand Up @@ -123,6 +126,7 @@ jobs:
name: GitHub Pages
needs: build-production
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
timeout-minutes: 10
runs-on: ubuntu-latest
environment:
name: github-pages
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci-compose-validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ permissions:
jobs:
validate:
name: "Render compose stacks"
timeout-minutes: 15
runs-on: ubuntu-latest
env:
COMPOSE_ENV_FILES: .env,release-lock.env
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci-docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ jobs:
(inputs.webapp_changed != 'true' || inputs.application_server_changed != 'true' ||
inputs.agent_images_changed != 'true' ||
inputs.postgres_image_changed != 'true')
timeout-minutes: 15
runs-on: ubuntu-latest
outputs:
application-server-published: ${{ steps.tag.outputs.application-server-published }}
Expand Down
59 changes: 30 additions & 29 deletions .github/workflows/ci-quality-gates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,46 +79,49 @@ jobs:
if: steps.should_run.outputs.run == 'true'
uses: ./.github/actions/setup-bun

- name: Setup caches
if: steps.should_run.outputs.run == 'true'
- name: Setup application-server caches
if: steps.should_run.outputs.run == 'true' && matrix.check == 'application-server-quality'
uses: ./.github/actions/setup-caches
with:
cache-type: application-server-quality
os: ${{ runner.os }}

- name: Setup server-contract caches
if: steps.should_run.outputs.run == 'true' && matrix.check == 'server-contracts'
uses: ./.github/actions/setup-caches
with:
cache-type: ${{ matrix.check }}
cache-type: server-contracts
os: ${{ runner.os }}

- name: Application-server formatting + agent runtime + contracts
if: steps.should_run.outputs.run == 'true' && matrix.check == 'application-server-quality'
run: |
bun install --frozen-lockfile
bun run check:package-manager
bun run check:agent-runtime-pins

ISSUES_FOUND=()
FMT_OK=true; PMD_OK=true; NULLNESS_OK=true; LINT_OK=true; TESTS_OK=true; TYPES_OK=true; SCRIPT_TYPES_OK=true; CONTRACTS_OK=true; ENV_OK=true; DOCS_OK=true; DIAGRAMS_OK=true; INSTRUCTIONS_OK=true
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

bun run format:java:check || { FMT_OK=false; ISSUES_FOUND+=("Java formatting failed. Run: bun run format:java"); }
bun run check:server || { SERVER_OK=false; ISSUES_FOUND+=("Server formatting or PMD failed. Run: bun run check:server"); }
bun run check:java-nullness \
|| { NULLNESS_OK=false; ISSUES_FOUND+=("Java nullness policy failed. Run: bun run check:java-nullness"); }
bun run lint:java || { PMD_OK=false; ISSUES_FOUND+=("PMD found violations. Run: bun run lint:java:report"); }
if [ "$PMD_OK" = "true" ] && [ "${{ inputs.pmd_canary }}" = "true" ]; then
if [ "$SERVER_OK" = "true" ] && [ "${{ inputs.pmd_canary }}" = "true" ]; then
PMD_CANARY=server/application/src/main/java/de/tum/cit/aet/hephaestus/Application.java
cp "$PMD_CANARY" "$RUNNER_TEMP/Application.java"
trap 'cp "$RUNNER_TEMP/Application.java" "$PMD_CANARY"' EXIT
sed -i '/public class Application {/a\ private int deliberatelyUnusedPmdCanary;' "$PMD_CANARY"
if bun run lint:java; then
PMD_OK=false
PMD_CANARY_OK=false
ISSUES_FOUND+=("PMD accepted a planted UnusedPrivateField violation; the gate is not analyzing current main sources")
fi
cp "$RUNNER_TEMP/Application.java" "$PMD_CANARY"
trap - EXIT
fi
bun run ci:agents \
|| { LINT_OK=false; ISSUES_FOUND+=("Lint or formatting failed outside the webapp. Run: bun run check:agents:fix"); }
bun run check:agents \
|| { TOOLING_OK=false; ISSUES_FOUND+=("Repository tooling checks failed. Run: bun run check:agents"); }
bun run test:agents \
|| { TESTS_OK=false; ISSUES_FOUND+=("Agent runtime test(s) failed. Run: bun run test:agents"); }
bun run typecheck:agents \
|| { TYPES_OK=false; ISSUES_FOUND+=("Agent TypeScript errors. Run: bun run typecheck:agents"); }
bun run typecheck:scripts \
|| { SCRIPT_TYPES_OK=false; ISSUES_FOUND+=("scripts/ TypeScript errors. Run: bun run typecheck:scripts"); }
bun run check:contracts || { CONTRACTS_OK=false; ISSUES_FOUND+=("Artifact-source contract validation failed. Run: bun run check:contracts"); }
# Reads server/application.yml against docker/compose.{app,core}.yaml — the deployment that
# has to deliver each setting. Both sides are behind this job's path filter.
Expand All @@ -140,13 +143,11 @@ jobs:
echo "### App Server Quality" >> $GITHUB_STEP_SUMMARY
echo "| Check | Status | Fix |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|-----|" >> $GITHUB_STEP_SUMMARY
[[ "$FMT_OK" == "false" ]] && echo "| Java formatting | :x: Failed | \`bun run format:java\` |" >> $GITHUB_STEP_SUMMARY
[[ "$PMD_OK" == "false" ]] && echo "| Java lint (PMD) | :x: Failed | \`bun run lint:java:report\` |" >> $GITHUB_STEP_SUMMARY
[[ "$SERVER_OK" == "false" ]] && echo "| Server formatting and PMD | :x: Failed | \`bun run check:server\` |" >> $GITHUB_STEP_SUMMARY
[[ "$PMD_CANARY_OK" == "false" ]] && echo "| PMD canary | :x: Failed | Inspect the planted-violation check |" >> $GITHUB_STEP_SUMMARY
[[ "$NULLNESS_OK" == "false" ]] && echo "| Java nullness policy | :x: Failed | \`bun run check:java-nullness\` |" >> $GITHUB_STEP_SUMMARY
[[ "$LINT_OK" == "false" ]] && echo "| Lint + format (outside webapp) | :x: Failed | \`bun run check:agents:fix\` |" >> $GITHUB_STEP_SUMMARY
[[ "$TOOLING_OK" == "false" ]] && echo "| Repository tooling | :x: Failed | \`bun run check:agents\` |" >> $GITHUB_STEP_SUMMARY
[[ "$TESTS_OK" == "false" ]] && echo "| Agent runtime tests | :x: Failed | \`bun run test:agents\` |" >> $GITHUB_STEP_SUMMARY
[[ "$TYPES_OK" == "false" ]] && echo "| Agent typecheck | :x: Failed | \`bun run typecheck:agents\` |" >> $GITHUB_STEP_SUMMARY
[[ "$SCRIPT_TYPES_OK" == "false" ]] && echo "| scripts/ typecheck | :x: Failed | \`bun run typecheck:scripts\` |" >> $GITHUB_STEP_SUMMARY
[[ "$CONTRACTS_OK" == "false" ]] && echo "| Artifact-source contracts | :x: Failed | \`bun run check:contracts\` |" >> $GITHUB_STEP_SUMMARY
[[ "$ENV_OK" == "false" ]] && echo "| Env delivery by runtime role | :x: Failed | \`bun run check:env\` |" >> $GITHUB_STEP_SUMMARY
[[ "$INSTRUCTIONS_OK" == "false" ]] && echo "| Agent instruction wiring | :x: Failed | \`bun run check:instructions\` |" >> $GITHUB_STEP_SUMMARY
Expand All @@ -165,8 +166,7 @@ jobs:
cd webapp

ISSUES_FOUND=()
LINT_OK=true
TYPES_OK=true
CLIENT_OK=true
COMPONENTS_OK=true
STORIES_OK=true
SORT_OK=true
Expand All @@ -175,12 +175,14 @@ jobs:
ROUTES_OK=true
TESTS_OK=true

bun run check || { LINT_OK=false; ISSUES_FOUND+=("Lint or formatting failed. Run: cd webapp && bun run check:fix"); }
bun run typecheck || { TYPES_OK=false; ISSUES_FOUND+=("TypeScript errors found. Run: cd webapp && bun run typecheck"); }
bun ../scripts/check-presentational-components.ts || { COMPONENTS_OK=false; ISSUES_FOUND+=("Components must take data as props. Run: bun run check:components"); }
bun ../scripts/check-story-prose.ts || { STORIES_OK=false; ISSUES_FOUND+=("Story prose renders HTML paragraphs. Run: bun run check:stories"); }
bun ../scripts/check-story-sort.ts || { SORT_OK=false; ISSUES_FOUND+=("Storybook sidebar order is stale. Run: bun run check:story-sort"); }
bun ../scripts/check-docs-tokens.ts && bun test ../scripts/check-docs-tokens.test.ts || { TOKENS_OK=false; ISSUES_FOUND+=("The docs site copies a web app colour that has since changed. Run: bun run check:docs-tokens"); }
(cd .. && bun run check:client) || {
CLIENT_OK=false
ISSUES_FOUND+=("Webapp lint, formatting, or typecheck failed. Run: bun run check:client")
}
(cd .. && bun run check:components) || { COMPONENTS_OK=false; ISSUES_FOUND+=("Components must take data as props. Run: bun run check:components"); }
(cd .. && bun run check:stories) || { STORIES_OK=false; ISSUES_FOUND+=("Story prose renders HTML paragraphs. Run: bun run check:stories"); }
(cd .. && bun run check:story-sort) || { SORT_OK=false; ISSUES_FOUND+=("Storybook sidebar order is stale. Run: bun run check:story-sort"); }
(cd .. && bun run check:docs-tokens) || { TOKENS_OK=false; ISSUES_FOUND+=("The docs site copies a web app colour that has since changed. Run: bun run check:docs-tokens"); }
timeout --kill-after=30s 10m bun run test \
|| { TESTS_OK=false; ISSUES_FOUND+=("Unit tests failed. Run: cd webapp && bun run test"); }

Expand All @@ -195,8 +197,7 @@ jobs:
echo "### Webapp Quality" >> $GITHUB_STEP_SUMMARY
echo "| Check | Status | Fix |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|-----|" >> $GITHUB_STEP_SUMMARY
[[ "$LINT_OK" == "false" ]] && echo "| Lint + format (oxlint + oxfmt) | :x: Failed | \`cd webapp && bun run check:fix\` |" >> $GITHUB_STEP_SUMMARY
[[ "$TYPES_OK" == "false" ]] && echo "| TypeScript | :x: Failed | \`cd webapp && bun run typecheck\` |" >> $GITHUB_STEP_SUMMARY
[[ "$CLIENT_OK" == "false" ]] && echo "| Lint, format, and TypeScript | :x: Failed | \`bun run check:client\` |" >> $GITHUB_STEP_SUMMARY
[[ "$COMPONENTS_OK" == "false" ]] && echo "| Presentational components | :x: Failed | \`bun run check:components\` |" >> $GITHUB_STEP_SUMMARY
[[ "$STORIES_OK" == "false" ]] && echo "| Story prose | :x: Failed | \`bun run check:stories\` |" >> $GITHUB_STEP_SUMMARY
[[ "$SORT_OK" == "false" ]] && echo "| Storybook sidebar order | :x: Failed | \`bun run check:story-sort\` |" >> $GITHUB_STEP_SUMMARY
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-server-clean-reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:

- name: Upload phase profiles
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0 # v7.0.1
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: server-phase-reference-${{ github.run_id }}
path: |
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ jobs:

workflow-lint:
name: "Workflow syntax"
timeout-minutes: 10
runs-on: ubuntu-latest
needs: [detect-changes]
if: |
Expand Down Expand Up @@ -287,6 +288,7 @@ jobs:

all-ci-passed:
name: "CI Status Gate"
timeout-minutes: 10
runs-on: ubuntu-latest
permissions:
actions: read
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/cleanup-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ on:
permissions: {}

concurrency:
group: hephaestus-preview-lifecycle
queue: max
group: hephaestus-preview-lifecycle-${{ github.event.pull_request.number }}
cancel-in-progress: false

jobs:
cleanup:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy-locked-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ on:

jobs:
deploy:
timeout-minutes: 20
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
permissions:
Expand Down
7 changes: 2 additions & 5 deletions .github/workflows/deploy-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,9 @@ jobs:
# Longer than the budgets inside the scripts (image wait, deploy, reachability), so a run that
# exceeds them reports a deployment status instead of being cancelled without one.
timeout-minutes: 40
# Serialized: admission counts the previews already holding a slot, so two concurrent runs would
# both see room. `queue: max` keeps the backlog instead of cancelling it; each queued run resolves
# the pull request's current head, so a burst of pushes collapses into one deployment.
concurrency:
group: hephaestus-preview-lifecycle
queue: max
group: hephaestus-preview-admission
cancel-in-progress: false
env:
COOLIFY_URL: ${{ vars.COOLIFY_URL }}
COOLIFY_APP_UUID: ${{ vars.COOLIFY_APP_UUID }}
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/deploy-with-helios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ on:
required: false
type: string

# Suggestion: Ensures only one workflow runs at a time for a given environment name
concurrency: ${{ github.event.inputs.environment_name }}

permissions:
contents: read
packages: read

jobs:
deploy-app:
uses: ls1intum/.github/.github/workflows/deploy-docker-compose.yml@main
uses: ls1intum/.github/.github/workflows/deploy-docker-compose.yml@5f645f96873d8b8b3a9b2e52d06626c71377f7ac # v1.2.0-24-g5f645f9
with:
environment: ${{ github.event.inputs.environment_name }}
docker-compose-file: './docker/compose.app.yaml'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/openapi-autocommit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Setup caches
uses: ./.github/actions/setup-caches
with:
cache-type: openapi-validation
cache-type: application-server-quality
os: ${{ runner.os }}

- name: Install dependencies
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ on:
jobs:
validate-title:
name: "Validate title"
timeout-minutes: 5
runs-on: ubuntu-latest
if: ${{ !github.event.pull_request.draft }}
permissions:
Expand Down Expand Up @@ -71,6 +72,7 @@ jobs:

assign-author:
name: "Assign author"
timeout-minutes: 5
runs-on: ubuntu-latest
permissions:
pull-requests: write
Expand All @@ -80,6 +82,7 @@ jobs:

labeler:
name: "Apply labels"
timeout-minutes: 5
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
11 changes: 3 additions & 8 deletions .github/workflows/reconcile-previews.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
name: Preview reconcile

# Event-driven cleanup can be missed — a run cancelled, a Coolify hiccup, a pull request closed while
# the lifecycle queue was busy. This sweeps what the events left behind, and joins the same global
# lifecycle group as deploy and close so admission cannot race reclamation.
on:
schedule:
- cron: "0 4 * * *"
Expand Down Expand Up @@ -59,14 +56,12 @@ jobs:
pull-requests: read
strategy:
fail-fast: false
# Every job below joins the global preview lifecycle group, so a higher value would only start
# runners that immediately queue.
max-parallel: 1
max-parallel: 5
matrix:
pr: ${{ fromJSON(needs.inventory.outputs.previews) }}
concurrency:
group: hephaestus-preview-lifecycle
queue: max
group: hephaestus-preview-lifecycle-${{ matrix.pr }}
cancel-in-progress: false
runs-on: ubuntu-latest
timeout-minutes: 8
env:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
${{ github.event.workflow_run.conclusion == 'success'
&& github.event.workflow_run.event == 'push'
&& github.event.workflow_run.head_repository.full_name == github.repository }}
timeout-minutes: 15
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down Expand Up @@ -137,6 +138,7 @@ jobs:
tag-images:
needs: release
if: needs.release.outputs.released == 'true'
timeout-minutes: 30
runs-on: ubuntu-latest
permissions:
packages: write
Expand Down Expand Up @@ -411,6 +413,7 @@ jobs:
publish-release:
needs: [release, tag-images]
if: needs.release.outputs.released == 'true'
timeout-minutes: 20
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down Expand Up @@ -557,6 +560,7 @@ jobs:
deploy-production:
needs: [release, deploy-staging]
if: needs.release.outputs.released == 'true'
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- name: Trigger Production Deploy
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/reusable-docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ jobs:
strategy:
fail-fast: true
matrix: ${{ fromJSON(inputs.single-arch && '{"include":[{"platform":"linux/amd64","runner":"ubuntu-24.04"}]}' || '{"include":[{"platform":"linux/amd64","runner":"ubuntu-24.04"},{"platform":"linux/arm64","runner":"ubuntu-24.04-arm"}]}') }}
timeout-minutes: 45
runs-on: ${{ matrix.runner }}
permissions:
contents: read
Expand Down Expand Up @@ -307,6 +308,7 @@ jobs:

merge:
name: Create manifest
timeout-minutes: 30
runs-on: ubuntu-latest
needs: build
if: ${{ !inputs.single-arch }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/version-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ permissions: {}

jobs:
version-pr:
timeout-minutes: 15
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down
Loading
Loading