> **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 After PR#111 `BuildDefinition.applyTo` had the highest Mutation-CRAP score of Werkator: 34 at a complexity of 34. A score is never below the complexity, so no test could bring it under the limit of 15. The method laid a build definition over its branch's settings in one `copy` of 21 fields, each with its own `?:` fallback, the docker and werkdock blocks nested inside. What the definition says falls into three groups, but the method did not show them: what the build runs, the rules the instance runs it under, and the sandbox it runs in. Only one test checked a single field of it (Scenario#72.01); every other field was held only by tests of the config loader. ## Non-Goals - No change in behaviour: which settings a definition can say, how they inherit, and which are pinned stay as they are. ## The Scenarios ### Feature: A build definition laid over its branch's settings #### Scenario#112.01: A definition that says nothing runs the branch's settings unchanged So that `builds.` with only a trigger builds exactly what the branch describes. - **Given** a branch with a non-default value for every setting - **When** an empty definition, or one with empty docker and werkdock blocks, is applied - **Then** the result equals the branch's settings ##### Verified by - [BuildDefinitionUnitTest](../../src/test/kotlin/de/hoennig/werkator/config/BuildDefinitionUnitTest.kt) — Scenario#112.01 #### Scenario#112.02: Every setting a definition says replaces the branch's own So that no key of `builds.` is read and then silently dropped. - **Given** the same branch, and a definition saying every setting, docker and werkdock included, with other values - **When** the definition is applied - **Then** every setting is the definition's ##### Verified by - [BuildDefinitionUnitTest](../../src/test/kotlin/de/hoennig/werkator/config/BuildDefinitionUnitTest.kt) — Scenario#112.02 #### Scenario#112.03: A definition saying some settings of a block keeps the rest of that block So that `docker.image` alone does not reset the branch's network, socket or environment. - **Given** the same branch, and a definition saying only the timeout, the docker image and the werkdock rootfs - **When** the definition is applied - **Then** those three are the definition's, everything else is the branch's ##### Verified by - [BuildDefinitionUnitTest](../../src/test/kotlin/de/hoennig/werkator/config/BuildDefinitionUnitTest.kt) — Scenario#112.03 ## The Solution `applyTo` lays the definition over the branch in three blocks: | Block | Settings | | ------------- | ------------------------------------------------------------------------ | | `withWork` | `buildCommand`, `cleanCommand`, `artifactDirs`, `stdoutLog`, `stderrLog` | | `withRules` | `requirePullRequest`, `statusContext`, `timeout`, `restartsInstance` | | `withSandbox` | `docker`, `werkdock` | `DockerOverrides.applyTo` and `WerkdockOverrides.applyTo` lay each sandbox's overrides over the branch's sandbox of that kind. The overrides and their config class now stand side by side, where Scenario#72.03 already holds that every setting of the one exists in the other. Measured with PIT as the nightly build runs it: | Method | Before | After | | ----------------------------- | ------ | ---------- | | `BuildDefinition.applyTo` | 34 | no mutants | | `BuildDefinition.withWork` | — | 6 | | `BuildDefinition.withRules` | — | 5 | | `BuildDefinition.withSandbox` | — | 5 | | `DockerOverrides.applyTo` | — | 8 | | `WerkdockOverrides.applyTo` | — | 6 | Every mutant of the new methods is killed, none is `INCONCLUSIVE`; each score equals its complexity. The gate `maxMutationCrap` falls from 35 to 34: the highest score left is `CapacitySizing.cpu` at 33.17. ## Additional Changes - Version 1.34.9 with its release note. - `BuildExecutorUnitTest`, Scenario#108.05, waits for the executing build's process before it cancels the build: a build counts as running before its process is started, and a cancel in between left no process to see terminated (`List is empty`, seen once in this PR's local build). ## Follow-up PRs - `CapacitySizing.cpu` (33.17) in its own PR.