Skip to content
Open
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
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ node_modules
example*

.git/

js/coverage/
9 changes: 9 additions & 0 deletions .github/composite/test/frontend-test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ inputs:
GPG_PASSPHRASE:
description: "GPG Passphrase"
required: true
UPLOAD_TEST_COV:
description: "Boolean indicating whether tests should be uploaded to Codecov or not."
required: false
default: false

runs:
using: "composite"
Expand All @@ -33,6 +37,11 @@ runs:
java-version: "25"
cache: "maven"

- name: Expose GitHub Runtime
uses: crazy-max/ghaction-github-runtime@v3

- name: Run script
shell: bash
run: bun .github/scripts/test/run-frontend-tests
env:
UPLOAD_TEST_COV: ${{ inputs.UPLOAD_TEST_COV }}
22 changes: 22 additions & 0 deletions .github/scripts/test/run-frontend-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ import { $ } from "bun";
import { getEnvVariables } from "load-secrets/env/load";
import { backend } from "utils/run-backend-instance";
import { db } from "utils/run-local-db";
import { uploadFrontendTests } from "utils/upload";

async function main() {
try {
const shouldUploadCoverage = process.env.UPLOAD_TEST_COV === "true";
const ciEnv =
shouldUploadCoverage ? await getEnvVariables(["ci"]) : undefined;
const codecovToken = ciEnv ? parseCiEnv(ciEnv).codecovToken : undefined;

const ciAppEnv = await getEnvVariables(["ci-app"]);
const localDbEnv = await db.start();
await backend.start({ ...ciAppEnv, ...localDbEnv });
Expand All @@ -19,12 +25,28 @@ async function main() {
await $`pnpm --dir js i --frozen-lockfile`;
await $$`pnpm --dir js run generate`;
await $$`pnpm --dir js run test`;

if (shouldUploadCoverage && codecovToken) {
await uploadFrontendTests(codecovToken);
}
} finally {
await backend.end();
await db.end();
}
}

function parseCiEnv(ciEnv: Record<string, string>) {
const codecovToken = (() => {
const v = ciEnv["CODECOV_TOKEN"];
if (!v) {
throw new Error("Missing CODECOV_TOKEN from .env.ci");
}
return v;
})();

return { codecovToken };
}

main()
.then(() => {
process.exit(0);
Expand Down
24 changes: 20 additions & 4 deletions .github/scripts/utils/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@ export async function uploadBackendTests(token: string) {
const dir = path.join(process.cwd(), "target/site/jacoco/");

await uploadArtifact(dir, "backend-jacoco-report");
await uploadToCodecov(token, dir);
await uploadToCodecov(token, dir, "backend");
}

async function uploadToCodecov(token: string, dir: string) {
export async function uploadFrontendTests(token: string) {
const dir = path.join(process.cwd(), "js/coverage/");

await uploadArtifact(dir, "frontend-coverage-report");
await uploadToCodecov(token, dir, "frontend");
}

async function uploadToCodecov(token: string, dir: string, flag: string) {
try {
const { exitCode } = Bun.spawnSync(["./codecov", "--help"]);
if (exitCode != 0) {
Expand Down Expand Up @@ -37,8 +44,17 @@ async function uploadToCodecov(token: string, dir: string) {
}

try {
console.log(`Uploading reports from ${dir} to Codecov...`);
const p2 = Bun.spawnSync(["./codecov", "do-upload", "--dir", dir]);
console.log(
`Uploading reports from ${dir} to Codecov with flag: ${flag}...`,
);
const p2 = Bun.spawnSync([
"./codecov",
"do-upload",
"--dir",
dir,
"--flag",
flag,
]);
if (p2.exitCode != 0) {
throw new Error(`Failed to load Codecov process\n\n${p2.stderr}`);
}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ jobs:
with:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
UPLOAD_TEST_COV: true

testBuildImage:
name: Build Test Docker Image
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ node_modules
scripts/**/index.js

/node_modules

js/coverage/
4 changes: 2 additions & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"vmware.vscode-boot-dev-pack",
"bradlc.vscode-tailwindcss",
"redhat.vscode-xml",
"emeraldwalk.runonsave"
"emeraldwalk.runonsave",
"vitest.explorer"
]
}

35 changes: 35 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,54 @@ codecov:
require_ci_to_pass: false
notify:
wait_for_ci: false
after_n_builds: 2

flags:
backend:
paths:
- src/main/java/
carryforward: true
frontend:
paths:
- js/src/
carryforward: true

coverage:
status:
project:
default:
target: 60%
informational: true
backend:
target: 60%
flags:
- backend
informational: true
frontend:
target: 60%
flags:
- frontend
informational: true
patch:
default:
informational: false
target: 80%
threshold: 5%
only_pulls: true
backend:
target: 80%
threshold: 5%
only_pulls: true
flags:
- backend
informational: false
frontend:
target: 80%
threshold: 5%
only_pulls: true
flags:
- frontend
informational: false

comment:
behavior: new # delete old and post new.
3 changes: 3 additions & 0 deletions example.env
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,6 @@ ACTUATOR_PASSWORD=
# (Optional for dev)
# Check `.env.example.ci` for details on how it's used, or the CI tech doc page on the wiki
REDIS_URL=

# set to "true" to enable mocked APIs in frontend.
VITE_MOCK=
4 changes: 4 additions & 0 deletions example.env.staging
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,7 @@ SECRET_KEY=
DOCKER_HUB_PAT=
DIGITAL_OCEAN_PAT=
DIGITAL_OCEAN_APP_ID=

# used by the frontend to load certain feature flags.
# looks for the string literal "true"
VITE_STAGING=true
14 changes: 12 additions & 2 deletions js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"dev": "vite",
"build": "vite build",
"typecheck": "tsc -b --noEmit",
"test": "pnpm run typecheck && pnpm run prettier && pnpm run lint && pnpm run build",
"vt": "vitest run --coverage",
"test": "pnpm run typecheck && pnpm run prettier && pnpm run lint && pnpm run build && pnpm run vt",
"fix": "pnpm run eslint:fix && pnpm run stylelint:fix && pnpm run prettier:fix",
"lint": "pnpm run eslint && pnpm run stylelint",
"generate": "openapi-typescript http://localhost:8080/v3/api-docs -o src/lib/api/types/schema.ts --properties-required-by-default --enum --make-paths-enum --dedupe-enums && prettier --write \"src/lib/api/types/schema.ts\"",
Expand Down Expand Up @@ -50,17 +51,24 @@
"@eslint/js": "^9.17.0",
"@eslint/plugin-kit": ">=0.3.4",
"@tailwindcss/postcss": "^4.1.14",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@types/react-syntax-highlighter": "^15.5.13",
"@vitejs/plugin-react": "^4.3.4",
"@vitest/coverage-v8": "4.0.18",
"eslint": "^9.17.0",
"eslint-plugin-no-relative-import-paths": "^1.6.1",
"eslint-plugin-perfectionist": "^4.8.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.16",
"globals": "^15.14.0",
"jsdom": "^27.4.0",
"msw": "^2.12.7",
"nodemon": "^3.1.10",
"openapi-typescript": "7.8.0",
"postcss": "^8.4.49",
Expand All @@ -75,8 +83,10 @@
"tailwindcss": "^4.1.14",
"typescript": "~5.6.3",
"typescript-eslint": "^8.19.0",
"uuid": "^13.0.0",
"vite": ">=6.4.1",
"vite-tsconfig-paths": "^5.1.4"
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^4.0.18"
},
"packageManager": "pnpm@10.24.0",
"pnpm": {
Expand Down
Loading