diff --git a/liquibase-cli/src/main/java/liquibase/integration/commandline/LiquibaseCommandLine.java b/liquibase-cli/src/main/java/liquibase/integration/commandline/LiquibaseCommandLine.java index 05f62f98c51..f5a1e3065a0 100644 --- a/liquibase-cli/src/main/java/liquibase/integration/commandline/LiquibaseCommandLine.java +++ b/liquibase-cli/src/main/java/liquibase/integration/commandline/LiquibaseCommandLine.java @@ -468,7 +468,6 @@ public int getPrecedence() { Scope.getCurrentScope().getLog(getClass()).fine("Cannot find local defaultsFile " + defaultsFile.getAbsolutePath()); } - return returnList; } diff --git a/liquibase-core/src/main/java/liquibase/command/CommandScope.java b/liquibase-core/src/main/java/liquibase/command/CommandScope.java index 04bd62f9881..ff6b1fef72b 100644 --- a/liquibase-core/src/main/java/liquibase/command/CommandScope.java +++ b/liquibase-core/src/main/java/liquibase/command/CommandScope.java @@ -58,6 +58,13 @@ public CommandDefinition getCommand() { return commandDefinition; } + /** + * Returns the complete config prefix (without a trailing period) for the command in this scope. + * @return + */ + public String getCompleteConfigPrefix() { + return completeConfigPrefix; + } /** * Adds the given key/value pair to the stored argument data. diff --git a/liquibase-core/src/main/java/liquibase/command/core/UpdateCommandStep.java b/liquibase-core/src/main/java/liquibase/command/core/UpdateCommandStep.java index 431a6c6622a..9c74e496517 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/UpdateCommandStep.java +++ b/liquibase-core/src/main/java/liquibase/command/core/UpdateCommandStep.java @@ -26,7 +26,7 @@ public class UpdateCommandStep extends AbstractCliWrapperCommandStep { CommandBuilder builder = new CommandBuilder(COMMAND_NAME, LEGACY_COMMAND_NAME); URL_ARG = builder.argument("url", String.class).required() - .description("The JDBC database connection URL").build(); + .description("The JDBC database connection URL").build(); DEFAULT_SCHEMA_NAME = builder.argument("defaultSchemaName", String.class) .description("The default schema name to use for the database connection").build(); DEFAULT_CATALOG_NAME_ARG = builder.argument("defaultCatalogName", String.class) diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfiguredValue.java b/liquibase-core/src/main/java/liquibase/configuration/ConfiguredValue.java index 23e8c57c444..1d0052238ff 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfiguredValue.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfiguredValue.java @@ -45,7 +45,6 @@ public DataType getValueObfuscated() { return rawValue; } - /** * Returns the "winning" value across all the possible {@link ConfigurationValueProvider}. * A {@link ProvidedValue} is always returned, even if the value was not configured. @@ -56,15 +55,16 @@ public ProvidedValue getProvidedValue() { return getProvidedValues().get(0); } - + /** + * + * Return true if a default value was the "winning" value + * + * @return boolean + * + */ public boolean wasDefaultValueUsed() { - for (ProvidedValue providedValue : this.getProvidedValues()) { - if (providedValue.getProvider() != null && providedValue.getProvider() instanceof ConfigurationDefinition.DefaultValueProvider) { - return true; - } - } - - return false; + ProvidedValue winningProvidedValue = getProvidedValue(); + return winningProvidedValue != null && winningProvidedValue.getProvider() instanceof ConfigurationDefinition.DefaultValueProvider; } /** diff --git a/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java b/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java index 5e29c6c4ff5..ef4b7637c63 100644 --- a/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java +++ b/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java @@ -113,7 +113,7 @@ public T prompt(String prompt, T valueIfNoEntry, InputHandler inputHandle message = "Invalid value: \"" + input + "\""; } this.sendMessage(message); - this.sendMessage(prompt + ": "); + this.sendMessage(initialMessage + ": "); } } } diff --git a/liquibase-core/src/main/java/liquibase/util/FileUtil.java b/liquibase-core/src/main/java/liquibase/util/FileUtil.java index dd718aaaada..50cf49ef924 100644 --- a/liquibase-core/src/main/java/liquibase/util/FileUtil.java +++ b/liquibase-core/src/main/java/liquibase/util/FileUtil.java @@ -11,7 +11,7 @@ private FileUtil() { throw new IllegalStateException("This utility class must not be instantiated. Sorry."); } - public static String getContents(File file) throws IOException { + public static String getContents(File file) throws IOException { if (!file.exists()) { return null; } diff --git a/liquibase-core/src/main/resources/liquibase/examples/json/blank-changelog.json b/liquibase-core/src/main/resources/liquibase/examples/json/blank-changelog.json new file mode 100644 index 00000000000..d912de64160 --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/json/blank-changelog.json @@ -0,0 +1,18 @@ +{ "databaseChangeLog": [ + "changeset": { + "id": "1", + "author": "your.name", + "changes": [ + { + } + ] + }, + "changeset": { + "id": "2", + "author": "your.name", + "changes": [ + { + } + ] + } +]} diff --git a/liquibase-core/src/main/resources/liquibase/examples/json/example-changelog.json b/liquibase-core/src/main/resources/liquibase/examples/json/example-changelog.json new file mode 100644 index 00000000000..e502227fca6 --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/json/example-changelog.json @@ -0,0 +1,120 @@ +{ "databaseChangeLog": [ + { + "changeSet": { + "id": "1", + "author": "your.name", + "changes": [ + { + "createTable": { + "tableName": "person", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primarykey": true, + "nullable": false + } + } + }, + { + "column": { + "name": "name", + "type": "varchar(50)" + } + }, + { + "column": { + "name": "addresss1", + "type": "varchar(50)" + } + }, + { + "column": { + "name": "addresss2", + "type": "varchar(50)" + } + }, + { + "column": { + "name": "city", + "type": "varchar(30)" + } + } + ] + } + }] + } + }, + { + "changeSet": { + "id": "2", + "author": "your.name", + "changes": [ + { + "createTable": { + "tableName": "company", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primarykey": true, + "nullable": false + } + } + }, + { + "column": { + "name": "name", + "type": "varchar(50)" + } + }, + { + "column": { + "name": "addresss1", + "type": "varchar(50)" + } + }, + { + "column": { + "name": "addresss2", + "type": "varchar(50)" + } + }, + { + "column": { + "name": "city", + "type": "varchar(30)" + } + } + ] + } + }] + } + }, + { + "changeSet": { + "id": "3", + "author": "your.name", + "changes": [ + { + "addColumn": { + "tableName": "company", + "columns": [ + { + "column": { + "name": "country", + "type": "varchar(2)" + } + } + ] + } + }] + } + } +]} diff --git a/liquibase-core/src/main/resources/liquibase/examples/json/example-changeset-json.txt b/liquibase-core/src/main/resources/liquibase/examples/json/example-changeset-json.txt new file mode 100644 index 00000000000..4c7e5d572a7 --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/json/example-changeset-json.txt @@ -0,0 +1,30 @@ +"changeSet": { + "id": "1", + "author": "dev", + "changes": [ + { + "createTable": { + "tableName": "person", + "columns": [ + { + "column": { + "name": "id", + "type": "int", + "autoIncrement": true, + "constraints": { + "primaryKey": true, + "nullable": false + } + } + }, + { + "column": { + "name": "name", + "type": "varchar(255)" + } + } + ] + } + } + ] +} diff --git a/liquibase-dist/src/main/archive/examples/sql/liquibase.properties b/liquibase-core/src/main/resources/liquibase/examples/json/liquibase.properties similarity index 98% rename from liquibase-dist/src/main/archive/examples/sql/liquibase.properties rename to liquibase-core/src/main/resources/liquibase/examples/json/liquibase.properties index 1f30dc71cea..5c2fd4e9888 100644 --- a/liquibase-dist/src/main/archive/examples/sql/liquibase.properties +++ b/liquibase-core/src/main/resources/liquibase/examples/json/liquibase.properties @@ -20,7 +20,7 @@ ## The url H2 example below is relative to 'pwd' resource. #### # Enter the path for your changelog file. -changeLogFile=samplechangelog.h2.sql +changeLogFile=example-changelog.json #### Enter the Target database 'url' information #### liquibase.command.url=jdbc:h2:tcp://localhost:9090/mem:dev diff --git a/liquibase-dist/src/main/archive/examples/sql/blankchangelog.h2.sql b/liquibase-core/src/main/resources/liquibase/examples/sql/blank-changelog.sql similarity index 100% rename from liquibase-dist/src/main/archive/examples/sql/blankchangelog.h2.sql rename to liquibase-core/src/main/resources/liquibase/examples/sql/blank-changelog.sql diff --git a/liquibase-dist/src/main/archive/examples/sql/samplechangelog.h2.sql b/liquibase-core/src/main/resources/liquibase/examples/sql/example-changelog.sql similarity index 100% rename from liquibase-dist/src/main/archive/examples/sql/samplechangelog.h2.sql rename to liquibase-core/src/main/resources/liquibase/examples/sql/example-changelog.sql diff --git a/liquibase-core/src/main/resources/liquibase/examples/sql/example-changeset-sql.txt b/liquibase-core/src/main/resources/liquibase/examples/sql/example-changeset-sql.txt new file mode 100644 index 00000000000..88f181639b6 --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/sql/example-changeset-sql.txt @@ -0,0 +1,7 @@ +(example-changeset-sql.txt) + +--changeset dev:1 +create table test1( + id int primary key, + name varchar(255) +); diff --git a/liquibase-dist/src/main/archive/examples/xml/liquibase.properties b/liquibase-core/src/main/resources/liquibase/examples/sql/liquibase.properties similarity index 98% rename from liquibase-dist/src/main/archive/examples/xml/liquibase.properties rename to liquibase-core/src/main/resources/liquibase/examples/sql/liquibase.properties index fa7fb0ff901..d15b155e6c5 100644 --- a/liquibase-dist/src/main/archive/examples/xml/liquibase.properties +++ b/liquibase-core/src/main/resources/liquibase/examples/sql/liquibase.properties @@ -20,7 +20,7 @@ ## The url H2 example below is relative to 'pwd' resource. #### # Enter the path for your changelog file. -changeLogFile=sample.changelog.xml +changeLogFile=example-changelog.sql #### Enter the Target database 'url' information #### liquibase.command.url=jdbc:h2:tcp://localhost:9090/mem:dev diff --git a/liquibase-dist/src/main/archive/examples/sql/liquibase.sqlplus.conf b/liquibase-core/src/main/resources/liquibase/examples/sql/liquibase.sqlplus.conf similarity index 100% rename from liquibase-dist/src/main/archive/examples/sql/liquibase.sqlplus.conf rename to liquibase-core/src/main/resources/liquibase/examples/sql/liquibase.sqlplus.conf diff --git a/liquibase-core/src/main/resources/liquibase/examples/start-h2 b/liquibase-core/src/main/resources/liquibase/examples/start-h2 new file mode 100644 index 00000000000..718090807bf --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/start-h2 @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +if [ -z "${LIQUIBASE_HOME}" ]; then + #liquibase home is not set + + LIQUIBASE_PATH="$(which liquibase)" + + if [ -z "${LIQUIBASE_PATH}" ]; then + echo "Must set LIQUIBASE_HOME environment variable, or have liquibase in your PATH" + exit 1 + fi + + LIQUIBASE_HOME=$(dirname "$(which liquibase)") +fi + +if [ -z "${JAVA_HOME}" ]; then + #JAVA_HOME not set, try to find a bundled version + if [ -d "${LIQUIBASE_HOME}/jre" ]; then + JAVA_HOME="$LIQUIBASE_HOME/jre" + elif [ -d "${LIQUIBASE_HOME}/.install4j/jre.bundle/Contents/Home" ]; then + JAVA_HOME="${LIQUIBASE_HOME}/.install4j/jre.bundle/Contents/Home" + fi +fi + +if [ -z "${JAVA_HOME}" ]; then + JAVA_PATH="$(which java)" + + if [ -z "${JAVA_PATH}" ]; then + echo "Cannot find java in your path. Install java or use the JAVA_HOME environment variable" + + exit 1 + fi +else + #Use path in JAVA_HOME + JAVA_PATH="${JAVA_HOME}/bin/java" +fi + + +# echo "${JAVA_PATH}" -cp "${LIQUIBASE_HOME}/lib/h2-1.4.200.jar:${LIQUIBASE_HOME}/liquibase.jar" liquibase.example.StartH2Main + +"${JAVA_PATH}" -cp "${LIQUIBASE_HOME}/lib/h2-1.4.200.jar:${LIQUIBASE_HOME}/liquibase.jar" liquibase.example.StartH2Main diff --git a/liquibase-core/src/main/resources/liquibase/examples/start-h2.bat b/liquibase-core/src/main/resources/liquibase/examples/start-h2.bat new file mode 100644 index 00000000000..21603ba57e4 --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/start-h2.bat @@ -0,0 +1,34 @@ +@echo off +if "%OS%" == "Windows_NT" setlocal + +setlocal enabledelayedexpansion + +rem %~dp0 is expanded pathname of the current script under NT +rem %~p0 is the directory of the current script + +if exist %~p0\..\liquibase.jar SET LIQUIBASE_HOME="%~p0\.." + +if "%LIQUIBASE_HOME%"=="" ( + FOR /F "tokens=* USEBACKQ" %%g IN (`where liquibase.bat`) do (SET "LIQUIBASE_HOME=%%~dpg") +) + +if "%LIQUIBASE_HOME%"=="" ( + echo "Must set LIQUIBASE_HOME environment variable, or have liquibase.bat in your PATH" + exit /B 1 +) + +if "%JAVA_HOME%"=="" ( + + rem check for jre dir in liquibase_home + if NOT "%LIQUIBASE_HOME%"=="" if exist "%LIQUIBASE_HOME%\jre" ( + set JAVA_HOME=%LIQUIBASE_HOME%\jre + ) +) + +if "%JAVA_HOME%"=="" ( + set JAVA_PATH=java +) else ( + set JAVA_PATH=%JAVA_HOME%\bin\java +) + +"%JAVA_PATH%" -cp "%LIQUIBASE_HOME%\lib\h2-1.4.200.jar;%LIQUIBASE_HOME%\liquibase.jar" liquibase.example.StartH2Main diff --git a/liquibase-dist/src/main/archive/examples/xml/blank.changelog.xml b/liquibase-core/src/main/resources/liquibase/examples/xml/blank-changelog.xml similarity index 75% rename from liquibase-dist/src/main/archive/examples/xml/blank.changelog.xml rename to liquibase-core/src/main/resources/liquibase/examples/xml/blank-changelog.xml index fc9b1d763d1..61e339e5c36 100644 --- a/liquibase-dist/src/main/archive/examples/xml/blank.changelog.xml +++ b/liquibase-core/src/main/resources/liquibase/examples/xml/blank-changelog.xml @@ -8,11 +8,11 @@ http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-4.6.xsd "> - + - + diff --git a/liquibase-dist/src/main/archive/examples/xml/sample.changelog.xml b/liquibase-core/src/main/resources/liquibase/examples/xml/example-changelog.xml similarity index 100% rename from liquibase-dist/src/main/archive/examples/xml/sample.changelog.xml rename to liquibase-core/src/main/resources/liquibase/examples/xml/example-changelog.xml diff --git a/liquibase-core/src/main/resources/liquibase/examples/xml/example-changeset-xml.txt b/liquibase-core/src/main/resources/liquibase/examples/xml/example-changeset-xml.txt new file mode 100644 index 00000000000..4f162b30621 --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/xml/example-changeset-xml.txt @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/liquibase-core/src/main/resources/liquibase/examples/xml/liquibase.properties b/liquibase-core/src/main/resources/liquibase/examples/xml/liquibase.properties new file mode 100644 index 00000000000..30b30d9ee9b --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/xml/liquibase.properties @@ -0,0 +1,76 @@ +#### _ _ _ _ +## | | (_) (_) | +## | | _ __ _ _ _ _| |__ __ _ ___ ___ +## | | | |/ _` | | | | | '_ \ / _` / __|/ _ \ +## | |___| | (_| | |_| | | |_) | (_| \__ \ __/ +## \_____/_|\__, |\__,_|_|_.__/ \__,_|___/\___| +## | | +## |_| +## +## The liquibase.properties file stores properties which do not change often, +## such as database connection information. Properties stored here save time +## and reduce risk of mistyped command line arguments. +## Learn more: https://www.liquibase.org/documentation/config_properties.html +#### +#### +## Note about relative and absolute paths: +## The liquibase.properties file requires paths for some properties. +## The classpath is the path/to/resources (ex. src/main/resources). +## The changeLogFile path is relative to the classpath. +## The url H2 example below is relative to 'pwd' resource. +#### +# Enter the path for your changelog file. +changeLogFile=example-changelog.xml + +#### Enter the Target database 'url' information #### +liquibase.command.url=jdbc:h2:tcp://localhost:9090/mem:dev + +# Enter the username for your Target database. +liquibase.command.username: dbuser + +# Enter the password for your Target database. +liquibase.command.password: letmein + +#### Enter the Source Database 'referenceUrl' information #### +## The source database is the baseline or reference against which your target database is compared for diff/diffchangelog commands. + +# Enter URL for the source database +liquibase.command.referenceUrl: jdbc:h2:tcp://localhost:9090/mem:integration + +# Enter the username for your source database +liquibase.command.referenceUsername: dbuser + +# Enter the password for your source database +liquibase.command.referencePassword: letmein + +# Logging Configuration +# logLevel controls the amount of logging information generated. If not set, the default logLevel is INFO. +# Valid values, from least amount of logging to most, are: +# OFF, ERROR, WARN, INFO, DEBUG, TRACE, ALL +# If you are having problems, setting the logLevel to DEBUG and re-running the command can be helpful. +# logLevel: DEBUG + +# The logFile property controls where logging messages are sent. If this is not set, then logging messages are +# displayed on the console. If this is set, then messages will be sent to a file with the given name. +# logFile: liquibase.log + + +#### Liquibase Pro Key Information #### +# Learn more, contact support, or get or renew a Pro Key at https://www.liquibase.com/protrial +# liquibase.pro.licensekey: + +#### Liquibase Hub Information #### +# Liquibase Hub is a free secure SaaS portal providing status reporting, monitoring & insights +# into your Liquibase database release automation. +# https://hub.liquibase.com + +## Add your free Hub API key here +# liquibase.hub.apikey: +# liquibase.hub.mode:all + + + + +## Get documentation at docs.liquibase.com ## +## Get certified courses at learn.liquibase.com ## +## Get support at liquibase.com/support ## diff --git a/liquibase-dist/src/main/archive/examples/xml/liquibase.sqlplus.conf b/liquibase-core/src/main/resources/liquibase/examples/xml/liquibase.sqlplus.conf similarity index 100% rename from liquibase-dist/src/main/archive/examples/xml/liquibase.sqlplus.conf rename to liquibase-core/src/main/resources/liquibase/examples/xml/liquibase.sqlplus.conf diff --git a/liquibase-core/src/main/resources/liquibase/examples/yaml/blank-changelog.yaml b/liquibase-core/src/main/resources/liquibase/examples/yaml/blank-changelog.yaml new file mode 100644 index 00000000000..771e1911fde --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/yaml/blank-changelog.yaml @@ -0,0 +1,12 @@ +databaseChangeLog: +- changeSet: + id: 1 + author: your.name + changes: + # Insert Yaml change objects here https://www.liquibase.org/documentation/yaml_format.html + +- changeSet: + id: 2 + author: your.name + changes: + # Insert Yaml change objects here https://www.liquibase.org/documentation/yaml_format.html diff --git a/liquibase-core/src/main/resources/liquibase/examples/yaml/example-changelog.yaml b/liquibase-core/src/main/resources/liquibase/examples/yaml/example-changelog.yaml new file mode 100644 index 00000000000..e102c5b95dc --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/yaml/example-changelog.yaml @@ -0,0 +1,47 @@ +databaseChangeLog: +- changeSet: + id: 1 + author: your.name + changes: + - createTable: + tableName: person + columns: + - column: + name: id + type: int + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: name + type: varchar(50) + +- changeSet: + id: 2 + author: your.name + changes: + - createTable: + tableName: company + columns: + - column: + name: id + type: int + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: name + type: varchar(50) + +- changeSet: + id: 3 + author: your.name + changes: + - addColumn: + tableName: company + columns: + - column: + name: country + type: varchar(2) diff --git a/liquibase-core/src/main/resources/liquibase/examples/yaml/example-changeset-yaml.txt b/liquibase-core/src/main/resources/liquibase/examples/yaml/example-changeset-yaml.txt new file mode 100644 index 00000000000..ac332f2bf23 --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/yaml/example-changeset-yaml.txt @@ -0,0 +1,17 @@ + - changeSet: + id: 1 + author: dev + changes: + - createTable: + tableName: person + columns: + - column: + name: id + type: int + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: name + type: varchar(255) diff --git a/liquibase-core/src/main/resources/liquibase/examples/yaml/liquibase.properties b/liquibase-core/src/main/resources/liquibase/examples/yaml/liquibase.properties new file mode 100644 index 00000000000..f964af53f06 --- /dev/null +++ b/liquibase-core/src/main/resources/liquibase/examples/yaml/liquibase.properties @@ -0,0 +1,76 @@ +#### _ _ _ _ +## | | (_) (_) | +## | | _ __ _ _ _ _| |__ __ _ ___ ___ +## | | | |/ _` | | | | | '_ \ / _` / __|/ _ \ +## | |___| | (_| | |_| | | |_) | (_| \__ \ __/ +## \_____/_|\__, |\__,_|_|_.__/ \__,_|___/\___| +## | | +## |_| +## +## The liquibase.properties file stores properties which do not change often, +## such as database connection information. Properties stored here save time +## and reduce risk of mistyped command line arguments. +## Learn more: https://www.liquibase.org/documentation/config_properties.html +#### +#### +## Note about relative and absolute paths: +## The liquibase.properties file requires paths for some properties. +## The classpath is the path/to/resources (ex. src/main/resources). +## The changeLogFile path is relative to the classpath. +## The url H2 example below is relative to 'pwd' resource. +#### +# Enter the path for your changelog file. +changeLogFile=example-changelog.yaml + +#### Enter the Target database 'url' information #### +liquibase.command.url=jdbc:h2:tcp://localhost:9090/mem:dev + +# Enter the username for your Target database. +liquibase.command.username: dbuser + +# Enter the password for your Target database. +liquibase.command.password: letmein + +#### Enter the Source Database 'referenceUrl' information #### +## The source database is the baseline or reference against which your target database is compared for diff/diffchangelog commands. + +# Enter URL for the source database +liquibase.command.referenceUrl: jdbc:h2:tcp://localhost:9090/mem:integration + +# Enter the username for your source database +liquibase.command.referenceUsername: dbuser + +# Enter the password for your source database +liquibase.command.referencePassword: letmein + +# Logging Configuration +# logLevel controls the amount of logging information generated. If not set, the default logLevel is INFO. +# Valid values, from least amount of logging to most, are: +# OFF, ERROR, WARN, INFO, DEBUG, TRACE, ALL +# If you are having problems, setting the logLevel to DEBUG and re-running the command can be helpful. +# logLevel: DEBUG + +# The logFile property controls where logging messages are sent. If this is not set, then logging messages are +# displayed on the console. If this is set, then messages will be sent to a file with the given name. +# logFile: liquibase.log + + +#### Liquibase Pro Key Information #### +# Learn more, contact support, or get or renew a Pro Key at https://www.liquibase.com/protrial +# liquibase.pro.licensekey: + +#### Liquibase Hub Information #### +# Liquibase Hub is a free secure SaaS portal providing status reporting, monitoring & insights +# into your Liquibase database release automation. +# https://hub.liquibase.com + +## Add your free Hub API key here +# liquibase.hub.apikey: +# liquibase.hub.mode:all + + + + +## Get documentation at docs.liquibase.com ## +## Get certified courses at learn.liquibase.com ## +## Get support at liquibase.com/support ## diff --git a/liquibase-core/src/test/groovy/liquibase/ui/ConsoleUIServiceTest.groovy b/liquibase-core/src/test/groovy/liquibase/ui/ConsoleUIServiceTest.groovy index ce4702e439c..8c8001c78e8 100644 --- a/liquibase-core/src/test/groovy/liquibase/ui/ConsoleUIServiceTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/ui/ConsoleUIServiceTest.groovy @@ -29,7 +29,7 @@ class ConsoleUIServiceTest extends Specification { "" | null | null | "Prompt here: " | String "x" | null | "x" | "Prompt here: " | String "1234" | null | 1234 | "Prompt here: " | Integer - ["x", "1234"] as String[] | 0 | 1234 | "Prompt here [0]: \nInvalid value: 'x': For input string: \"x\"\nPrompt here: " | Integer + ["x", "1234"] as String[] | 0 | 1234 | "Prompt here [0]: \nInvalid value: 'x': For input string: \"x\"\nPrompt here [0]:" | Integer "true" | false | true | "Prompt here [false]: " | Boolean "false" | false | false | "Prompt here [false]: " | Boolean } diff --git a/liquibase-dist/src/main/assembly/assembly-bin.xml b/liquibase-dist/src/main/assembly/assembly-bin.xml index abccacf4b96..54a8c34149f 100644 --- a/liquibase-dist/src/main/assembly/assembly-bin.xml +++ b/liquibase-dist/src/main/assembly/assembly-bin.xml @@ -45,6 +45,13 @@ **/* + + ${project.basedir}/../liquibase-core/target/classes/liquibase/examples + examples + + **/* + + diff --git a/liquibase-dist/src/main/install4j/liquibase.install4j b/liquibase-dist/src/main/install4j/liquibase.install4j index e13cc83226d..2ed315b28d9 100644 --- a/liquibase-dist/src/main/install4j/liquibase.install4j +++ b/liquibase-dist/src/main/install4j/liquibase.install4j @@ -1,7 +1,7 @@ - + diff --git a/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/command/CommandTests.groovy b/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/command/CommandTests.groovy index abcc9b8db99..109bfe4bb57 100644 --- a/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/command/CommandTests.groovy +++ b/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/command/CommandTests.groovy @@ -21,6 +21,7 @@ import liquibase.database.jvm.JdbcConnection import liquibase.extension.testing.TestDatabaseConnections import liquibase.extension.testing.TestFilter import liquibase.extension.testing.setup.* +import liquibase.extension.testing.setup.SetupCleanResources.CleanupMode import liquibase.hub.HubService import liquibase.hub.core.MockHubService import liquibase.integration.commandline.LiquibaseCommandLineConfiguration @@ -41,6 +42,7 @@ import org.junit.ComparisonFailure import spock.lang.Specification import spock.lang.Unroll +import java.util.concurrent.Callable import java.util.logging.Level import java.util.regex.Pattern @@ -289,12 +291,9 @@ Long Description: ${commandDefinition.getLongDescription() ?: "NOT SET"} } return } - } - finally { - if (testDef.setup != null) { - for (def setup : testDef.setup) { - setup.cleanup() - } + } finally { + if (testDef.commandTestDefinition.afterMethodInvocation != null) { + testDef.commandTestDefinition.afterMethodInvocation.call() } } } as Scope.ScopedRunnerWithReturn) @@ -311,35 +310,43 @@ Long Description: ${commandDefinition.getLongDescription() ?: "NOT SET"} throw new RuntimeException("Results were expected but none were found for " + testDef.commandTestDefinition.command) } - then: - checkOutput("Command Output", outputStream.toString(), testDef.expectedOutput) - checkOutput("UI Output", uiOutputWriter.toString(), testDef.expectedUI) - checkOutput("UI Error Output", uiErrorWriter.toString(), testDef.expectedUIErrors) - checkOutput("Log Messages", logService.getLogAsString(Level.FINE), testDef.expectedLogs) - - checkFileContent(testDef.expectedFileContent, "Command File Content") - checkDatabaseContent(testDef.expectedDatabaseContent, database, "Database snapshot content") - - if (!testDef.expectedResults.isEmpty()) { - for (def returnedResult : results.getResults().entrySet()) { - def expectedResult = testDef.expectedResults.get(returnedResult.getKey()) - def expectedValue = expectedResult instanceof Closure ? expectedResult.call() : String.valueOf(expectedResult) - def seenValue = String.valueOf(returnedResult.getValue()) - - assert expectedValue != "null": "No expectedResult for returned result '" + returnedResult.getKey() + "' of: " + seenValue - assert seenValue == expectedValue + try { + checkOutput("Command Output", outputStream.toString(), testDef.expectedOutput) + checkOutput("UI Output", uiOutputWriter.toString(), testDef.expectedUI) + checkOutput("UI Error Output", uiErrorWriter.toString(), testDef.expectedUIErrors) + checkOutput("Log Messages", logService.getLogAsString(Level.FINE), testDef.expectedLogs) + + checkFileContent(testDef.expectedFileContent, "Command File Content") + checkDatabaseContent(testDef.expectedDatabaseContent, database, "Database snapshot content") + + if (!testDef.expectedResults.isEmpty()) { + for (def returnedResult : results.getResults().entrySet()) { + def expectedResult = testDef.expectedResults.get(returnedResult.getKey()) + def expectedValue = expectedResult instanceof Closure ? expectedResult.call() : String.valueOf(expectedResult) + def seenValue = String.valueOf(returnedResult.getValue()) + + assert expectedValue != "null": "No expectedResult for returned result '" + returnedResult.getKey() + "' of: " + seenValue + assert seenValue == expectedValue + } + } + if (testDef.expectFileToExist != null) { + assert testDef.expectFileToExist.exists(): "File '${testDef.expectFileToExist.getAbsolutePath()}' should exist" + } + if (testDef.expectFileToNotExist != null) { + assert !testDef.expectFileToNotExist.exists(): "File '${testDef.expectFileToNotExist.getAbsolutePath()}' should not exist" + } + } finally { + if (testDef.setup != null) { + for (def setup : testDef.setup) { + setup.cleanup() + } + } } - } - if (testDef.expectFileToExist != null) { - assert testDef.expectFileToExist.exists(): "File '${testDef.expectFileToExist.getAbsolutePath()}' should exist" - } - if (testDef.expectFileToNotExist != null) { - assert !testDef.expectFileToNotExist.exists(): "File '${testDef.expectFileToNotExist.getAbsolutePath()}' should not exist" - } - where: - permutation << getAllRunTestPermutations() + + where: + permutation << getAllRunTestPermutations() } static OutputCheck assertNotContains(String substring) { @@ -550,6 +557,12 @@ Long Description: ${commandDefinition.getLongDescription() ?: "NOT SET"} List runTests = new ArrayList<>() String signature + /** + * An optional method that will be called after the execution of each run command. This is executed within + * the same scope as the command that is run for the test. This method will always be called, regardless of + * exceptions thrown from within the test. + */ + Callable afterMethodInvocation void run(@DelegatesTo(RunTestDefinition) Closure testClosure) { run(null, testClosure) @@ -836,10 +849,28 @@ Long Description: ${commandDefinition.getLongDescription() ?: "NOT SET"} this.setups.add(new SetupRunChangelog(changeLogPath, labels)) } + /* + * Create files and directories + */ void createTempResource(String originalFile, String newFile) { this.setups.add(new SetupCreateTempResources(originalFile, newFile)) } + void createTempResource(String originalFile, String newFile, String baseDir) { + this.setups.add(new SetupCreateTempResources(originalFile, newFile, baseDir)) + } + + /** + * @param fileLastModifiedDate if not null, the newly created file's last modified date will be set to this value + */ + void createTempResource(String originalFile, String newFile, String baseDir, Date fileLastModifiedDate) { + this.setups.add(new SetupCreateTempResources(originalFile, newFile, baseDir, fileLastModifiedDate)) + } + + void createTempDirectoryResource(String directory) { + this.setups.add(new SetupCreateDirectoryResources(directory)) + } + /** * * Copy a specified file to another path @@ -865,13 +896,24 @@ Long Description: ${commandDefinition.getLongDescription() ?: "NOT SET"} * * Delete the specified resources * - * @param fileToDeletes + * @param filesToDelete * */ void cleanResources(String... filesToDelete) { this.setups.add(new SetupCleanResources(filesToDelete)) } + /** + * + * Delete the specified resources at possibly setup and cleanup + * + * @param filesToDelete + * + */ + void cleanResources(CleanupMode cleanOnSetup, String... filesToDelete) { + this.setups.add(new SetupCleanResources(cleanOnSetup, filesToDelete)) + } + /** * Mark the changeSets within a changelog as ran without actually running them */ @@ -1042,6 +1084,7 @@ Long Description: ${commandDefinition.getLongDescription() ?: "NOT SET"} @Override def T prompt(String prompt, T valueIfNoEntry, InputHandler inputHandler, Class type) { + this.sendMessage(prompt + ": "); return valueIfNoEntry } diff --git a/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCleanResources.groovy b/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCleanResources.groovy index 66cb594cf82..20db33ac81b 100644 --- a/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCleanResources.groovy +++ b/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCleanResources.groovy @@ -1,42 +1,74 @@ package liquibase.extension.testing.setup -import liquibase.Contexts -import liquibase.LabelExpression -import liquibase.Liquibase -import liquibase.changelog.ChangeLogHistoryService -import liquibase.changelog.ChangeLogHistoryServiceFactory -import liquibase.database.Database -import liquibase.database.DatabaseFactory -import liquibase.database.jvm.JdbcConnection + import liquibase.extension.testing.TestDatabaseConnections -import liquibase.integration.commandline.CommandLineResourceAccessor -import liquibase.resource.CompositeResourceAccessor -import liquibase.resource.FileSystemResourceAccessor -import java.nio.file.Paths +import java.nio.file.FileSystems +import java.nio.file.Files +import java.nio.file.Path class SetupCleanResources extends TestSetup { private final List resourcesToDelete = new ArrayList<>() + public enum CleanupMode { CLEAN_ON_SETUP, CLEAN_ON_CLEANUP, CLEAN_ON_BOTH} + private CleanupMode cleanupMode SetupCleanResources(String[] resourcesToDelete) { + this(CleanupMode.CLEAN_ON_CLEANUP, resourcesToDelete) + } + + SetupCleanResources(CleanupMode cleanupMode, String[] resourcesToDelete) { + this.cleanupMode = cleanupMode this.resourcesToDelete.addAll(resourcesToDelete as Set) } @Override void setup(TestDatabaseConnections.ConnectionStatus connectionStatus) throws Exception { + if (cleanupMode == CleanupMode.CLEAN_ON_CLEANUP) { + return + } + deleteFiles(resourcesToDelete) + } + + @Override + void cleanup() { + if (cleanupMode == CleanupMode.CLEAN_ON_SETUP) { + return + } + deleteFiles(resourcesToDelete) + } + + private void deleteFiles(List resourcesToDelete) { for (String fileToDelete : resourcesToDelete) { + File f = null URL url = Thread.currentThread().getContextClassLoader().getResource(fileToDelete) if (url == null) { - return + f = new File(fileToDelete) + } else { + f = new File(url.toURI()) } - File f = new File(url.toURI()) + + if (! f.exists()) { + continue + } + if (f.isFile()) { + f.delete() + } else { + f.deleteDir() + } + + // + // This will handle files and directories + // + /* if (f.exists()) { - boolean b = f.delete() - if (b) { - assert !f.exists(): "The file '$f' was not deleted" - } + Path path = FileSystems.getDefault().getPath(f.getAbsolutePath()); + Files.walk(path) + .sorted(Comparator.reverseOrder()) + .map({ p -> p.toFile() }) + .forEach({ file -> file.delete() }) } + */ } } } diff --git a/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCreateDirectoryResources.groovy b/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCreateDirectoryResources.groovy new file mode 100644 index 00000000000..4bdb2201240 --- /dev/null +++ b/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCreateDirectoryResources.groovy @@ -0,0 +1,23 @@ +package liquibase.extension.testing.setup + +import liquibase.extension.testing.TestDatabaseConnections + +class SetupCreateDirectoryResources extends TestSetup { + + private String directory + + SetupCreateDirectoryResources(String directory) { + this.directory = directory + } + + @Override + void setup(TestDatabaseConnections.ConnectionStatus connectionStatus) throws Exception { + File f = new File(directory) + boolean b = f.mkdirs() + if (! b) { + if (! f.exists()) { + throw new RuntimeException("Unable to create directory '" + directory + "'") + } + } + } +} diff --git a/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCreateTempResources.groovy b/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCreateTempResources.groovy index cb015f02577..f864ceaf770 100644 --- a/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCreateTempResources.groovy +++ b/liquibase-extension-testing/src/main/groovy/liquibase/extension/testing/setup/SetupCreateTempResources.groovy @@ -7,10 +7,22 @@ class SetupCreateTempResources extends TestSetup { private String originalFile private String newFile + private String baseDir + private Date lastModified SetupCreateTempResources(String originalFile, String newFile) { + this(originalFile, newFile, "target/test-classes") + } + + SetupCreateTempResources(String originalFile, String newFile, String baseDir) { + this(originalFile, newFile, baseDir, null) + } + + SetupCreateTempResources(String originalFile, String newFile, String baseDir, Date lastModified) { this.originalFile = originalFile this.newFile = newFile + this.baseDir = baseDir + this.lastModified = lastModified } @Override @@ -18,7 +30,10 @@ class SetupCreateTempResources extends TestSetup { URL url = Thread.currentThread().getContextClassLoader().getResource(originalFile) File f = new File(url.toURI()) String contents = FileUtil.getContents(f) - File outputFile = new File("target/test-classes", newFile) + File outputFile = new File(baseDir, newFile) FileUtil.write(contents, outputFile) + if (lastModified != null) { + outputFile.setLastModified(lastModified.getTime()) + } } } diff --git a/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/diffChangelog.test.groovy b/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/diffChangelog.test.groovy index 1400e4eb921..d802cb4d082 100644 --- a/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/diffChangelog.test.groovy +++ b/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/diffChangelog.test.groovy @@ -7,6 +7,7 @@ import liquibase.change.core.AddPrimaryKeyChange import liquibase.change.core.CreateTableChange import liquibase.exception.CommandExecutionException import liquibase.exception.CommandValidationException +import liquibase.extension.testing.setup.SetupCleanResources import liquibase.structure.core.Column import java.util.regex.Pattern @@ -71,7 +72,7 @@ Optional Args: ] setup { - cleanResources("diffChangelog-test.xml") + cleanResources(SetupCleanResources.CleanupMode.CLEAN_ON_SETUP, "diffChangelog-test.xml") database = [ new CreateTableChange( tableName: "FirstTable", @@ -115,7 +116,7 @@ Optional Args: ] setup { - cleanResources("diffChangeLog-test.xml") + cleanResources(SetupCleanResources.CleanupMode.CLEAN_ON_SETUP, "diffChangeLog-test.xml") database = [ new CreateTableChange( tableName: "SharedTable", @@ -173,7 +174,7 @@ Optional Args: ] setup { - cleanResources("diffChangelogOrder-test.xml") + cleanResources(SetupCleanResources.CleanupMode.CLEAN_ON_SETUP, "diffChangelogOrder-test.xml") database = [ new CreateTableChange( tableName: "person", diff --git a/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/generateChangelog.test.groovy b/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/generateChangelog.test.groovy index eae820c7f38..79d5f189281 100644 --- a/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/generateChangelog.test.groovy +++ b/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/generateChangelog.test.groovy @@ -4,6 +4,7 @@ import liquibase.change.ColumnConfig import liquibase.change.core.CreateTableChange import liquibase.change.core.TagDatabaseChange import liquibase.exception.CommandValidationException +import liquibase.extension.testing.setup.SetupCleanResources CommandTests.define { command = ["generateChangelog"] @@ -51,7 +52,7 @@ Optional Args: changelogFile: "target/test-classes/changelog-test.xml" ] setup { - cleanResources("changelog-test.xml") + cleanResources(SetupCleanResources.CleanupMode.CLEAN_ON_SETUP, "changelog-test.xml") database = [ new CreateTableChange( tableName: "FirstTable", diff --git a/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/registerChangelog.test.groovy b/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/registerChangelog.test.groovy index eb83e9da85b..28bdd453618 100644 --- a/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/registerChangelog.test.groovy +++ b/liquibase-integration-tests/src/test/resources/liquibase/extension/testing/command/registerChangelog.test.groovy @@ -2,7 +2,6 @@ package liquibase.extension.testing.command import liquibase.exception.CommandExecutionException import liquibase.exception.CommandValidationException -import liquibase.extension.testing.setup.SetupCreateTempResources import liquibase.hub.core.MockHubService import java.util.regex.Pattern