refactor(seed): the boards and the esports history load on start, not in a migration - #1328
Merged
Merged
Conversation
… in a migration Both seeds were repeatable Flyway migrations written in Kotlin that read CSV off the classpath. Seed data is not schema, and once migrations run in their own Job the runner cannot execute Kotlin at all, so they had to leave first. They become ShippedBoards and ShippedEsports: the same raw-JDBC upserts, keyed the same way, in one transaction as Flyway gave them, behind the same bean-plus-listener shape the art steps already use. Records are ordered ahead of art, which the migrator used to guarantee by running before the context was up. flyway.ignore-migration-patterns is set to repeatable:missing. Every database that ran these still carries their history rows, validate refuses an applied migration it cannot resolve, and that would stop the application booting rather than fail a test. A versioned migration going missing stays an error. detekt exempted these files through db/migration, which they have left; the two rules that actually fire on them, MagicNumber and LongMethod, name them instead.
Contributor
Changes
0.41 test lines per prod line. Coverage
No baseline is cached from Patch coverage: 93.9%, 62 of 66 changed lines covered. 4 uncovered lines in this pull request
|
BoardArtSystemTest failed with "No board in the seeded history carries a photo": the art ran before the records it hangs on. @order was on the class, and ApplicationListenerMethodAdapter resolves an @eventlistener's order from the method alone, so it was never applied and the two listeners raced. A class-level @order looks correct and does nothing, so a test asserts the annotation is on each onReady and that records sort before art. Both cases fail when the annotation is moved back to the class.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1295. Part of #1289.
The boards and the esports history were loaded by two repeatable Flyway migrations written in Kotlin, which read their CSV off the classpath and hashed the files to decide whether to re-run. Seed data is not schema, and the migrator is about to stop being able to run this at all: #1297 moves migrations into a Job, and #1296 replaces Flyway with Liquibase. A Liquibase CLI cannot execute Kotlin, so the seeds have to leave before the migrator can be swapped.
What this achieves
R__Boards_seedandR__Esports_seedbecomeShippedBoardsandShippedEsports, ordinary beans that run onApplicationReadyEvent. The schema migrator is left with schema.Nothing about what lands in the database changes. The upserts are the same raw JDBC, keyed the same way, with the same
<=>no-op guards, the same "deletion outranks the files", and the same rule that an attached account is never re-matched. The five integration tests covering that behaviour are unchanged except for how they invoke the loader.How
The files moved with
git mv, so the diff reads as a move rather than a rewrite.migrate(Context)becomesapply(), wrapped in oneTransactionTemplatewithDataSourceUtils.getConnection— the same all-or-nothing transaction Flyway used to provide, taken from the transaction rather than opened beside it.The shape is the one this codebase already uses for work that cannot happen in a migration.
StoredImageRenditionsBackfillstates it outright — in the application rather than a migration, and idempotent, so every start after the first does nothing — and both art steps are a worker bean plus a thinApplicationReadyEventlistener that logs and swallows so a failure never blocks start-up. The new loaders are that, andSeedCsvstays a constructor default rather than a bean, asShippedArtalready has it.The tests stop building a hand-rolled Flyway
Contextover a raw connection and call the bean. The two parsing tests moved out of thedb.migrationpackage, which no longer describes them.Not in scope
Liquibase (#1296) and the pre-rollout migration Job (#1297). This only takes the Kotlin out of the migrator's way.
The seeds' own behaviour. Their idempotency was already thorough and is left alone deliberately — changing where code runs from and what it does in the same pull request would make the integration tests useless as a control.
Worth a reviewer's attention
flyway.ignore-migration-patterns: repeatable:missingis the load-bearing line here. Deleting a repeatable migration leaves its row inflyway_schema_history, and Flyway's default (*:future) makes validate reject an applied migration it can no longer resolve — the application refuses to boot. Those rows cannot be cleaned by a migration either, because validate runs before migrate. CI cannot catch this: it builds a fresh database with no history to be missing from. The pattern is scoped so a missing versioned migration is still an error.ApplicationReadyEventlisteners now, soSeedOrderputs records at 100 and art at 200. Without it a fresh database would intermittently get art with nothing to attach it to.**/db/migration/**, which they have left. Re-granting all 19 by filename would have silently exempted them fromClassNamingandSwallowedExceptionthey no longer need, so only the two that actually fire are named:MagicNumber, because the numbers are JDBC parameter positions, andLongMethod, which the existing comment already covers.TestCleanUpListenerrestoresgamefrom a snapshot of what the migration left, andgameis now populated atApplicationReadyEventinstead. That still happens before the first test method, so the snapshot should be unchanged — but it is reasoning, and the integration run is what confirms it.Verification
Locally:
compileKotlin,compileTestKotlin,compileIntegrationTestKotlinandcompileTestFixturesKotlinall build;ktlintCheck,detekt,detektIntegrationTestSourceSetanddetektTestFixturesSourceSetare green; the parsing unit tests pass.The database-backed integration tests —
BoardSeedLoadIT,EsportsSeedLoadIT,RecoveredAttributionIT,ShippedBoardArtIT,ShippedArtIT— are the real proof that the semantics survived the move, and they need MariaDB, so CI runs them.