Files
werkator/docs/prs/2026-10-04-PR#115-forgejo-export-by-topic.md
miandmhoennig 81ab917e64
werkator build succeeded after 01:58
werkator/deploy build succeeded after 00:08
Forgejo export notes asked topic by topic, a job written as header and steps, export:forgejo in steps (v1.35.1) (#115)
## The Problem

The Forgejo workflow export (RFC 0006) held three methods above the Mutation-CRAP limit of 15, all by complexity:

| Method                                 | Mutation-CRAP | Complexity | What it did in one body                                                               |
| -------------------------------------- | ------------- | ---------- | ------------------------------------------------------------------------------------- |
| `ForgejoWorkflowExporter.settingNotes` | 31.63         | 27         | thirteen checks of what a workflow cannot carry over, from the container to `$branch` |
| `ExportForgejoCommand.call`            | 21.13         | 13         | found the repository, converted, reported, and wrote, each with its own exit          |
| `ForgejoWorkflowExporter.job`          | 19.15         | 19         | collected the notes, wrote the job's header, and wrote its steps                      |

A score is never below the complexity, so no test could bring them under 15.
This is one of seven groups the methods above 15 fall into; each group gets its own PR.

## Non-Goals

- No change in the exported workflows, the notes and their order, or the command's output and exit codes.

## The Scenarios

### Feature: What a workflow cannot carry over is named

#### Scenario#115.01: The werkdock notes name the sandbox's rootfs and its env, and a shared Gradle home only while it is enabled

So that a disabled sandbox is not reported as something to move to a runner.

- **Given** a definition with an enabled werkdock sandbox, a rootfs URL, a Gradle home and an env, and one with only a Gradle home
- **When** the configuration is exported
- **Then** the first names the rootfs file, the env keys, and the Gradle home, in this order
- **And** the second names nothing

##### Verified by

- [ForgejoWorkflowExporterUnitTest](../../src/test/kotlin/de/hoennig/werkator/forgejo/ForgejoWorkflowExporterUnitTest.kt) — Scenario#115.01
- Everything else of the export keeps its tests of PR#92 and PR#114, unchanged.

## The Solution

`settingNotes` asks topic by topic, in the order of the configuration reference, so the notes keep their order:

| Topic           | Notes                                                     |
| --------------- | --------------------------------------------------------- |
| `dockerNotes`   | `dockerfile`, `network`, `socket`                         |
| `werkdockNotes` | the sandbox's rootfs, `env`, `gradleHome`                 |
| `logNotes`      | `stdoutLog`/`stderrLog`                                   |
| `hostNotes`     | `requirePullRequest`, `statusContext`, `restartsInstance` |
| `stepNotes`     | `timeout`, a multi-line command, `$branch`                |

`job` collects the notes and writes `jobHeader` — runner, predecessor, branches, container, env, time limit — and `jobSteps` — checkout, clean, build, artifacts.

`ExportForgejoCommand.call` reads as its steps: `repositoryRoot`, `exportOf`, `refusedAsStrict`, then `printAll` or `write`.
A usage error is one `UsageError` thrown where it is found and answered in one place, with exit 2 as before.

Measured with PIT as the nightly build runs it, before Scenario#115.01 was added:

| Method                                  | Before | After |
| --------------------------------------- | ------ | ----- |
| `ForgejoWorkflowExporter.settingNotes`  | 31.63  | 1     |
| `ExportForgejoCommand.call`             | 21.13  | 3     |
| `ForgejoWorkflowExporter.job`           | 19.15  | 4.37  |
| `ForgejoWorkflowExporter.werkdockNotes` | —      | 10.86 |
| `ForgejoWorkflowExporter.jobHeader`     | —      | 10.01 |
| `ForgejoWorkflowExporter.dockerNotes`   | —      | 9     |
| `ForgejoWorkflowExporter.stepNotes`     | —      | 8     |
| `ForgejoWorkflowExporter.jobSteps`      | —      | 7     |
| `ForgejoWorkflowExporter.hostNotes`     | —      | 5     |
| `ExportForgejoCommand.exportOf`         | —      | 4.25  |

The highest score left in the export is `ForgejoWorkflowExporter.scalar` at 14.17, unchanged; none is `INCONCLUSIVE`.
The gate `maxMutationCrap` stays at 32: the highest score left in Werkator is `SystemHealth.assess$diskUtilization` at 31.28.

## Additional Changes

- Version 1.35.1 with its release note.

## Follow-up PRs

The other six groups above 15, one PR each:

- Health verdict and System page view: `SystemHealth.assess$diskUtilization` (31.28), `SystemMetricsView.from` (25.28), `HistoryPeaks.of` (16.38).
- Git and Gitea access: `GitService.authenticated` (30.12), `GiteaClient.readOpenPullRequests` (20.78).
- Sizing advice: `CapacitySizing.ram` (26.87), `column` (26.83), `disk` (21.19), `UiFormats.adviceLabel` (15.55).
- Installation: `NginxProxyManager.resolveSettings` (27.44), `InitCommand.createSystemdFiles` (17.40).
- The watcher's triggering and retention: `ConfigLoader.isTriggered` (26.16), `FileArtifactStore.prune` (23.50).
- Build lists and the repository line: `BuildsApiController.current` (22.15), `UiFormats.repoStatusLine` (16.03), `UiController.baseModel` (15.69).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: mhoennig <michael@hoennig.de>
Reviewed-on: #115
2026-10-04 21:22:21 +02:00

89 lines
5.2 KiB
Markdown

> **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
The Forgejo workflow export (RFC 0006) held three methods above the Mutation-CRAP limit of 15, all by complexity:
| Method | Mutation-CRAP | Complexity | What it did in one body |
| -------------------------------------- | ------------- | ---------- | ------------------------------------------------------------------------------------- |
| `ForgejoWorkflowExporter.settingNotes` | 31.63 | 27 | thirteen checks of what a workflow cannot carry over, from the container to `$branch` |
| `ExportForgejoCommand.call` | 21.13 | 13 | found the repository, converted, reported, and wrote, each with its own exit |
| `ForgejoWorkflowExporter.job` | 19.15 | 19 | collected the notes, wrote the job's header, and wrote its steps |
A score is never below the complexity, so no test could bring them under 15.
This is one of seven groups the methods above 15 fall into; each group gets its own PR.
## Non-Goals
- No change in the exported workflows, the notes and their order, or the command's output and exit codes.
## The Scenarios
### Feature: What a workflow cannot carry over is named
#### Scenario#115.01: The werkdock notes name the sandbox's rootfs and its env, and a shared Gradle home only while it is enabled
So that a disabled sandbox is not reported as something to move to a runner.
- **Given** a definition with an enabled werkdock sandbox, a rootfs URL, a Gradle home and an env, and one with only a Gradle home
- **When** the configuration is exported
- **Then** the first names the rootfs file, the env keys, and the Gradle home, in this order
- **And** the second names nothing
##### Verified by
- [ForgejoWorkflowExporterUnitTest](../../src/test/kotlin/de/hoennig/werkator/forgejo/ForgejoWorkflowExporterUnitTest.kt) — Scenario#115.01
- Everything else of the export keeps its tests of PR#92 and PR#114, unchanged.
## The Solution
`settingNotes` asks topic by topic, in the order of the configuration reference, so the notes keep their order:
| Topic | Notes |
| --------------- | --------------------------------------------------------- |
| `dockerNotes` | `dockerfile`, `network`, `socket` |
| `werkdockNotes` | the sandbox's rootfs, `env`, `gradleHome` |
| `logNotes` | `stdoutLog`/`stderrLog` |
| `hostNotes` | `requirePullRequest`, `statusContext`, `restartsInstance` |
| `stepNotes` | `timeout`, a multi-line command, `$branch` |
`job` collects the notes and writes `jobHeader` — runner, predecessor, branches, container, env, time limit — and `jobSteps` — checkout, clean, build, artifacts.
`ExportForgejoCommand.call` reads as its steps: `repositoryRoot`, `exportOf`, `refusedAsStrict`, then `printAll` or `write`.
A usage error is one `UsageError` thrown where it is found and answered in one place, with exit 2 as before.
Measured with PIT as the nightly build runs it, before Scenario#115.01 was added:
| Method | Before | After |
| --------------------------------------- | ------ | ----- |
| `ForgejoWorkflowExporter.settingNotes` | 31.63 | 1 |
| `ExportForgejoCommand.call` | 21.13 | 3 |
| `ForgejoWorkflowExporter.job` | 19.15 | 4.37 |
| `ForgejoWorkflowExporter.werkdockNotes` | — | 10.86 |
| `ForgejoWorkflowExporter.jobHeader` | — | 10.01 |
| `ForgejoWorkflowExporter.dockerNotes` | — | 9 |
| `ForgejoWorkflowExporter.stepNotes` | — | 8 |
| `ForgejoWorkflowExporter.jobSteps` | — | 7 |
| `ForgejoWorkflowExporter.hostNotes` | — | 5 |
| `ExportForgejoCommand.exportOf` | — | 4.25 |
The highest score left in the export is `ForgejoWorkflowExporter.scalar` at 14.17, unchanged; none is `INCONCLUSIVE`.
The gate `maxMutationCrap` stays at 32: the highest score left in Werkator is `SystemHealth.assess$diskUtilization` at 31.28.
## Additional Changes
- Version 1.35.1 with its release note.
## Follow-up PRs
The other six groups above 15, one PR each:
- Health verdict and System page view: `SystemHealth.assess$diskUtilization` (31.28), `SystemMetricsView.from` (25.28), `HistoryPeaks.of` (16.38).
- Git and Gitea access: `GitService.authenticated` (30.12), `GiteaClient.readOpenPullRequests` (20.78).
- Sizing advice: `CapacitySizing.ram` (26.87), `column` (26.83), `disk` (21.19), `UiFormats.adviceLabel` (15.55).
- Installation: `NginxProxyManager.resolveSettings` (27.44), `InitCommand.createSystemdFiles` (17.40).
- The watcher's triggering and retention: `ConfigLoader.isTriggered` (26.16), `FileArtifactStore.prune` (23.50).
- Build lists and the repository line: `BuildsApiController.current` (22.15), `UiFormats.repoStatusLine` (16.03), `UiController.baseModel` (15.69).