Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve update summary count calculations (DAT-16656 and DAT-16357) #5634

Merged
merged 10 commits into from
Mar 13, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import liquibase.changelog.RanChangeSet
import liquibase.database.Database
import liquibase.exception.CommandExecutionException
import liquibase.exception.CommandValidationException
import liquibase.extension.testing.setup.SetupEnvironmentVariableProvider

import java.util.regex.Pattern

Expand Down Expand Up @@ -511,7 +510,7 @@ Optional Args:
[
"""
UPDATE SUMMARY
Run: 1
Run: 0
Previously run: 0
Filtered out: 0
-------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class ShouldRunChangeSetFilter implements ChangeSetFilter {

private final Map<String, RanChangeSet> ranChangeSets;
private final boolean ignoreClasspathPrefix;
public static final String CHANGESET_ALREADY_RAN_MESSAGE = "Changeset already ran";


public ShouldRunChangeSetFilter(Database database, boolean ignoreClasspathPrefix) throws DatabaseException {
this.ignoreClasspathPrefix = ignoreClasspathPrefix;
Expand Down Expand Up @@ -64,7 +66,7 @@ public ChangeSetFilterResult accepts(ChangeSet changeSet) {
if (changeSet.shouldRunOnChange() && checksumChanged(changeSet, ranChangeSet)) {
return new ChangeSetFilterResult(true, "Changeset checksum changed", this.getClass(), getMdcName(), getDisplayName());
}
return new ChangeSetFilterResult(false, "Changeset already ran", this.getClass(), getMdcName(), getDisplayName());
return new ChangeSetFilterResult(false, CHANGESET_ALREADY_RAN_MESSAGE, this.getClass(), getMdcName(), getDisplayName());
}
return new ChangeSetFilterResult(true, "Changeset has not ran yet", this.getClass(), getMdcName(), getDisplayName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public void run(CommandResultsBuilder resultsBuilder) throws Exception {
runChangeLogIterator.run(new UpdateVisitor(database, changeExecListener, new ShouldRunChangeSetFilter(database)),
new RuntimeEnvironment(database, contexts, labelExpression));
} finally {
UpdateSummaryDetails details = ShowSummaryUtil.buildSummaryDetails(databaseChangeLog, getShowSummary(commandScope), getShowSummaryOutput(commandScope), statusVisitor, resultsBuilder.getOutputStream(), runChangeLogIterator);
UpdateSummaryDetails details = ShowSummaryUtil.buildSummaryDetails(databaseChangeLog, getShowSummary(commandScope), getShowSummaryOutput(commandScope), statusVisitor, resultsBuilder.getOutputStream(), runChangeLogIterator, changeExecListener);
if (details != null) {
updateReportParameters.getOperationInfo().setUpdateSummaryMsg(details.getOutput());
updateReportParameters.getChangesetInfo().addAllToPendingChangesetInfoList(details.getSkipped());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package liquibase.util;

import liquibase.*;
import liquibase.GlobalConfiguration;
import liquibase.Scope;
import liquibase.UpdateSummaryEnum;
import liquibase.UpdateSummaryOutputEnum;
import liquibase.changelog.ChangeLogIterator;
import liquibase.changelog.ChangeSet;
import liquibase.changelog.ChangeSetStatus;
Expand All @@ -9,6 +12,8 @@
import liquibase.changelog.filter.ChangeSetFilterResult;
import liquibase.changelog.filter.DbmsChangeSetFilter;
import liquibase.changelog.filter.ShouldRunChangeSetFilter;
import liquibase.changelog.visitor.ChangeExecListener;
import liquibase.changelog.visitor.DefaultChangeExecListener;
import liquibase.changelog.visitor.StatusVisitor;
import liquibase.exception.LiquibaseException;
import liquibase.logging.mdc.MdcKey;
Expand Down Expand Up @@ -62,22 +67,41 @@ public static void showUpdateSummary(DatabaseChangeLog changeLog, UpdateSummaryE
*/
public static void showUpdateSummary(DatabaseChangeLog changeLog, UpdateSummaryEnum showSummary, UpdateSummaryOutputEnum showSummaryOutput, StatusVisitor statusVisitor, OutputStream outputStream, ChangeLogIterator runChangeLogIterator)
throws LiquibaseException, IOException {
buildSummaryDetails(changeLog, showSummary, showSummaryOutput, statusVisitor, outputStream, runChangeLogIterator);
buildSummaryDetails(changeLog, showSummary, showSummaryOutput, statusVisitor, outputStream, runChangeLogIterator, null);
}

/**
* Show a summary of the changesets which were executed AND return an object with the records of what has happened.
*
* @param changeLog The changelog used in this update
* @param showSummary Flag to control whether we show the summary
* @param showSummaryOutput Flag to control where we show the summary
* @param statusVisitor The StatusVisitor used to determine statuses
* @param outputStream The OutputStream to use for the summary
* @param changeLog The changelog used in this update
* @param showSummary Flag to control whether we show the summary
* @param showSummaryOutput Flag to control where we show the summary
* @param statusVisitor The StatusVisitor used to determine statuses
* @param outputStream The OutputStream to use for the summary
* @return the details of the update summary
* @throws LiquibaseException Thrown by this method
* @throws IOException Thrown by this method
* @deprecated use {@link ShowSummaryUtil#buildSummaryDetails(DatabaseChangeLog, UpdateSummaryEnum, UpdateSummaryOutputEnum, StatusVisitor, OutputStream, ChangeLogIterator, ChangeExecListener)} instead.
*/
public static UpdateSummaryDetails buildSummaryDetails(DatabaseChangeLog changeLog, UpdateSummaryEnum showSummary, UpdateSummaryOutputEnum showSummaryOutput, StatusVisitor statusVisitor, OutputStream outputStream, ChangeLogIterator runChangeLogIterator)
@Deprecated
public static UpdateSummaryDetails buildSummaryDetails(DatabaseChangeLog changeLog, UpdateSummaryEnum showSummary, UpdateSummaryOutputEnum showSummaryOutput, StatusVisitor statusVisitor, OutputStream outputStream, ChangeLogIterator runChangeLogIterator) throws LiquibaseException, IOException {
return buildSummaryDetails(changeLog, showSummary, showSummaryOutput, statusVisitor,outputStream, runChangeLogIterator, null);
}

/**
* Show a summary of the changesets which were executed AND return an object with the records of what has happened.
*
* @param changeLog The changelog used in this update
* @param showSummary Flag to control whether we show the summary
* @param showSummaryOutput Flag to control where we show the summary
* @param statusVisitor The StatusVisitor used to determine statuses
* @param outputStream The OutputStream to use for the summary
* @param changeExecListener
* @return the details of the update summary
* @throws LiquibaseException Thrown by this method
* @throws IOException Thrown by this method
*/
public static UpdateSummaryDetails buildSummaryDetails(DatabaseChangeLog changeLog, UpdateSummaryEnum showSummary, UpdateSummaryOutputEnum showSummaryOutput, StatusVisitor statusVisitor, OutputStream outputStream, ChangeLogIterator runChangeLogIterator, ChangeExecListener changeExecListener)
throws LiquibaseException, IOException {
//
// Check the global flag to turn the summary off
Expand Down Expand Up @@ -113,7 +137,7 @@ public static UpdateSummaryDetails buildSummaryDetails(DatabaseChangeLog changeL
//
// Only show the summary
//
UpdateSummaryDetails summaryDetails = showSummary(changeLog, statusVisitor, skippedChangeSets, filterDenied, outputStream, showSummaryOutput, runChangeLogIterator);
UpdateSummaryDetails summaryDetails = showSummary(changeLog, statusVisitor, skippedChangeSets, filterDenied, outputStream, showSummaryOutput, runChangeLogIterator, changeExecListener);
summaryDetails.getSummary().setValue(showSummary.toString());
boolean shouldPrintDetailTable = showSummary != UpdateSummaryEnum.SUMMARY && (!skippedChangeSets.isEmpty() || !denied.isEmpty() || !additionalChangeSetStatus.isEmpty());

Expand Down Expand Up @@ -270,17 +294,18 @@ private static UpdateSummaryDetails showSummary(DatabaseChangeLog changeLog,
List<ChangeSetStatus> filterDenied,
OutputStream outputStream,
UpdateSummaryOutputEnum showSummaryOutput,
ChangeLogIterator runChangeLogIterator) throws LiquibaseException {
ChangeLogIterator runChangeLogIterator,
ChangeExecListener changeExecListener) throws LiquibaseException {
StringBuilder builder = new StringBuilder();
builder.append(System.lineSeparator());
int totalInChangelog = changeLog.getChangeSets().size() + skippedChangeSets.size();
int skipped = skippedChangeSets.size();
int filtered = filterDenied.size();
ShowSummaryGeneratorFactory showSummaryGeneratorFactory = Scope.getCurrentScope().getSingleton(ShowSummaryGeneratorFactory.class);
ShowSummaryGenerator showSummaryGenerator = showSummaryGeneratorFactory.getShowSummaryGenerator();
int additional = showSummaryGenerator.getAllAdditionalChangeSetStatus(runChangeLogIterator).size();
int totalAccepted = statusVisitor.getChangeSetsToRun().size() - additional;
int totalPreviouslyRun = totalInChangelog - filtered - skipped - totalAccepted - additional;
showSummaryGenerator.getAllAdditionalChangeSetStatus(runChangeLogIterator);
int totalAccepted = calculateAccepted(statusVisitor, changeExecListener);
int totalPreviouslyRun = calculatePreviouslyRun(statusVisitor);
UpdateSummary updateSummaryMdc = new UpdateSummary(null, totalAccepted, totalPreviouslyRun, null, totalInChangelog);

String message = "UPDATE SUMMARY";
Expand Down Expand Up @@ -343,6 +368,28 @@ private static UpdateSummaryDetails showSummary(DatabaseChangeLog changeLog,
return updateSummaryDetails;
}

private static int calculatePreviouslyRun(StatusVisitor statusVisitor) {
return (int) statusVisitor.getStatuses().stream().filter(
s -> s.getFilterResults().stream().anyMatch(
fr -> fr.getFilter().isAssignableFrom(ShouldRunChangeSetFilter.class) && !fr.isAccepted() && fr.getMessage().equals(ShouldRunChangeSetFilter.CHANGESET_ALREADY_RAN_MESSAGE)
)
).count();
}

/**
* Calculate the accepted number of changesets.
* The status visitor provides a list of changesets that are expected to execute, not the actual list of
* executed changesets. We retain this code despite its inaccuracy for backwards compatibility, in case
* a change exec listener is not provided.
*/
private static int calculateAccepted(StatusVisitor statusVisitor, ChangeExecListener changeExecListener) {
int ran = statusVisitor.getChangeSetsToRun().size();
if (changeExecListener instanceof DefaultChangeExecListener) {
ran = ((DefaultChangeExecListener) changeExecListener).getDeployedChangeSets().size();
}
return ran;
}

//
// Create a Writer to display the summary
//
Expand Down