> Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation. ## The Problem Two methods of the installation are above the Kotlin target of 15, measured by the nightly mutation build of 2026-10-05: | Method | Mutation-CRAP | Complexity | Mutation score | |-------------------------------------|---------------|------------|----------------| | `NginxProxyManager.resolveSettings` | 27.44 | 18 | 0.69 | | `InitCommand.createSystemdFiles` | 17.40 | 5 | 0.21 | `resolveSettings` checks every setting of the managed nginx and builds its settings in one method; no test tried invalid ports, an invalid upstream host or a configured state directory. `createSystemdFiles` writes six files and prints what it wrote and how to install it; no test read that output, so 38 of 48 mutants survived. ## Non-Goals - No change in behaviour: the same settings are refused with the same warnings, the same files are written with the same lines printed. - The other groups above 15 follow in their own PRs. ## The Scenarios ### Feature: the managed nginx refuses what it cannot run #### Scenario#124.01: every setting nginx cannot run with is refused, a configured state directory read as the host means it So that a misconfigured nginx is refused before a container starts, and a valid one is never refused. - **Given** the managed nginx is enabled - **When** a port is 0 or above 65535, both ports are the same, the upstream host is no host name, or `server.port` takes the HTTPS port - **Then** no settings are resolved, and the warning names the reason - **When** the ports are 1 and 65535, or an upstream host of its own is configured - **Then** the settings carry them - **When** `stateDir` starts with `~/`, or is relative - **Then** it is the home directory's, or the repository's ##### Verified by - [NginxProxyManagerUnitTest](../../src/test/kotlin/de/hoennig/werkator/server/NginxProxyManagerUnitTest.kt) `every setting nginx cannot run with is refused, the ports up to their limits accepted (Scenario#124.01)`, `a configured state directory has its ~ expanded and is read relative to the repository (Scenario#124.01)`, and the earlier tests of the server name and the `server.port` collision ### Feature: init --systemd says what it did #### Scenario#124.02: init --systemd says what it created and how to install it So that the person running `init --systemd` can follow the printed steps without reading the code. - **Given** a repository whose configuration has a public base URL - **When** `init --systemd` runs - **Then** it prints one `created` line for the unit, the environment file, the two Docker cleanup units, the `.htaccess` and the maintenance page - **and** the `ln -sf` and `systemctl --user` lines that install all three units - **When** it runs again - **Then** it says that the environment file already exists and is not overwritten - **When** the jar path cannot be determined - **Then** it prints the error and writes no unit ##### Verified by - [InitCommandUnitTest](../../src/test/kotlin/de/hoennig/werkator/commands/InitCommandUnitTest.kt) `--systemd says what it created and how to install it, and keeps a host's environment file (Scenario#124.02)`, `--systemd without a resolvable jar path generates no unit file` ## The Solution `resolveSettings` keeps the order: disabled, then the checks, then the settings. `refusalOf` returns the reason a configuration cannot run, in the words of the former warnings, and `null` when it can; `portsValid` and `stateDirOf` hold the port check and the state directory. `createSystemdFiles` hands the writing to a `GeneratedFiles` helper, which writes a file and prints its `created` line, and to one step per kind of file: `writeServiceUnit`, `writeEnvFile`, `writeHostFiles`; `printInstallHints` prints the install lines. A local PIT run of `NginxProxyManager` and `InitCommand` afterwards: | Method | Mutation-CRAP | Complexity | Mutation score | |-------------------------------------|---------------|------------|----------------| | `NginxProxyManager.resolveSettings` | 5.58 | 5 | 0.71 | | `NginxProxyManager.refusalOf` | 7 | 7 | 1.00 | | `NginxProxyManager.portsValid` | 8.30 | 8 | 0.83 | | `NginxProxyManager.stateDirOf` | 3.14 | 3 | 0.75 | | `InitCommand.createSystemdFiles` | 2.09 | 2 | 0.71 | | `InitCommand.writeEnvFile` | 2.15 | 2 | 0.67 | | `InitCommand.writeHostFiles` | 2 | 2 | 1.00 | | `InitCommand.printInstallHints` | 1 | 1 | 0.86 | The highest score left in both classes is `InitCommand.runningVersion` at 10.75. The project maximum is now `FileArtifactStore.prune` at 23.50, so the gate goes down from 28 to 24. ## Additional Changes - `maxMutationCrap` in `build.gradle.kts` lowered from 28 to 24. - Version 1.37.5 with its entry in `releases.html`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: mhoennig <michael@hoennig.de> Reviewed-on: #124
5.3 KiB
PR#124: Managed nginx Settings and systemd Files Split into Their Steps
WARNING: This document describes only the change applied in this PR. It may already be outdated once the next PR is merged. Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation.
The Problem
Two methods of the installation are above the Kotlin target of 15, measured by the nightly mutation build of 2026-10-05:
| Method | Mutation-CRAP | Complexity | Mutation score |
|---|---|---|---|
NginxProxyManager.resolveSettings |
27.44 | 18 | 0.69 |
InitCommand.createSystemdFiles |
17.40 | 5 | 0.21 |
resolveSettings checks every setting of the managed nginx and builds its settings in one method; no test tried invalid ports, an invalid upstream host or a configured state directory.
createSystemdFiles writes six files and prints what it wrote and how to install it; no test read that output, so 38 of 48 mutants survived.
Non-Goals
- No change in behaviour: the same settings are refused with the same warnings, the same files are written with the same lines printed.
- The other groups above 15 follow in their own PRs.
The Scenarios
Feature: the managed nginx refuses what it cannot run
Scenario#124.01: every setting nginx cannot run with is refused, a configured state directory read as the host means it
So that a misconfigured nginx is refused before a container starts, and a valid one is never refused.
- Given the managed nginx is enabled
- When a port is 0 or above 65535, both ports are the same, the upstream host is no host name, or
server.porttakes the HTTPS port - Then no settings are resolved, and the warning names the reason
- When the ports are 1 and 65535, or an upstream host of its own is configured
- Then the settings carry them
- When
stateDirstarts with~/, or is relative - Then it is the home directory's, or the repository's
Verified by
- NginxProxyManagerUnitTest
every setting nginx cannot run with is refused, the ports up to their limits accepted (Scenario#124.01),a configured state directory has its ~ expanded and is read relative to the repository (Scenario#124.01), and the earlier tests of the server name and theserver.portcollision
Feature: init --systemd says what it did
Scenario#124.02: init --systemd says what it created and how to install it
So that the person running init --systemd can follow the printed steps without reading the code.
- Given a repository whose configuration has a public base URL
- When
init --systemdruns - Then it prints one
createdline for the unit, the environment file, the two Docker cleanup units, the.htaccessand the maintenance page- and the
ln -sfandsystemctl --userlines that install all three units
- and the
- When it runs again
- Then it says that the environment file already exists and is not overwritten
- When the jar path cannot be determined
- Then it prints the error and writes no unit
Verified by
- InitCommandUnitTest
--systemd says what it created and how to install it, and keeps a host's environment file (Scenario#124.02),--systemd without a resolvable jar path generates no unit file
The Solution
resolveSettings keeps the order: disabled, then the checks, then the settings.
refusalOf returns the reason a configuration cannot run, in the words of the former warnings, and null when it can; portsValid and stateDirOf hold the port check and the state directory.
createSystemdFiles hands the writing to a GeneratedFiles helper, which writes a file and prints its created line, and to one step per kind of file: writeServiceUnit, writeEnvFile, writeHostFiles; printInstallHints prints the install lines.
A local PIT run of NginxProxyManager and InitCommand afterwards:
| Method | Mutation-CRAP | Complexity | Mutation score |
|---|---|---|---|
NginxProxyManager.resolveSettings |
5.58 | 5 | 0.71 |
NginxProxyManager.refusalOf |
7 | 7 | 1.00 |
NginxProxyManager.portsValid |
8.30 | 8 | 0.83 |
NginxProxyManager.stateDirOf |
3.14 | 3 | 0.75 |
InitCommand.createSystemdFiles |
2.09 | 2 | 0.71 |
InitCommand.writeEnvFile |
2.15 | 2 | 0.67 |
InitCommand.writeHostFiles |
2 | 2 | 1.00 |
InitCommand.printInstallHints |
1 | 1 | 0.86 |
The highest score left in both classes is InitCommand.runningVersion at 10.75.
The project maximum is now FileArtifactStore.prune at 23.50, so the gate goes down from 28 to 24.
Additional Changes
maxMutationCrapinbuild.gradle.ktslowered from 28 to 24.- Version 1.37.5 with its entry in
releases.html.
🤖 Generated with Claude Code