Rename the machine configuration along with its directory

Found by the deployment to vm4006: the move renames the directory and
leaves the file inside it alone, so the machine configuration ended up at
`.git/werkator/.gittally.yml` — a pair of names the lookup did not
expect, because it pairs directory and file name. The instance resolved
empty credentials, no public URL and none of the host's build
definitions, and said nothing about it. That is the exact failure this
change exists to prevent, produced by the change itself.

`StateDirMigration` now renames the configuration with the directory,
unless one under the current name is already there. `ConfigFiles` carries
`.git/werkator/.gittally.yml` as a third candidate as well, for a
directory somebody moved by hand, where the migration never runs and so
can rename nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-31 09:10:16 +02:00
co-authored by Claude Opus 5
parent 8499bb7a53
commit 39dac4b51b
6 changed files with 91 additions and 4 deletions
@@ -108,6 +108,22 @@ So that an operator who moved the directory by hand does not lose the live state
- [StateDirMigrationTest: "leaves both alone when the current directory already exists"](../../src/test/kotlin/de/hoennig/werkator/StateDirMigrationTest.kt)
- [StateDirMigrationTest: "does nothing where there is no pre-rename directory"](../../src/test/kotlin/de/hoennig/werkator/StateDirMigrationTest.kt)
#### Scenario#1.06: The machine configuration survives a directory that moved without it
So that the move cannot produce a pair of names its own lookup does not expect.
- **Given** a state directory that has moved to `.git/werkator/`
- **and** the machine configuration inside it still named `.gittally.yml`
- **When** the configuration is loaded
- **Then** its settings take effect
- **and** where the move did it, the file carries the current name afterwards
##### Verified by
- [StateDirMigrationTest: "renames the machine configuration inside the moved directory"](../../src/test/kotlin/de/hoennig/werkator/StateDirMigrationTest.kt)
- [StateDirMigrationTest: "never overwrites a machine configuration that already carries the current name"](../../src/test/kotlin/de/hoennig/werkator/StateDirMigrationTest.kt)
- [ConfigLoaderTest: "finds the machine config left under its old name in an already-moved directory"](../../src/test/kotlin/de/hoennig/werkator/config/ConfigLoaderTest.kt)
## The Solution
**One spelling rule.**
@@ -120,6 +136,11 @@ This is what turns a rename into a decidable question instead of a matter of tas
The current name wins and the old file is then ignored rather than merged — two files side by side are a half-done rename, not a layering.
Error messages name the file that was actually read, so they never point at a file that does not exist.
**A move that finishes the job.**
The deployment to vm4006 found the gap the hard way: the move renames the *directory* and leaves the file inside it alone, so the machine configuration ended up at `.git/werkator/.gittally.yml` — a pair of names the lookup did not expect.
The instance came up with empty credentials and no host build definitions, without an error, which is the failure this PR exists to prevent.
`StateDirMigration` now renames the configuration along with the directory, unless one under the current name is already there, and `ConfigFiles` carries the intermediate path as a third candidate for a directory somebody moved by hand.
**A one-time move for the state.**
[`StateDirMigration`](../../src/main/kotlin/de/hoennig/werkator/StateDirMigration.kt) renames `.git/gittally` to `.git/werkator` from `CliRunner`, before any command resolves a path under it and therefore before the second Spring context of `server` exists.
A fallback was rejected here: unlike a configuration, the state is written, so a fallback would have to decide on every write which of two directories wins, where a one-time move decides once and leaves a single path behind.
+4 -1
View File
@@ -170,7 +170,10 @@ tar xzf ~/werkator-runtime-linux-x64.tar.gz -C ~/opt
# 4. artifact root: a move on the same filesystem, instant in both directions
mv ~/.local/state/gittally ~/.local/state/werkator
# 5. let the state directory move itself, and read what it says
# 5. let the state directory move itself, and read what it says.
# Check the output: publicBaseUrl, git.account and the host's build
# definitions must be there. Empty ones mean the machine configuration
# was not found — nothing fails on its own in that case.
cd ~/hs.hsadmin.ng
~/opt/werkator/jre/bin/java -jar ~/opt/werkator/lib/werkator.jar config:print --full