Skip to content

Enhance media disk support and add WireGuard validation jobs #249

Enhance media disk support and add WireGuard validation jobs

Enhance media disk support and add WireGuard validation jobs #249

Workflow file for this run

name: Full Pipeline
on:
pull_request:
branches: [main]
concurrency:
group: full-${{ github.ref }}
cancel-in-progress: true
env:
JAVA_VERSION: '21'
NODE_VERSION: '24'
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
detect-changes:
name: Detect Changes
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
any-kotlin: ${{ steps.compute.outputs.any-kotlin }}
any-frontend: ${{ steps.compute.outputs.any-frontend }}
run-system-tests: ${{ steps.compute.outputs.run-system-tests }}
lint-kotlin-matrix: ${{ steps.matrix.outputs.lint-kotlin }}
test-kotlin-unit-matrix: ${{ steps.matrix.outputs.test-kotlin-unit }}
test-kotlin-integration-matrix: ${{ steps.matrix.outputs.test-kotlin-integration }}
verify-coverage-matrix: ${{ steps.matrix.outputs.verify-coverage }}
steps:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
workflow:
- '.github/workflows/full.yml'
- '.github/workflows/system-tests.yml'
auth-api:
- 'services/auth-api/**'
assistant-api:
- 'services/assistant-api/**'
kotlin-common:
- 'libs/kotlin-common/**'
build-logic:
- 'build-logic/**'
gradle-config:
- 'gradle/**'
- 'gradle.properties'
- 'build.gradle.kts'
- 'settings.gradle.kts'
- 'gradlew'
- 'gradlew.bat'
auth-ui:
- 'services/auth-ui/**'
assistant-ui:
- 'services/assistant-ui/**'
app-ui:
- 'services/app-ui/**'
vue-common:
- 'libs/vue-common/**'
frontend-config:
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- 'eslint.config.ts'
system-tests:
- 'services/system-tests/**'
infra:
- 'infra/**'
- 'docker-compose.yml'
- name: Compute change flags
id: compute
env:
FILTER_WORKFLOW: ${{ steps.filter.outputs.workflow }}
FILTER_KOTLIN_COMMON: ${{ steps.filter.outputs.kotlin-common }}
FILTER_BUILD_LOGIC: ${{ steps.filter.outputs.build-logic }}
FILTER_GRADLE_CONFIG: ${{ steps.filter.outputs.gradle-config }}
FILTER_AUTH_API: ${{ steps.filter.outputs.auth-api }}
FILTER_ASSISTANT_API: ${{ steps.filter.outputs.assistant-api }}
FILTER_VUE_COMMON: ${{ steps.filter.outputs.vue-common }}
FILTER_FRONTEND_CONFIG: ${{ steps.filter.outputs.frontend-config }}
FILTER_AUTH_UI: ${{ steps.filter.outputs.auth-ui }}
FILTER_ASSISTANT_UI: ${{ steps.filter.outputs.assistant-ui }}
FILTER_APP_UI: ${{ steps.filter.outputs.app-ui }}
FILTER_SYSTEM_TESTS: ${{ steps.filter.outputs.system-tests }}
FILTER_INFRA: ${{ steps.filter.outputs.infra }}
run: |
any() { for v in "$@"; do [[ "$v" == "true" ]] && echo "true" && return; done; echo "false"; }
KOTLIN_SHARED=$(any "$FILTER_WORKFLOW" "$FILTER_KOTLIN_COMMON" "$FILTER_BUILD_LOGIC" "$FILTER_GRADLE_CONFIG")
FRONTEND_SHARED=$(any "$FILTER_WORKFLOW" "$FILTER_VUE_COMMON" "$FILTER_FRONTEND_CONFIG")
AUTH_API_KOTLIN=$(any "$KOTLIN_SHARED" "$FILTER_AUTH_API")
ASSISTANT_API_KOTLIN=$(any "$KOTLIN_SHARED" "$FILTER_ASSISTANT_API")
KOTLIN_COMMON_CHANGED="$KOTLIN_SHARED"
ANY_KOTLIN=$(any "$KOTLIN_SHARED" "$FILTER_AUTH_API" "$FILTER_ASSISTANT_API")
ANY_FRONTEND=$(any "$FRONTEND_SHARED" "$FILTER_AUTH_UI" "$FILTER_ASSISTANT_UI" "$FILTER_APP_UI")
ANY_SERVICE=$(any "$ANY_KOTLIN" "$ANY_FRONTEND")
RUN_SYSTEM_TESTS=$(any "$FILTER_WORKFLOW" "$FILTER_SYSTEM_TESTS" "$FILTER_INFRA" "$ANY_SERVICE")
echo "any-kotlin=$ANY_KOTLIN" >> "$GITHUB_OUTPUT"
echo "any-frontend=$ANY_FRONTEND" >> "$GITHUB_OUTPUT"
echo "run-system-tests=$RUN_SYSTEM_TESTS" >> "$GITHUB_OUTPUT"
echo "auth-api-kotlin=$AUTH_API_KOTLIN" >> "$GITHUB_OUTPUT"
echo "assistant-api-kotlin=$ASSISTANT_API_KOTLIN" >> "$GITHUB_OUTPUT"
echo "kotlin-common-changed=$KOTLIN_COMMON_CHANGED" >> "$GITHUB_OUTPUT"
- name: Build dynamic matrices
id: matrix
env:
AUTH_API_KOTLIN: ${{ steps.compute.outputs.auth-api-kotlin }}
ASSISTANT_API_KOTLIN: ${{ steps.compute.outputs.assistant-api-kotlin }}
KOTLIN_COMMON_CHANGED: ${{ steps.compute.outputs.kotlin-common-changed }}
run: |
KOTLIN_MATRIX="[]"
if [[ "$AUTH_API_KOTLIN" == "true" ]]; then
KOTLIN_MATRIX=$(echo "$KOTLIN_MATRIX" | jq -c '. + [{"module":"auth-api","gradle-path":":services:auth-api"}]')
fi
if [[ "$ASSISTANT_API_KOTLIN" == "true" ]]; then
KOTLIN_MATRIX=$(echo "$KOTLIN_MATRIX" | jq -c '. + [{"module":"assistant-api","gradle-path":":services:assistant-api"}]')
fi
if [[ "$KOTLIN_COMMON_CHANGED" == "true" ]]; then
KOTLIN_MATRIX=$(echo "$KOTLIN_MATRIX" | jq -c '. + [{"module":"kotlin-common","gradle-path":":libs:kotlin-common"}]')
fi
echo "lint-kotlin=$KOTLIN_MATRIX" >> "$GITHUB_OUTPUT"
echo "test-kotlin-unit=$KOTLIN_MATRIX" >> "$GITHUB_OUTPUT"
INT_MATRIX="[]"
if [[ "$AUTH_API_KOTLIN" == "true" ]]; then
INT_MATRIX=$(echo "$INT_MATRIX" | jq -c '. + [{"module":"auth-api","gradle-path":":services:auth-api"}]')
fi
if [[ "$ASSISTANT_API_KOTLIN" == "true" ]]; then
INT_MATRIX=$(echo "$INT_MATRIX" | jq -c '. + [{"module":"assistant-api","gradle-path":":services:assistant-api"}]')
fi
echo "test-kotlin-integration=$INT_MATRIX" >> "$GITHUB_OUTPUT"
COV_MATRIX="[]"
if [[ "$AUTH_API_KOTLIN" == "true" ]]; then
COV_MATRIX=$(echo "$COV_MATRIX" | jq -c '. + [{"module":"auth-api","gradle-path":":services:auth-api","has-integration":true}]')
fi
if [[ "$ASSISTANT_API_KOTLIN" == "true" ]]; then
COV_MATRIX=$(echo "$COV_MATRIX" | jq -c '. + [{"module":"assistant-api","gradle-path":":services:assistant-api","has-integration":true}]')
fi
if [[ "$KOTLIN_COMMON_CHANGED" == "true" ]]; then
COV_MATRIX=$(echo "$COV_MATRIX" | jq -c '. + [{"module":"kotlin-common","gradle-path":":libs:kotlin-common","has-integration":false}]')
fi
echo "verify-coverage=$COV_MATRIX" >> "$GITHUB_OUTPUT"
validate-nomad:
name: Validate Nomad Jobs
needs: detect-changes
if: needs.detect-changes.outputs.run-system-tests == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Nomad
run: |
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/hashicorp.list > /dev/null
sudo apt-get update && sudo apt-get install -y nomad
- name: Validate HCL and JSON
run: |
errors=0
while IFS= read -r -d '' f; do
echo "==> $f"
nomad fmt -check "$f" || { echo "FAIL (fmt): $f"; errors=1; }
output=$(nomad job validate "$f" 2>&1) || {
if echo "$output" | grep -q 'Vault.*not enabled'; then
echo " (skipped — Vault not available in CI)"
else
echo "$output"; echo "FAIL (validate): $f"; errors=1
fi
}
done < <(find infra/nomad/jobs -name '*.hcl' -print0 | sort -z)
[[ "$errors" -eq 0 ]] || exit 1
find infra/nomad/vault -name '*.json' -print0 | while IFS= read -r -d '' f; do
echo "==> $f"
python3 -m json.tool "$f" > /dev/null
done
lint-kotlin:
name: Lint Kotlin (${{ matrix.module }})
needs: detect-changes
if: needs.detect-changes.outputs.any-kotlin == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
include: ${{ fromJson(needs.detect-changes.outputs.lint-kotlin-matrix) }}
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-java-gradle
with:
java-version: ${{ env.JAVA_VERSION }}
- run: bash infra/scripts/run-strict-command.sh ./gradlew ${{ matrix.gradle-path }}:detekt ${{ matrix.gradle-path }}:ktlintCheck
lint-frontend:
name: Lint Frontend
needs: detect-changes
if: needs.detect-changes.outputs.any-frontend == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-node-pnpm
with:
node-version: ${{ env.NODE_VERSION }}
- run: pnpm -r lint --max-warnings 0
- run: pnpm format:check
test-kotlin-unit:
name: Kotlin Unit Tests (${{ matrix.module }})
needs: detect-changes
if: needs.detect-changes.outputs.any-kotlin == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
include: ${{ fromJson(needs.detect-changes.outputs.test-kotlin-unit-matrix) }}
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-java-gradle
with:
java-version: ${{ env.JAVA_VERSION }}
- run: bash infra/scripts/run-strict-command.sh ./gradlew ${{ matrix.gradle-path }}:test
test-frontend-unit:
name: Frontend Unit Tests
needs: detect-changes
if: needs.detect-changes.outputs.any-frontend == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-node-pnpm
with:
node-version: ${{ env.NODE_VERSION }}
- run: pnpm -r test -- --coverage
test-kotlin-integration:
name: Kotlin Integration Tests (${{ matrix.module }})
needs: detect-changes
if: needs.detect-changes.outputs.any-kotlin == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
include: ${{ fromJson(needs.detect-changes.outputs.test-kotlin-integration-matrix) }}
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-java-gradle
with:
java-version: ${{ env.JAVA_VERSION }}
- run: bash infra/scripts/run-strict-command.sh ./gradlew ${{ matrix.gradle-path }}:integrationTest
verify-coverage:
name: Coverage Threshold (${{ matrix.module }})
needs: [detect-changes, test-kotlin-unit, test-kotlin-integration]
if: always() && needs.detect-changes.outputs.any-kotlin == 'true' && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
runs-on: ubuntu-latest
strategy:
matrix:
include: ${{ fromJson(needs.detect-changes.outputs.verify-coverage-matrix) }}
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-java-gradle
with:
java-version: ${{ env.JAVA_VERSION }}
- name: Run tests and verify coverage (80%)
if: matrix.has-integration
run: bash infra/scripts/run-strict-command.sh ./gradlew ${{ matrix.gradle-path }}:test ${{ matrix.gradle-path }}:integrationTest ${{ matrix.gradle-path }}:jacocoTestCoverageVerification
- name: Run tests and verify coverage (80%) - unit only
if: '!matrix.has-integration'
run: bash infra/scripts/run-strict-command.sh ./gradlew ${{ matrix.gradle-path }}:test ${{ matrix.gradle-path }}:jacocoTestCoverageVerification
test-architecture:
name: Architecture Tests
needs: detect-changes
if: needs.detect-changes.outputs.any-kotlin == 'true' || needs.detect-changes.outputs.any-frontend == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-java-gradle
with:
java-version: ${{ env.JAVA_VERSION }}
- uses: ./.github/actions/setup-node-pnpm
with:
node-version: ${{ env.NODE_VERSION }}
- run: bash infra/scripts/run-strict-command.sh ./gradlew :services:auth-api:test :services:assistant-api:test --tests "*ArchitectureTest*"
- run: pnpm -r depcruise
system-tests:
name: System Tests
needs: [detect-changes]
if: needs.detect-changes.outputs.run-system-tests == 'true'
uses: ./.github/workflows/system-tests.yml
with:
java-version: '21'
security-scan:
name: Security Scan
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: aquasecurity/trivy-action@master
with:
scan-type: fs
scan-ref: .
severity: CRITICAL,HIGH
- uses: ./.github/actions/setup-node-pnpm
with:
node-version: ${{ env.NODE_VERSION }}
- run: pnpm audit --audit-level=high || true
- name: Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
pipeline-complete:
name: Pipeline Complete
if: always()
needs:
- detect-changes
- validate-nomad
- lint-kotlin
- lint-frontend
- test-kotlin-unit
- test-frontend-unit
- test-kotlin-integration
- verify-coverage
- test-architecture
- system-tests
- security-scan
runs-on: ubuntu-latest
steps:
- name: Check pipeline result
run: |
if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" || "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
echo "Pipeline failed or was cancelled"
exit 1
fi
echo "All checks passed (some may have been skipped due to no relevant changes)"