{"sha":"386d2c163f03bc8af225744f05742af80a94225b","node_id":"C_kwDOAG1oCtoAKDM4NmQyYzE2M2YwM2JjOGFmMjI1NzQ0ZjA1NzQyYWY4MGE5NDIyNWI","commit":{"author":{"name":"Andrea Angella","email":"andrea.angella@red-gate.com","date":"2022-01-17T15:13:16Z"},"committer":{"name":"Andrea Angella","email":"andrea.angella@red-gate.com","date":"2022-01-17T15:13:16Z"},"message":"internal changes","tree":{"sha":"5f4c61cd8e7e8fad9c2d4811e7378c293cfb3f69","url":"https://api.github.com/repos/flyway/flyway/git/trees/5f4c61cd8e7e8fad9c2d4811e7378c293cfb3f69"},"url":"https://api.github.com/repos/flyway/flyway/git/commits/386d2c163f03bc8af225744f05742af80a94225b","comment_count":0,"verification":{"verified":false,"reason":"unsigned","signature":null,"payload":null}},"url":"https://api.github.com/repos/flyway/flyway/commits/386d2c163f03bc8af225744f05742af80a94225b","html_url":"https://github.com/flyway/flyway/commit/386d2c163f03bc8af225744f05742af80a94225b","comments_url":"https://api.github.com/repos/flyway/flyway/commits/386d2c163f03bc8af225744f05742af80a94225b/comments","author":{"login":"angellaa","id":641111,"node_id":"MDQ6VXNlcjY0MTExMQ==","avatar_url":"https://avatars.githubusercontent.com/u/641111?v=4","gravatar_id":"","url":"https://api.github.com/users/angellaa","html_url":"https://github.com/angellaa","followers_url":"https://api.github.com/users/angellaa/followers","following_url":"https://api.github.com/users/angellaa/following{/other_user}","gists_url":"https://api.github.com/users/angellaa/gists{/gist_id}","starred_url":"https://api.github.com/users/angellaa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/angellaa/subscriptions","organizations_url":"https://api.github.com/users/angellaa/orgs","repos_url":"https://api.github.com/users/angellaa/repos","events_url":"https://api.github.com/users/angellaa/events{/privacy}","received_events_url":"https://api.github.com/users/angellaa/received_events","type":"User","site_admin":false},"committer":{"login":"angellaa","id":641111,"node_id":"MDQ6VXNlcjY0MTExMQ==","avatar_url":"https://avatars.githubusercontent.com/u/641111?v=4","gravatar_id":"","url":"https://api.github.com/users/angellaa","html_url":"https://github.com/angellaa","followers_url":"https://api.github.com/users/angellaa/followers","following_url":"https://api.github.com/users/angellaa/following{/other_user}","gists_url":"https://api.github.com/users/angellaa/gists{/gist_id}","starred_url":"https://api.github.com/users/angellaa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/angellaa/subscriptions","organizations_url":"https://api.github.com/users/angellaa/orgs","repos_url":"https://api.github.com/users/angellaa/repos","events_url":"https://api.github.com/users/angellaa/events{/privacy}","received_events_url":"https://api.github.com/users/angellaa/received_events","type":"User","site_admin":false},"parents":[{"sha":"7d62c43bdc4b14dd3c96847cd4908bc16c85647d","url":"https://api.github.com/repos/flyway/flyway/commits/7d62c43bdc4b14dd3c96847cd4908bc16c85647d","html_url":"https://github.com/flyway/flyway/commit/7d62c43bdc4b14dd3c96847cd4908bc16c85647d"}],"stats":{"total":192,"additions":100,"deletions":92},"files":[{"sha":"a69a2a86e954b83ad2eb9c6f0bb0253f278a7928","filename":".gitignore","status":"modified","additions":1,"deletions":0,"changes":1,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/.gitignore","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/.gitignore","contents_url":"https://api.github.com/repos/flyway/flyway/contents/.gitignore?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -21,4 +21,5 @@ target\n \n flyway-core/SPOOLEDCONTENTS.SQL\n flyway-cli-sample/jars/\n+flyway-*compare/**/resources/*compare/\n out/**"},{"sha":"ea0978753ba8e97045d94ae8298d0c5e1f1b5b0a","filename":"flyway-commandline/src/main/assembly/component.xml","status":"modified","additions":10,"deletions":0,"changes":10,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/flyway-commandline%2Fsrc%2Fmain%2Fassembly%2Fcomponent.xml","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/flyway-commandline%2Fsrc%2Fmain%2Fassembly%2Fcomponent.xml","contents_url":"https://api.github.com/repos/flyway/flyway/contents/flyway-commandline%2Fsrc%2Fmain%2Fassembly%2Fcomponent.xml?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -91,6 +91,16 @@\n 644\n \n \n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n \n target/editions/enterprise\n lib/enterprise"},{"sha":"5a62167fcbaf54acd00e23ca9bed1a3fc5761cec","filename":"flyway-commandline/src/main/java/org/flywaydb/commandline/CommandLineArguments.java","status":"modified","additions":7,"deletions":12,"changes":19,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/flyway-commandline%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcommandline%2FCommandLineArguments.java","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/flyway-commandline%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcommandline%2FCommandLineArguments.java","contents_url":"https://api.github.com/repos/flyway/flyway/contents/flyway-commandline%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcommandline%2FCommandLineArguments.java?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -56,9 +56,6 @@ public static boolean isValid(String value) {\n }\n }\n \n- // Flags\n- // GNU standards require --version, --help and their single-letter forms\n- // RG standards mandate --help / -h\n private static final String DEBUG_FLAG = \"-X\";\n private static final String QUIET_FLAG = \"-q\";\n private static final String SUPPRESS_PROMPT_FLAG = \"-n\";\n@@ -86,11 +83,9 @@ public static boolean isValid(String value) {\n \n private static final Set COMMAND_LINE_ONLY_OPTIONS = new HashSet<>(Arrays.asList(\n OUTPUT_FILE, OUTPUT_TYPE, COLOR, WORKING_DIRECTORY, INFO_SINCE_DATE,\n- INFO_UNTIL_DATE, INFO_SINCE_VERSION, INFO_UNTIL_VERSION, INFO_OF_STATE\n- ));\n+ INFO_UNTIL_DATE, INFO_SINCE_VERSION, INFO_UNTIL_VERSION, INFO_OF_STATE));\n \n private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(\"dd/MM/yyyy HH:mm\");\n-\n private static final List VALID_OPERATIONS_AND_FLAGS = getValidOperationsAndFlags();\n \n private static List getValidOperationsAndFlags() {\n@@ -141,11 +136,9 @@ private static String getArgumentValue(String argName, String[] allArgs) {\n \n private static String parseConfigurationOptionValueFromArg(String arg) {\n int index = arg.indexOf(\"=\");\n-\n if (index < 0 || index == arg.length()) {\n return \"\";\n }\n-\n return arg.substring(index + 1);\n }\n \n@@ -185,6 +178,12 @@ private static boolean isConfigurationArg(String arg) {\n return arg.startsWith(\"-\") && arg.contains(\"=\");\n }\n \n+ public List getFlags() {\n+ return Arrays.stream(args)\n+ .filter(a -> a.startsWith(\"-\") && !a.contains(\"=\"))\n+ .collect(Collectors.toList());\n+ }\n+\n public void validate() {\n for (String arg : args) {\n if (!isConfigurationArg(arg) && !VALID_OPERATIONS_AND_FLAGS.contains(arg) && !isHandledByExtension(arg)) {\n@@ -282,21 +281,17 @@ public MigrationVersion getInfoUntilVersion() {\n \n public MigrationState getInfoOfState() {\n String stateStr = getArgumentValue(INFO_OF_STATE, args);\n-\n if (!StringUtils.hasText(stateStr)) {\n return null;\n }\n-\n return MigrationState.valueOf(stateStr.toUpperCase(Locale.ENGLISH));\n }\n \n private MigrationVersion parseVersion(String argument) {\n String versionStr = getArgumentValue(argument, args);\n-\n if (versionStr.isEmpty()) {\n return null;\n }\n-\n return MigrationVersion.fromVersion(versionStr);\n }\n "},{"sha":"6c247f183706ca0dc97e73f16a595c43f8277307","filename":"flyway-commandline/src/main/java/org/flywaydb/commandline/Main.java","status":"modified","additions":1,"deletions":1,"changes":2,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/flyway-commandline%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcommandline%2FMain.java","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/flyway-commandline%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcommandline%2FMain.java","contents_url":"https://api.github.com/repos/flyway/flyway/contents/flyway-commandline%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcommandline%2FMain.java?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -292,7 +292,7 @@ private static OperationResultBase executeOperation(Flyway flyway, String operat\n boolean handled = false;\n for (CommandExtension extension : PluginRegister.getPlugins(CommandExtension.class)) {\n if (extension.handlesCommand(operation)) {\n- result = extension.handle(operation, config);\n+ result = extension.handle(operation, config, commandLineArguments.getFlags());\n handled = true;\n }\n }"},{"sha":"ffb391d6a257439112e91c8d666ac918f4497991","filename":"flyway-core/src/main/java/org/flywaydb/core/api/Location.java","status":"modified","additions":15,"deletions":34,"changes":49,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Fapi%2FLocation.java","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Fapi%2FLocation.java","contents_url":"https://api.github.com/repos/flyway/flyway/contents/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Fapi%2FLocation.java?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -29,54 +29,41 @@ public final class Location implements Comparable {\n * The prefix for classpath locations.\n */\n private static final String CLASSPATH_PREFIX = \"classpath:\";\n-\n /**\n * The prefix for filesystem locations.\n */\n public static final String FILESYSTEM_PREFIX = \"filesystem:\";\n-\n /**\n * The prefix for AWS S3 locations.\n */\n private static final String AWS_S3_PREFIX = \"s3:\";\n-\n /**\n * The prefix for Google Cloud Storage locations.\n */\n private static final String GCS_PREFIX = \"gcs:\";\n \n /**\n- * The prefix part of the location. Can be either classpath: or filesystem:.\n- *\n * @return The prefix part of the location. Can be either classpath: or filesystem:.\n */\n @Getter\n private final String prefix;\n-\n /**\n * The path part of the location.\n */\n private String rawPath;\n-\n /**\n * The first folder in the path. This will equal rawPath if the path does not contain any wildcards\n *\n * @return The root part of the path part of the location.\n */\n @Getter\n private String rootPath;\n-\n /**\n- * @return The regex that matches wildcards in teh original path. Null if the original path did not contain any wildcards.\n+ * @return The regex that matches wildcards in the original path. Null if the original path did not contain any wildcards.\n */\n @Getter\n private Pattern pathRegex = null;\n \n- /**\n- * Creates a new location.\n- *\n- * @param descriptor The location descriptor.\n- */\n public Location(String descriptor) {\n String normalizedDescriptor = descriptor.trim();\n \n@@ -118,7 +105,7 @@ public Location(String descriptor) {\n * Process the rawPath into a rootPath and a regex.\n * Supported wildcards:\n * **: Match any 0 or more directories\n- * *: Match any sequence of non-seperator characters\n+ * *: Match any sequence of non-separator characters\n * ?: Match any single character\n */\n private void processRawPath() {\n@@ -128,14 +115,14 @@ private void processRawPath() {\n String separator = isFileSystem() ? File.separator : \"/\";\n String escapedSeparator = separator.replace(\"\\\\\", \"\\\\\\\\\").replace(\"/\", \"\\\\/\");\n \n- // split on either of the path seperators\n+ // split on either of the path separators\n String[] pathSplit = rawPath.split(\"[\\\\\\\\/]\");\n \n StringBuilder rootPart = new StringBuilder();\n StringBuilder patternPart = new StringBuilder();\n \n boolean endsInFile = false;\n- boolean skipSeperator = false;\n+ boolean skipSeparator = false;\n boolean inPattern = false;\n for (String pathPart : pathSplit) {\n endsInFile = false;\n@@ -145,8 +132,8 @@ private void processRawPath() {\n }\n \n if (inPattern) {\n- if (skipSeperator) {\n- skipSeperator = false;\n+ if (skipSeparator) {\n+ skipSeparator = false;\n } else {\n patternPart.append(\"/\");\n }\n@@ -155,8 +142,8 @@ private void processRawPath() {\n if (\"**\".equals(pathPart)) {\n regex = \"([^/]+/)*?\";\n \n- // this pattern contains the ending seperator, so make sure we skip appending it after\n- skipSeperator = true;\n+ // this pattern contains the ending separator, so make sure we skip appending it after\n+ skipSeparator = true;\n } else {\n endsInFile = pathPart.contains(\".\");\n \n@@ -172,16 +159,16 @@ private void processRawPath() {\n }\n }\n \n- // We always append a seperator before each part, so ensure we skip it when setting the final rootPath\n- rootPath = rootPart.length() > 0 ? rootPart.toString().substring(1) : \"\";\n+ // We always append a separator before each part, so ensure we skip it when setting the final rootPath\n+ rootPath = rootPart.length() > 0 ? rootPart.substring(1) : \"\";\n \n- // Again, skip first seperator\n- String pattern = patternPart.toString().substring(1);\n+ // Again, skip first separator\n+ String pattern = patternPart.substring(1);\n \n- // Replace the temporary / with the actual escaped seperator\n+ // Replace the temporary / with the actual escaped separator\n pattern = pattern.replace(\"/\", escapedSeparator);\n \n- // Append the rootpath if it is non-empty\n+ // Append the rootPath if it is non-empty\n if (rootPart.length() > 0) {\n pattern = rootPath.replace(separator, escapedSeparator) + escapedSeparator + pattern;\n }\n@@ -204,15 +191,12 @@ public boolean matchesPath(String path) {\n if (pathRegex == null) {\n return true;\n }\n-\n return pathRegex.matcher(path).matches();\n }\n \n /**\n * Returns the path relative to this location. If the location path contains wildcards, the returned path will be relative\n * to the last non-wildcard folder in the path.\n- *\n- * @return the path relative to this location\n */\n public String getPathRelativeToThis(String path) {\n if (pathRegex != null && pathRegex.pattern().contains(\"?\")) {\n@@ -275,7 +259,6 @@ public boolean isParentOf(Location other) {\n if (pathRegex != null || other.pathRegex != null) {\n return false;\n }\n-\n if (isClassPath() && other.isClassPath()) {\n return (other.getDescriptor() + \"/\").startsWith(getDescriptor() + \"/\");\n }\n@@ -299,7 +282,7 @@ public String getDescriptor() {\n return prefix + rawPath;\n }\n \n- @SuppressWarnings(\"NullableProblems\")\n+ @Override\n public int compareTo(Location o) {\n return getDescriptor().compareTo(o.getDescriptor());\n }\n@@ -312,9 +295,7 @@ public boolean equals(Object o) {\n if (o == null || getClass() != o.getClass()) {\n return false;\n }\n-\n Location location = (Location) o;\n-\n return getDescriptor().equals(location.getDescriptor());\n }\n "},{"sha":"175324c91bd9b8d542a8953dc0d8461b7fabf72c","filename":"flyway-core/src/main/java/org/flywaydb/core/extensibility/CommandExtension.java","status":"modified","additions":3,"deletions":1,"changes":4,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Fextensibility%2FCommandExtension.java","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Fextensibility%2FCommandExtension.java","contents_url":"https://api.github.com/repos/flyway/flyway/contents/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Fextensibility%2FCommandExtension.java?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -15,8 +15,10 @@\n */\n package org.flywaydb.core.extensibility;\n \n+import org.flywaydb.core.api.FlywayException;\n import org.flywaydb.core.api.output.OperationResultBase;\n \n+import java.util.List;\n import java.util.Map;\n \n /**\n@@ -45,5 +47,5 @@ public interface CommandExtension extends Plugin {\n * @param config The configuration provided to Flyway\n * @return The result of this command being handled\n */\n- OperationResultBase handle(String command, Map config);\n+ OperationResultBase handle(String command, Map config, List flags) throws FlywayException;\n }\n\\ No newline at end of file"},{"sha":"8932ac2f48ffd9e9e22294002acb777138443f2c","filename":"flyway-core/src/main/java/org/flywaydb/core/extensibility/ConfigurationProvider.java","status":"modified","additions":1,"deletions":1,"changes":2,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Fextensibility%2FConfigurationProvider.java","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Fextensibility%2FConfigurationProvider.java","contents_url":"https://api.github.com/repos/flyway/flyway/contents/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Fextensibility%2FConfigurationProvider.java?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -21,5 +21,5 @@\n \n public interface ConfigurationProvider extends Plugin {\n Map getConfiguration(T configurationExtension, ClassicConfiguration flywayConfiguration) throws Exception;\n- Class extends ConfigurationExtension> getConfigurationExtensionClass();\n+ Class getConfigurationExtensionClass();\n }\n\\ No newline at end of file"},{"sha":"d6d1591db4caf85ddcbd5cbb09b4c31c15dab5ac","filename":"flyway-core/src/main/java/org/flywaydb/core/internal/util/FileCopyUtils.java","status":"modified","additions":2,"deletions":22,"changes":24,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Finternal%2Futil%2FFileCopyUtils.java","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Finternal%2Futil%2FFileCopyUtils.java","contents_url":"https://api.github.com/repos/flyway/flyway/contents/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Finternal%2Futil%2FFileCopyUtils.java?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -18,13 +18,7 @@\n import lombok.AccessLevel;\n import lombok.NoArgsConstructor;\n \n-import java.io.ByteArrayOutputStream;\n-import java.io.IOException;\n-import java.io.InputStream;\n-import java.io.OutputStream;\n-import java.io.Reader;\n-import java.io.StringWriter;\n-import java.io.Writer;\n+import java.io.*;\n import java.nio.charset.Charset;\n \n /**\n@@ -38,7 +32,7 @@ public class FileCopyUtils {\n *\n * @param in the reader to copy from\n * @return the String that has been copied to\n- * @throws java.io.IOException in case of I/O errors\n+ * @throws IOException in case of I/O errors\n */\n public static String copyToString(Reader in) throws IOException {\n StringWriter out = new StringWriter();\n@@ -53,20 +47,6 @@ public static String copyToString(Reader in) throws IOException {\n return str;\n }\n \n- /**\n- * Copy the contents of the given InputStream into a new byte array.\n- * Closes the stream when done.\n- *\n- * @param in the stream to copy from\n- * @return the new byte array that has been copied to\n- * @throws IOException in case of I/O errors\n- */\n- public static byte[] copyToByteArray(InputStream in) throws IOException {\n- ByteArrayOutputStream out = new ByteArrayOutputStream(4096);\n- copy(in, out);\n- return out.toByteArray();\n- }\n-\n /**\n * Copy the contents of the given InputStream into a new String based on this encoding.\n * Closes the stream when done."},{"sha":"adcf5f1f2383317ede71b5a3a82866539fca479b","filename":"flyway-core/src/main/java/org/flywaydb/core/internal/util/JsonUtils.java","status":"added","additions":49,"deletions":0,"changes":49,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Finternal%2Futil%2FJsonUtils.java","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Finternal%2Futil%2FJsonUtils.java","contents_url":"https://api.github.com/repos/flyway/flyway/contents/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Finternal%2Futil%2FJsonUtils.java?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -0,0 +1,49 @@\n+/*\n+ * Copyright (C) Red Gate Software Ltd 2010-2022\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+package org.flywaydb.core.internal.util;\n+\n+import com.google.gson.*;\n+import lombok.AccessLevel;\n+import lombok.NoArgsConstructor;\n+import org.flywaydb.core.api.FlywayException;\n+\n+import java.io.File;\n+import java.io.FileWriter;\n+\n+@NoArgsConstructor(access = AccessLevel.PRIVATE)\n+public class JsonUtils {\n+ public static String jsonToFile(String folder, String filename, String json, String... properties) {\n+ JsonObject obj = JsonParser.parseString(json).getAsJsonObject();\n+ for (String property : properties) {\n+ obj = obj.getAsJsonObject(property);\n+ }\n+ return jsonToFile(folder, filename, obj);\n+ }\n+\n+ public static String jsonToFile(String folder, String filename, Object json) {\n+ Gson gson = new GsonBuilder()\n+ .serializeNulls()\n+ .setPrettyPrinting()\n+ .create();\n+ String fullFilename = folder + File.separator + filename + \".json\";\n+ try (FileWriter fileWriter = new FileWriter(fullFilename)) {\n+ gson.toJson(json, fileWriter);\n+ return fullFilename;\n+ } catch (Exception e) {\n+ throw new FlywayException(\"Unable to write JSON to file: \" + e.getMessage());\n+ }\n+ }\n+}\n\\ No newline at end of file"},{"sha":"ea89171da5f2c28708b37178a302d73ac47f3a64","filename":"flyway-core/src/main/java/org/flywaydb/core/internal/util/Locations.java","status":"modified","additions":9,"deletions":21,"changes":30,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Finternal%2Futil%2FLocations.java","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Finternal%2Futil%2FLocations.java","contents_url":"https://api.github.com/repos/flyway/flyway/contents/flyway-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fflywaydb%2Fcore%2Finternal%2Futil%2FLocations.java?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -27,14 +27,9 @@\n */\n @CustomLog\n public class Locations {\n- /**\n- * The backing list.\n- */\n private final List locations = new ArrayList<>();\n \n /**\n- * Creates a new Locations wrapper with these raw locations.\n- *\n * @param rawLocations The raw locations to process.\n */\n public Locations(String... rawLocations) {\n@@ -46,14 +41,16 @@ public Locations(String... rawLocations) {\n }\n \n /**\n- * Creates a new Locations wrapper with these locations.\n- *\n * @param rawLocations The locations to process.\n */\n public Locations(List rawLocations) {\n processLocations(rawLocations);\n }\n \n+ public List getLocations() {\n+ return locations;\n+ }\n+\n private void processLocations(List rawLocations) {\n List sortedLocations = new ArrayList<>(rawLocations);\n Collections.sort(sortedLocations);\n@@ -66,21 +63,14 @@ private void processLocations(List rawLocations) {\n \n Location parentLocation = getParentLocationIfExists(normalizedLocation, locations);\n if (parentLocation != null) {\n- LOG.warn(\"Discarding location '\" + normalizedLocation + \"' as it is a sublocation of '\" + parentLocation + \"'\");\n+ LOG.warn(\"Discarding location '\" + normalizedLocation + \"' as it is a sub-location of '\" + parentLocation + \"'\");\n continue;\n }\n \n locations.add(normalizedLocation);\n }\n }\n \n- /**\n- * @return The locations.\n- */\n- public List getLocations() {\n- return locations;\n- }\n-\n /**\n * Retrieves this location's parent within this list, if any.\n *\n@@ -89,11 +79,9 @@ public List getLocations() {\n * @return The parent location. {@code null} if none.\n */\n private Location getParentLocationIfExists(Location location, List finalLocations) {\n- for (Location finalLocation : finalLocations) {\n- if (finalLocation.isParentOf(location)) {\n- return finalLocation;\n- }\n- }\n- return null;\n+ return finalLocations.stream()\n+ .filter(fl -> fl.isParentOf(location))\n+ .findFirst()\n+ .orElse(null);\n }\n }\n\\ No newline at end of file"},{"sha":"cf89d8be886254320c1bbc19dd331734876374bb","filename":"pom.xml","status":"modified","additions":2,"deletions":0,"changes":2,"blob_url":"https://github.com/flyway/flyway/blob/386d2c163f03bc8af225744f05742af80a94225b/pom.xml","raw_url":"https://github.com/flyway/flyway/raw/386d2c163f03bc8af225744f05742af80a94225b/pom.xml","contents_url":"https://api.github.com/repos/flyway/flyway/contents/pom.xml?ref=386d2c163f03bc8af225744f05742af80a94225b","patch":"@@ -88,6 +88,8 @@\n \n \n \n+\n+\n \n \n "}]}