Managed nginx settings and systemd files split into their steps, gate down to 24 (v1.37.5) #124

Merged
mi merged 2 commits from mihoe/installation-steps into main 2026-10-05 19:29:56 +02:00
Owner

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 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 --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

> 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)
mi added 1 commit 2026-10-05 18:58:59 +02:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mi changed title from WIP: Managed nginx settings and systemd files split into their steps to Managed nginx settings and systemd files split into their steps, gate down to 24 (v1.37.5) 2026-10-05 19:09:30 +02:00
mi added 1 commit 2026-10-05 19:09:30 +02:00
mi merged commit 108264d405 into main 2026-10-05 19:29:56 +02:00
mi deleted branch mihoe/installation-steps 2026-10-05 19:29:56 +02:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mi/werkator#124