mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-28 11:25:00 +00:00
fix: resolve duplicate flyway migration versions
This commit is contained in:
parent
e42f3950bf
commit
ed07472dad
5 changed files with 98 additions and 3 deletions
|
|
@ -99,11 +99,11 @@
|
|||
|
||||
- `V12__governance_notifications.sql`
|
||||
- `user_notification.created_at / read_at`
|
||||
- `V13__api_token_timestamptz.sql`
|
||||
- `V24__api_token_timestamptz.sql`
|
||||
- `api_token.expires_at / last_used_at / revoked_at / created_at`
|
||||
- `V14__account_merge_request_timestamptz.sql`
|
||||
- `V25__account_merge_request_timestamptz.sql`
|
||||
- `account_merge_request.token_expires_at / completed_at / created_at`
|
||||
- `V15__skill_version_timestamptz.sql`
|
||||
- `V26__skill_version_timestamptz.sql`
|
||||
- `skill_version.published_at / created_at / yanked_at`
|
||||
- `V16__skill_hidden_at_timestamptz.sql`
|
||||
- `skill.hidden_at`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
package com.iflytek.skillhub.db;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class FlywayMigrationGuardrailTest {
|
||||
|
||||
private static final Pattern VERSIONED_MIGRATION_PATTERN =
|
||||
Pattern.compile("^V(?<version>\\d+)__(?<description>.+)\\.sql$");
|
||||
|
||||
@Test
|
||||
void versionedMigrations_mustUseUniqueVersions() throws IOException {
|
||||
Map<Integer, List<String>> versions = new LinkedHashMap<>();
|
||||
|
||||
for (Path file : migrationFiles()) {
|
||||
Matcher matcher = VERSIONED_MIGRATION_PATTERN.matcher(file.getFileName().toString());
|
||||
if (!matcher.matches()) {
|
||||
continue;
|
||||
}
|
||||
int version = Integer.parseInt(matcher.group("version"));
|
||||
versions.computeIfAbsent(version, ignored -> new ArrayList<>())
|
||||
.add(relativeToRepo(file));
|
||||
}
|
||||
|
||||
List<String> duplicates = versions.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().size() > 1)
|
||||
.map(entry -> "V" + entry.getKey() + " -> " + entry.getValue())
|
||||
.toList();
|
||||
|
||||
assertThat(duplicates).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void versionedMigrations_mustRemainContiguous() throws IOException {
|
||||
List<Integer> versions = migrationFiles().stream()
|
||||
.map(path -> VERSIONED_MIGRATION_PATTERN.matcher(path.getFileName().toString()))
|
||||
.filter(Matcher::matches)
|
||||
.map(matcher -> Integer.parseInt(matcher.group("version")))
|
||||
.sorted()
|
||||
.toList();
|
||||
|
||||
List<String> gaps = new ArrayList<>();
|
||||
for (int expected = 1; expected <= versions.size(); expected++) {
|
||||
int actual = versions.get(expected - 1);
|
||||
if (actual != expected) {
|
||||
gaps.add("expected V" + expected + " but found V" + actual);
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(gaps).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void migrationFiles_mustMatchFlywayVersionedNaming() throws IOException {
|
||||
List<String> invalidFiles = migrationFiles().stream()
|
||||
.map(path -> path.getFileName().toString())
|
||||
.filter(name -> !VERSIONED_MIGRATION_PATTERN.matcher(name).matches())
|
||||
.sorted()
|
||||
.toList();
|
||||
|
||||
assertThat(invalidFiles).isEmpty();
|
||||
}
|
||||
|
||||
private List<Path> migrationFiles() throws IOException {
|
||||
Path root = repoRoot()
|
||||
.resolve("server")
|
||||
.resolve("skillhub-app")
|
||||
.resolve("src/main/resources/db/migration");
|
||||
try (var stream = Files.list(root)) {
|
||||
return stream
|
||||
.filter(path -> path.getFileName().toString().endsWith(".sql"))
|
||||
.sorted(Comparator.comparing(path -> path.getFileName().toString()))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
private Path repoRoot() {
|
||||
return Path.of("").toAbsolutePath().getParent().getParent();
|
||||
}
|
||||
|
||||
private String relativeToRepo(Path file) {
|
||||
return repoRoot().relativize(file).toString();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue