[jOOQ/jOOQ#9506] More work on Migrations API:
- Don't throw exceptions in HistoryImpl::toString - LogMojo should log history as well - Reuse FilePattern::fileComparator also to sort IDs when loading files - LogMojo should also include HistoryMojo output - Make CommitType::getId optional for per-SQL-file metadata usage
This commit is contained in:
parent
32c51bbc3e
commit
f086212738
@ -90,6 +90,10 @@
|
||||
<groupId>org.jooq</groupId>
|
||||
<artifactId>jooq</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
|
||||
@ -48,6 +48,7 @@ import org.jooq.Migration;
|
||||
import org.jooq.Version;
|
||||
import org.jooq.tools.StringUtils;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
import org.apache.maven.plugins.annotations.Mojo;
|
||||
|
||||
/**
|
||||
@ -65,28 +66,30 @@ public class HistoryMojo extends AbstractMigrateMojo {
|
||||
|
||||
@Override
|
||||
final void execute1(Migration migration) throws Exception {
|
||||
if (getLog().isInfoEnabled()) {
|
||||
for (HistoryVersion version : migration.dsl().migrations().history()) {
|
||||
getLog().info(string(version.migratedAt()) + " - Version: " + string(version.version()));
|
||||
if (getLog().isInfoEnabled())
|
||||
for (HistoryVersion version : migration.dsl().migrations().history())
|
||||
log(getLog(), version);
|
||||
}
|
||||
|
||||
if (version.version().parents().size() > 1) {
|
||||
getLog().info(" Merged parents: ");
|
||||
static final void log(Log log, HistoryVersion version) {
|
||||
log.info(" " + string(version.migratedAt()) + " - Version: " + string(version.version()));
|
||||
|
||||
for (Version p : version.version().parents())
|
||||
getLog().info(" - " + string(p));
|
||||
}
|
||||
}
|
||||
if (version.version().parents().size() > 1) {
|
||||
log.info(" Merged parents: ");
|
||||
|
||||
for (Version p : version.version().parents())
|
||||
log.info(" - " + string(p));
|
||||
}
|
||||
}
|
||||
|
||||
private final String string(Instant instant) {
|
||||
private static final String string(Instant instant) {
|
||||
if (instant == null)
|
||||
return "0000-00-00T00:00:00.000Z";
|
||||
else
|
||||
return StringUtils.rightPad(instant.toString(), 24);
|
||||
}
|
||||
|
||||
private final String string(Version version) {
|
||||
private static final String string(Version version) {
|
||||
return version.id() + (!isEmpty(version.message()) ? " (" + version.message() + ")" : "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,9 +37,16 @@
|
||||
*/
|
||||
package org.jooq.migrations.maven;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.apache.maven.plugins.annotations.LifecyclePhase.GENERATE_SOURCES;
|
||||
import static org.apache.maven.plugins.annotations.ResolutionScope.TEST;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.jooq.History;
|
||||
import org.jooq.HistoryVersion;
|
||||
import org.jooq.Migration;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.tools.StringUtils;
|
||||
@ -63,7 +70,31 @@ public class LogMojo extends AbstractMigrateMojo {
|
||||
@Override
|
||||
final void execute1(Migration migration) throws Exception {
|
||||
if (getLog().isInfoEnabled()) {
|
||||
History history = migration.dsl().migrations().history();
|
||||
List<HistoryVersion> versions = StreamSupport
|
||||
.stream(history.spliterator(), false)
|
||||
.collect(toList());
|
||||
|
||||
if (versions.isEmpty()) {
|
||||
getLog().info("No migration history available yet");
|
||||
}
|
||||
else {
|
||||
getLog().info("Migration history");
|
||||
|
||||
for (HistoryVersion version : versions.subList(
|
||||
Math.max(0, versions.size() - 5),
|
||||
versions.size()
|
||||
)) {
|
||||
HistoryMojo.log(getLog(), version);
|
||||
}
|
||||
}
|
||||
|
||||
Query[] queries = migration.queries().queries();
|
||||
|
||||
getLog().info("Outstanding queries from " + migration.from() + " to " + migration.to() + ": "
|
||||
+ (queries.length == 0 ? "none" : "")
|
||||
);
|
||||
|
||||
log(getLog(), queries);
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,6 +168,10 @@ public final class FilePattern {
|
||||
);
|
||||
}
|
||||
|
||||
public final Comparator<File> fileComparator() {
|
||||
return fileComparator(sort());
|
||||
}
|
||||
|
||||
public static final Comparator<File> fileComparator(Sort sort) {
|
||||
if (sort == null)
|
||||
sort = SEMANTIC;
|
||||
|
||||
@ -39,6 +39,7 @@ package org.jooq.impl;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.unmodifiableCollection;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.jooq.impl.Tools.filter;
|
||||
import static org.jooq.impl.Tools.isEmpty;
|
||||
@ -48,6 +49,7 @@ import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -291,7 +293,10 @@ final class CommitsImpl implements Commits {
|
||||
// [#9506] TODO: Turning a directory into a MigrationsType (and various other conversion)
|
||||
// could be made reusable. This is certainly very useful for testing and interop,
|
||||
// e.g. also to support other formats (Flyway, Liquibase) as source
|
||||
TreeMap<String, CommitType> idToCommit = new TreeMap<>();
|
||||
TreeMap<String, CommitType> idToCommit = new TreeMap<>(comparing(
|
||||
java.io.File::new,
|
||||
pattern.fileComparator()
|
||||
));
|
||||
|
||||
List<FileData> list = files.stream().map(s -> new FileData(pattern, s)).collect(toList());
|
||||
|
||||
@ -303,6 +308,7 @@ final class CommitsImpl implements Commits {
|
||||
.withId(f.id)
|
||||
.withAuthor(f.author)
|
||||
.withMessage(f.message)
|
||||
.withTags(f.tags)
|
||||
);
|
||||
|
||||
for (FileData f : list) {
|
||||
@ -334,6 +340,9 @@ final class CommitsImpl implements Commits {
|
||||
);
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Loading files into: " + new MigrationsType().withCommits(idToCommit.values()));
|
||||
|
||||
return load(new MigrationsType().withCommits(idToCommit.values()));
|
||||
}
|
||||
|
||||
|
||||
@ -339,6 +339,9 @@ class HistoryImpl extends AbstractScope implements History {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "History [" + current() + "]";
|
||||
if (!isEmpty(versions))
|
||||
return "History [" + current() + "]";
|
||||
else
|
||||
return "History []";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1379,11 +1379,32 @@ final class Interpreter {
|
||||
}
|
||||
|
||||
private static final DataDefinitionException notExists(Named named) {
|
||||
return notExists(named.getClass().getSimpleName(), named);
|
||||
return notExists(typeName(named), named);
|
||||
}
|
||||
|
||||
private static final DataDefinitionException alreadyExists(Named named) {
|
||||
return alreadyExists(named.getClass().getSimpleName(), named);
|
||||
return alreadyExists(typeName(named), named);
|
||||
}
|
||||
|
||||
private static final String typeName(Named named) {
|
||||
|
||||
// TODO: Move this to the Named interface
|
||||
if (named instanceof Catalog)
|
||||
return "Catalog";
|
||||
else if (named instanceof Schema)
|
||||
return "Schema";
|
||||
else if (named instanceof Table)
|
||||
return "Table";
|
||||
else if (named instanceof Field)
|
||||
return "Field";
|
||||
else if (named instanceof Sequence)
|
||||
return "Sequence";
|
||||
else if (named instanceof Domain)
|
||||
return "Domain";
|
||||
else if (named instanceof Synonym)
|
||||
return "Synonym";
|
||||
else
|
||||
return named.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
private static final DataDefinitionException notExists(String type, Named named) {
|
||||
|
||||
@ -212,11 +212,37 @@ final class MigrationImpl extends AbstractScope implements Migration {
|
||||
|
||||
private final void revertUntracked(DefaultMigrationContext ctx, MigrationListener listener, HistoryRecord currentRecord) {
|
||||
if (ctx.revertUntrackedQueries.queries().length > 0)
|
||||
if (!TRUE.equals(dsl().settings().isMigrationRevertUntracked()))
|
||||
throw new DataMigrationVerificationException(
|
||||
"Non-empty difference between actual schema and migration from schema: " + ctx.revertUntrackedQueries +
|
||||
(currentRecord == null ? ("\n\nUse Settings.migrationAutoBaseline to automatically set a baseline") : "")
|
||||
);
|
||||
if (!TRUE.equals(dsl().settings().isMigrationRevertUntracked())) {
|
||||
if (currentRecord == null) {
|
||||
throw new DataMigrationVerificationException(
|
||||
"""
|
||||
Non-empty difference between actual schema and migration from schema: {queries}.
|
||||
|
||||
Possible remedies:
|
||||
- Use Settings.migrationAutoBaseline to automatically set a baseline.
|
||||
""".replace("{queries}", "" + ctx.revertUntrackedQueries)
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new DataMigrationVerificationException(
|
||||
"""
|
||||
Non-empty difference between actual schema and migration from schema: {queries}.
|
||||
|
||||
This can happen for two reasons:
|
||||
1) The migration specification of a version that has already been installed has been modified.
|
||||
2) The database schemas contain untracked objects.
|
||||
|
||||
Possible remedies if 1):
|
||||
- Revert changes to the migration specification and move those changes to a new version.
|
||||
|
||||
Possible remedies if 2):
|
||||
- Use Settings.migrationRevertUntracked to automatically drop unknown objects (at your own risk!)
|
||||
- Manually drop or move unknown objects outside of managed schemas.
|
||||
- Update migration scripts to track missing objects.
|
||||
""".replace("{queries}", "" + ctx.revertUntrackedQueries)
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (listener != null)
|
||||
execute(ctx, listener, ctx.revertUntrackedQueries);
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ import org.jooq.util.jaxb.tools.XMLBuilder;
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <all>
|
||||
* <element name="parents" type="{http://www.jooq.org/xsd/jooq-migrations-3.20.0.xsd}ParentsType" minOccurs="0"/>
|
||||
* <element name="id" type="{http://www.w3.org/2001/XMLSchema}string"/>
|
||||
* <element name="id" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
|
||||
* <element name="message" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
|
||||
* <element name="author" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
|
||||
* <element name="tags" type="{http://www.jooq.org/xsd/jooq-migrations-3.20.0.xsd}TagsType" minOccurs="0"/>
|
||||
@ -49,7 +49,6 @@ public class CommitType implements Serializable, XMLAppendable
|
||||
{
|
||||
|
||||
private final static long serialVersionUID = 32000L;
|
||||
@XmlElement(required = true)
|
||||
protected String id;
|
||||
protected String message;
|
||||
protected String author;
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
<complexType name="CommitType">
|
||||
<all>
|
||||
<element name="parents" type="tns:ParentsType" minOccurs="0" maxOccurs="1" />
|
||||
<element name="id" type="string" minOccurs="1" maxOccurs="1" />
|
||||
<element name="id" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="message" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="author" type="string" minOccurs="0" maxOccurs="1" />
|
||||
<element name="tags" type="tns:TagsType" minOccurs="0" maxOccurs="1" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user