S2 EsLint implementation
All checks were successful
Build, test and publish / verify (push) Successful in 1m40s
All checks were successful
Build, test and publish / verify (push) Successful in 1m40s
This commit is contained in:
184
docs/s2-hook-timings.json
Normal file
184
docs/s2-hook-timings.json
Normal file
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"date": "2026-10-29",
|
||||
"machine": "AMD Ryzen 7 7730U with Radeon Graphics",
|
||||
"system": "linux 7.0.0-38-generic",
|
||||
"node": "v22.22.3",
|
||||
"npm": "10.9.8",
|
||||
"scopes": {
|
||||
"single": [
|
||||
"agiledancers-fe/src/app/app.ts"
|
||||
],
|
||||
"mixed": [
|
||||
"agiledancers-fe/src/app/app.ts",
|
||||
"agiledancers-fe/src/app/app.html",
|
||||
"agiledancers-fe/src/app/app.css",
|
||||
"agiledancers-fe/angular.json",
|
||||
"agiledancers-fe/eslint.config.mjs",
|
||||
"agiledancers-fe/e2e/school-management.spec.ts"
|
||||
],
|
||||
"all": [
|
||||
"agiledancers-fe/.dockerignore",
|
||||
"agiledancers-fe/.editorconfig",
|
||||
"agiledancers-fe/.gitignore",
|
||||
"agiledancers-fe/.nvmrc",
|
||||
"agiledancers-fe/.prettierignore",
|
||||
"agiledancers-fe/.prettierrc",
|
||||
"agiledancers-fe/.vscode/extensions.json",
|
||||
"agiledancers-fe/.vscode/launch.json",
|
||||
"agiledancers-fe/.vscode/tasks.json",
|
||||
"agiledancers-fe/Dockerfile",
|
||||
"agiledancers-fe/README.md",
|
||||
"agiledancers-fe/angular.json",
|
||||
"agiledancers-fe/e2e/school-management.spec.ts",
|
||||
"agiledancers-fe/eslint.config.mjs",
|
||||
"agiledancers-fe/lint-staged.config.mjs",
|
||||
"agiledancers-fe/nginx/default.conf.template",
|
||||
"agiledancers-fe/package.json",
|
||||
"agiledancers-fe/playwright.config.ts",
|
||||
"agiledancers-fe/proxy.conf.json",
|
||||
"agiledancers-fe/public/favicon.svg",
|
||||
"agiledancers-fe/src/app/app.config.ts",
|
||||
"agiledancers-fe/src/app/app.css",
|
||||
"agiledancers-fe/src/app/app.html",
|
||||
"agiledancers-fe/src/app/app.routes.ts",
|
||||
"agiledancers-fe/src/app/app.spec.ts",
|
||||
"agiledancers-fe/src/app/app.ts",
|
||||
"agiledancers-fe/src/app/core/api-error.ts",
|
||||
"agiledancers-fe/src/app/core/api-models.ts",
|
||||
"agiledancers-fe/src/app/core/school-api.spec.ts",
|
||||
"agiledancers-fe/src/app/core/school-api.ts",
|
||||
"agiledancers-fe/src/app/schools/school-page.html",
|
||||
"agiledancers-fe/src/app/schools/school-page.ts",
|
||||
"agiledancers-fe/src/app/schools/schools-page.html",
|
||||
"agiledancers-fe/src/app/schools/schools-page.ts",
|
||||
"agiledancers-fe/src/app/shared/confirm-dialog.ts",
|
||||
"agiledancers-fe/src/app/shared/dialog-frame.ts",
|
||||
"agiledancers-fe/src/app/shared/entity-editor.spec.ts",
|
||||
"agiledancers-fe/src/app/shared/entity-editor.ts",
|
||||
"agiledancers-fe/src/app/shared/group-members.spec.ts",
|
||||
"agiledancers-fe/src/app/shared/group-members.ts",
|
||||
"agiledancers-fe/src/app/shared/school-transfer.spec.ts",
|
||||
"agiledancers-fe/src/app/shared/school-transfer.ts",
|
||||
"agiledancers-fe/src/hook-fixture.ts",
|
||||
"agiledancers-fe/src/index.html",
|
||||
"agiledancers-fe/src/main.ts",
|
||||
"agiledancers-fe/src/styles.css",
|
||||
"agiledancers-fe/tools/check-hook.mjs",
|
||||
"agiledancers-fe/tools/install-hooks.mjs",
|
||||
"agiledancers-fe/tsconfig.app.json",
|
||||
"agiledancers-fe/tsconfig.eslint.json",
|
||||
"agiledancers-fe/tsconfig.json",
|
||||
"agiledancers-fe/tsconfig.spec.json"
|
||||
]
|
||||
},
|
||||
"timings": [
|
||||
{
|
||||
"mode": "combined",
|
||||
"scope": "single",
|
||||
"repeat": 1,
|
||||
"seconds": 2.875
|
||||
},
|
||||
{
|
||||
"mode": "combined",
|
||||
"scope": "single",
|
||||
"repeat": 2,
|
||||
"seconds": 2.776
|
||||
},
|
||||
{
|
||||
"mode": "combined",
|
||||
"scope": "single",
|
||||
"repeat": 3,
|
||||
"seconds": 2.894
|
||||
},
|
||||
{
|
||||
"mode": "combined",
|
||||
"scope": "mixed",
|
||||
"repeat": 1,
|
||||
"seconds": 3.779
|
||||
},
|
||||
{
|
||||
"mode": "combined",
|
||||
"scope": "mixed",
|
||||
"repeat": 2,
|
||||
"seconds": 4.099
|
||||
},
|
||||
{
|
||||
"mode": "combined",
|
||||
"scope": "mixed",
|
||||
"repeat": 3,
|
||||
"seconds": 4.478
|
||||
},
|
||||
{
|
||||
"mode": "combined",
|
||||
"scope": "all",
|
||||
"repeat": 1,
|
||||
"seconds": 5.916
|
||||
},
|
||||
{
|
||||
"mode": "combined",
|
||||
"scope": "all",
|
||||
"repeat": 2,
|
||||
"seconds": 6.137
|
||||
},
|
||||
{
|
||||
"mode": "combined",
|
||||
"scope": "all",
|
||||
"repeat": 3,
|
||||
"seconds": 4.728
|
||||
},
|
||||
{
|
||||
"mode": "prettier-only",
|
||||
"scope": "single",
|
||||
"repeat": 1,
|
||||
"seconds": 0.313
|
||||
},
|
||||
{
|
||||
"mode": "prettier-only",
|
||||
"scope": "single",
|
||||
"repeat": 2,
|
||||
"seconds": 0.338
|
||||
},
|
||||
{
|
||||
"mode": "prettier-only",
|
||||
"scope": "single",
|
||||
"repeat": 3,
|
||||
"seconds": 0.401
|
||||
},
|
||||
{
|
||||
"mode": "prettier-only",
|
||||
"scope": "mixed",
|
||||
"repeat": 1,
|
||||
"seconds": 0.648
|
||||
},
|
||||
{
|
||||
"mode": "prettier-only",
|
||||
"scope": "mixed",
|
||||
"repeat": 2,
|
||||
"seconds": 0.72
|
||||
},
|
||||
{
|
||||
"mode": "prettier-only",
|
||||
"scope": "mixed",
|
||||
"repeat": 3,
|
||||
"seconds": 0.647
|
||||
},
|
||||
{
|
||||
"mode": "prettier-only",
|
||||
"scope": "all",
|
||||
"repeat": 1,
|
||||
"seconds": 1.573
|
||||
},
|
||||
{
|
||||
"mode": "prettier-only",
|
||||
"scope": "all",
|
||||
"repeat": 2,
|
||||
"seconds": 1.441
|
||||
},
|
||||
{
|
||||
"mode": "prettier-only",
|
||||
"scope": "all",
|
||||
"repeat": 3,
|
||||
"seconds": 1.276
|
||||
}
|
||||
]
|
||||
}
|
||||
126
docs/s2-validation.md
Normal file
126
docs/s2-validation.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# S2 implementation evidence
|
||||
|
||||
Validated on the development mini-PC on 2026-10-29: AMD Ryzen 7 7730U (8 cores,
|
||||
16 threads), Ubuntu 26.04.1 LTS, Linux 7.0.0-38-generic x86_64, approximately
|
||||
27 GiB RAM, Node v22.22.3, npm 10.9.8. The standalone Docker build uses the
|
||||
existing Node 24.15.0 image.
|
||||
|
||||
## Lint scope and rules
|
||||
|
||||
ESLint 10.13.0, typescript-eslint 8.72.1 and angular-eslint 22.6.0 support the
|
||||
existing Angular 22 and TypeScript 6.0.3 versions. Framework versions are unchanged.
|
||||
The flat configuration applies recommended JavaScript, recommended type-checked
|
||||
TypeScript and recommended Angular rules, plus the recommended template rules
|
||||
for both inline and external templates. No rule suppressions were needed.
|
||||
`eslint-config-prettier` prevents conflicts with the existing formatting settings.
|
||||
|
||||
`tsconfig.eslint.json` supplies one explicit type-checking project covering
|
||||
application files, unit tests, Playwright tests and root TypeScript configuration.
|
||||
This includes E2E and Playwright configuration outside Angular's app/test
|
||||
compilation projects, without changing the application compilation scope.
|
||||
Node types resolve `process.env` in those files. The existing test findings were
|
||||
fixed by treating Playwright response JSON as unknown before checking its shape,
|
||||
and returning an explicit resolved promise from the fake file reader.
|
||||
|
||||
Injected probes confirmed `no-floating-promises` for application, unit-test,
|
||||
Playwright and configuration TypeScript; `no-unused-vars` for JavaScript;
|
||||
and `template/no-negated-async` in both external and inline Angular templates.
|
||||
Generated files are excluded. A warning-only CLI probe returned exit status 1
|
||||
with `--max-warnings 0`.
|
||||
|
||||
## Complete hook measurements
|
||||
|
||||
Run from the repository root, with dependencies installed:
|
||||
|
||||
```sh
|
||||
node agiledancers-fe/tools/check-hook.mjs
|
||||
```
|
||||
|
||||
This creates an isolated temporary Git repository from the current frontend and
|
||||
hook sources, links the installed dependency directory, makes an initial fixture
|
||||
commit and installs the real Husky wrapper. The real checkout and its index are
|
||||
not staged or committed by the checks. The temporary repository is retained and
|
||||
its report path is printed so failures can be inspected.
|
||||
|
||||
Each timed invocation runs `sh .husky/_/pre-commit` in a new process. Timing
|
||||
starts before Husky and includes file selection, lint-staged backup, hiding
|
||||
unstaged edits, fresh tool startup, formatting/checking, restaging and cleanup.
|
||||
No ESLint or Prettier cache is enabled. The final measurement ran while the
|
||||
standalone Docker build was also running; all selected-hook runs still passed. Three fresh executions per scenario and
|
||||
candidate are recorded; there is no runtime timeout interrupting writers.
|
||||
|
||||
The combined candidate uses the same hook, adding type-aware ESLint after
|
||||
Prettier. The selected configuration uses only Prettier. Staged scopes are:
|
||||
|
||||
- Single: `src/app/app.ts`.
|
||||
- Mixed: application TS, HTML and CSS, `angular.json`, `eslint.config.mjs` and
|
||||
the Playwright spec (six files).
|
||||
- All: all 52 maintained frontend files, including non-applicable files that the
|
||||
hook must skip, plus a small TS preservation-test fixture; generated lockfile
|
||||
excluded. Exact paths and raw measurements are in
|
||||
[the timing report](s2-hook-timings.json).
|
||||
|
||||
| Candidate | Staged scope | Run 1 | Run 2 | Run 3 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| combined | single | 2.875 s | 2.776 s | 2.894 s |
|
||||
| combined | mixed | 3.779 s | 4.099 s | 4.478 s |
|
||||
| combined | all | 5.916 s | 6.137 s | 4.728 s |
|
||||
| prettier-only | single | 0.313 s | 0.338 s | 0.401 s |
|
||||
| prettier-only | mixed | 0.648 s | 0.720 s | 0.647 s |
|
||||
| prettier-only | all | 1.573 s | 1.441 s | 1.276 s |
|
||||
|
||||
The combined candidate exceeds three seconds, so it is rejected. Every measured
|
||||
Prettier-only execution is below three seconds, so that hook is installed. These
|
||||
are measurements on this mini-PC, not a guarantee for other machines or future
|
||||
repository sizes. Rerun the checks when the tooling or scope changes.
|
||||
|
||||
## Preservation and installation checks
|
||||
|
||||
The isolated checks assert all of the following against the real hook, comparing
|
||||
both cached and unstaged binary diffs, status and stash state where appropriate:
|
||||
|
||||
- Partially staged formatting updates only the intended index version and
|
||||
retains independent unstaged changes in the same file.
|
||||
- An unrelated file with both staged and unstaged edits remains intact.
|
||||
- A commit without frontend changes leaves the state unchanged.
|
||||
- `package-lock.json` is not formatted or restaged.
|
||||
- A formatter syntax error after another file has been formatted aborts and
|
||||
restores the original index and worktree.
|
||||
- A conflict restoring an unstaged change on the formatted line aborts and
|
||||
restores the original index and worktree.
|
||||
- The rejected combined candidate also restores all changes when ESLint fails
|
||||
after successful formatting.
|
||||
- No backup stash remains after successful recovery.
|
||||
- `CI=true` and `HUSKY=0` leave an existing hooks configuration untouched;
|
||||
normal local installation selects `.husky/_`.
|
||||
|
||||
A real local `npm ci` successfully installed `.husky/_` in this checkout.
|
||||
Docker sets `CI=true` for installation and copies the prepare entry point before
|
||||
`npm ci`, so the lifecycle script can safely skip hook installation. The
|
||||
standalone build runs lint, tests and production compilation after copying sources.
|
||||
|
||||
## Build and pipeline verification
|
||||
|
||||
The full Java-based pipeline was executed locally without invoking publication:
|
||||
|
||||
```sh
|
||||
JAVA_HOME=/usr/lib/jvm/java-25-openjdk-amd64 \
|
||||
PATH=/usr/lib/jvm/java-25-openjdk-amd64/bin:/home/wanja-krah/.nvm/versions/node/v22.22.3/bin:/usr/local/bin:/usr/bin:/bin \
|
||||
TARGET_PLATFORM=linux/amd64 CI_RUN_ID=s2-local CI_RUN_ATTEMPT=2 \
|
||||
java ci/Ci.java verify
|
||||
```
|
||||
|
||||
Results: 20 backend tests, 17 CI-helper tests, clean frontend lint, 14 frontend
|
||||
unit tests, production build, both application images and both container E2E
|
||||
tests passed. Diagnostics remain in the ignored `ci/artifacts/` directory.
|
||||
A Gitea workflow run for these uncommitted changes has not been executed.
|
||||
|
||||
The CI-helper regression checks assert that lint immediately follows `npm ci`
|
||||
and precedes tests/build; a lint failure stops frontend verification with its
|
||||
nonzero status. Existing failed-verification and publication guards ensure only
|
||||
a completely verified commit can publish. The shared command runner writes lint
|
||||
output to the job log and retained `verify.log`. CI never invokes `lint:fix`.
|
||||
|
||||
`npm run lint:fix` followed by `npm run lint` also passed without further changes.
|
||||
The standalone Docker build was checked separately with an isolated Docker
|
||||
configuration to avoid the desktop credential helper; no images were published.
|
||||
Reference in New Issue
Block a user