├── .github ├── ubuntu │ ├── all-apt-prereqs.sh │ ├── exasol.sh │ ├── firebird.sh │ ├── mysql.sh │ ├── oracle.sh │ ├── pg.sh │ ├── snowflake.sh │ ├── sqlite.sh │ └── vertica.sh └── workflows │ ├── cockroach.yml │ ├── coverage.yml │ ├── exasol.yml │ ├── firebird.yml │ ├── mysql.yml │ ├── oracle.yml │ ├── os.yml │ ├── perl.yml │ ├── pg.yml │ ├── release.yml │ ├── snowflake.yml │ ├── sqlite.yml │ ├── vertica.yml │ └── yugabyte.yml ├── .gitignore ├── Changes ├── LICENSE.md ├── MANIFEST.SKIP ├── README.md ├── bin └── sqitch ├── dist.ini ├── dist ├── cpanfile └── sqitch.spec ├── etc ├── templates │ ├── deploy │ │ ├── cockroach.tmpl │ │ ├── exasol.tmpl │ │ ├── firebird.tmpl │ │ ├── mysql.tmpl │ │ ├── oracle.tmpl │ │ ├── pg.tmpl │ │ ├── snowflake.tmpl │ │ ├── sqlite.tmpl │ │ └── vertica.tmpl │ ├── revert │ │ ├── cockroach.tmpl │ │ ├── exasol.tmpl │ │ ├── firebird.tmpl │ │ ├── mysql.tmpl │ │ ├── oracle.tmpl │ │ ├── pg.tmpl │ │ ├── snowflake.tmpl │ │ ├── sqlite.tmpl │ │ └── vertica.tmpl │ └── verify │ │ ├── cockroach.tmpl │ │ ├── exasol.tmpl │ │ ├── firebird.tmpl │ │ ├── mysql.tmpl │ │ ├── oracle.tmpl │ │ ├── pg.tmpl │ │ ├── snowflake.tmpl │ │ ├── sqlite.tmpl │ │ └── vertica.tmpl └── tools │ ├── upgrade-registry-to-mysql-5.5.0.sql │ └── upgrade-registry-to-mysql-5.6.4.sql ├── inc ├── Menlo │ └── Sqitch.pm └── Module │ └── Build │ └── Sqitch.pm ├── lib ├── App │ ├── Sqitch.pm │ └── Sqitch │ │ ├── Command.pm │ │ ├── Command │ │ ├── add.pm │ │ ├── bundle.pm │ │ ├── check.pm │ │ ├── checkout.pm │ │ ├── config.pm │ │ ├── deploy.pm │ │ ├── engine.pm │ │ ├── help.pm │ │ ├── init.pm │ │ ├── log.pm │ │ ├── plan.pm │ │ ├── rebase.pm │ │ ├── revert.pm │ │ ├── rework.pm │ │ ├── show.pm │ │ ├── status.pm │ │ ├── tag.pm │ │ ├── target.pm │ │ ├── upgrade.pm │ │ └── verify.pm │ │ ├── Config.pm │ │ ├── DateTime.pm │ │ ├── Engine.pm │ │ ├── Engine │ │ ├── Upgrade │ │ │ ├── cockroach-1.0.sql │ │ │ ├── cockroach-1.1.sql │ │ │ ├── exasol-1.0.sql │ │ │ ├── exasol-1.1.sql │ │ │ ├── firebird-1.0.sql │ │ │ ├── firebird-1.1.sql │ │ │ ├── mysql-1.0.sql │ │ │ ├── mysql-1.1.sql │ │ │ ├── oracle-1.0.sql │ │ │ ├── oracle-1.1.sql │ │ │ ├── pg-1.0.sql │ │ │ ├── pg-1.1.sql │ │ │ ├── snowflake-1.0.sql │ │ │ ├── snowflake-1.1.sql │ │ │ ├── sqlite-1.0.sql │ │ │ ├── sqlite-1.1.sql │ │ │ ├── vertica-1.0.sql │ │ │ └── vertica-1.1.sql │ │ ├── cockroach.pm │ │ ├── cockroach.sql │ │ ├── exasol.pm │ │ ├── exasol.sql │ │ ├── firebird.pm │ │ ├── firebird.sql │ │ ├── mysql.pm │ │ ├── mysql.sql │ │ ├── oracle.pm │ │ ├── oracle.sql │ │ ├── pg.pm │ │ ├── pg.sql │ │ ├── snowflake.pm │ │ ├── snowflake.sql │ │ ├── sqlite.pm │ │ ├── sqlite.sql │ │ ├── vertica.pm │ │ └── vertica.sql │ │ ├── ItemFormatter.pm │ │ ├── Plan.pm │ │ ├── Plan │ │ ├── Blank.pm │ │ ├── Change.pm │ │ ├── ChangeList.pm │ │ ├── Depend.pm │ │ ├── Line.pm │ │ ├── LineList.pm │ │ ├── Pragma.pm │ │ └── Tag.pm │ │ ├── Role │ │ ├── ConnectingCommand.pm │ │ ├── ContextCommand.pm │ │ ├── DBIEngine.pm │ │ ├── RevertDeployCommand.pm │ │ └── TargetConfigCommand.pm │ │ ├── Target.pm │ │ ├── Types.pm │ │ └── X.pm ├── sqitch-add-usage.pod ├── sqitch-add.pod ├── sqitch-authentication.pod ├── sqitch-bundle-usage.pod ├── sqitch-bundle.pod ├── sqitch-check-usage.pod ├── sqitch-check.pod ├── sqitch-checkout-usage.pod ├── sqitch-checkout.pod ├── sqitch-config-usage.pod ├── sqitch-config.pod ├── sqitch-configuration.pod ├── sqitch-deploy-usage.pod ├── sqitch-deploy.pod ├── sqitch-engine-usage.pod ├── sqitch-engine.pod ├── sqitch-environment.pod ├── sqitch-help-usage.pod ├── sqitch-help.pod ├── sqitch-init-usage.pod ├── sqitch-init.pod ├── sqitch-log-usage.pod ├── sqitch-log.pod ├── sqitch-passwords.pod ├── sqitch-plan-usage.pod ├── sqitch-plan.pod ├── sqitch-rebase-usage.pod ├── sqitch-rebase.pod ├── sqitch-revert-usage.pod ├── sqitch-revert.pod ├── sqitch-rework-usage.pod ├── sqitch-rework.pod ├── sqitch-show-usage.pod ├── sqitch-show.pod ├── sqitch-status-usage.pod ├── sqitch-status.pod ├── sqitch-tag-usage.pod ├── sqitch-tag.pod ├── sqitch-target-usage.pod ├── sqitch-target.pod ├── sqitch-upgrade-usage.pod ├── sqitch-upgrade.pod ├── sqitch-verify-usage.pod ├── sqitch-verify.pod ├── sqitch.pod ├── sqitchchanges.pod ├── sqitchcommands.pod ├── sqitchguides.pod ├── sqitchtutorial-exasol.pod ├── sqitchtutorial-firebird.pod ├── sqitchtutorial-mysql.pod ├── sqitchtutorial-oracle.pod ├── sqitchtutorial-snowflake.pod ├── sqitchtutorial-sqlite.pod ├── sqitchtutorial-vertica.pod ├── sqitchtutorial.pod └── sqitchusage.pod ├── po ├── App-Sqitch.pot ├── de_DE.po ├── fr_FR.po └── it_IT.po ├── t ├── add.t ├── add_change.conf ├── base.t ├── blank.t ├── bundle.t ├── change.t ├── changelist.t ├── check.t ├── checkout.t ├── cockroach.t ├── command.t ├── config.t ├── configuration.t ├── conn_cmd_role.t ├── core.conf ├── core_target.conf ├── cx_cmd_role.t ├── datetime.t ├── dbiengine_role.t ├── depend.t ├── deploy.t ├── die.pl ├── echo.pl ├── editor.conf ├── engine.conf ├── engine.t ├── engine │ ├── deploy │ │ ├── func │ │ │ └── add_user.sql │ │ ├── users.sql │ │ └── widgets.sql │ ├── revert │ │ ├── func │ │ │ └── add_user.sql │ │ ├── users.sql │ │ └── widgets.sql │ ├── reworked │ │ ├── deploy │ │ │ └── users@alpha.sql │ │ └── revert │ │ │ └── users@alpha.sql │ └── sqitch.plan ├── engine_cmd.t ├── exasol.t ├── firebird.t ├── help.t ├── init.t ├── item_formatter.t ├── lib │ ├── App │ │ └── Sqitch │ │ │ ├── Command │ │ │ ├── bad.pm │ │ │ └── good.pm │ │ │ └── Engine │ │ │ ├── bad.pm │ │ │ └── good.pm │ ├── DBIEngineTest.pm │ ├── LC.pm │ ├── MockOutput.pm │ ├── TestConfig.pm │ └── upgradable_registries │ │ ├── cockroach.sql │ │ ├── exasol.sql │ │ ├── firebird.sql │ │ ├── mysql.sql │ │ ├── oracle.sql │ │ ├── pg.sql │ │ ├── snowflake.sql │ │ ├── sqlite.sql │ │ └── vertica.sql ├── linelist.t ├── local.conf ├── log.t ├── mooseless.t ├── multiplan.conf ├── mysql.t ├── odbc │ ├── odbcinst.ini │ ├── snowflake.ini │ └── vertica.ini ├── options.t ├── oracle.t ├── pg.t ├── plan.t ├── plan_cmd.t ├── plans │ ├── bad-change.plan │ ├── changes-only.plan │ ├── dependencies.plan │ ├── deploy-and-revert.plan │ ├── dos.plan │ ├── dupe-change-diff-tag.plan │ ├── dupe-change.plan │ ├── dupe-tag.plan │ ├── multi.plan │ ├── pragmas.plan │ ├── project_deps.plan │ ├── reserved-tag.plan │ └── widgets.plan ├── pragma.t ├── read.pl ├── rebase.t ├── revert.t ├── rework.conf ├── rework.t ├── show.t ├── snowflake.t ├── sqitch ├── sqitch.conf ├── sql │ ├── deploy │ │ ├── curry.sql │ │ ├── dr_evil.sql │ │ ├── lolz.sql │ │ ├── oops.sql │ │ ├── roles.sql │ │ ├── tacos.sql │ │ ├── users.sql │ │ └── widgets.sql │ ├── revert │ │ ├── curry.sql │ │ ├── dr_evil.sql │ │ ├── lolz.sql │ │ ├── roles.sql │ │ ├── tacos.sql │ │ ├── users.sql │ │ └── widgets.sql │ ├── sqitch.plan │ └── verify │ │ └── users.sql ├── sqlite.t ├── status.t ├── tag.t ├── tag_cmd.t ├── target.conf ├── target.t ├── target_cmd.t ├── templates.conf ├── upgrade.t ├── user.conf ├── verify.t ├── vertica.t ├── win32.t └── x.t └── xt ├── dependency_report ├── gen_release_changes ├── locale ├── LocaleData │ ├── de_DE │ │ └── LC_MESSAGES │ │ │ └── App-Sqitch.mo │ ├── fr_FR │ │ └── LC_MESSAGES │ │ │ └── App-Sqitch.mo │ └── it_IT │ │ └── LC_MESSAGES │ │ └── App-Sqitch.mo ├── README.md ├── po │ ├── de_DE.po │ ├── fr_FR.po │ └── it_IT.po └── test-cli.t ├── release.md └── release ├── pod-coverage.t ├── pod-spelling.t └── pod.t /.github/ubuntu/all-apt-prereqs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | sudo apt-get update -qq 6 | sudo apt-get remove -qq mysql-common # https://github.com/actions/virtual-environments/issues/5067#issuecomment-1038752575 7 | sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq \ 8 | libicu-dev gettext aspell-en software-properties-common \ 9 | curl unixodbc-dev odbcinst unixodbc \ 10 | default-jre \ 11 | firebird-dev firebird3.0-utils \ 12 | mysql-client default-libmysqlclient-dev \ 13 | libarchive-tools \ 14 | libaio1t64 15 | cat t/odbc/odbcinst.ini | sudo tee -a /etc/odbcinst.ini 16 | 17 | # instantclient still wants libaio.so.1. https://askubuntu.com/a/1514001 18 | sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 19 | -------------------------------------------------------------------------------- /.github/ubuntu/exasol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Download dependencies. 6 | if [ -z "$SKIP_DEPENDS" ]; then 7 | sudo apt-get update -qq 8 | sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq curl unixodbc-dev odbcinst unixodbc default-jre 9 | cat t/odbc/odbcinst.ini | sudo tee -a /etc/odbcinst.ini 10 | fi 11 | 12 | # Prepare the configuration. 13 | mkdir -p /opt/exasol 14 | 15 | # Download and unpack Exasol ODBC Driver & EXAplus. 16 | curl -sSLO https://x-up.s3.amazonaws.com/7.x/24.2.0/Exasol_ODBC-24.2.0-Linux_x86_64.tar.gz 17 | curl -sSLO https://x-up.s3.amazonaws.com/7.x/24.2.1/EXAplus-24.2.1.tar.gz 18 | sudo tar -xzf Exasol_ODBC-24.2.0-Linux_x86_64.tar.gz -C /opt/exasol --strip-components 2 19 | sudo tar -xzf EXAplus-24.2.1.tar.gz -C /opt/exasol --strip-components 2 20 | 21 | # Add to the path. 22 | if [[ -n "$GITHUB_PATH" ]]; then 23 | echo "/opt/exasol" >> "$GITHUB_PATH" 24 | fi 25 | -------------------------------------------------------------------------------- /.github/ubuntu/firebird.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Download dependencies. 6 | if [ -z "$SKIP_DEPENDS" ]; then 7 | sudo apt-get update -qq 8 | sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq firebird-dev firebird3.0-utils 9 | fi 10 | 11 | # Tell DBD::Firebird where to find the libraries. 12 | if [[ -n "$GITHUB_ENV" ]]; then 13 | echo "FIREBIRD_HOME=/usr" >> "$GITHUB_ENV" 14 | fi 15 | -------------------------------------------------------------------------------- /.github/ubuntu/mysql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Download dependencies. 6 | if [ -z "$SKIP_DEPENDS" ]; then 7 | sudo apt-get update -qq 8 | sudo apt-get remove -qq mysql-common # https://github.com/actions/virtual-environments/issues/5067#issuecomment-1038752575 9 | sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq mariadb-client libmariadbd-dev 10 | fi 11 | -------------------------------------------------------------------------------- /.github/ubuntu/oracle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | version=23.6.0.24.10 6 | icdr=2360000 7 | 8 | # Download dependencies. 9 | if [ -z "$SKIP_DEPENDS" ]; then 10 | # Install libaio and bsdtar, required to get --strip-components for a zip file. 11 | sudo apt-get update -qq 12 | sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq libarchive-tools libaio1t64 13 | 14 | # instantclient still wants libaio.so.1. https://askubuntu.com/a/1514001 15 | sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 16 | fi 17 | 18 | # Download Instant Client. 19 | # https://www.oracle.com/database/technologies/instant-client/downloads.html 20 | baseurl="https://download.oracle.com/otn_software/linux/instantclient/${icdr}" 21 | curl -sSLO "${baseurl}/instantclient-basic-linux.x64-${version}.zip" 22 | curl -sSLO "${baseurl}/instantclient-sqlplus-linux.x64-${version}.zip" 23 | curl -sSLO "${baseurl}/instantclient-sdk-linux.x64-${version}.zip" 24 | 25 | # Unpack Intant Client. 26 | mkdir -p /opt/instantclient 27 | bsdtar -C /opt/instantclient --strip-components 1 -zxf "instantclient-basic-linux.x64-${version}.zip" 28 | bsdtar -C /opt/instantclient --strip-components 1 -zxf "instantclient-sqlplus-linux.x64-${version}.zip" 29 | bsdtar -C /opt/instantclient --strip-components 1 -zxf "instantclient-sdk-linux.x64-${version}.zip" 30 | 31 | if [[ -n "$GITHUB_PATH" ]]; then 32 | echo "/opt/instantclient" >> "$GITHUB_PATH" 33 | fi 34 | 35 | if [[ -n "$GITHUB_ENV" ]]; then 36 | echo "ORACLE_HOME=/opt/instantclient" >> "$GITHUB_ENV" 37 | if [[ -z "$LD_LIBRARY_PATH" ]]; then 38 | echo "LD_LIBRARY_PATH=/opt/instantclient" >> "$GITHUB_ENV" 39 | else 40 | echo "LD_LIBRARY_PATH=/opt/instantclient:$LD_LIBRARY_PATH" >> "$GITHUB_ENV" 41 | fi 42 | fi 43 | -------------------------------------------------------------------------------- /.github/ubuntu/pg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | PGVERSION=${PGVERSION:=${1:-14}} 6 | [[ $PGVERSION =~ ^[0-9]$ ]] && PGVERSION+=.0 7 | 8 | curl -O https://salsa.debian.org/postgresql/postgresql-common/-/raw/master/pgdg/apt.postgresql.org.sh 9 | sudo sh apt.postgresql.org.sh -i -t -v $PGVERSION 10 | sudo pg_createcluster --start $PGVERSION test -p 5432 --locale=C -- -A trust -E UTF8 11 | 12 | if [[ -n "$GITHUB_PATH" ]]; then 13 | echo "/usr/lib/postgresql/$POSTGRES/bin" >> "$GITHUB_PATH" 14 | fi 15 | -------------------------------------------------------------------------------- /.github/ubuntu/snowflake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Set up Snowflake. 6 | if [ -z "$SKIP_DEPENDS" ]; then 7 | sudo apt-get update -qq 8 | sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq unixodbc-dev odbcinst unixodbc 9 | cat t/odbc/odbcinst.ini | sudo tee -a /etc/odbcinst.ini 10 | fi 11 | 12 | # Set the SnowSQL workspace. 13 | export WORKSPACE=/opt/snowflake 14 | 15 | # https://docs.snowflake.net/manuals/release-notes/client-change-log-snowsql.html 16 | # https://sfc-repo.snowflakecomputing.com/index.html 17 | curl -sSLo snowsql.bash https://sfc-repo.snowflakecomputing.com/snowsql/bootstrap/1.3/linux_x86_64/snowsql-1.3.2-linux_x86_64.bash 18 | curl -sSLo snowdbc.tgz https://sfc-repo.snowflakecomputing.com/odbc/linux/latest/snowflake_linux_x8664_odbc-3.5.0.tgz 19 | 20 | # Install and configure ODBC. 21 | mkdir -p "$WORKSPACE/.snowsql" 22 | sudo tar --strip-components 1 -C "$WORKSPACE" -xzf snowdbc.tgz 23 | sudo mv "$WORKSPACE/ErrorMessages/en-US" "$WORKSPACE/lib/" 24 | 25 | # Set up the DSN for key pair auth. 26 | perl -npE 's/KEY_PASSWORD/$ENV{SNOWFLAKE_KEY_PASSWORD}/g' t/odbc/snowflake.ini | sudo tee -a /etc/odbc.ini 27 | printf "%s" "${SNOWFLAKE_KEY_FILE}" > "$WORKSPACE/rsa_key.p8" 28 | 29 | # Install, update, and configure SnowSQL. 30 | sed -e '1,/^exit$/d' snowsql.bash | sudo tar -C "$WORKSPACE" -zxf - 31 | "$WORKSPACE/snowsql" -Uv 32 | ( 33 | printf "[connections]\nprivate_key_path=%s/rsa_key.p8\n\n" "$WORKSPACE" 34 | printf "[options]\nnoup = true\n" 35 | ) > "$WORKSPACE/.snowsql/config" 36 | 37 | # Add to the path. 38 | if [[ -n "$GITHUB_PATH" ]]; then 39 | echo "$WORKSPACE" >> "$GITHUB_PATH" 40 | fi 41 | 42 | # Tell SnowSQL where to find the config. 43 | if [[ -n "$GITHUB_ENV" ]]; then 44 | echo "WORKSPACE=$WORKSPACE" >> "$GITHUB_ENV" 45 | fi 46 | -------------------------------------------------------------------------------- /.github/ubuntu/sqlite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | SQLITE=${SQLITE:=${1:-3.40.1}} 6 | echo "Instaling SQLite $SQLITE" 7 | 8 | # Convert to the SQLITE_VERSION_NUMBER format https://sqlite.org/c3ref/c_source_id.html 9 | SQLITE=$(perl -e 'my @v = split /[.]/, shift; printf "%d%02d%02d%02d\n", @v[0..3]' "$SQLITE") 10 | 11 | # Since 3.7.16.1, the URL includes the year in the path. 12 | # 3.18.2, 3.18.1, 3.9.3, and 3.7.11 missing. 13 | # https://sqlite.org/chronology.html 14 | # https://stackoverflow.com/a/37712117/79202 15 | if (( $SQLITE >= 3450000 )); then YEAR=2024 16 | elif (( $SQLITE >= 3400200 )); then YEAR=2023 17 | elif (( $SQLITE >= 3370200 )); then YEAR=2022 18 | elif (( $SQLITE >= 3340100 )); then YEAR=2021 19 | elif (( $SQLITE >= 3310000 )); then YEAR=2020 20 | elif (( $SQLITE >= 3270000 )); then YEAR=2019 21 | elif (( $SQLITE >= 3220000 )); then YEAR=2018 22 | elif (( $SQLITE >= 3160000 )); then YEAR=2017 23 | elif (( $SQLITE >= 3100000 )); then YEAR=2016 24 | elif (( $SQLITE >= 3080800 )); then YEAR=2015 25 | elif (( $SQLITE >= 3080300 )); then YEAR=2014 26 | elif (( $SQLITE >= 3071601 )); then YEAR=2013 # Earliest release with year in path. 27 | else 28 | echo "Unsupported version $SQLITE" >&2 29 | exit 64 30 | fi 31 | 32 | # Download, compile, and install SQLite. 33 | curl -o sqlite.zip https://sqlite.org/$YEAR/sqlite-amalgamation-$SQLITE.zip 34 | unzip -j sqlite.zip -d /opt/sqlite 35 | cd /opt/sqlite 36 | # Build the CLI. 37 | gcc shell.c sqlite3.c -lpthread -ldl -o sqlite3 38 | # Build the shared library 39 | gcc -c -fPIC sqlite3.c 40 | gcc -shared -o libsqlite3.so -fPIC sqlite3.o -ldl -lpthread 41 | 42 | # Hand-build DBD::SQLite against the version of SQLite just installed. 43 | DIST=$(cpanm --info DBD::SQLite) # ISHIGAKI/DBD-SQLite-1.70.tar.gz 44 | URL=https://cpan.metacpan.org/authors/id/${DIST:0:1}/${DIST:0:2}/$DIST 45 | curl -o dbd.tar.gz "$URL" 46 | tar zxvf dbd.tar.gz --strip-components 1 47 | perl -i -pe 's/^if\s*\(\s*0\s*\)\s\{/if (1) {/' Makefile.PL 48 | perl Makefile.PL SQLITE_INC=/opt/sqlite SQLITE_LIB=/opt/sqlite 49 | make && make install 50 | 51 | if [[ -n "$GITHUB_PATH" ]]; then 52 | echo "/opt/sqlite" >> "$GITHUB_PATH" 53 | fi 54 | 55 | if [[ -n "$GITHUB_ENV" ]]; then 56 | if [[ -z "$LD_LIBRARY_PATH" ]]; then 57 | echo "LD_LIBRARY_PATH=/opt/sqlite" >> "$GITHUB_ENV" 58 | else 59 | echo "LD_LIBRARY_PATH=/opt/sqlite:$LD_LIBRARY_PATH" >> "$GITHUB_ENV" 60 | fi 61 | fi 62 | -------------------------------------------------------------------------------- /.github/ubuntu/vertica.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [ -z "$SKIP_DEPENDS" ]; then 6 | sudo apt-get update -qq 7 | sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq unixodbc-dev odbcinst unixodbc 8 | cat t/odbc/odbcinst.ini | sudo tee -a /etc/odbcinst.ini 9 | fi 10 | 11 | cat t/odbc/vertica.ini | sudo tee -a /etc/vertica.ini 12 | 13 | # https://www.vertica.com/download/vertica/client-drivers/ 14 | curl -sSLO https://www.vertica.com/client_drivers/24.2.x/24.2.0-1/vertica-client-24.2.0-1.x86_64.tar.gz 15 | sudo tar -xzf vertica-client-24.2.0-1.x86_64.tar.gz -C / 16 | 17 | if [[ -n "$GITHUB_PATH" ]]; then 18 | echo "/opt/vertica/bin" >> "$GITHUB_PATH" 19 | fi 20 | -------------------------------------------------------------------------------- /.github/workflows/cockroach.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's Cockroach engine on all supported versions of 2 | # Postgres. It runs for pushes and pull requests on the `main`, `develop`, 3 | # `**cockroach**`, and `**engine**` branches. 4 | name: 🪳 Cockroach 5 | on: 6 | push: 7 | branches: [main, develop, "**engine**", "**cockroach**" ] 8 | pull_request: 9 | branches: [main, develop, "**engine**", "**cockroach**" ] 10 | jobs: 11 | Cockroach: 12 | strategy: 13 | matrix: 14 | # curl https://registry.hub.docker.com/v2/repositories/cockroachdb/cockroach/tags\?page_size\=10000 | jq '.results[].name 15 | version: ['23.1', '22.2', '21.2'] 16 | name: 🪳 Cockroach ${{ matrix.version }} 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Start CockroachDB 20 | run: docker run -d -p 26257:26257 cockroachdb/cockroach:latest-v${{ matrix.version }} start-single-node --insecure 21 | - uses: actions/checkout@v4 22 | - name: Setup Perl 23 | id: perl 24 | uses: shogo82148/actions-setup-perl@v1 25 | with: { perl-version: latest } 26 | - name: Cache CPAN Modules 27 | uses: actions/cache@v4 28 | with: 29 | path: local 30 | key: perl-${{ steps.perl.outputs.perl-hash }} 31 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 32 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::Pg 33 | - name: prove 34 | env: 35 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 36 | LIVE_COCKROACH_REQUIRED: true 37 | SQITCH_TEST_COCKROACH_URI: db:cockroach://root@localhost:26257/ 38 | run: prove -lvr t/cockroach.t 39 | -------------------------------------------------------------------------------- /.github/workflows/exasol.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's Exasol engine on recent supported versions of 2 | # Oracle. It runs for pushes and pull requests on the `main`, `develop`, 3 | # `**exasol**`, and `**engine**` branches. 4 | name: ☀️ Exasol 5 | on: 6 | push: 7 | branches: [main, develop, "**engine**", "**exasol**" ] 8 | pull_request: 9 | branches: [main, develop, "**engine**", "**exasol**" ] 10 | jobs: 11 | Exasol: 12 | strategy: 13 | matrix: 14 | exasol: ['8', '7.1', '7.0'] 15 | name: ☀️ Exasol ${{ matrix.exasol }} 16 | runs-on: ubuntu-latest 17 | services: 18 | exasol: 19 | image: exasol/docker-db:latest-${{ matrix.exasol }} 20 | ports: [ 8563 ] 21 | options: --privileged 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Setup Clients 25 | run: .github/ubuntu/exasol.sh 26 | - name: Setup Perl 27 | id: perl 28 | uses: shogo82148/actions-setup-perl@v1 29 | with: { perl-version: latest } 30 | - name: Cache CPAN Modules 31 | uses: actions/cache@v4 32 | with: 33 | path: local 34 | key: perl-${{ steps.perl.outputs.perl-hash }} 35 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 36 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::ODBC 37 | - name: prove 38 | env: 39 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 40 | LIVE_EXASOL_REQUIRED: true 41 | SQITCH_TEST_EXASOL_URI: db:exasol://sys:exasol@127.0.0.1:${{ job.services.exasol.ports[8563] }}/?Driver=Exasol;SSLCERTIFICATE=SSL_VERIFY_NONE 42 | run: prove -lvr t/exasol.t 43 | -------------------------------------------------------------------------------- /.github/workflows/firebird.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's Firebird engine on all supported versions of 2 | # Postgres. It runs for pushes and pull requests on the `main`, `develop`, 3 | # `**firebird**`, and `**engine**` branches. 4 | name: 🔥 Firebird 5 | on: 6 | push: 7 | branches: [main, develop, "**engine**", "**firebird**" ] 8 | pull_request: 9 | branches: [main, develop, "**engine**", "**firebird**" ] 10 | jobs: 11 | Firebird: 12 | strategy: 13 | matrix: 14 | include: 15 | - { version: '5', image: ghcr.io/fdcastel/firebird, dir: /var/lib/firebird/data } 16 | - { version: '4', image: ghcr.io/fdcastel/firebird, dir: /var/lib/firebird/data } 17 | - { version: '3', image: ghcr.io/fdcastel/firebird, dir: /var/lib/firebird/data } 18 | - { version: '2.5-ss', image: jacobalberty/firebird, dir: /firebird/data } # deprecated 19 | - { version: '2.5-sc', image: jacobalberty/firebird, dir: /firebird/data } # deprecated 20 | name: 🔥 Firebird ${{ matrix.version }} 21 | runs-on: ubuntu-latest 22 | services: 23 | # Run the Firebird service in a container we can connect to. Means that the 24 | # CLI and libraries DBD::firebird use are static to the version on the runner 25 | # machine. 26 | firebird: 27 | image: ${{ matrix.image }}:${{ matrix.version }} 28 | ports: [ 3050 ] 29 | env: 30 | ISC_PASSWORD: nix # for jacobalberty/firebird only 31 | FIREBIRD_ROOT_PASSWORD: nix 32 | FIREBIRD_DATABASE: sqitchtest.db 33 | steps: 34 | - uses: actions/checkout@v4 35 | - name: Setup Clients 36 | run: .github/ubuntu/firebird.sh 37 | - name: Setup Perl 38 | id: perl 39 | uses: shogo82148/actions-setup-perl@v1 40 | with: { perl-version: latest } 41 | - name: Cache CPAN Modules 42 | uses: actions/cache@v4 43 | with: 44 | path: local 45 | key: perl-${{ steps.perl.outputs.perl-hash }} 46 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 47 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::Firebird 48 | - name: prove 49 | env: 50 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 51 | LIVE_FIREBIRD_REQUIRED: true 52 | SQITCH_TEST_FIREBIRD_URI: db:firebird://sysdba:nix@127.0.0.1:${{ job.services.firebird.ports[3050] }}/${{ matrix.dir }}/sqitchtest.db 53 | run: prove -lvr t/firebird.t 54 | -------------------------------------------------------------------------------- /.github/workflows/mysql.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's MySQL engine on all supported versions of MySQL. 2 | # It runs for pushes and pull requests on the `main`, `develop`, `**mysql**`, 3 | # `**maria**`, and `**engine**` branches. 4 | name: 🐬 MySQL 5 | on: 6 | push: 7 | branches: [main, develop, "**engine**", "**mysql**", "**maria**" ] 8 | pull_request: 9 | branches: [main, develop, "**engine**", "**mysql**", "**maria**" ] 10 | jobs: 11 | MySQL: 12 | strategy: 13 | matrix: 14 | include: 15 | # curl -s https://registry.hub.docker.com/v2/repositories/library/mysql/tags\?page_size\=10000 | jq '.results[].name' 16 | - { version: '9.1', icon: 🐬, name: MySQL, image: mysql } 17 | - { version: '8.4', icon: 🐬, name: MySQL, image: mysql } 18 | - { version: '5.7', icon: 🐬, name: MySQL, image: mysql } 19 | - { version: '5.6', icon: 🐬, name: MySQL, image: mysql } 20 | - { version: '5.5', icon: 🐬, name: MySQL, image: mysql } 21 | # curl -s https://registry.hub.docker.com/v2/repositories/library/mariadb/tags\?page_size\=10000 | jq '.results[].name' 22 | - { version: '11.6', icon: 🦭, name: MariaDB, image: mariadb } 23 | - { version: '11.5', icon: 🦭, name: MariaDB, image: mariadb } 24 | - { version: '11.4', icon: 🦭, name: MariaDB, image: mariadb } 25 | - { version: '11.3', icon: 🦭, name: MariaDB, image: mariadb } 26 | - { version: '11.2', icon: 🦭, name: MariaDB, image: mariadb } 27 | - { version: '11.1', icon: 🦭, name: MariaDB, image: mariadb } 28 | - { version: '11.0', icon: 🦭, name: MariaDB, image: mariadb } 29 | - { version: '10.11', icon: 🦭, name: MariaDB, image: mariadb } 30 | - { version: '10.10', icon: 🦭, name: MariaDB, image: mariadb } 31 | - { version: '10.9', icon: 🦭, name: MariaDB, image: mariadb } 32 | - { version: '10.8', icon: 🦭, name: MariaDB, image: mariadb } 33 | - { version: '10.7', icon: 🦭, name: MariaDB, image: mariadb } 34 | - { version: '10.6', icon: 🦭, name: MariaDB, image: mariadb } 35 | - { version: '10.5', icon: 🦭, name: MariaDB, image: mariadb } 36 | - { version: '10.4', icon: 🦭, name: MariaDB, image: mariadb } 37 | - { version: '10.3', icon: 🦭, name: MariaDB, image: mariadb } 38 | - { version: '10.2', icon: 🦭, name: MariaDB, image: mariadb } 39 | - { version: '10.1', icon: 🦭, name: MariaDB, image: mariadb } 40 | - { version: '10.0', icon: 🦭, name: MariaDB, image: mariadb } 41 | name: ${{ matrix.icon }} ${{ matrix.name }} ${{ matrix.version }} 42 | runs-on: ubuntu-latest 43 | services: 44 | # Run the MySQL service in a container we can connect to. Means that the 45 | # CLI and libraries DBD::MariaDB use are static to the version on the runner 46 | # machine. 47 | mysql: 48 | image: "${{ matrix.image }}:${{ matrix.version }}" 49 | env: { MYSQL_ALLOW_EMPTY_PASSWORD: yes } 50 | ports: [ 3306 ] 51 | options: --health-cmd="healthcheck.sh --innodb_initialized || mysqladmin ping --protocol=tcp" --health-interval=5s --health-timeout=2s --health-retries=3 52 | steps: 53 | - uses: actions/checkout@v4 54 | - name: Setup Clients 55 | run: .github/ubuntu/mysql.sh 56 | - name: Setup Perl 57 | id: perl 58 | uses: shogo82148/actions-setup-perl@v1 59 | with: { perl-version: latest } 60 | - name: Cache CPAN Modules 61 | uses: actions/cache@v4 62 | with: 63 | path: local 64 | key: perl-${{ steps.perl.outputs.perl-hash }} 65 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 66 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::MariaDB 67 | - name: prove 68 | env: 69 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 70 | LIVE_MYSQL_REQUIRED: true 71 | SQITCH_TEST_MYSQL_URI: "db:mysql://root@127.0.0.1:${{ job.services.mysql.ports[3306] }}/information_schema" 72 | run: prove -lvr t/mysql.t 73 | -------------------------------------------------------------------------------- /.github/workflows/oracle.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's Oracle engine on recent supported versions of 2 | # Oracle. It runs for pushes and pull requests on the `main`, `develop`, 3 | # `**oracle**`, and `**engine**` branches. 4 | name: 🔮 Oracle 5 | on: 6 | push: 7 | branches: [main, develop, "**engine**", "**oracle**" ] 8 | pull_request: 9 | branches: [main, develop, "**engine**", "**oracle**" ] 10 | jobs: 11 | Oracle: 12 | strategy: 13 | matrix: 14 | include: 15 | # In 11g, APP_USER "sqitchtest" is created in XE, but in more recent 16 | # versions it is created in the XEPDB1 pluggable database, which we 17 | # cannot connect to using a URI. So we use an existing user in those 18 | # versions. Uncomment code in skip_unless in t/oracle.t to find other 19 | # user schemas that will work. 20 | # * Image Source: https://github.com/gvenzl/oci-oracle-xe/ 21 | # * Image Issue: https://github.com/gvenzl/oci-oracle-xe/issues/46 22 | # * DBD::Oracle Issue: https://github.com/perl5-dbi/DBD-Oracle/issues/131 23 | # https://registry.hub.docker.com/v2/repositories/gvenzl/oracle-xe/tags\?page_size\=10000 | jq '.results[].name' 24 | - { version: 21c, tag: 21-slim, service: XE, altUser: dbsnmp } 25 | - { version: 18c, tag: 18-slim, service: XE, altUser: gsmuser } 26 | - { version: 11g, tag: 11-slim, service: XE, altuser: sqitchtest } 27 | name: "🔮 Oracle ${{ matrix.version }}" 28 | runs-on: ubuntu-latest 29 | services: 30 | oracle: 31 | image: gvenzl/oracle-xe:${{ matrix.tag }} 32 | ports: [ 1521 ] 33 | env: 34 | ORACLE_PASSWORD: oracle 35 | APP_USER: sqitchtest 36 | APP_USER_PASSWORD: sqitchtest 37 | options: >- 38 | --health-cmd healthcheck.sh 39 | --health-interval 20s 40 | --health-timeout 10s 41 | --health-retries 10 42 | steps: 43 | - uses: actions/checkout@v4 44 | - name: Setup Clients 45 | run: .github/ubuntu/oracle.sh 46 | - name: Setup Perl 47 | id: perl 48 | uses: shogo82148/actions-setup-perl@v1 49 | with: { perl-version: latest } 50 | - name: Cache CPAN Modules 51 | uses: actions/cache@v4 52 | with: 53 | path: local 54 | key: perl-${{ steps.perl.outputs.perl-hash }} 55 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 56 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::Oracle 57 | - name: prove 58 | env: 59 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 60 | LIVE_ORACLE_REQUIRED: true 61 | SQITCH_TEST_ALT_ORACLE_REGISTRY: "${{ matrix.altUser }}" 62 | SQITCH_TEST_ORACLE_URI: db:oracle://system:oracle@127.0.0.1:${{ job.services.oracle.ports[1521] }}/${{ matrix.service }} 63 | run: prove -lvr t/oracle.t 64 | -------------------------------------------------------------------------------- /.github/workflows/os.yml: -------------------------------------------------------------------------------- 1 | # This workflow is intended to be the default to check for compatibility across 2 | # operating systems without much overhead. It uses the latest version of Perl on 3 | # the latest versions of Ubuntu, macOS, and Windows. Think of it as a quick 4 | # check for working branches. 5 | name: 💿 OS 6 | on: 7 | push: 8 | branches: ['*'] 9 | pull_request: 10 | schedule: 11 | - cron: '0 14 2 * *' # Monthly at 2pm on the second 12 | jobs: 13 | OS: 14 | strategy: 15 | matrix: 16 | include: 17 | - { icon: 🐧, on: ubuntu, name: Linux } 18 | - { icon: 🍎, on: macos, name: macOS } 19 | - { icon: 🪟, on: windows, name: Windows } 20 | name: ${{ matrix.icon }} ${{ matrix.name }} 21 | runs-on: ${{ matrix.on }}-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Setup Perl 25 | id: perl 26 | uses: shogo82148/actions-setup-perl@v1 27 | with: { perl-version: latest } 28 | - run: perl -V 29 | - if: runner.os == 'Linux' 30 | name: Install Apt Packages 31 | run: sudo apt-get install -qq aspell-en language-pack-fr language-pack-en language-pack-de language-pack-it 32 | - name: Cache CPAN Modules 33 | uses: actions/cache@v4 34 | with: 35 | path: local 36 | key: perl-${{ steps.perl.outputs.perl-hash }} 37 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends ExtUtils::MakeMaker List::MoreUtils::XS 38 | - if: runner.os == 'Windows' 39 | run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends Encode Win32::Console::ANSI Win32API::Net Win32::Locale Win32::ShellQuote DateTime::TimeZone::Local::Win32 40 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 41 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends Test::Spelling Test::Pod Test::Pod::Coverage 42 | - name: prove 43 | env: { PERL5LIB: "${{ github.workspace }}/local/lib/perl5" } 44 | run: prove -lrj4 45 | -------------------------------------------------------------------------------- /.github/workflows/perl.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's basic functionality (no database testing) on all 2 | # supported versions of Perl on Ubuntu, macOS, and Windows. It runs for pushes 3 | # and pull requests on the main and develop branches. 4 | name: 🧅 Perl 5 | on: 6 | push: 7 | branches: [main, develop, "**perl**"] 8 | pull_request: 9 | branches: [main, develop, "**perl**"] 10 | jobs: 11 | Perl: 12 | strategy: 13 | matrix: 14 | os: [[🐧, ubuntu], [🍎, macos], [🪟, windows]] 15 | perl: [ '5.40', '5.38', '5.36', '5.34', '5.32', '5.30', '5.28', '5.26', '5.24', '5.22', '5.20', '5.18', '5.16', '5.14', '5.12' ] 16 | exclude: 17 | - { os: [🪟, windows], perl: '5.12' } # https://github.com/shogo82148/actions-setup-perl/issues/876 18 | - { os: [🪟, windows], perl: '5.14' } # https://github.com/shogo82148/actions-setup-perl/issues/881 19 | name: 🧅 Perl ${{ matrix.perl }} on ${{ matrix.os[0] }} ${{ matrix.os[1] }} 20 | runs-on: ${{ matrix.os[1] }}-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Setup Perl 24 | id: perl 25 | uses: shogo82148/actions-setup-perl@v1 26 | with: { perl-version: "${{ matrix.perl }}" } 27 | - run: perl -V 28 | - if: runner.os == 'Linux' 29 | name: Install Apt Packages 30 | run: sudo apt-get install -qq language-pack-fr language-pack-en language-pack-de language-pack-it 31 | - name: Cache CPAN Modules 32 | uses: actions/cache@v4 33 | with: 34 | path: local 35 | key: perl-${{ steps.perl.outputs.perl-hash }} 36 | - if: runner.os == 'Windows' 37 | run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends Encode Win32::Console::ANSI Win32API::Net Win32::Locale Win32::ShellQuote DateTime::TimeZone::Local::Win32 38 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 39 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends Test::Spelling Test::Pod Test::Pod::Coverage 40 | - name: prove 41 | env: { PERL5LIB: "${{ github.workspace }}/local/lib/perl5" } 42 | run: prove -lrj4 43 | -------------------------------------------------------------------------------- /.github/workflows/pg.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's PostgreSQL engine on all supported versions of 2 | # Postgres. It runs for pushes and pull requests on the `main`, `develop`, 3 | # `**postgres**`, `**yugabyte**`, and `**engine**` branches. 4 | name: 🐘 Postgres 5 | on: 6 | push: 7 | branches: [main, develop, "**engine**", "**postgres**", "**yugabyte**" ] 8 | pull_request: 9 | branches: [main, develop, "**engine**", "**postgres**", "**yugabyte**" ] 10 | jobs: 11 | Postgres: 12 | strategy: 13 | matrix: 14 | pg: [17, 16, 15, 14, 13, 12, 11, 10, 9.6, 9.5, 9.4, 9.3, 9.2, 9.1, '9.0', 8.4] 15 | name: 🐘 Postgres ${{ matrix.pg }} 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Setup Perl 20 | id: perl 21 | uses: shogo82148/actions-setup-perl@v1 22 | with: { perl-version: latest } 23 | - name: Cache CPAN Modules 24 | uses: actions/cache@v4 25 | with: 26 | path: local 27 | key: perl-${{ steps.perl.outputs.perl-hash }} 28 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 29 | # DBD::Pg always build against the Debian packaged client, alas, so go 30 | # ahead and let it be cached. If can figure out how to install the 31 | # version-specific client (https://github.com/bucardo/dbdpg/issues/84), 32 | # use cpm install --global to install DBD::Pg for a version-specific 33 | # build each time. 34 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::Pg 35 | - name: Install Postgres 36 | env: { PERL5LIB: "${{ github.workspace }}/local/lib/perl5" } 37 | run: .github/ubuntu/pg.sh ${{ matrix.pg }} 38 | - name: prove 39 | env: 40 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 41 | LIVE_PG_REQUIRED: true 42 | SQITCH_TEST_PG_URI: db:pg://postgres@/postgres 43 | run: prove -lvr t/pg.t 44 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Release 2 | on: 3 | push: 4 | tags: [v*] 5 | jobs: 6 | release: 7 | name: 🚀 Release 8 | runs-on: ubuntu-latest 9 | env: 10 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 11 | steps: 12 | - name: Check out the repo 13 | uses: actions/checkout@v4 14 | - name: Setup Perl 15 | id: perl 16 | uses: shogo82148/actions-setup-perl@v1 17 | with: { perl-version: latest } 18 | - name: Cache CPAN Modules 19 | uses: actions/cache@v4 20 | with: 21 | path: local 22 | key: perl-${{ steps.perl.outputs.perl-hash }} 23 | - name: Install Prereqs 24 | run: | 25 | sudo apt-get update -qq 26 | sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq libicu-dev gettext aspell-en software-properties-common 27 | - name: Install Dist::Zilla 28 | run: cpm install --verbose --show-build-log-on-failure --no-test Dist::Zilla 29 | - name: Install Build Dependencies 30 | env: { PERL5LIB: "${{ github.workspace }}/local/lib/perl5" } 31 | run: local/bin/dzil authordeps | xargs cpm install --verbose --show-build-log-on-failure --no-test 32 | - name: Prepare PAUSE 33 | env: 34 | CPAN_USERNAME: ${{ secrets.CPAN_USERNAME }} 35 | CPAN_PASSWORD: ${{ secrets.CPAN_PASSWORD }} 36 | run: | 37 | echo "user $CPAN_USERNAME" > ~/.pause 38 | echo "password $CPAN_PASSWORD" >> ~/.pause 39 | - name: Set Local Git User and Email 40 | run: | 41 | git config --global user.name "sqitch-github-actions[bot]" 42 | git config --global user.name "sqitch-github-actions[bot]@users.noreply.github.com" 43 | - name: Build and Release on CPAN 44 | id: cpan 45 | env: 46 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 47 | DZIL_CONFIRMRELEASE_DEFAULT: "yes" 48 | run: | 49 | local/bin/dzil release 50 | echo "tarball=$( ls App-Sqitch-*.tar.gz )" >> $GITHUB_OUTPUT 51 | - name: Generate Release Changes 52 | run: xt/gen_release_changes 53 | - name: Create GitHub Release 54 | id: release 55 | uses: actions/create-release@v1 56 | with: 57 | tag_name: ${{ github.ref }} 58 | release_name: Release ${{ github.ref }} 59 | body_path: latest_changes.md 60 | - name: Upload Release Asset 61 | uses: actions/upload-release-asset@v1 62 | with: 63 | upload_url: ${{ steps.release.outputs.upload_url }} 64 | asset_path: ./${{ steps.cpan.outputs.tarball }} 65 | asset_name: ${{ steps.cpan.outputs.tarball }} 66 | asset_content_type: application/gzip 67 | -------------------------------------------------------------------------------- /.github/workflows/snowflake.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's Snowflake engine. It runs for pushes and pull 2 | # requests on the `main`, `develop`, `**snowflake**`, and `**engine**` branches. 3 | name: ❄️ Snowflake 4 | on: 5 | push: 6 | branches: [main, develop, "**engine**", "**snowflake**" ] 7 | pull_request: 8 | branches: [main, develop, "**engine**", "**snowflake**" ] 9 | jobs: 10 | Snowflake: 11 | name: ❄️ Snowflake 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Setup Clients 16 | env: 17 | SNOWFLAKE_KEY_PASSWORD: ${{ secrets.SNOWFLAKE_KEY_PASSWORD }} 18 | SNOWFLAKE_KEY_FILE: ${{ secrets.SNOWFLAKE_KEY_FILE }} 19 | run: .github/ubuntu/snowflake.sh 20 | - name: Setup Perl 21 | id: perl 22 | uses: shogo82148/actions-setup-perl@v1 23 | with: { perl-version: latest } 24 | - name: Cache CPAN Modules 25 | uses: actions/cache@v4 26 | with: 27 | path: local 28 | key: perl-${{ steps.perl.outputs.perl-hash }} 29 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 30 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::ODBC 31 | - name: prove 32 | env: 33 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 34 | LIVE_SNOWFLAKE_REQUIRED: true 35 | SNOWSQL_PRIVATE_KEY_PASSPHRASE: ${{ secrets.SNOWFLAKE_KEY_PASSWORD }} 36 | SQITCH_TEST_SNOWFLAKE_URI: db:snowflake://${{ secrets.SNOWFLAKE_USERNAME }}@sra81677.us-east-1/sqitchtest?DSN=sqitch;warehouse=compute_wh 37 | run: prove -lvr t/snowflake.t 38 | -------------------------------------------------------------------------------- /.github/workflows/sqlite.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's SQLite engine on all supported versions of 2 | # Postgres. It runs for pushes and pull requests on the `main`, `develop`, 3 | # `**sqlite**`, and `**engine**` branches. 4 | name: 💡 SQLite 5 | on: 6 | push: 7 | branches: [main, develop, "**engine**", "**sqlite**" ] 8 | pull_request: 9 | branches: [main, develop, "**engine**", "**sqlite**" ] 10 | jobs: 11 | SQLite: 12 | strategy: 13 | matrix: 14 | # https://sqlite.org/chronology.html 15 | sqlite: [3.47.2, 3.46.1, 3.45.3, 3.44.2, 3.43.2, 3.42.0, 3.41.2, 3.40.1, 3.39.4, 3.38.5, 3.37.2, 3.36.0, 3.35.5, 3.34.1, 3.33.0, 3.32.3, 3.31.1, 3.30.1, 3.29.0, 3.28.0, 3.27.2, 3.26.0, 3.25.3, 3.24.0, 3.23.1, 3.22.0, 3.21.0, 3.20.1, 3.19.3, 3.18.0, 3.17.0, 3.16.2, 3.15.2, 3.14.2, 3.13.0, 3.12.2, 3.11.1, 3.10.2, 3.9.2, 3.8.11.1, 3.8.6] 16 | name: 💡 SQLite ${{ matrix.sqlite }} 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Setup Perl 21 | id: perl 22 | uses: shogo82148/actions-setup-perl@v1 23 | with: { perl-version: latest } 24 | - name: Cache CPAN Modules 25 | uses: actions/cache@v4 26 | with: 27 | path: local 28 | key: perl-${{ steps.perl.outputs.perl-hash }} 29 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 30 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBI 31 | - name: Install SQLite 32 | env: { PERL5LIB: "${{ github.workspace }}/local/lib/perl5" } 33 | run: .github/ubuntu/sqlite.sh ${{ matrix.sqlite }} 34 | - name: prove 35 | env: 36 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 37 | LIVE_SQLITE_REQUIRED: true 38 | run: prove -lvr t/sqlite.t 39 | -------------------------------------------------------------------------------- /.github/workflows/vertica.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's Vertica engine on all supported versions of 2 | # Vertica. It runs for pushes and pull requests on the `main`, `develop`, 3 | # `**vertica**`, and `**engine**` branches. 4 | name: 🔺 Vertica 5 | on: 6 | push: 7 | branches: [main, develop, "**engine**", "**vertica**" ] 8 | pull_request: 9 | branches: [main, develop, "**engine**", "**vertica**" ] 10 | jobs: 11 | Vertica: 12 | strategy: 13 | matrix: 14 | include: 15 | - { label: '24.1', version: 24.1.0-0, image: vertica/vertica-ce, db: VMart } 16 | - { label: '23.4', version: 23.4.0-0, image: vertica/vertica-ce, db: VMart } 17 | - { label: '12.0', version: 12.0.4-0, image: vertica/vertica-ce, db: VMart } 18 | - { label: '11.0', version: 11.1.1-0, image: vertica/vertica-ce, db: VMart } 19 | - { label: '10.1', version: 10.1.1-0, image: vertica/vertica-ce, db: VMart } 20 | - { label: '9.2', version: 9.2.1-0, image: cjonesy/docker-vertica, db: docker } 21 | - { label: '9.1', version: 9.1.1-0, image: cjonesy/docker-vertica, db: docker } 22 | - { label: '8.1', version: 8.1.1-0, image: cjonesy/docker-vertica, db: docker } 23 | - { label: '8.0', version: 8.0.0-0, image: cjonesy/docker-vertica, db: docker } 24 | - { label: '7.2', version: 7.2.3-18, image: cjonesy/docker-vertica, db: docker } 25 | name: 🔺 Vertica ${{ matrix.label }} 26 | runs-on: ubuntu-latest 27 | services: 28 | vertica: 29 | image: ${{ matrix.image }}:${{ matrix.version }} 30 | ports: [ 5433 ] 31 | steps: 32 | - uses: actions/checkout@v4 33 | - name: Setup Clients 34 | run: .github/ubuntu/vertica.sh 35 | - name: Setup Perl 36 | id: perl 37 | uses: shogo82148/actions-setup-perl@v1 38 | with: { perl-version: latest } 39 | - name: Cache CPAN Modules 40 | uses: actions/cache@v4 41 | with: 42 | path: local 43 | key: perl-${{ steps.perl.outputs.perl-hash }} 44 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 45 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::ODBC 46 | - name: prove 47 | env: 48 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 49 | LIVE_VERTICA_REQUIRED: true 50 | SQITCH_TEST_VSQL_URI: db:vertica://dbadmin@localhost:${{ job.services.vertica.ports[5433] }}/${{ matrix.db }}?Driver=Vertica 51 | run: prove -lvr t/vertica.t 52 | -------------------------------------------------------------------------------- /.github/workflows/yugabyte.yml: -------------------------------------------------------------------------------- 1 | # This workflow tests Sqitch's PostgreSQL engine on all supported versions of 2 | # YugabyteDB. It runs for pushes and pull requests on the `main`, `develop`, 3 | # `**postgres**`, `**yugabyte**`, and `**engine**` branches. 4 | name: 💫 Yugabyte 5 | on: 6 | push: 7 | branches: [main, develop, "**engine**", "**postgres**", "**yugabyte**" ] 8 | pull_request: 9 | branches: [main, develop, "**engine**", "**postgres**", "**yugabyte**" ] 10 | jobs: 11 | Yugabyte: 12 | strategy: 13 | matrix: 14 | include: 15 | # curl https://registry.hub.docker.com/v2/repositories/yugabytedb/yugabyte/tags\?page_size\=10000 | jq '.results[].name' | sort 16 | - { version: '2024.2', tag: 2024.2.0.0-b145 } 17 | - { version: '2024.1', tag: 2024.1.3.1-b8 } 18 | - { version: '2.23', tag: 2.23.1.0-b220 } 19 | - { version: '2.21', tag: 2.21.1.0-b271 } 20 | - { version: '2.20', tag: 2.20.8.1-b2 } 21 | - { version: '2.19', tag: 2.19.0.0-b190 } 22 | - { version: '2.18', tag: 2.18.9.0-b17 } 23 | - { version: '2.17', tag: 2.17.3.0-b152 } 24 | - { version: '2.16', tag: 2.16.9.0-b67 } 25 | - { version: '2.15', tag: 2.15.3.2-b1 } 26 | - { version: '2.14', tag: 2.14.17.0-b6 } 27 | - { version: '2.13', tag: 2.13.2.0-b135 } 28 | - { version: '2.12', tag: 2.12.12.0-b12 } 29 | - { version: '2.11', tag: 2.11.2.0-b89 } 30 | - { version: '2.8', tag: 2.8.12.0-b5 } 31 | - { version: '2.6', tag: 2.6.20.0-b10 } 32 | name: 💫 Yugabyte ${{ matrix.version }} 33 | runs-on: ubuntu-latest 34 | steps: 35 | - name: Setup YugabyteDB cluster 36 | id: yugabyte 37 | # https://github.com/yugabyte/yugabyte-db-action/issues/5 38 | # uses: yugabyte/yugabyte-db-action@master 39 | uses: jameshartig/yugabyte-db-action@master 40 | with: 41 | yb_image_tag: "${{ matrix.tag }}" 42 | - uses: actions/checkout@v4 43 | - name: Setup Perl 44 | id: perl 45 | uses: shogo82148/actions-setup-perl@v1 46 | with: { perl-version: latest } 47 | - name: Cache CPAN Modules 48 | uses: actions/cache@v4 49 | with: 50 | path: local 51 | key: perl-${{ steps.perl.outputs.perl-hash }} 52 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile 53 | - run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::Pg 54 | - name: prove 55 | env: 56 | PERL5LIB: "${{ github.workspace }}/local/lib/perl5" 57 | LIVE_PG_REQUIRED: true 58 | SQITCH_TEST_PG_URI: db:pg://yugabyte@localhost:${{ steps.yugabyte.outputs.ysql_port }}/ 59 | run: prove -lvr t/pg.t 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # add files you don't want in git here 2 | /_build 3 | /blib 4 | -* 5 | /MANIFEST 6 | /MANIFEST.bak 7 | /*META.* 8 | /Build 9 | /Makefile* 10 | /pm_to_blib 11 | /App-Sqitch-* 12 | *.rpm 13 | /_rpmbuild 14 | /target 15 | .build/ 16 | .al 17 | /latest_changes.md 18 | /local/ 19 | /LocaleData/ 20 | /lib/LocaleData/ 21 | .vscode/ 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2025 David E. Wheeler, 2012-2021 iovation Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.SKIP: -------------------------------------------------------------------------------- 1 | # Avoid version control files. 2 | \bRCS\b 3 | \bCVS\b 4 | ,v$ 5 | \B\.git 6 | 7 | # Avoid Makemaker generated and utility files. 8 | \bMakefile$ 9 | \bblib 10 | \bMakeMaker-\d 11 | \bpm_to_blib$ 12 | \bblibdirs$ 13 | ^MANIFEST\.SKIP$ 14 | 15 | # Avoid Module::Build generated and utility files. 16 | \bBuild$ 17 | \b_build 18 | 19 | # Avoid temp and backup files. 20 | ~$ 21 | \.tmp$ 22 | \.old$ 23 | \.bak$ 24 | \#$ 25 | \b\.# 26 | \.swp$ 27 | \.swo$ 28 | 29 | # Avoid build files. 30 | ^App-Sqitch 31 | \b_rpmbuild 32 | ^rpm\.spec$ 33 | ^target 34 | ^arco 35 | ^po/ 36 | 37 | ^dist\.ini$ 38 | ^MYMETA\.yml$ 39 | ^MYMETA\.json$ 40 | ^latest_changes\.md$ 41 | 42 | # Development tools. 43 | ^xt/ 44 | ^local/ 45 | -------------------------------------------------------------------------------- /bin/sqitch: -------------------------------------------------------------------------------- 1 | #!perl -w -CAS 2 | 3 | # VERSION 4 | use locale; 5 | use App::Sqitch; 6 | exit App::Sqitch->go; 7 | -------------------------------------------------------------------------------- /dist.ini: -------------------------------------------------------------------------------- 1 | name = App-Sqitch 2 | license = MIT 3 | copyright_holder = "iovation Inc., David E. Wheeler" 4 | copyright_year = 2012-2025 5 | version = v1.5.3 6 | 7 | [GatherDir] 8 | exclude_filename = dist/cpanfile 9 | 10 | [PruneCruft] 11 | [ManifestSkip] 12 | [MetaYAML] 13 | [MetaJSON] 14 | [License] 15 | [Readme] 16 | [ExecDir] 17 | [ShareDir] 18 | [Manifest] 19 | [TestRelease] 20 | [ConfirmRelease] 21 | [UploadToCPAN] 22 | [RunExtraTests] 23 | [OurPkgVersion] 24 | 25 | [CPANFile] 26 | filename = dist/cpanfile 27 | 28 | [CopyFilesFromBuild] 29 | copy = dist/cpanfile 30 | 31 | [LocaleTextDomain] 32 | share_dir = lib 33 | 34 | [ModuleBuild] 35 | mb_class = Module::Build::Sqitch 36 | mb_version = 0.35 37 | 38 | [MetaNoIndex] 39 | directory = priv 40 | 41 | [MetaResources] 42 | repository.url = https://github.com/sqitchers/sqitch/ 43 | homepage = https://sqitch.org/ 44 | bugtracker.web = https://github.com/sqitchers/sqitch/issues/ 45 | 46 | [Git::Check] 47 | allow_dirty = cpanfile 48 | 49 | [AutoPrereqs] 50 | skip = ^Win32 51 | skip = ^DBD:: 52 | 53 | [Prereqs / BuildRecommends] 54 | Menlo::CLI::Compat = 0 55 | 56 | [Prereqs / RuntimeRequires] 57 | Devel::StackTrace = 1.30 58 | PerlIO::utf8_strict = 0 59 | Template::Tiny = 0.11 60 | DateTime = 1.04 61 | DateTime::TimeZone = 0 62 | Pod::Escapes = 1.04 63 | IO::Pager = 0.34 64 | Algorithm::Backoff::Exponential = 0.006 65 | 66 | [Prereqs / RuntimeRecommends] 67 | Pod::Simple = 1.41 68 | Class::XSAccessor = 1.18 69 | Type::Tiny::XS = 0.010 70 | Template = 0 71 | 72 | [Prereqs / DevelopRecommends] 73 | Test::Pod = 1.41 74 | Test::Pod::Coverage = 1.08 75 | Test::Spelling = 0 76 | Test::MockObject::Extends = 1.20180705 77 | DBD::SQLite = 1.37 78 | DBD::Pg = 2.0 79 | DBD::MariaDB = 1.0 80 | MySQL::Config = 0 81 | DBD::Firebird = 1.11 82 | DBD::ODBC = 1.59 83 | Time::HiRes = 0 84 | Time::Local = 0 85 | 86 | [Prereqs / DevelopSuggests] 87 | DBD::Oracle = 1.23 88 | 89 | [Prereqs / TestRequires] 90 | DBD::Mem = 0 91 | 92 | ;; Recommend author dependencies (dzil) in develop/recommends. 93 | [Prereqs::AuthorDeps] 94 | relation = recommends 95 | 96 | ;; Below are dependencies for different engines. 97 | [OptionalFeature / postgres] 98 | -description = Support for managing Postgres, Yugabyte, and Cockroch databases 99 | -prompt = 0 100 | DBD::Pg = 2.0 101 | 102 | [OptionalFeature / sqlite] 103 | -description = Support for managing SQLite databases 104 | -prompt = 0 105 | DBD::SQLite = 1.37 106 | 107 | [OptionalFeature / mysql] 108 | -description = Support for managing MySQL databases 109 | -prompt = 0 110 | DBD::MariaDB = 1.0 111 | MySQL::Config = 0 112 | 113 | [OptionalFeature / firebird] 114 | -description = Support for managing Firebird databases 115 | -prompt = 0 116 | DBD::Firebird = 1.11 117 | Time::HiRes = 0 118 | Time::Local = 0 119 | 120 | [OptionalFeature / oracle] 121 | -description = Support for managing Oracle databases 122 | -prompt = 0 123 | DBD::Oracle = 1.23 124 | 125 | [OptionalFeature / vertica] 126 | -description = Support for managing Vertica databases 127 | -prompt = 0 128 | DBD::ODBC = 1.59 129 | 130 | [OptionalFeature / exasol] 131 | -description = Support for managing Exasol databases 132 | -prompt = 0 133 | DBD::ODBC = 1.59 134 | 135 | [OptionalFeature / snowflake] 136 | -description = Support for managing Snowflake databases 137 | -prompt = 0 138 | DBD::ODBC = 1.59 139 | 140 | [OptionalFeature / odbc] 141 | -description = Include the ODBC driver. 142 | -prompt = 0 143 | DBD::ODBC = 1.59 144 | -------------------------------------------------------------------------------- /etc/templates/deploy/cockroach.tmpl: -------------------------------------------------------------------------------- 1 | -- Deploy [% project %]:[% change %] to [% engine %] 2 | [% FOREACH item IN requires -%] 3 | -- requires: [% item %] 4 | [% END -%] 5 | [% FOREACH item IN conflicts -%] 6 | -- conflicts: [% item %] 7 | [% END -%] 8 | 9 | -- XXX Add DDLs here. 10 | -------------------------------------------------------------------------------- /etc/templates/deploy/exasol.tmpl: -------------------------------------------------------------------------------- 1 | -- Deploy [% project %]:[% change %] to [% engine %] 2 | [% FOREACH item IN requires -%] 3 | -- requires: [% item %] 4 | [% END -%] 5 | [% FOREACH item IN conflicts -%] 6 | -- conflicts: [% item %] 7 | [% END -%] 8 | 9 | -- XXX Add DDLs here. 10 | 11 | COMMIT; 12 | -------------------------------------------------------------------------------- /etc/templates/deploy/firebird.tmpl: -------------------------------------------------------------------------------- 1 | -- Deploy [% project %]:[% change %] to [% engine %] 2 | [% FOREACH item IN requires -%] 3 | -- requires: [% item %] 4 | [% END -%] 5 | [% FOREACH item IN conflicts -%] 6 | -- conflicts: [% item %] 7 | [% END -%] 8 | 9 | -- XXX Add DDLs here. 10 | 11 | COMMIT; 12 | -------------------------------------------------------------------------------- /etc/templates/deploy/mysql.tmpl: -------------------------------------------------------------------------------- 1 | -- Deploy [% project %]:[% change %] to [% engine %] 2 | [% FOREACH item IN requires -%] 3 | -- requires: [% item %] 4 | [% END -%] 5 | [% FOREACH item IN conflicts -%] 6 | -- conflicts: [% item %] 7 | [% END -%] 8 | 9 | BEGIN; 10 | 11 | -- XXX Add DDLs here. 12 | 13 | COMMIT; 14 | -------------------------------------------------------------------------------- /etc/templates/deploy/oracle.tmpl: -------------------------------------------------------------------------------- 1 | -- Deploy [% project %]:[% change %] to [% engine %] 2 | [% FOREACH item IN requires -%] 3 | -- requires: [% item %] 4 | [% END -%] 5 | [% FOREACH item IN conflicts -%] 6 | -- conflicts: [% item %] 7 | [% END -%] 8 | 9 | -- XXX Add DDLs here. 10 | -------------------------------------------------------------------------------- /etc/templates/deploy/pg.tmpl: -------------------------------------------------------------------------------- 1 | -- Deploy [% project %]:[% change %] to [% engine %] 2 | [% FOREACH item IN requires -%] 3 | -- requires: [% item %] 4 | [% END -%] 5 | [% FOREACH item IN conflicts -%] 6 | -- conflicts: [% item %] 7 | [% END -%] 8 | 9 | BEGIN; 10 | 11 | -- XXX Add DDLs here. 12 | 13 | COMMIT; 14 | -------------------------------------------------------------------------------- /etc/templates/deploy/snowflake.tmpl: -------------------------------------------------------------------------------- 1 | -- Deploy [% project %]:[% change %] to [% engine %] 2 | [% FOREACH item IN requires -%] 3 | -- requires: [% item %] 4 | [% END -%] 5 | [% FOREACH item IN conflicts -%] 6 | -- conflicts: [% item %] 7 | [% END -%] 8 | 9 | USE WAREHOUSE &warehouse; 10 | 11 | -- XXX Add DDLs here. 12 | -------------------------------------------------------------------------------- /etc/templates/deploy/sqlite.tmpl: -------------------------------------------------------------------------------- 1 | -- Deploy [% project %]:[% change %] to [% engine %] 2 | [% FOREACH item IN requires -%] 3 | -- requires: [% item %] 4 | [% END -%] 5 | [% FOREACH item IN conflicts -%] 6 | -- conflicts: [% item %] 7 | [% END -%] 8 | 9 | BEGIN; 10 | 11 | -- XXX Add DDLs here. 12 | 13 | COMMIT; 14 | -------------------------------------------------------------------------------- /etc/templates/deploy/vertica.tmpl: -------------------------------------------------------------------------------- 1 | -- Deploy [% project %]:[% change %] to [% engine %] 2 | [% FOREACH item IN requires -%] 3 | -- requires: [% item %] 4 | [% END -%] 5 | [% FOREACH item IN conflicts -%] 6 | -- conflicts: [% item %] 7 | [% END -%] 8 | 9 | -- XXX Add DDLs here. 10 | -------------------------------------------------------------------------------- /etc/templates/revert/cockroach.tmpl: -------------------------------------------------------------------------------- 1 | -- Revert [% project %]:[% change %] from [% engine %] 2 | 3 | -- XXX Add DDLs here. 4 | -------------------------------------------------------------------------------- /etc/templates/revert/exasol.tmpl: -------------------------------------------------------------------------------- 1 | -- Revert [% project %]:[% change %] from [% engine %] 2 | 3 | -- XXX Add DDLs here. 4 | 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /etc/templates/revert/firebird.tmpl: -------------------------------------------------------------------------------- 1 | -- Revert [% project %]:[% change %] from [% engine %] 2 | 3 | -- XXX Add DDLs here. 4 | 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /etc/templates/revert/mysql.tmpl: -------------------------------------------------------------------------------- 1 | -- Revert [% project %]:[% change %] from [% engine %] 2 | 3 | BEGIN; 4 | 5 | -- XXX Add DDLs here. 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /etc/templates/revert/oracle.tmpl: -------------------------------------------------------------------------------- 1 | -- Revert [% project %]:[% change %] from [% engine %] 2 | 3 | -- XXX Add DDLs here. 4 | -------------------------------------------------------------------------------- /etc/templates/revert/pg.tmpl: -------------------------------------------------------------------------------- 1 | -- Revert [% project %]:[% change %] from [% engine %] 2 | 3 | BEGIN; 4 | 5 | -- XXX Add DDLs here. 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /etc/templates/revert/snowflake.tmpl: -------------------------------------------------------------------------------- 1 | -- Revert [% project %]:[% change %] from [% engine %] 2 | 3 | USE WAREHOUSE &warehouse; 4 | 5 | -- XXX Add DDLs here. 6 | -------------------------------------------------------------------------------- /etc/templates/revert/sqlite.tmpl: -------------------------------------------------------------------------------- 1 | -- Revert [% project %]:[% change %] from [% engine %] 2 | 3 | BEGIN; 4 | 5 | -- XXX Add DDLs here. 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /etc/templates/revert/vertica.tmpl: -------------------------------------------------------------------------------- 1 | -- Revert [% project %]:[% change %] from [% engine %] 2 | 3 | -- XXX Add DDLs here. 4 | -------------------------------------------------------------------------------- /etc/templates/verify/cockroach.tmpl: -------------------------------------------------------------------------------- 1 | -- Verify [% project %]:[% change %] on [% engine %] 2 | 3 | -- XXX Add verifications here. 4 | -------------------------------------------------------------------------------- /etc/templates/verify/exasol.tmpl: -------------------------------------------------------------------------------- 1 | -- Verify [% project %]:[% change %] on [% engine %] 2 | 3 | -- XXX Add verifications here. 4 | 5 | ROLLBACK; 6 | -------------------------------------------------------------------------------- /etc/templates/verify/firebird.tmpl: -------------------------------------------------------------------------------- 1 | -- Verify [% project %]:[% change %] on [% engine %] 2 | 3 | -- XXX Add verifications here. 4 | 5 | ROLLBACK; 6 | -------------------------------------------------------------------------------- /etc/templates/verify/mysql.tmpl: -------------------------------------------------------------------------------- 1 | -- Verify [% project %]:[% change %] on [% engine %] 2 | 3 | BEGIN; 4 | 5 | -- XXX Add verifications here. 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /etc/templates/verify/oracle.tmpl: -------------------------------------------------------------------------------- 1 | -- Verify [% project %]:[% change %] on [% engine %] 2 | 3 | -- XXX Add verifications here. 4 | -------------------------------------------------------------------------------- /etc/templates/verify/pg.tmpl: -------------------------------------------------------------------------------- 1 | -- Verify [% project %]:[% change %] on [% engine %] 2 | 3 | BEGIN; 4 | 5 | -- XXX Add verifications here. 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /etc/templates/verify/snowflake.tmpl: -------------------------------------------------------------------------------- 1 | -- Verify [% project %]:[% change %] on [% engine %] 2 | 3 | USE WAREHOUSE &warehouse; 4 | 5 | -- XXX Add verifications here. 6 | -------------------------------------------------------------------------------- /etc/templates/verify/sqlite.tmpl: -------------------------------------------------------------------------------- 1 | -- Verify [% project %]:[% change %] on [% engine %] 2 | 3 | BEGIN; 4 | 5 | -- XXX Add verifications here. 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /etc/templates/verify/vertica.tmpl: -------------------------------------------------------------------------------- 1 | -- Verify [% project %]:[% change %] on [% engine %] 2 | 3 | -- XXX Add verifications here. 4 | -------------------------------------------------------------------------------- /etc/tools/upgrade-registry-to-mysql-5.5.0.sql: -------------------------------------------------------------------------------- 1 | -- This script upgrades the Sqitch registry for MySQL 5.5.0 and higher. It 2 | -- sets up triggers in the registry to use it to emulate CHECK constraints. If 3 | -- you have an existing Sqitch registry that was upgraded from an earlier 4 | -- version of MySQL to 5.5.0 or higher, you'll need to run this script as a 5 | -- super user to update it, like so: 6 | 7 | -- mysql -u root sqitch --execute "source `sqitch --etc`/tools/upgrade-registry-to-mysql-5.5.0.sql' 8 | 9 | DELIMITER | 10 | CREATE TRIGGER ck_insert_dependency BEFORE INSERT ON dependencies 11 | FOR EACH ROW BEGIN 12 | IF (NEW.type = 'require' AND NEW.dependency_id IS NULL) 13 | OR (NEW.type = 'conflict' AND NEW.dependency_id IS NOT NULL) 14 | THEN 15 | SIGNAL SQLSTATE 'ERR0R' SET MESSAGE_TEXT = 'Type must be "require" with dependency_id set or "conflict" with dependency_id not set'; 16 | END IF; 17 | END; 18 | | 19 | 20 | CREATE TRIGGER ck_update_dependency BEFORE UPDATE ON dependencies 21 | FOR EACH ROW BEGIN 22 | IF (NEW.type = 'require' AND NEW.dependency_id IS NULL) 23 | OR (NEW.type = 'conflict' AND NEW.dependency_id IS NOT NULL) 24 | THEN 25 | SIGNAL SQLSTATE 'ERR0R' SET MESSAGE_TEXT = 'Type must be "require" with dependency_id set or "conflict" with dependency_id not set'; 26 | END IF; 27 | END; 28 | | 29 | 30 | DELIMITER ; 31 | -------------------------------------------------------------------------------- /etc/tools/upgrade-registry-to-mysql-5.6.4.sql: -------------------------------------------------------------------------------- 1 | -- This script upgrades the Sqitch registry for MySQL 5.6.4 and higher. Sqitch 2 | -- expects datetime columns to have a precision on 5.6.4 and higher. If you have 3 | -- an existing Sqitch registry that was upgraded from an earlier version of MySQL 4 | -- to 5.6.4 or higher, you'll need to run this script to update it, like so: 5 | 6 | -- mysql -u root sqitch --execute "source `sqitch --etc`/tools/upgrade-registry-to-mysql-5.6.4.sql' 7 | 8 | ALTER TABLE releases CHANGE installed_at installed_at DATETIME(6) NOT NULL; 9 | ALTER TABLE projects CHANGE created_at created_at DATETIME(6) NOT NULL; 10 | ALTER TABLE changes CHANGE committed_at committed_at DATETIME(6) NOT NULL, 11 | CHANGE planned_at planned_at DATETIME(6) NOT NULL; 12 | ALTER TABLE tags CHANGE committed_at committed_at DATETIME(6) NOT NULL, 13 | CHANGE planned_at planned_at DATETIME(6) NOT NULL; 14 | ALTER TABLE events CHANGE committed_at committed_at DATETIME(6) NOT NULL, 15 | CHANGE planned_at planned_at DATETIME(6) NOT NULL; 16 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Command/help.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Command::help; 2 | 3 | use 5.010; 4 | use strict; 5 | use warnings; 6 | use utf8; 7 | use Locale::TextDomain qw(App-Sqitch); 8 | use App::Sqitch::X qw(hurl); 9 | use Types::Standard qw(Bool); 10 | use Pod::Find; 11 | use Moo; 12 | extends 'App::Sqitch::Command'; 13 | 14 | # VERSION 15 | 16 | has guide => ( 17 | is => 'ro', 18 | isa => Bool, 19 | default => 0, 20 | ); 21 | 22 | sub options { 23 | # XXX Add --all at some point, to output a list of all possible commands. 24 | return qw( 25 | guide|g 26 | ); 27 | } 28 | 29 | sub execute { 30 | my ( $self, $command ) = @_; 31 | $self->find_and_show('sqitch' . ( 32 | $command ? ($command =~ /^changes|tutorial/ ? '' : '-') . $command 33 | : $self->guide ? 'guides' 34 | : 'commands' 35 | )); 36 | } 37 | 38 | sub find_and_show { 39 | my ( $self, $look_for ) = (shift, shift); 40 | 41 | my $pod = Pod::Find::pod_where({ 42 | '-inc' => 1, 43 | '-script' => 1 44 | }, $look_for ) or hurl { 45 | ident => 'help', 46 | message => __x('No manual entry for {command}', command => $look_for), 47 | exitval => 1, 48 | }; 49 | 50 | $self->_pod2usage( 51 | '-input' => $pod, 52 | '-verbose' => 2, 53 | '-exitval' => 0, 54 | @_, 55 | ); 56 | } 57 | 58 | 1; 59 | 60 | __END__ 61 | 62 | =head1 Name 63 | 64 | App::Sqitch::Command::help - Display help information about Sqitch 65 | 66 | =head1 Synopsis 67 | 68 | my $cmd = App::Sqitch::Command::help->new(%params); 69 | $cmd->execute; 70 | 71 | =head1 Description 72 | 73 | If you want to know how to use the C command, you probably want to be 74 | reading C. But if you really want to know how the C command 75 | works, read on. 76 | 77 | =head1 Interface 78 | 79 | =head2 Attributes 80 | 81 | =head3 C 82 | 83 | Boolean indicating whether to list the guides. 84 | 85 | =head2 Instance Methods 86 | 87 | =head3 C 88 | 89 | $help->execute($command); 90 | 91 | Executes the help command. If a command is passed, the help for that command will 92 | be shown. If it cannot be found, Sqitch will throw an error and exit. If no 93 | command is specified, the L will be shown. 94 | 95 | =head3 C 96 | 97 | $help->find_and_show($file, %options); 98 | 99 | Does the work of finding the pod file C<$file> and passing it on to 100 | L, along with any additional options for Pod::Usage's constructor. 101 | 102 | =head1 See Also 103 | 104 | =over 105 | 106 | =item L 107 | 108 | Documentation for the C command to the Sqitch command-line client. 109 | 110 | =item L 111 | 112 | The Sqitch command-line client. 113 | 114 | =back 115 | 116 | =head1 Author 117 | 118 | David E. Wheeler 119 | 120 | =head1 License 121 | 122 | Copyright (c) 2012-2025 David E. Wheeler, 2012-2021 iovation Inc. 123 | 124 | Permission is hereby granted, free of charge, to any person obtaining a copy 125 | of this software and associated documentation files (the "Software"), to deal 126 | in the Software without restriction, including without limitation the rights 127 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 128 | copies of the Software, and to permit persons to whom the Software is 129 | furnished to do so, subject to the following conditions: 130 | 131 | The above copyright notice and this permission notice shall be included in all 132 | copies or substantial portions of the Software. 133 | 134 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 135 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 136 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 137 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 138 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 139 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 140 | SOFTWARE. 141 | 142 | =cut 143 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Command/upgrade.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Command::upgrade; 2 | 3 | use 5.010; 4 | use strict; 5 | use warnings; 6 | use utf8; 7 | use Moo; 8 | use App::Sqitch::Types qw(URI Maybe Str Bool HashRef); 9 | use Locale::TextDomain qw(App-Sqitch); 10 | use App::Sqitch::X qw(hurl); 11 | use List::Util qw(first); 12 | use namespace::autoclean; 13 | extends 'App::Sqitch::Command'; 14 | with 'App::Sqitch::Role::ConnectingCommand'; 15 | 16 | # VERSION 17 | 18 | has target => ( 19 | is => 'ro', 20 | isa => Str, 21 | ); 22 | 23 | sub options { 24 | return qw( 25 | target|t=s 26 | ); 27 | } 28 | 29 | sub execute { 30 | my $self = shift; 31 | my ($targets) = $self->parse_args( 32 | target => $self->target, 33 | args => \@_, 34 | ); 35 | 36 | # Warn on multiple targets. 37 | my $target = shift @{ $targets }; 38 | $self->warn(__x( 39 | 'Too many targets specified; using {target}', 40 | target => $target->name, 41 | )) if @{ $targets }; 42 | 43 | my $engine = $target->engine; 44 | 45 | if ($engine->needs_upgrade) { 46 | $self->info(__x( 47 | 'Upgrading registry {registry} to version {version}', 48 | registry => $engine->registry_destination, 49 | version => $engine->registry_release, 50 | )); 51 | $engine->upgrade_registry; 52 | } else { 53 | $self->info(__x( 54 | 'Registry {registry} is up-to-date at version {version}', 55 | registry => $engine->registry_destination, 56 | version => $engine->registry_release, 57 | )); 58 | } 59 | 60 | return $self; 61 | } 62 | 63 | 1; 64 | 65 | __END__ 66 | 67 | =head1 Name 68 | 69 | App::Sqitch::Command::upgrade - Upgrade the Sqitch registry 70 | 71 | =head1 Synopsis 72 | 73 | my $cmd = App::Sqitch::Command::upgrade->new(%params); 74 | $cmd->execute; 75 | 76 | =head1 Description 77 | 78 | If you want to know how to use the C command, you probably want to be 79 | reading C. But if you really want to know how the C 80 | command works, read on. 81 | 82 | =head1 Interface 83 | 84 | =head2 Class Methods 85 | 86 | =head3 C 87 | 88 | my @opts = App::Sqitch::Command::upgrade->options; 89 | 90 | Returns a list of L option specifications for the command-line 91 | options for the C command. 92 | 93 | =head2 Attributes 94 | 95 | =head3 C 96 | 97 | The upgrade target. 98 | 99 | =head2 Instance Methods 100 | 101 | =head3 C 102 | 103 | $upgrade->execute; 104 | 105 | Executes the upgrade command. 106 | 107 | =head1 See Also 108 | 109 | =over 110 | 111 | =item L 112 | 113 | Documentation for the C command to the Sqitch command-line client. 114 | 115 | =item L 116 | 117 | The Sqitch command-line client. 118 | 119 | =back 120 | 121 | =head1 Author 122 | 123 | David E. Wheeler 124 | 125 | =head1 License 126 | 127 | Copyright (c) 2012-2025 David E. Wheeler, 2012-2021 iovation Inc. 128 | 129 | Permission is hereby granted, free of charge, to any person obtaining a copy 130 | of this software and associated documentation files (the "Software"), to deal 131 | in the Software without restriction, including without limitation the rights 132 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 133 | copies of the Software, and to permit persons to whom the Software is 134 | furnished to do so, subject to the following conditions: 135 | 136 | The above copyright notice and this permission notice shall be included in all 137 | copies or substantial portions of the Software. 138 | 139 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 140 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 141 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 142 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 143 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 144 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 145 | SOFTWARE. 146 | 147 | =cut 148 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/cockroach-1.0.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | 3 | CREATE TABLE :"registry".releases ( 4 | version REAL PRIMARY KEY, 5 | installed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 6 | installer_name TEXT NOT NULL, 7 | installer_email TEXT NOT NULL 8 | ); 9 | 10 | COMMENT ON TABLE :"registry".releases IS 'Sqitch registry releases.'; 11 | COMMENT ON COLUMN :"registry".releases.version IS 'Version of the Sqitch registry.'; 12 | COMMENT ON COLUMN :"registry".releases.installed_at IS 'Date the registry release was installed.'; 13 | COMMENT ON COLUMN :"registry".releases.installer_name IS 'Name of the user who installed the registry release.'; 14 | COMMENT ON COLUMN :"registry".releases.installer_email IS 'Email address of the user who installed the registry release.'; 15 | 16 | -- Add the script_hash column to the changes table. Copy change_id for now. 17 | ALTER TABLE :"registry".changes ADD COLUMN script_hash TEXT NULL UNIQUE; 18 | UPDATE :"registry".changes SET script_hash = change_id; 19 | COMMENT ON COLUMN :"registry".changes.script_hash IS 'Deploy script SHA-1 hash.'; 20 | 21 | -- Allow "merge" events. 22 | -- Stricly speaking the `IF EXISTS` should not be required here, but funkyness 23 | -- in Cockroach schema changes require it. 24 | ALTER TABLE :"registry".events DROP CONSTRAINT IF EXISTS events_event_check; 25 | ALTER TABLE :"registry".events ADD CONSTRAINT events_event_check 26 | CHECK (event IN ('deploy', 'revert', 'fail', 'merge')); 27 | 28 | COMMENT ON SCHEMA :"registry" IS 'Sqitch database deployment metadata v1.0.'; 29 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/cockroach-1.1.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | DROP INDEX :"registry".changes_script_hash_key CASCADE; 3 | ALTER TABLE :"registry".changes ADD UNIQUE (project, script_hash); 4 | COMMENT ON SCHEMA :"registry" IS 'Sqitch database deployment metadata v1.1.'; 5 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/exasol-1.0.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ®istry..releases ( 2 | version FLOAT PRIMARY KEY, 3 | installed_at TIMESTAMP WITH LOCAL TIME ZONE DEFAULT current_timestamp NOT NULL, 4 | installer_name VARCHAR2(512) NOT NULL, 5 | installer_email VARCHAR2(512) NOT NULL 6 | ); 7 | 8 | COMMENT ON TABLE ®istry..releases IS 'Sqitch registry releases.'; 9 | COMMENT ON COLUMN ®istry..releases.version IS 'Version of the Sqitch registry.'; 10 | COMMENT ON COLUMN ®istry..releases.installed_at IS 'Date the registry release was installed.'; 11 | COMMENT ON COLUMN ®istry..releases.installer_name IS 'Name of the user who installed the registry release.'; 12 | COMMENT ON COLUMN ®istry..releases.installer_email IS 'Email address of the user who installed the registry release.'; 13 | 14 | -- Add the script_hash column to the changes table. Copy change_id for now. 15 | ALTER TABLE ®istry..changes ADD script_hash CHAR(40) NULL; 16 | UPDATE ®istry..changes SET script_hash = change_id; 17 | COMMENT ON COLUMN ®istry..changes.script_hash IS 'Deploy script SHA-1 hash.'; 18 | 19 | COMMENT ON SCHEMA ®istry IS 'Sqitch database deployment metadata v1.0.'; 20 | 21 | COMMIT; 22 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/exasol-1.1.sql: -------------------------------------------------------------------------------- 1 | -- Nothing to do here.. Exasol doesn't support UNIQUE constraints, except in 2 | -- the form of PRIMARY KEY. 3 | COMMENT ON SCHEMA ®istry IS 'Sqitch database deployment metadata v1.1.'; 4 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/firebird-1.0.sql: -------------------------------------------------------------------------------- 1 | SET AUTOddl OFF; 2 | 3 | CREATE TABLE releases ( 4 | version FLOAT NOT NULL PRIMARY KEY, 5 | installed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, 6 | installer_name VARCHAR(255) NOT NULL, 7 | installer_email VARCHAR(255) NOT NULL 8 | ); 9 | 10 | COMMENT ON TABLE releases IS 'Sqitch registry releases.'; 11 | COMMENT ON COLUMN releases.version IS 'Version of the Sqitch registry.'; 12 | COMMENT ON COLUMN releases.installed_at IS 'Date the registry release was installed.'; 13 | COMMENT ON COLUMN releases.installer_name IS 'Name of the user who installed the registry release.'; 14 | COMMENT ON COLUMN releases.installer_email IS 'Email address of the user who installed the registry release.'; 15 | 16 | -- Add the script_hash column to the changes table. 17 | ALTER TABLE changes ADD script_hash VARCHAR(40) UNIQUE; 18 | COMMIT; 19 | UPDATE changes SET script_hash = change_id; 20 | COMMENT ON COLUMN changes.script_hash IS 'Deploy script SHA-1 hash.'; 21 | 22 | -- Allow "merge" events. 23 | SET TERM ^; 24 | EXECUTE BLOCK AS 25 | DECLARE trig VARCHAR(64); 26 | BEGIN 27 | SELECT TRIM(cc.rdb$constraint_name) 28 | FROM rdb$relation_constraints rc 29 | JOIN rdb$check_constraints cc ON rc.rdb$constraint_name = cc.rdb$constraint_name 30 | JOIN rdb$triggers trg ON cc.rdb$trigger_name = trg.rdb$trigger_name 31 | WHERE rc.rdb$relation_name = 'EVENTS' 32 | AND rc.rdb$constraint_type = 'CHECK' 33 | AND trg.rdb$trigger_type = 1 34 | INTO trig; 35 | EXECUTE STATEMENT 'ALTER TABLE EVENTS DROP CONSTRAINT ' || trig; 36 | END^ 37 | 38 | SET TERM ;^ 39 | COMMIT; 40 | 41 | ALTER TABLE events ADD CONSTRAINT check_event_type CHECK ( 42 | event IN ('deploy', 'revert', 'fail', 'merge') 43 | ); 44 | 45 | COMMIT; 46 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/firebird-1.1.sql: -------------------------------------------------------------------------------- 1 | SET AUTOddl OFF; 2 | 3 | SET TERM ^; 4 | EXECUTE BLOCK AS 5 | DECLARE uniq VARCHAR(64); 6 | BEGIN 7 | SELECT TRIM(rdb$constraint_name) 8 | FROM rdb$relation_constraints 9 | WHERE rdb$relation_name = 'CHANGES' 10 | AND rdb$constraint_type = 'UNIQUE' 11 | INTO uniq; 12 | EXECUTE STATEMENT 'ALTER TABLE CHANGES DROP CONSTRAINT ' || uniq; 13 | END^ 14 | 15 | EXECUTE BLOCK AS 16 | DECLARE trig VARCHAR(64); 17 | BEGIN 18 | SELECT TRIM(cc.rdb$constraint_name) 19 | FROM rdb$relation_constraints rc 20 | JOIN rdb$check_constraints cc ON rc.rdb$constraint_name = cc.rdb$constraint_name 21 | JOIN rdb$triggers trg ON cc.rdb$trigger_name = trg.rdb$trigger_name 22 | WHERE rc.rdb$relation_name = 'DEPENDENCIES' 23 | AND rc.rdb$constraint_type = 'CHECK' 24 | AND trg.rdb$trigger_type = 1 25 | INTO trig; 26 | EXECUTE STATEMENT 'ALTER TABLE DEPENDENCIES DROP CONSTRAINT ' || trig; 27 | END^ 28 | 29 | SET TERM ;^ 30 | COMMIT; 31 | 32 | -- Drop check_event_type; we give it a new name below. 33 | ALTER TABLE events DROP CONSTRAINT check_event_type; 34 | COMMIT; 35 | 36 | -- Create the new unique constraint. 37 | ALTER TABLE changes ADD UNIQUE (project, script_hash); 38 | 39 | -- Give the check constraints name consistent with other engines. 40 | ALTER TABLE dependencies ADD CONSTRAINT dependencies_check CHECK ( 41 | (type = 'require' AND dependency_id IS NOT NULL) 42 | OR (type = 'conflict' AND dependency_id IS NULL) 43 | ); 44 | 45 | ALTER TABLE events ADD CONSTRAINT events_event_check CHECK ( 46 | event IN ('deploy', 'revert', 'fail', 'merge') 47 | ); 48 | 49 | COMMIT; 50 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/mysql-1.0.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE releases ( 2 | version FLOAT PRIMARY KEY 3 | COMMENT 'Version of the Sqitch registry.', 4 | installed_at TIMESTAMP NOT NULL 5 | COMMENT 'Date the registry release was installed.', 6 | installer_name VARCHAR(255) NOT NULL 7 | COMMENT 'Name of the user who installed the registry release.', 8 | installer_email VARCHAR(255) NOT NULL 9 | COMMENT 'Email address of the user who installed the registry release.' 10 | ) ENGINE InnoDB, 11 | CHARACTER SET 'utf8', 12 | COMMENT 'Sqitch registry releases.' 13 | ; 14 | 15 | -- Add the script_hash column to the changes table. Copy change_id for now. 16 | ALTER TABLE changes ADD COLUMN script_hash VARCHAR(40) NULL UNIQUE AFTER change_id; 17 | UPDATE changes SET script_hash = change_id; 18 | 19 | -- Allow "merge" events. 20 | ALTER TABLE events CHANGE event event ENUM ('deploy', 'fail', 'merge', 'revert') NOT NULL; 21 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/mysql-1.1.sql: -------------------------------------------------------------------------------- 1 | DROP INDEX script_hash ON changes; 2 | ALTER TABLE changes ADD UNIQUE(project, script_hash); 3 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/oracle-1.0.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ®istry..releases ( 2 | version FLOAT PRIMARY KEY, 3 | installed_at TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL, 4 | installer_name VARCHAR2(512 CHAR) NOT NULL, 5 | installer_email VARCHAR2(512 CHAR) NOT NULL 6 | ); 7 | 8 | COMMENT ON TABLE ®istry..releases IS 'Sqitch registry releases.'; 9 | COMMENT ON COLUMN ®istry..releases.version IS 'Version of the Sqitch registry.'; 10 | COMMENT ON COLUMN ®istry..releases.installed_at IS 'Date the registry release was installed.'; 11 | COMMENT ON COLUMN ®istry..releases.installer_name IS 'Name of the user who installed the registry release.'; 12 | COMMENT ON COLUMN ®istry..releases.installer_email IS 'Email address of the user who installed the registry release.'; 13 | 14 | -- Add the script_hash column to the changes table. Copy change_id for now. 15 | ALTER TABLE ®istry..changes ADD script_hash CHAR(40) NULL UNIQUE; 16 | UPDATE ®istry..changes SET script_hash = change_id; 17 | COMMENT ON COLUMN ®istry..changes.script_hash IS 'Deploy script SHA-1 hash.'; 18 | 19 | DECLARE 20 | CURSOR c_event_constraints IS 21 | SELECT constraint_name 22 | FROM user_cons_columns 23 | WHERE table_name = 'EVENTS' AND column_name = 'EVENT'; 24 | rec_consname c_event_constraints%ROWTYPE; 25 | BEGIN 26 | OPEN c_event_constraints; 27 | LOOP 28 | FETCH c_event_constraints INTO rec_consname; 29 | IF c_event_constraints%NOTFOUND THEN EXIT; END IF; 30 | 31 | -- Drop the constraint. 32 | EXECUTE IMMEDIATE 'ALTER TABLE ®istry..events DROP CONSTRAINT ' 33 | || rec_consname.constraint_name; 34 | END LOOP; 35 | CLOSE c_event_constraints; 36 | 37 | -- Use EXECUTE IMMEDIATE because ALTER isn't allowed in PL/SQL. 38 | EXECUTE IMMEDIATE 'ALTER TABLE ®istry..events MODIFY event NOT NULL'; 39 | END; 40 | / 41 | 42 | ALTER TABLE ®istry..events ADD CONSTRAINT check_event_type CHECK ( 43 | event IN ('deploy', 'revert', 'fail', 'merge') 44 | ); 45 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/oracle-1.1.sql: -------------------------------------------------------------------------------- 1 | COLUMN cname for a30 new_value check_name; 2 | 3 | SELECT u.constraint_name AS cname 4 | FROM user_constraints u 5 | JOIN user_cons_columns c ON u.constraint_name = c.constraint_name 6 | WHERE u.table_name = 'CHANGES' 7 | AND u.constraint_type = 'U' 8 | AND c.column_name = 'SCRIPT_HASH'; 9 | 10 | ALTER TABLE ®istry..changes DROP CONSTRAINT &check_name; 11 | ALTER TABLE ®istry..changes ADD CONSTRAINT &check_name UNIQUE (project, script_hash); 12 | 13 | -- Rename the changes check constraint. 14 | ALTER TABLE ®istry..events RENAME CONSTRAINT check_event_type TO events_event_check; 15 | 16 | -- Rename the dependencies check constraint. 17 | SELECT constraint_name AS cname 18 | FROM user_cons_columns 19 | WHERE table_name = 'DEPENDENCIES' 20 | AND column_name = 'DEPENDENCY_ID' 21 | AND constraint_name IN ( 22 | SELECT constraint_name 23 | FROM user_cons_columns 24 | WHERE table_name = 'DEPENDENCIES' 25 | AND column_name = 'TYPE' 26 | ); 27 | 28 | ALTER TABLE ®istry..dependencies 29 | RENAME CONSTRAINT &check_name TO dependencies_check; 30 | 31 | 32 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/pg-1.0.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | SET client_min_messages = warning; 4 | 5 | CREATE TABLE :"registry".releases ( 6 | version REAL PRIMARY KEY, 7 | installed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 8 | installer_name TEXT NOT NULL, 9 | installer_email TEXT NOT NULL 10 | ):tableopts; 11 | 12 | COMMENT ON TABLE :"registry".releases IS 'Sqitch registry releases.'; 13 | COMMENT ON COLUMN :"registry".releases.version IS 'Version of the Sqitch registry.'; 14 | COMMENT ON COLUMN :"registry".releases.installed_at IS 'Date the registry release was installed.'; 15 | COMMENT ON COLUMN :"registry".releases.installer_name IS 'Name of the user who installed the registry release.'; 16 | COMMENT ON COLUMN :"registry".releases.installer_email IS 'Email address of the user who installed the registry release.'; 17 | 18 | -- Add the script_hash column to the changes table. Copy change_id for now. 19 | ALTER TABLE :"registry".changes ADD COLUMN script_hash TEXT NULL UNIQUE; 20 | UPDATE :"registry".changes SET script_hash = change_id; 21 | COMMENT ON COLUMN :"registry".changes.script_hash IS 'Deploy script SHA-1 hash.'; 22 | 23 | -- Allow "merge" events. 24 | ALTER TABLE :"registry".events DROP CONSTRAINT events_event_check; 25 | ALTER TABLE :"registry".events ADD CONSTRAINT events_event_check 26 | CHECK (event IN ('deploy', 'revert', 'fail', 'merge')); 27 | 28 | COMMENT ON SCHEMA :"registry" IS 'Sqitch database deployment metadata v1.0.'; 29 | 30 | COMMIT; 31 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/pg-1.1.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | SET client_min_messages = warning; 4 | ALTER TABLE :"registry".changes DROP CONSTRAINT changes_script_hash_key; 5 | ALTER TABLE :"registry".changes ADD UNIQUE (project, script_hash); 6 | COMMENT ON SCHEMA :"registry" IS 'Sqitch database deployment metadata v1.1.'; 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/snowflake-1.0.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE ®istry.releases ( 2 | version FLOAT PRIMARY KEY, 3 | installed_at TIMESTAMP_TZ NOT NULL DEFAULT current_timestamp, 4 | installer_name TEXT NOT NULL, 5 | installer_email TEXT NOT NULL 6 | ); 7 | 8 | COMMENT ON TABLE ®istry.releases IS 'Sqitch registry releases.'; 9 | COMMENT ON COLUMN ®istry.releases.version IS 'Version of the Sqitch registry.'; 10 | COMMENT ON COLUMN ®istry.releases.installed_at IS 'Date the registry release was installed.'; 11 | COMMENT ON COLUMN ®istry.releases.installer_name IS 'Name of the user who installed the registry release.'; 12 | COMMENT ON COLUMN ®istry.releases.installer_email IS 'Email address of the user who installed the registry release.'; 13 | 14 | -- Add the script_hash column to the changes table. Copy change_id for now. 15 | ALTER TABLE ®istry.changes ADD script_hash TEXT NULL; 16 | ALTER WAREHOUSE &warehouse RESUME IF SUSPENDED; 17 | USE WAREHOUSE &warehouse; 18 | UPDATE ®istry.changes SET script_hash = change_id; 19 | ALTER TABLE ®istry.changes ADD UNIQUE(script_hash); 20 | COMMENT ON COLUMN ®istry.changes.script_hash IS 'Deploy script SHA-1 hash.'; 21 | 22 | COMMENT ON SCHEMA ®istry IS 'Sqitch database deployment metadata v1.0.'; 23 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/snowflake-1.1.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE ®istry.changes DROP UNIQUE(script_hash); 2 | ALTER TABLE ®istry.changes ADD UNIQUE(project, script_hash); 3 | COMMENT ON SCHEMA ®istry IS 'Sqitch database deployment metadata v1.0.'; 4 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/sqlite-1.0.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | CREATE TABLE releases ( 4 | version FLOAT PRIMARY KEY, 5 | installed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 6 | installer_name TEXT NOT NULL, 7 | installer_email TEXT NOT NULL 8 | ); 9 | 10 | -- Create a new changes table with script_hash. 11 | CREATE TABLE new_changes ( 12 | change_id TEXT PRIMARY KEY, 13 | script_hash TEXT NULL UNIQUE, 14 | change TEXT NOT NULL, 15 | project TEXT NOT NULL REFERENCES projects(project) ON UPDATE CASCADE, 16 | note TEXT NOT NULL DEFAULT '', 17 | committed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 18 | committer_name TEXT NOT NULL, 19 | committer_email TEXT NOT NULL, 20 | planned_at DATETIME NOT NULL, 21 | planner_name TEXT NOT NULL, 22 | planner_email TEXT NOT NULL 23 | ); 24 | 25 | -- Copy all the data to the new table and move it into place. 26 | INSERT INTO new_changes 27 | SELECT change_id, change_id, change, project, note, 28 | committed_at, committer_name, committer_email, 29 | planned_at, planner_name, planner_email 30 | FROM changes; 31 | PRAGMA foreign_keys = OFF; 32 | DROP TABLE changes; 33 | ALTER TABLE new_changes RENAME TO changes; 34 | PRAGMA foreign_keys = ON; 35 | 36 | -- Create a new events table with support for "merge" events. 37 | CREATE TABLE new_events ( 38 | event TEXT NOT NULL CHECK (event IN ('deploy', 'revert', 'fail', 'merge')), 39 | change_id TEXT NOT NULL, 40 | change TEXT NOT NULL, 41 | project TEXT NOT NULL REFERENCES projects(project) ON UPDATE CASCADE, 42 | note TEXT NOT NULL DEFAULT '', 43 | requires TEXT NOT NULL DEFAULT '', 44 | conflicts TEXT NOT NULL DEFAULT '', 45 | tags TEXT NOT NULL DEFAULT '', 46 | committed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 47 | committer_name TEXT NOT NULL, 48 | committer_email TEXT NOT NULL, 49 | planned_at DATETIME NOT NULL, 50 | planner_name TEXT NOT NULL, 51 | planner_email TEXT NOT NULL, 52 | PRIMARY KEY (change_id, committed_at) 53 | ); 54 | 55 | INSERT INTO new_events 56 | SELECT * FROM events; 57 | PRAGMA foreign_keys = OFF; 58 | DROP TABLE events; 59 | ALTER TABLE new_events RENAME TO events; 60 | PRAGMA foreign_keys = ON; 61 | 62 | COMMIT; 63 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/sqlite-1.1.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Create a new changes table with updated unique constraint. 4 | CREATE TABLE new_changes ( 5 | change_id TEXT PRIMARY KEY, 6 | script_hash TEXT NULL, 7 | change TEXT NOT NULL, 8 | project TEXT NOT NULL REFERENCES projects(project) ON UPDATE CASCADE, 9 | note TEXT NOT NULL DEFAULT '', 10 | committed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 11 | committer_name TEXT NOT NULL, 12 | committer_email TEXT NOT NULL, 13 | planned_at DATETIME NOT NULL, 14 | planner_name TEXT NOT NULL, 15 | planner_email TEXT NOT NULL, 16 | UNIQUE(project, script_hash) 17 | ); 18 | 19 | -- Copy all the data to the new table and move it into place. 20 | INSERT INTO new_changes 21 | SELECT * FROM changes; 22 | PRAGMA foreign_keys = OFF; 23 | DROP TABLE changes; 24 | ALTER TABLE new_changes RENAME TO changes; 25 | PRAGMA foreign_keys = ON; 26 | 27 | COMMIT; 28 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/vertica-1.0.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE :"registry".releases ( 2 | version FLOAT PRIMARY KEY ENABLED, 3 | installed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 4 | installer_name VARCHAR(1024) NOT NULL, 5 | installer_email VARCHAR(1024) NOT NULL 6 | ); 7 | 8 | COMMENT ON TABLE :"registry".releases IS 'Sqitch registry releases.'; 9 | 10 | -- Add the script_hash column to the changes table. Copy change_id for now. 11 | ALTER TABLE :"registry".changes ADD COLUMN script_hash CHAR(40); 12 | UPDATE :"registry".changes SET script_hash = change_id; 13 | ALTER TABLE :"registry".changes ADD UNIQUE(script_hash) ENABLED; 14 | 15 | COMMENT ON SCHEMA :"registry" IS 'Sqitch database deployment metadata v1.0.'; 16 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/Upgrade/vertica-1.1.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE :"registry".changes DROP CONSTRAINT c_unique; 2 | ALTER TABLE :"registry".changes ADD UNIQUE(project, script_hash) ENABLED; 3 | COMMENT ON SCHEMA :"registry" IS 'Sqitch database deployment metadata v1.1.'; 4 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/cockroach.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Engine::cockroach; 2 | 3 | use 5.010; 4 | use Moo; 5 | use namespace::autoclean; 6 | 7 | extends 'App::Sqitch::Engine::pg'; 8 | 9 | # VERSION 10 | 11 | sub key { 'cockroach' } 12 | sub name { 'CockroachDB' } 13 | sub driver { 'DBD::Pg 2.0' } 14 | 15 | sub _ts2char_format { 16 | q{experimental_strftime(%s AT TIME ZONE 'UTC', 'year:%%Y:month:%%m:day:%%d:hour:%%H:minute:%%M:second:%%S:time_zone:UTC')}; 17 | } 18 | 19 | # Override to avoid locking the changes table, as Cockroach does not support 20 | # explicit table locks. 21 | sub begin_work { 22 | my $self = shift; 23 | $self->dbh->begin_work; 24 | return $self; 25 | } 26 | 27 | # Override to return true, as Cockroach does not support advisory locks. 28 | sub wait_lock { 29 | # Cockroach does not support advisory locks. 30 | # https://github.com/cockroachdb/cockroach/issues/13546 31 | return 1; 32 | } 33 | 34 | sub _no_table_error { 35 | $DBI::state && $DBI::state eq '42P01'; # undefined_table 36 | } 37 | 38 | sub _run_registry_file { 39 | my ($self, $file) = @_; 40 | my $schema = $self->registry; 41 | 42 | $self->_run( 43 | '--file' => $file, 44 | '--set' => "registry=$schema", 45 | ); 46 | 47 | $self->dbh->do('SET search_path = ?', undef, $schema); 48 | } 49 | 50 | 1; 51 | 52 | __END__ 53 | 54 | =head1 Name 55 | 56 | App::Sqitch::Engine::cockroach - Sqitch CockroachDB Engine 57 | 58 | =head1 Synopsis 59 | 60 | my $pg = App::Sqitch::Engine->load( engine => 'cockroach' ); 61 | 62 | =head1 Description 63 | 64 | App::Sqitch::Engine::cockroach provides the CockroachDB storage engine for Sqitch. It 65 | supports CockroachDB v21 and higher, and relies on the Postgres toolchain (C 66 | client, L database driver, etc.). 67 | 68 | =head1 Author 69 | 70 | David E. Wheeler 71 | 72 | =head1 License 73 | 74 | Copyright (c) 2012-2025 David E. Wheeler, 2012-2021 iovation Inc. 75 | 76 | Permission is hereby granted, free of charge, to any person obtaining a copy 77 | of this software and associated documentation files (the "Software"), to deal 78 | in the Software without restriction, including without limitation the rights 79 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 80 | copies of the Software, and to permit persons to whom the Software is 81 | furnished to do so, subject to the following conditions: 82 | 83 | The above copyright notice and this permission notice shall be included in all 84 | copies or substantial portions of the Software. 85 | 86 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 87 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 88 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 89 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 90 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 91 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 92 | SOFTWARE. 93 | 94 | =cut 95 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/sqlite.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | CREATE TABLE releases ( 4 | version FLOAT PRIMARY KEY, 5 | installed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 6 | installer_name TEXT NOT NULL, 7 | installer_email TEXT NOT NULL 8 | ); 9 | 10 | CREATE TABLE projects ( 11 | project TEXT PRIMARY KEY, 12 | uri TEXT NULL UNIQUE, 13 | created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 14 | creator_name TEXT NOT NULL, 15 | creator_email TEXT NOT NULL 16 | ); 17 | 18 | CREATE TABLE changes ( 19 | change_id TEXT PRIMARY KEY, 20 | script_hash TEXT NULL, 21 | change TEXT NOT NULL, 22 | project TEXT NOT NULL REFERENCES projects(project) ON UPDATE CASCADE, 23 | note TEXT NOT NULL DEFAULT '', 24 | committed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 25 | committer_name TEXT NOT NULL, 26 | committer_email TEXT NOT NULL, 27 | planned_at DATETIME NOT NULL, 28 | planner_name TEXT NOT NULL, 29 | planner_email TEXT NOT NULL, 30 | UNIQUE(project, script_hash) 31 | ); 32 | 33 | CREATE TABLE tags ( 34 | tag_id TEXT PRIMARY KEY, 35 | tag TEXT NOT NULL, 36 | project TEXT NOT NULL REFERENCES projects(project) ON UPDATE CASCADE, 37 | change_id TEXT NOT NULL REFERENCES changes(change_id) ON UPDATE CASCADE, 38 | note TEXT NOT NULL DEFAULT '', 39 | committed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 40 | committer_name TEXT NOT NULL, 41 | committer_email TEXT NOT NULL, 42 | planned_at DATETIME NOT NULL, 43 | planner_name TEXT NOT NULL, 44 | planner_email TEXT NOT NULL, 45 | UNIQUE(project, tag) 46 | ); 47 | 48 | CREATE TABLE dependencies ( 49 | change_id TEXT NOT NULL REFERENCES changes(change_id) ON UPDATE CASCADE ON DELETE CASCADE, 50 | type TEXT NOT NULL, 51 | dependency TEXT NOT NULL, 52 | dependency_id TEXT NULL REFERENCES changes(change_id) ON UPDATE CASCADE 53 | CONSTRAINT dependencies_check CHECK ( 54 | (type = 'require' AND dependency_id IS NOT NULL) 55 | OR (type = 'conflict' AND dependency_id IS NULL) 56 | ), 57 | PRIMARY KEY (change_id, dependency) 58 | ); 59 | 60 | CREATE TABLE events ( 61 | event TEXT NOT NULL CONSTRAINT events_event_check CHECK ( 62 | event IN ('deploy', 'revert', 'fail', 'merge') 63 | ), 64 | change_id TEXT NOT NULL, 65 | change TEXT NOT NULL, 66 | project TEXT NOT NULL REFERENCES projects(project) ON UPDATE CASCADE, 67 | note TEXT NOT NULL DEFAULT '', 68 | requires TEXT NOT NULL DEFAULT '', 69 | conflicts TEXT NOT NULL DEFAULT '', 70 | tags TEXT NOT NULL DEFAULT '', 71 | committed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 72 | committer_name TEXT NOT NULL, 73 | committer_email TEXT NOT NULL, 74 | planned_at DATETIME NOT NULL, 75 | planner_name TEXT NOT NULL, 76 | planner_email TEXT NOT NULL, 77 | PRIMARY KEY (change_id, committed_at) 78 | ); 79 | 80 | COMMIT; 81 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Engine/vertica.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA :"registry"; 2 | 3 | COMMENT ON SCHEMA :"registry" IS 'Sqitch database deployment metadata v1.1.'; 4 | 5 | CREATE TABLE :"registry".releases ( 6 | version FLOAT PRIMARY KEY ENABLED, 7 | installed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 8 | installer_name VARCHAR(1024) NOT NULL, 9 | installer_email VARCHAR(1024) NOT NULL 10 | ); 11 | 12 | COMMENT ON TABLE :"registry".releases IS 'Sqitch registry releases.'; 13 | 14 | CREATE TABLE :"registry".projects ( 15 | project VARCHAR(1024) PRIMARY KEY ENABLED ENCODING AUTO, 16 | uri VARCHAR(1024) NULL UNIQUE ENABLED, 17 | created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 18 | creator_name VARCHAR(1024) NOT NULL, 19 | creator_email VARCHAR(1024) NOT NULL 20 | ); 21 | 22 | COMMENT ON TABLE :"registry".projects IS 'Sqitch projects deployed to this database.'; 23 | 24 | CREATE TABLE :"registry".changes ( 25 | change_id CHAR(40) PRIMARY KEY ENABLED ENCODING AUTO, 26 | script_hash CHAR(40) NULL UNIQUE ENABLED, 27 | change VARCHAR(1024) NOT NULL, 28 | project VARCHAR(1024) NOT NULL REFERENCES :"registry".projects(project), 29 | note VARCHAR(65000) NOT NULL DEFAULT '', 30 | committed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 31 | committer_name VARCHAR(1024) NOT NULL, 32 | committer_email VARCHAR(1024) NOT NULL, 33 | planned_at TIMESTAMPTZ NOT NULL, 34 | planner_name VARCHAR(1024) NOT NULL, 35 | planner_email VARCHAR(1024) NOT NULL 36 | ); 37 | 38 | COMMENT ON TABLE :"registry".changes IS 'Tracks the changes currently deployed to the database.'; 39 | 40 | CREATE TABLE :"registry".tags ( 41 | tag_id CHAR(40) PRIMARY KEY ENABLED ENCODING AUTO, 42 | tag VARCHAR(1024) NOT NULL, 43 | project VARCHAR(1024) NOT NULL REFERENCES :"registry".projects(project), 44 | change_id CHAR(40) NOT NULL REFERENCES :"registry".changes(change_id), 45 | note VARCHAR(65000) NOT NULL DEFAULT '', 46 | committed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 47 | committer_name VARCHAR(1024) NOT NULL, 48 | committer_email VARCHAR(1024) NOT NULL, 49 | planned_at TIMESTAMPTZ NOT NULL, 50 | planner_name VARCHAR(1024) NOT NULL, 51 | planner_email VARCHAR(1024) NOT NULL, 52 | UNIQUE(project, tag) ENABLED 53 | ); 54 | 55 | COMMENT ON TABLE :"registry".tags IS 'Tracks the tags currently applied to the database.'; 56 | 57 | CREATE TABLE :"registry".dependencies ( 58 | change_id CHAR(40) NOT NULL REFERENCES :"registry".changes(change_id), 59 | type VARCHAR(8) NOT NULL ENCODING AUTO, 60 | dependency VARCHAR(2048) NOT NULL, 61 | dependency_id CHAR(40) NULL REFERENCES :"registry".changes(change_id), 62 | PRIMARY KEY (change_id, dependency) ENABLED 63 | ); 64 | 65 | COMMENT ON TABLE :"registry".dependencies IS 'Tracks the currently satisfied dependencies.'; 66 | 67 | CREATE TABLE :"registry".events ( 68 | event VARCHAR(6) NOT NULL ENCODING AUTO, 69 | change_id CHAR(40) NOT NULL, 70 | change VARCHAR(1024) NOT NULL, 71 | project VARCHAR(1024) NOT NULL REFERENCES :"registry".projects(project), 72 | note VARCHAR(65000) NOT NULL DEFAULT '', 73 | requires LONG VARCHAR NOT NULL DEFAULT '{}', 74 | conflicts LONG VARCHAR NOT NULL DEFAULT '{}', 75 | tags LONG VARCHAR NOT NULL DEFAULT '{}', 76 | committed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 77 | committer_name VARCHAR(1024) NOT NULL, 78 | committer_email VARCHAR(1024) NOT NULL, 79 | planned_at TIMESTAMPTZ NOT NULL, 80 | planner_name VARCHAR(1024) NOT NULL, 81 | planner_email VARCHAR(1024) NOT NULL, 82 | PRIMARY KEY (change_id, committed_at) ENABLED 83 | ); 84 | 85 | COMMENT ON TABLE :"registry".events IS 'Contains full history of all deployment events.'; 86 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Plan/Blank.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Plan::Blank; 2 | 3 | use 5.010; 4 | use utf8; 5 | use namespace::autoclean; 6 | use Moo; 7 | extends 'App::Sqitch::Plan::Line'; 8 | 9 | # VERSION 10 | 11 | has '+name' => ( default => '', required => 0 ); 12 | 13 | sub format_name { '' } 14 | 15 | 1; 16 | 17 | __END__ 18 | 19 | =head1 Name 20 | 21 | App::Sqitch::Plan::Blank - Sqitch deployment plan blank line 22 | 23 | =head1 Synopsis 24 | 25 | my $plan = App::Sqitch::Plan->new( sqitch => $sqitch ); 26 | for my $line ($plan->lines) { 27 | say $line->as_string; 28 | } 29 | 30 | =head1 Description 31 | 32 | An App::Sqitch::Plan::Blank represents a blank line or comment-only line in 33 | the plan file. See L for its interface. The only 34 | difference is that the C is always an empty string. 35 | 36 | =head1 Author 37 | 38 | David E. Wheeler 39 | 40 | =head1 License 41 | 42 | Copyright (c) 2012-2025 David E. Wheeler, 2012-2021 iovation Inc. 43 | 44 | Permission is hereby granted, free of charge, to any person obtaining a copy 45 | of this software and associated documentation files (the "Software"), to deal 46 | in the Software without restriction, including without limitation the rights 47 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 48 | copies of the Software, and to permit persons to whom the Software is 49 | furnished to do so, subject to the following conditions: 50 | 51 | The above copyright notice and this permission notice shall be included in all 52 | copies or substantial portions of the Software. 53 | 54 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 55 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 56 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 57 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 58 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 59 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 60 | SOFTWARE. 61 | 62 | =cut 63 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Plan/LineList.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Plan::LineList; 2 | 3 | use 5.010; 4 | use strict; 5 | use utf8; 6 | 7 | # VERSION 8 | 9 | sub new { 10 | my $class = shift; 11 | my (@list, %index); 12 | for my $line (@_) { 13 | push @list => $line; 14 | $index{ $line } = $#list; 15 | } 16 | 17 | return bless { 18 | list => \@list, 19 | lookup => \%index, 20 | } 21 | } 22 | 23 | sub count { scalar @{ shift->{list} } } 24 | sub items { @{ shift->{list} } } 25 | sub item_at { shift->{list}->[shift] } 26 | sub index_of { shift->{lookup}{+shift} } 27 | 28 | sub append { 29 | my ( $self, $line ) = @_; 30 | my $list = $self->{list}; 31 | push @{ $list } => $line; 32 | $self->{lookup}{$line} = $#$list; 33 | } 34 | 35 | sub insert_at { 36 | my ( $self, $line, $idx ) = @_; 37 | 38 | # Add the line to the list. 39 | my $list = $self->{list}; 40 | splice @{ $list }, $idx, 0, $line; 41 | 42 | # Reindex. 43 | my $index = $self->{lookup}; 44 | $index->{ $list->[$_] } = $_ for $idx..$#$list; 45 | return $self; 46 | } 47 | 48 | 1; 49 | 50 | __END__ 51 | 52 | =head1 Name 53 | 54 | App::Sqitch::Plan::LineList - Sqitch deployment plan line list 55 | 56 | =head1 Synopsis 57 | 58 | my $list = App::Sqitch::Plan::LineList->new(@lines); 59 | 60 | my @lines = $list->items; 61 | my $index = $list->index_of($line); 62 | 63 | $lines->append($another_line); 64 | 65 | =head1 Description 66 | 67 | This module is used internally by L to manage plan file 68 | lines. It's modeled on L, but is much simpler and hews closer 69 | to the API of L. 70 | 71 | =head1 Interface 72 | 73 | =head2 Constructors 74 | 75 | =head3 C 76 | 77 | my $plan = App::Sqitch::Plan::LineList->new(map { $_->name => @_ } @changes ); 78 | 79 | Instantiates and returns a App::Sqitch::Plan::LineList object. The parameters 80 | should be a key/value list of lines. Keys may be duplicated, as long as a tag 81 | appears between each instance of a key. 82 | 83 | =head2 Instance Methods 84 | 85 | =head3 C 86 | 87 | =head3 C 88 | 89 | =head3 C 90 | 91 | =head3 C 92 | 93 | =head3 C 94 | 95 | =head3 C 96 | 97 | =head1 See Also 98 | 99 | =over 100 | 101 | =item L 102 | 103 | The Sqitch plan. 104 | 105 | =back 106 | 107 | =head1 Author 108 | 109 | David E. Wheeler 110 | 111 | =head1 License 112 | 113 | Copyright (c) 2012-2025 David E. Wheeler, 2012-2021 iovation Inc. 114 | 115 | Permission is hereby granted, free of charge, to any person obtaining a copy 116 | of this software and associated documentation files (the "Software"), to deal 117 | in the Software without restriction, including without limitation the rights 118 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 119 | copies of the Software, and to permit persons to whom the Software is 120 | furnished to do so, subject to the following conditions: 121 | 122 | The above copyright notice and this permission notice shall be included in all 123 | copies or substantial portions of the Software. 124 | 125 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 126 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 127 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 128 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 129 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 130 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 131 | SOFTWARE. 132 | 133 | =cut 134 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Plan/Pragma.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Plan::Pragma; 2 | 3 | use 5.010; 4 | use utf8; 5 | use namespace::autoclean; 6 | use Moo; 7 | use App::Sqitch::Types qw(Str); 8 | extends 'App::Sqitch::Plan::Line'; 9 | 10 | # VERSION 11 | 12 | has value => ( 13 | is => 'ro', 14 | isa => Str, 15 | ); 16 | 17 | has hspace => ( 18 | is => 'ro', 19 | isa => Str, 20 | default => '', 21 | ); 22 | 23 | sub BUILDARGS { 24 | my $class = shift; 25 | my $p = @_ == 1 && ref $_[0] ? { %{ +shift } } : { @_ }; 26 | $p->{value} =~ s/\s+$// if $p->{value}; 27 | $p->{op} //= ''; 28 | return $p; 29 | } 30 | 31 | sub format_name { 32 | my $self = shift; 33 | return '%' . $self->hspace . $self->name; 34 | } 35 | 36 | sub format_value { 37 | shift->value // ''; 38 | } 39 | 40 | sub format_content { 41 | my $self = shift; 42 | join '', $self->format_name, $self->format_operator, $self->format_value; 43 | } 44 | 45 | sub as_string { 46 | my $self = shift; 47 | return $self->lspace 48 | . $self->format_content 49 | . $self->rspace 50 | . $self->format_note; 51 | } 52 | 53 | 1; 54 | 55 | __END__ 56 | 57 | =head1 Name 58 | 59 | App::Sqitch::Plan::Pragma.pm - Sqitch deployment plan blank line 60 | 61 | =head1 Synopsis 62 | 63 | my $plan = App::Sqitch::Plan->new( sqitch => $sqitch ); 64 | for my $line ($plan->lines) { 65 | say $line->as_string; 66 | } 67 | 68 | =head1 Description 69 | 70 | An App::Sqitch::Plan::Pragma represents a plan file pragma. See 71 | L for its interface. 72 | 73 | =head1 Interface 74 | 75 | In addition to the interface inherited from L, 76 | App::Sqitch::Plan::Line::Pragma adds a few methods of its own. 77 | 78 | =head2 Accessors 79 | 80 | =head3 C 81 | 82 | The value of the pragma. 83 | 84 | =head3 C 85 | 86 | The operator, including surrounding white space. 87 | 88 | =head3 C 89 | 90 | The horizontal space between the pragma and its value. 91 | 92 | =head2 Instance Methods 93 | 94 | =head3 C 95 | 96 | Formats the value for output. If there is no value, an empty string is 97 | returned. Otherwise the value is returned as-is. 98 | 99 | =head1 Author 100 | 101 | David E. Wheeler 102 | 103 | =head1 License 104 | 105 | Copyright (c) 2012-2025 David E. Wheeler, 2012-2021 iovation Inc. 106 | 107 | Permission is hereby granted, free of charge, to any person obtaining a copy 108 | of this software and associated documentation files (the "Software"), to deal 109 | in the Software without restriction, including without limitation the rights 110 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 111 | copies of the Software, and to permit persons to whom the Software is 112 | furnished to do so, subject to the following conditions: 113 | 114 | The above copyright notice and this permission notice shall be included in all 115 | copies or substantial portions of the Software. 116 | 117 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 118 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 119 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 120 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 121 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 122 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 123 | SOFTWARE. 124 | 125 | =cut 126 | -------------------------------------------------------------------------------- /lib/App/Sqitch/Role/ConnectingCommand.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Role::ConnectingCommand; 2 | 3 | use 5.010; 4 | use strict; 5 | use warnings; 6 | use utf8; 7 | use Moo::Role; 8 | use App::Sqitch::Types qw(ArrayRef); 9 | 10 | # VERSION 11 | 12 | requires 'options'; 13 | requires 'configure'; 14 | requires 'target_params'; 15 | 16 | has _params => ( 17 | is => 'ro', 18 | isa => ArrayRef, 19 | default => sub { [] }, 20 | ); 21 | 22 | around options => sub { 23 | my $orig = shift; 24 | return $orig->(@_), qw( 25 | registry=s 26 | client|db-client=s 27 | db-name|d=s 28 | db-user|db-username|u=s 29 | db-host|h=s 30 | db-port|p=i 31 | ); 32 | }; 33 | 34 | around configure => sub { 35 | my ( $orig, $class, $config, $opt ) = @_; 36 | 37 | # Grab the options we're responsible for. 38 | my @params = ( 39 | (exists $opt->{db_user} ? ('user', => delete $opt->{db_user}) : ()), 40 | (exists $opt->{db_host} ? ('host', => delete $opt->{db_host}) : ()), 41 | (exists $opt->{db_port} ? ('port', => delete $opt->{db_port}) : ()), 42 | (exists $opt->{db_name} ? ('dbname' => delete $opt->{db_name}) : ()), 43 | (exists $opt->{registry} ? ('registry' => delete $opt->{registry}) : ()), 44 | (exists $opt->{client} ? ('client' => delete $opt->{client}) : ()), 45 | ); 46 | 47 | # Let the command take care of its options. 48 | my $params = $class->$orig($config, $opt); 49 | 50 | # Hang on to the target parameters. 51 | $params->{_params} = \@params; 52 | return $params; 53 | }; 54 | 55 | around target_params => sub { 56 | my ($orig, $self) = (shift, shift); 57 | return $self->$orig(@_), @{ $self->_params }; 58 | }; 59 | 60 | 1; 61 | 62 | __END__ 63 | 64 | =head1 Name 65 | 66 | App::Sqitch::Role::ConnectingCommand - A command that connects to a target 67 | 68 | =head1 Synopsis 69 | 70 | package App::Sqitch::Command::deploy; 71 | extends 'App::Sqitch::Command'; 72 | with 'App::Sqitch::Role::ConnectingCommand'; 73 | 74 | =head1 Description 75 | 76 | This role encapsulates the options and target parameters required by commands 77 | that connect to a database target. 78 | 79 | =head1 Interface 80 | 81 | =head2 Class Methods 82 | 83 | =head3 C 84 | 85 | my @opts = App::Sqitch::Command::deploy->options; 86 | 87 | Adds database connection options. 88 | 89 | =head3 C 90 | 91 | Configures the options used for target parameters. 92 | 93 | =head2 Instance Methods 94 | 95 | =head3 C 96 | 97 | Returns a list of parameters to be passed to App::Sqitch::Target's C 98 | and C methods. 99 | =head1 See Also 100 | 101 | =over 102 | 103 | =item L 104 | 105 | The C command deploys changes to a database. 106 | 107 | =item L 108 | 109 | The C command reverts changes from a database. 110 | 111 | =item L 112 | 113 | The C command shows the event log for a database. 114 | 115 | =back 116 | 117 | =head1 Author 118 | 119 | David E. Wheeler 120 | 121 | =head1 License 122 | 123 | Copyright (c) 2012-2025 David E. Wheeler, 2012-2021 iovation Inc. 124 | 125 | Permission is hereby granted, free of charge, to any person obtaining a copy 126 | of this software and associated documentation files (the "Software"), to deal 127 | in the Software without restriction, including without limitation the rights 128 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 129 | copies of the Software, and to permit persons to whom the Software is 130 | furnished to do so, subject to the following conditions: 131 | 132 | The above copyright notice and this permission notice shall be included in all 133 | copies or substantial portions of the Software. 134 | 135 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 136 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 137 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 138 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 139 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 140 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 141 | SOFTWARE. 142 | 143 | =cut 144 | -------------------------------------------------------------------------------- /lib/sqitch-add-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-add-usage - Sqitch add usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch add [options] [template options] [] 8 | 9 | =head1 Options 10 | 11 | -c --change name of the change to add 12 | -r --requires require change 13 | -x --conflicts declare conflicting change 14 | -a --all add change to all project plans 15 | -s --set set a template variable 16 | -n --note a note describing the change 17 | 18 | -t --template name of the templates to use 19 | --template-directory path to directory containing templates 20 | --use [template=path] path to named template 21 | 22 | --with [script] create named script 23 | --without [script] do not create named script 24 | -e --edit, --open-editor open change scripts in an editor 25 | -f --plan-file path to a deployment plan file 26 | -------------------------------------------------------------------------------- /lib/sqitch-bundle-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-bundle-usage - Sqitch bundle usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch bundle [options] [] [] [] 8 | 9 | =head1 Options 10 | 11 | --dest-dir --dir destination directory to which to copy files 12 | --from change from which to start bundling 13 | --to change to which to end bundling 14 | -f --plan-file path to a deployment plan file 15 | -------------------------------------------------------------------------------- /lib/sqitch-check-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-check-usage - Sqitch check usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch check [options] [] 8 | 9 | =head1 Options 10 | 11 | -t --target database to which to connect 12 | --project project for which to perform the checks 13 | --registry registry schema or database 14 | --db-client path to the engine command-line client 15 | -d --db-name database name 16 | -u --db-user database user name 17 | -h --db-host database server host name 18 | -p --db-port database server port number 19 | -f --plan-file path to a deployment plan file 20 | -------------------------------------------------------------------------------- /lib/sqitch-check.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-check - Checks for divergences between planned and deployed changes. 4 | 5 | =head1 Synopsis 6 | 7 | sqitch check [options] [] 8 | 9 | =head1 Description 10 | 11 | Compares the state of the working directory and the database by comparing the 12 | SHA1 hashes of the deploy scripts. Fails and reports divergence for all 13 | changes with non-matching hashes, indicating that the project deploy scripts 14 | differ from the scripts that were used to deploy to the database. 15 | 16 | The C<< >> parameter specifies the database to which to connect, 17 | and may also be specified as the C<--target> option. It can be target name, 18 | a URI, an engine name, or plan file path. 19 | 20 | =head1 Options 21 | 22 | =over 23 | 24 | =item C<-t> 25 | 26 | =item C<--target> 27 | 28 | The target database to which to connect. This option can be either a URI or 29 | the name of a target in the configuration. 30 | 31 | =item C<--project> 32 | 33 | Project for which to retrieve the status. Defaults to the status of the 34 | current project, if a plan can be found. 35 | 36 | =item C<--registry> 37 | 38 | sqitch check --registry registry 39 | 40 | The name of the Sqitch registry schema or database in which sqitch stores its 41 | own data. 42 | 43 | =item C<--db-client> 44 | 45 | =item C<--client> 46 | 47 | sqitch check --client /usr/local/pgsql/bin/psql 48 | 49 | Path to the command-line client for the database engine. Defaults to a client 50 | in the current path named appropriately for the database engine. 51 | 52 | =item C<-d> 53 | 54 | =item C<--db-name> 55 | 56 | sqitch check --db-name widgets 57 | sqitch check -d bricolage 58 | 59 | Name of the database. In general, L and URIs are 60 | preferred, but this option can be used to override the database name in a 61 | target. 62 | 63 | =item C<-u> 64 | 65 | =item C<--db-user> 66 | 67 | =item C<--db-username> 68 | 69 | sqitch check --db-username root 70 | sqitch check --db-user postgres 71 | sqitch check -u Mom 72 | 73 | User name to use when connecting to the database. Does not apply to all 74 | engines. In general, L and URIs are preferred, but this 75 | option can be used to override the user name in a target. 76 | 77 | =item C<-h> 78 | 79 | =item C<--db-host> 80 | 81 | sqitch check --db-host db.example.com 82 | sqitch check -h appdb.example.net 83 | 84 | Host name to use when connecting to the database. Does not apply to all 85 | engines. In general, L and URIs are preferred, but this 86 | option can be used to override the host name in a target. 87 | 88 | =item C<-p> 89 | 90 | =item C<--db-port> 91 | 92 | sqitch check --db-port 7654 93 | sqitch check -p 5431 94 | 95 | Port number to connect to. Does not apply to all engines. In general, 96 | L and URIs are preferred, but this option can be used 97 | to override the port in a target. 98 | 99 | =item C<--plan-file> 100 | 101 | =item C<-f> 102 | 103 | sqitch check --plan-file my.plan 104 | 105 | Path to the deployment plan file. Overrides target, engine, and core 106 | configuration values. Defaults to F<$top_dir/sqitch.plan>. 107 | 108 | =back 109 | 110 | =head1 Sqitch 111 | 112 | Part of the L suite. 113 | -------------------------------------------------------------------------------- /lib/sqitch-checkout-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-checkout-usage - Sqitch checkout usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch checkout [options] [] 8 | 9 | =head1 Options 10 | 11 | -t --target database to which to connect 12 | --mode deploy failure reversion mode (all, tag, or change) 13 | --verify run verify scripts after deploying each change 14 | --no-verify do not run verify scripts 15 | -s --set set a database client variable 16 | -r --set-revert set a database client revert variable 17 | -e --set-deploy set a database client deploy variable 18 | --log-only log changes without running them 19 | --lock-timeout seconds to wait for target lock 20 | -y disable the prompt before reverting 21 | --registry registry schema or database 22 | --db-client path to the engine command-line client 23 | -d --db-name database name 24 | -u --db-user database user name 25 | -h --db-host database server host name 26 | -p --db-port database server port number 27 | -f --plan-file path to a deployment plan file 28 | -------------------------------------------------------------------------------- /lib/sqitch-config-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-config-usage - Sqitch config usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch [options] config [config options] 8 | 9 | =head1 Options 10 | 11 | Config file location 12 | 13 | --local use local config file 14 | --user use user config file 15 | --system use system config file 16 | -f, --file use given config file 17 | 18 | Action 19 | 20 | --get get value: name [value-regex] 21 | --get-all get all values: key [value-regex] 22 | --get-regexp get values for regexp: name-regex [value-regex] 23 | --replace-all replace all matching variables: name value [value_regex] 24 | --add adds a new variable: name value 25 | --unset removes a variable: name [value-regex] 26 | --unset-all removes all matches: name [value-regex] 27 | --rename-section rename section: old-name new-name 28 | --remove-section remove a section: name 29 | -l, --list list all 30 | -e, --edit opens an editor 31 | 32 | Type 33 | 34 | --bool value is "true" or "false" 35 | --int value is decimal number 36 | --num value is decimal number 37 | --bool-or-int value is --bool or --int 38 | -------------------------------------------------------------------------------- /lib/sqitch-deploy-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-deploy-usage - Sqitch deploy usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch deploy [options] [] 8 | 9 | =head1 Options 10 | 11 | -t --target database to which to connect 12 | --to-change deploy to change 13 | --mode failure reversion mode 14 | -s --set set a database client variable 15 | --verify run verify scripts after each change 16 | --no-verify do not run verify scripts 17 | --log-only log changes without running them 18 | --lock-timeout seconds to wait for target lock 19 | --registry registry schema or database 20 | --db-client path to the engine command-line client 21 | -d --db-name database name 22 | -u --db-user database user name 23 | -h --db-host database server host name 24 | -p --db-port database server port number 25 | -f --plan-file path to a deployment plan file 26 | -------------------------------------------------------------------------------- /lib/sqitch-engine-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-engine-usage - Sqitch engine usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch engine 8 | sqitch engine [-v | --verbose] 9 | sqitch engine add [engine-options] 10 | sqitch engine alter [engine-options] 11 | sqitch engine remove 12 | sqitch engine show 13 | 14 | =head1 Options 15 | 16 | -v, --verbose be verbose; must be placed before an action 17 | --target database target 18 | --registry registry schema or database 19 | --client path to engine command-line client 20 | -f --plan-file path to deployment plan file 21 | --top-dir path to directory with plan and scripts 22 | --extension change script file name extension 23 | --dir = path to named directory 24 | -s --set set a database client variable 25 | -------------------------------------------------------------------------------- /lib/sqitch-help-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-help-usage - Sqitch help usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch help [--guide] [] [] 8 | 9 | =head1 Options 10 | 11 | -g --guide Print list of guides 12 | 13 | -------------------------------------------------------------------------------- /lib/sqitch-help.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-help - Display help for Sqitch and Sqitch commands 4 | 5 | =head1 Synopsis 6 | 7 | sqitch help [COMMAND] 8 | sqitch help --guide 9 | 10 | =head1 Description 11 | 12 | With no options and no C given, the synopsis of the C options 13 | and a list of the most commonly used Sqitch commands will be displayed. 14 | 15 | If the option C<--guide> or C<-g> is given, then a list of Sqitch guides will 16 | be displayed 17 | 18 | If a Sqitch command is named, the documentation for that command will be 19 | displayed. 20 | 21 | =head1 Options 22 | 23 | =over 24 | 25 | =item C<-g> 26 | 27 | =item C<--guide> 28 | 29 | Prints a list of available Sqitch guides. 30 | 31 | =back 32 | 33 | =head1 Sqitch 34 | 35 | Part of the L suite. 36 | -------------------------------------------------------------------------------- /lib/sqitch-init-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-init-usage - Sqitch init usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch init 8 | sqitch init --uri 9 | 10 | =head1 Options 11 | 12 | --uri associate a URI with the project plan 13 | --engine database engine 14 | --top-dir path to directory with plan and scripts 15 | -f --plan-file path to deployment plan file 16 | --target database target 17 | --registry registry schema or database 18 | --client path to engine command-line client 19 | --extension change script file name extension 20 | --dir = path to named directory 21 | -s --set set a database client variable 22 | -------------------------------------------------------------------------------- /lib/sqitch-log-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-log-usage - Sqitch log usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch log [options] [] 8 | 9 | =head1 Options 10 | 11 | Search options: 12 | 13 | -t --target database to which to connect 14 | --event type of event 15 | --change-pattern --change match regex against committer names 17 | -n --max-count show only specified number of events 18 | --skip skip the specified number of events 19 | --reverse show events in reverse order 20 | --no-reverse don't show events in reverse order 21 | 22 | Formatting: 23 | 24 | -f --format show events in the specified format 25 | --date-format --date show dates in the specified format 26 | --color use ANSI colors 27 | --no-color never use ANSI colors 28 | --abbrev abbreviate change IDs 29 | --oneline shorthand for --format oneline --abbrev 6 30 | --headers show headers for the target 31 | --no-headers don't show target headers 32 | 33 | Connection: 34 | 35 | --registry registry schema or database 36 | --db-client path to the engine command-line client 37 | -d --db-name database name 38 | -u --db-user database user name 39 | -h --db-host database server host name 40 | -p --db-port database server port number 41 | -------------------------------------------------------------------------------- /lib/sqitch-passwords.pod: -------------------------------------------------------------------------------- 1 | =encoding UTF-8 2 | 3 | =head1 Name 4 | 5 | sqitch-passwords - Guide to using database passwords with Sqitch 6 | 7 | =head1 Description 8 | 9 | This guide has been moved to L. 10 | 11 | =head1 Sqitch 12 | 13 | Part of the L suite. 14 | -------------------------------------------------------------------------------- /lib/sqitch-plan-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-plan-usage - Sqitch plan usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch plan [options] [] 8 | 9 | =head1 Options 10 | 11 | Search options: 12 | 13 | -t --target database target specifying the plan 14 | --event type of event 15 | --change-pattern --change match regex against change names 16 | --planner-pattern --planner match regex against committer names 17 | -n --max-count show only specified number of events 18 | --skip skip the specified number of events 19 | --reverse show events in reverse order 20 | --no-reverse don't show events in reverse order 21 | 22 | Formatting 23 | 24 | -f --format show events in the specified format 25 | --date-format --date show dates in the specified format 26 | --color use ANSI colors 27 | --no-color never use ANSI colors 28 | --abbrev abbreviate change IDs 29 | --oneline shorthand for --format oneline --abbrev 6 30 | --headers show headers for plan file and project 31 | --no-headers don't show plan headers 32 | 33 | -------------------------------------------------------------------------------- /lib/sqitch-rebase-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-rebase-usage - Sqitch rebase usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch rebase [options] [revert-change options] [deploy-change options]] [] 8 | 9 | =head1 Options 10 | 11 | -t --target database to which to connect 12 | -m --modified revert to before the earliest modified change 13 | --onto --onto-change revert to change 14 | --upto --upto-change deploy to change 15 | --mode deploy reversion mode (all, tag, change) 16 | --verify run verify scripts after each change 17 | --no-verify do not run verify scripts 18 | -s --set set a database client variable 19 | -r --set-revert set a database client revert variable 20 | -e --set-deploy set a database client deploy variable 21 | --log-only log changes without running them 22 | --lock-timeout seconds to wait for target lock 23 | -y disable the prompt before reverting 24 | --registry registry schema or database 25 | --db-client path to the engine command-line client 26 | -d --db-name database name 27 | -u --db-user database user name 28 | -h --db-host database server host name 29 | -p --db-port database server port number 30 | -f --plan-file path to a deployment plan file 31 | -------------------------------------------------------------------------------- /lib/sqitch-revert-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-revert-usage - Sqitch revert usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch revert [options] [] 8 | 9 | =head1 Options 10 | 11 | -t --target database to which to connect 12 | --to-change revert to change 13 | -m --modified revert to before the earliest modified change 14 | -s --set set a database client variable 15 | --log-only log changes without running them 16 | --lock-timeout seconds to wait for target lock 17 | -y disable the prompt before reverting 18 | --registry registry schema or database 19 | --db-client path to the engine command-line client 20 | -d --db-name database name 21 | -u --db-user database user name 22 | -h --db-host database server host name 23 | -p --db-port database server port number 24 | -f --plan-file path to a deployment plan file 25 | -------------------------------------------------------------------------------- /lib/sqitch-rework-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-rework-usage - Sqitch rework usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch rework [options] changename 8 | 9 | =head1 Options 10 | 11 | -c --change --change-name name of the change to rework 12 | -r --requires require change 13 | -x --conflicts declare conflicting change 14 | -n --note a note describing the change 15 | -a --all rework the change in all plans in the project 16 | -e --edit --open-editor open change scripts in an editor 17 | --no-edit --no-open-editor do not open the change scripts in an editor 18 | -f --plan-file path to a deployment plan file 19 | 20 | -------------------------------------------------------------------------------- /lib/sqitch-show-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-show-usage - Sqitch show usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch show [options] 8 | 9 | C<< >> can be one of: change, tag, deploy, revert, verify 10 | 11 | =head1 Options 12 | 13 | -t --target database target specifying the plan 14 | -e --exists suppress output, exit 0 when object exists 15 | -f --plan-file path to a deployment plan file 16 | -------------------------------------------------------------------------------- /lib/sqitch-show.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-show - Show object information or script contents 4 | 5 | =head1 Synopsis 6 | 7 | sqitch show [options] 8 | 9 | =head1 Description 10 | 11 | Shows information about Sqitch objects. The first argument must be the type of 12 | object to show, and the second must be a key identifier for the object in the 13 | plan. The second argument must be a a change name or tag as specified in 14 | L. The supported types include: 15 | 16 | =over 17 | 18 | =item C 19 | 20 | A change object. Outputs the text used to generate the change SHA1 ID. 21 | 22 | =item C 23 | 24 | A tag. Outputs the text used to generate the tag SHA1 ID. 25 | 26 | =item C 27 | 28 | A change deploy script. 29 | 30 | =item C 31 | 32 | A change revert script. 33 | 34 | =item C 35 | 36 | A change verify script. 37 | 38 | =back 39 | 40 | =head1 Options 41 | 42 | =over 43 | 44 | =item C<-t> 45 | 46 | =item C<--target> 47 | 48 | The target database, the plan for which should be read before deciding what 49 | object to show. This option should be the name of a target in the 50 | configuration. 51 | 52 | =item C<-e> 53 | 54 | =item C<--exists> 55 | 56 | Suppress all output; instead exit with zero status if C<< >> exists 57 | and is a valid object. 58 | 59 | =item C<--plan-file> 60 | 61 | =item C<-f> 62 | 63 | Path to the deployment plan file. Overrides target, engine, and core 64 | configuration values. Defaults to F<$top_dir/sqitch.plan>. 65 | 66 | =back 67 | 68 | =head2 Examples 69 | 70 | =over 71 | 72 | =item * Show information about a specific change: 73 | 74 | sqitch show change add_users_table 75 | 76 | =item * Show information about a change by ID: 77 | 78 | sqitch show change be7cd00571d7151eacb0691e825dfc8980cc14ff 79 | 80 | =item * Show the most recent change info: 81 | 82 | sqitch show change @HEAD 83 | 84 | =item * Show information about a tag: 85 | 86 | sqitch show tag @beta1 87 | 88 | =item * Show the contents of a deploy file: 89 | 90 | sqitch show deploy add_users_table@HEAD 91 | 92 | =back 93 | 94 | =head1 Sqitch 95 | 96 | Part of the L suite. 97 | -------------------------------------------------------------------------------- /lib/sqitch-status-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-status-usage - Sqitch status usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch status [options] [] 8 | 9 | =head1 Options 10 | 11 | -t --target database to which to connect 12 | --project project for which to retrieve the status 13 | --show-changes include a list of deployed changes 14 | --show-tags include a list of applied tags 15 | --date-format display dates using the specified format 16 | --registry registry schema or database 17 | --db-client path to the engine command-line client 18 | -d --db-name database name 19 | -u --db-user database user name 20 | -h --db-host database server host name 21 | -p --db-port database server port number 22 | -f --plan-file path to a deployment plan file 23 | -------------------------------------------------------------------------------- /lib/sqitch-tag-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-tag-usage - Sqitch tag usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch tag [options] [] [] 8 | 9 | =head1 Options 10 | 11 | -t --tag name of the tag to add 12 | -c --change name of the change to tag 13 | -a --all tag all project plans 14 | -n --note a note describing the tag 15 | -f --plan-file path to a deployment plan file 16 | -------------------------------------------------------------------------------- /lib/sqitch-target-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-target-usage - Sqitch target usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch target 8 | sqitch target [-v | --verbose] 9 | sqitch target add [target-options] 10 | sqitch target alter [target-options] 11 | sqitch target remove 12 | sqitch target rename 13 | sqitch target show 14 | 15 | =head1 Options 16 | 17 | -v, --verbose be verbose; must be placed before an action 18 | --uri database URI 19 | --registry registry schema or database 20 | --client path to engine command-line client 21 | -f --plan-file path to deployment plan file 22 | --top-dir path to directory with plan and scripts 23 | --extension change script file name extension 24 | --dir = path to named directory 25 | -s --set set a database client variable 26 | -------------------------------------------------------------------------------- /lib/sqitch-upgrade-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-upgrade-usage - Sqitch upgrade usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch upgrade [options] [] 8 | 9 | =head1 Options 10 | 11 | -t --target database to which to connect 12 | --registry registry schema or database 13 | --db-client path to the engine command-line client 14 | -d --db-name database name 15 | -u --db-user database user name 16 | -h --db-host database server host name 17 | -p --db-port database server port number 18 | -------------------------------------------------------------------------------- /lib/sqitch-upgrade.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-upgrade - Upgrade the registry to the current version 4 | 5 | =head1 Synopsis 6 | 7 | sqitch upgrade [options] [] 8 | 9 | =head1 Description 10 | 11 | Upgrades the Sqitch registry for a database. That is, it makes sure that the 12 | schema the Sqitch uses for its registry is up-to-date. This will occasionally 13 | be necessary when new features are added to Sqitch that require registry 14 | schema changes. 15 | 16 | The C<< >> parameter specifies the database to which to connect, 17 | and may also be specified as the C<--target> option. It can be target name, 18 | a URI, an engine name, or plan file path. 19 | 20 | =head1 Options 21 | 22 | =over 23 | 24 | =item C<-t> 25 | 26 | =item C<--target> 27 | 28 | The target database to which to connect. This option can be either a URI or 29 | the name of a target in the configuration. 30 | 31 | =item C<--registry> 32 | 33 | sqitch upgrade --registry registry 34 | 35 | The name of the Sqitch registry schema or database in which sqitch stores its 36 | own data. 37 | 38 | =item C<--db-client> 39 | 40 | =item C<--client> 41 | 42 | sqitch upgrade --client /usr/local/pgsql/bin/psql 43 | 44 | Path to the command-line client for the database engine. Defaults to a client 45 | in the current path named appropriately for the database engine. 46 | 47 | =item C<-d> 48 | 49 | =item C<--db-name> 50 | 51 | sqitch upgrade --db-name widgets 52 | sqitch upgrade -d bricolage 53 | 54 | Name of the database. In general, L and URIs are 55 | preferred, but this option can be used to override the database name in a 56 | target. 57 | 58 | =item C<-u> 59 | 60 | =item C<--db-user> 61 | 62 | =item C<--db-username> 63 | 64 | sqitch upgrade --db-username root 65 | sqitch upgrade --db-user postgres 66 | sqitch upgrade -u Mom 67 | 68 | User name to use when connecting to the database. Does not apply to all 69 | engines. In general, L and URIs are preferred, but this 70 | option can be used to override the user name in a target. 71 | 72 | =item C<-h> 73 | 74 | =item C<--db-host> 75 | 76 | sqitch upgrade --db-host db.example.com 77 | sqitch upgrade -h appdb.example.net 78 | 79 | Host name to use when connecting to the database. Does not apply to all 80 | engines. In general, L and URIs are preferred, but this 81 | option can be used to override the host name in a target. 82 | 83 | =item C<-p> 84 | 85 | =item C<--db-port> 86 | 87 | sqitch upgrade --db-port 7654 88 | sqitch upgrade -p 5431 89 | 90 | Port number to connect to. Does not apply to all engines. In general, 91 | L and URIs are preferred, but this option can be used 92 | to override the port in a target. 93 | 94 | =back 95 | 96 | =head1 Sqitch 97 | 98 | Part of the L suite. 99 | -------------------------------------------------------------------------------- /lib/sqitch-verify-usage.pod: -------------------------------------------------------------------------------- 1 | =head1 Name 2 | 3 | sqitch-verify-usage - Sqitch verify usage statement 4 | 5 | =head1 Usage 6 | 7 | sqitch verify [options] [] 8 | 9 | =head1 Options 10 | 11 | -t --target database to which to connect 12 | --from-change verify from change 13 | --to-change verify to change 14 | -s --set set a database client variable 15 | --registry registry schema or database 16 | --db-client path to the engine command-line client 17 | -d --db-name database name 18 | -u --db-user database user name 19 | -h --db-host database server host name 20 | -p --db-port database server port number 21 | -f --plan-file path to a deployment plan file 22 | -------------------------------------------------------------------------------- /lib/sqitchcommands.pod: -------------------------------------------------------------------------------- 1 | =begin private 2 | 3 | Keep private so it's not displayed, but will still be indexed by the CPAN 4 | toolchain. 5 | 6 | =head1 Name 7 | 8 | sqitchcommands - List of common sqitch commands 9 | 10 | =end private 11 | 12 | =head1 Usage 13 | 14 | sqitch [--etc-path | --help | --man | --version] 15 | sqitch [--chdir ] [--no-pager] [--quiet] [--verbose] 16 | [] [] 17 | 18 | =head1 Common Commands 19 | 20 | The most commonly used sqitch commands are: 21 | 22 | add Add a new change to the plan 23 | bundle Bundle a Sqitch project for distribution 24 | checkout Revert, checkout another VCS branch, and re-deploy changes 25 | config Get and set local, user, or system options 26 | deploy Deploy changes to a database 27 | engine Manage database engine configuration 28 | help Display help information about Sqitch commands 29 | init Initialize a project 30 | log Show change logs for a database 31 | plan Show the contents of a plan 32 | rebase Revert and redeploy database changes 33 | revert Revert changes from a database 34 | rework Duplicate a change in the plan and revise its scripts 35 | show Show information about changes and tags, or change script contents 36 | status Show the current deployment status of a database 37 | tag Add or list tags in the plan 38 | target Manage target database configuration 39 | upgrade Upgrade the registry to the current version 40 | verify Verify changes to a database 41 | 42 | See C<< sqitch help >> or C<< sqitch help >> to read about 43 | a specific command or concept. See C<< sqitch help --guide >> for a list of 44 | conceptual guides. 45 | -------------------------------------------------------------------------------- /lib/sqitchguides.pod: -------------------------------------------------------------------------------- 1 | =begin private 2 | 3 | Keep private so it's not displayed, but will still be indexed by the CPAN 4 | toolchain. 5 | 6 | =head1 Name 7 | 8 | sqitchguides - List of common Sqitch guides 9 | 10 | =end private 11 | 12 | The common Sqitch guides are: 13 | 14 | changes Specifying changes for Sqitch 15 | configuration Hierarchical engine and target configuration 16 | environment Environment variables 17 | authentication Specifying target authentication credentials 18 | tutorial PostgreSQL Tutorial 19 | tutorial-firebird Firebird Tutorial 20 | tutorial-mysql MySQL Tutorial 21 | tutorial-oracle Oracle Tutorial 22 | tutorial-sqlite SQLite Tutorial 23 | tutorial-vertica Vertica Tutorial 24 | tutorial-exasol Exasol Tutorial 25 | tutorial-snowflake Snowflake Tutorial 26 | 27 | See C<< sqitch help >> or C<< sqitch help >> to read about 28 | a specific command or concept. 29 | -------------------------------------------------------------------------------- /lib/sqitchusage.pod: -------------------------------------------------------------------------------- 1 | =begin private 2 | 3 | Keep private so it's not displayed, but will still be indexed by the CPAN 4 | toolchain. 5 | 6 | =head1 Name 7 | 8 | sqitchusage - Sqitch usage statement 9 | 10 | =end private 11 | 12 | =head1 Usage 13 | 14 | sqitch [options] [command-options] [args] 15 | 16 | =head1 Options 17 | 18 | -C --chdir --cd Change to directory before performing any actions 19 | --etc-path Print the path to the etc directory and exit 20 | --no-pager Do not pipe output into a pager 21 | --quiet Quiet mode with non-error output suppressed 22 | -V --verbose Increment verbosity 23 | --version Print the version number and exit 24 | --help Show a list of commands and exit 25 | --man Print the introductory documentation and exit 26 | -------------------------------------------------------------------------------- /t/add_change.conf: -------------------------------------------------------------------------------- 1 | [add] 2 | template_directory = t 3 | template_name = hi 4 | all = true 5 | [add "variables"] 6 | foo = bar 7 | baz = hi 8 | baz = there 9 | baz = you 10 | 11 | -------------------------------------------------------------------------------- /t/configuration.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use Test::More tests => 22; 6 | #use Test::More 'no_plan'; 7 | use File::Spec; 8 | use Test::Exception; 9 | use Test::NoWarnings; 10 | 11 | my $CLASS; 12 | BEGIN { 13 | $CLASS = 'App::Sqitch::Config'; 14 | use_ok $CLASS or die; 15 | } 16 | 17 | # protect against user's environment variables 18 | delete @ENV{qw( SQITCH_CONFIG SQITCH_USER_CONFIG SQITCH_SYSTEM_CONFIG )}; 19 | 20 | isa_ok my $config = $CLASS->new, $CLASS, 'New config object'; 21 | is $config->confname, 'sqitch.conf', 'confname should be "sqitch.conf"'; 22 | ok !$config->initialized, 'Should not be initialized'; 23 | 24 | my $hd = $^O eq 'MSWin32' && "$]" < '5.016' ? $ENV{HOME} || $ENV{USERPROFILE} : (glob('~'))[0]; 25 | 26 | SKIP: { 27 | skip 'System dir can be modified at build time', 1 28 | if $INC{'App/Sqitch/Config.pm'} =~ /\bblib\b/; 29 | is $config->system_dir, File::Spec->catfile( 30 | $Config::Config{prefix}, 'etc', 'sqitch' 31 | ), 'Default system directory should be correct'; 32 | } 33 | 34 | is $config->user_dir, File::Spec->catfile( 35 | $hd, '.sqitch' 36 | ), 'Default user directory should be correct'; 37 | 38 | is $config->global_file, File::Spec->catfile( 39 | $config->system_dir, 'sqitch.conf' 40 | ), 'Default global file name should be correct'; 41 | 42 | my $file = File::Spec->catfile(qw(FOO BAR)); 43 | $ENV{SQITCH_SYSTEM_CONFIG} = $file; 44 | is $config->global_file, $file, 45 | 'Should preferably get SQITCH_SYSTEM_CONFIG file from global_file'; 46 | is $config->system_file, $config->global_file, 'system_file should alias global_file'; 47 | 48 | is $config->user_file, File::Spec->catfile( 49 | $hd, '.sqitch', 'sqitch.conf' 50 | ), 'Default user file name should be correct'; 51 | 52 | $ENV{SQITCH_USER_CONFIG} = $file, 53 | is $config->user_file, $file, 54 | 'Should preferably get SQITCH_USER_CONFIG file from user_file'; 55 | 56 | is $config->local_file, 'sqitch.conf', 57 | 'Local file should be correct'; 58 | is $config->dir_file, $config->local_file, 'dir_file should alias local_file'; 59 | 60 | SQITCH_CONFIG: { 61 | local $ENV{SQITCH_CONFIG} = 'sqitch.ini'; 62 | is $config->local_file, 'sqitch.ini', 'local_file should prefer $SQITCH_CONFIG'; 63 | is $config->dir_file, 'sqitch.ini', 'And so should dir_file'; 64 | } 65 | 66 | chdir 't'; 67 | isa_ok $config = $CLASS->new, $CLASS, 'Another config object'; 68 | ok $config->initialized, 'Should be initialized'; 69 | is_deeply $config->get_section(section => 'core'), { 70 | engine => "pg", 71 | extension => "ddl", 72 | top_dir => "migrations", 73 | uri => 'https://github.com/sqitchers/sqitch/', 74 | pager => "less -r", 75 | }, 'get_section("core") should work'; 76 | 77 | is_deeply $config->get_section(section => 'engine.pg'), { 78 | client => "/usr/local/pgsql/bin/psql", 79 | }, 'get_section("engine.pg") should work'; 80 | 81 | # Make sure it works with irregular casing. 82 | is_deeply $config->get_section(section => 'foo.BAR'), { 83 | baz => 'hello', 84 | yep => undef, 85 | }, 'get_section() whould work with capitalized subsection'; 86 | 87 | # Should work with multiple subsections and case-preserved keys. 88 | is_deeply $config->get_section(section => 'guess.Yes.No'), { 89 | red => 'true', 90 | Calico => 'false', 91 | }, 'get_section() whould work with mixed case subsections'; 92 | -------------------------------------------------------------------------------- /t/conn_cmd_role.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use 5.010; 6 | use utf8; 7 | use Test::More; 8 | use App::Sqitch; 9 | use lib 't/lib'; 10 | use TestConfig; 11 | 12 | my $ROLE; 13 | 14 | BEGIN { 15 | $ROLE = 'App::Sqitch::Role::ConnectingCommand'; 16 | use_ok $ROLE or die; 17 | } 18 | 19 | COMMAND: { 20 | # Stub out a command. 21 | package App::Sqitch::Command::click; 22 | use Moo; 23 | extends 'App::Sqitch::Command'; 24 | with $ROLE; 25 | $INC{'App/Sqitch/Command/click.pm'} = __FILE__; 26 | 27 | sub options { 28 | return qw( 29 | foo 30 | quack|k=s 31 | ); 32 | } 33 | } 34 | 35 | my $CLASS = 'App::Sqitch::Command::click'; 36 | can_ok $CLASS, 'does'; 37 | ok $CLASS->does($ROLE), "$CLASS does $ROLE"; 38 | 39 | is_deeply [$CLASS->options], [qw( 40 | foo 41 | quack|k=s 42 | registry=s 43 | client|db-client=s 44 | db-name|d=s 45 | db-user|db-username|u=s 46 | db-host|h=s 47 | db-port|p=i 48 | )], 'Options should include connection options'; 49 | 50 | ############################################################################## 51 | # Test configure. 52 | my $opts = {}; 53 | my $config = TestConfig->new; 54 | my @params; 55 | is_deeply $CLASS->configure($config, $opts), { _params => \@params }, 56 | 'Should get no params for no options'; 57 | 58 | $opts->{db_name} = 'disco'; 59 | push @params => dbname => 'disco'; 60 | is_deeply $CLASS->configure($config, $opts), { _params => \@params }, 61 | 'Should get dbname for --db-name'; 62 | 63 | $opts = { 64 | db_user => '', 65 | db_host => undef, 66 | db_port => 0, 67 | db_name => '', 68 | }; 69 | @params = ( 70 | user => '', 71 | host => undef, 72 | port => 0, 73 | dbname => '', 74 | ); 75 | 76 | is_deeply $CLASS->configure($config, $opts), { _params => \@params }, 77 | 'Should collect existing but false params'; 78 | 79 | $opts = { 80 | db_user => 'theory', 81 | db_host => 'justatheory.com', 82 | db_port => 9876, 83 | db_name => 'funk', 84 | registry => 'crickets', 85 | client => '/bin/true', 86 | quack => 'woof', 87 | }; 88 | @params = ( 89 | user => 'theory', 90 | host => 'justatheory.com', 91 | port => 9876, 92 | dbname => 'funk', 93 | registry => 'crickets', 94 | client => '/bin/true', 95 | ); 96 | is_deeply $CLASS->configure($config, $opts), 97 | { _params => \@params, quack => 'woof' }, 98 | 'Should collect params'; 99 | 100 | ############################################################################## 101 | # Test target_params. 102 | my $sqitch = App::Sqitch->new(config => $config); 103 | isa_ok my $cmd = $CLASS->new( 104 | sqitch => $sqitch, 105 | quack => 'beep', 106 | _params => \@params, 107 | ), $CLASS; 108 | 109 | is_deeply [$cmd->target_params], [sqitch => $sqitch, @params], 110 | 'Should get connection params from target_params'; 111 | 112 | done_testing; 113 | -------------------------------------------------------------------------------- /t/core.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | -------------------------------------------------------------------------------- /t/core_target.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | target = db:pg:whatever 3 | -------------------------------------------------------------------------------- /t/cx_cmd_role.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use 5.010; 6 | use utf8; 7 | use Test::More; 8 | use Path::Class; 9 | use App::Sqitch; 10 | use lib 't/lib'; 11 | use TestConfig; 12 | use Test::MockModule; 13 | use Locale::TextDomain qw(App-Sqitch); # XXX Until deprecation removed below. 14 | 15 | my $ROLE; 16 | 17 | BEGIN { 18 | $ROLE = 'App::Sqitch::Role::ContextCommand'; 19 | use_ok $ROLE or die; 20 | } 21 | 22 | COMMAND: { 23 | # Stub out a command. 24 | package App::Sqitch::Command::click; 25 | use Moo; 26 | extends 'App::Sqitch::Command'; 27 | with $ROLE; 28 | $INC{'App/Sqitch/Command/click.pm'} = __FILE__; 29 | 30 | sub options { 31 | return qw( 32 | foo 33 | quack|k=s 34 | ); 35 | } 36 | } 37 | 38 | my $CLASS = 'App::Sqitch::Command::click'; 39 | can_ok $CLASS, 'does'; 40 | ok $CLASS->does($ROLE), "$CLASS does $ROLE"; 41 | 42 | is_deeply [$CLASS->options], [qw( 43 | foo 44 | quack|k=s 45 | plan-file|f=s 46 | top-dir=s 47 | )], 'Options should include context options'; 48 | 49 | 50 | # Silence warnings. 51 | my $mock = Test::MockModule->new('App::Sqitch'); 52 | my $warning; 53 | $mock->mock(warn => sub { $warning = $_[1] }); 54 | 55 | ############################################################################## 56 | # Test configure. 57 | my $opts = {}; 58 | my $config = TestConfig->new; 59 | is_deeply $CLASS->configure($config, $opts), { _cx => [] }, 60 | 'Should get no params for no options'; 61 | 62 | $opts = { 63 | top_dir => '', 64 | plan_file => '0', 65 | }; 66 | is_deeply $CLASS->configure($config, $opts), { _cx => [] }, 67 | 'Should get no params for empty options'; 68 | is $warning, undef, 'Should have no warning'; 69 | 70 | $opts = { top_dir => 't' }; 71 | my @params = ( top_dir => dir 't'); 72 | is_deeply $CLASS->configure($config, $opts), { _cx => \@params }, 73 | 'Should get top_dir'; 74 | is $warning, __x( 75 | " Option --top-dir is deprecated for {command} and other non-configuration commands.\n Use --chdir instead.", 76 | command => $CLASS->command, 77 | ), 'Should have --top-dir deprecation warning'; 78 | $warning = undef; 79 | 80 | $opts = { 81 | top_dir => 'lib', 82 | plan_file => 'README.md', 83 | quack => 'woof', 84 | }; 85 | @params = ( 86 | top_dir => dir('lib'), 87 | plan_file => file('README.md'), 88 | ); 89 | is_deeply $CLASS->configure($config, $opts), 90 | { _cx => \@params, quack => 'woof' }, 91 | 'Should collect params'; 92 | is $warning, __x( 93 | " Option --top-dir is deprecated for {command} and other non-configuration commands.\n Use --chdir instead.", 94 | command => $CLASS->command, 95 | ), 'Should have --top-dir deprecation warning again'; 96 | 97 | ############################################################################## 98 | # Test target_params. 99 | my $sqitch = App::Sqitch->new(config => $config); 100 | isa_ok my $cmd = $CLASS->new( 101 | sqitch => $sqitch, 102 | quack => 'beep', 103 | _cx => \@params, 104 | ), $CLASS; 105 | 106 | is_deeply [$cmd->target_params], [sqitch => $sqitch, @params], 107 | 'Should get context params from target_params'; 108 | 109 | done_testing; 110 | -------------------------------------------------------------------------------- /t/datetime.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use utf8; 6 | use Test::More tests => 33; 7 | #use Test::More 'no_plan'; 8 | use Locale::TextDomain qw(App-Sqitch); 9 | use Test::NoWarnings; 10 | use Test::Exception; 11 | use Encode; 12 | use lib 't/lib'; 13 | use LC; 14 | use TestConfig; 15 | 16 | my $CLASS = 'App::Sqitch::DateTime'; 17 | require_ok $CLASS; 18 | local $ENV{TZ} = 'America/Vancouver'; 19 | 20 | ok my $dt = $CLASS->now, 'Construct a datetime object'; 21 | is_deeply [$dt->as_string_formats], [qw( 22 | raw 23 | iso 24 | iso8601 25 | rfc 26 | rfc2822 27 | full 28 | long 29 | medium 30 | short 31 | )], 'as_string_formats should be correct'; 32 | 33 | my $rfc = do { 34 | my $clone = $dt->clone; 35 | $clone->set_time_zone('local'); 36 | $clone->set_locale('en_US'); 37 | ( my $rv = $clone->strftime('%a, %d %b %Y %H:%M:%S %z') ) =~ s/\+0000$/-0000/; 38 | $rv; 39 | }; 40 | 41 | my $iso = do { 42 | my $clone = $dt->clone; 43 | $clone->set_time_zone('local'); 44 | join ' ', $clone->ymd('-'), $clone->hms(':'), $clone->strftime('%z') 45 | }; 46 | 47 | my $ldt = do { 48 | my $clone = $dt->clone; 49 | $clone->set_time_zone('local'); 50 | $clone->set_locale($LC::TIME); 51 | $clone; 52 | }; 53 | 54 | my $raw = do { 55 | my $clone = $dt->clone; 56 | $clone->set_time_zone('UTC'); 57 | $clone->iso8601 . 'Z'; 58 | }; 59 | 60 | for my $spec ( 61 | [ full => $ldt->format_cldr( $ldt->locale->datetime_format_full )], 62 | [ long => $ldt->format_cldr( $ldt->locale->datetime_format_long )], 63 | [ medium => $ldt->format_cldr( $ldt->locale->datetime_format_medium )], 64 | [ short => $ldt->format_cldr( $ldt->locale->datetime_format_short )], 65 | [ raw => $raw ], 66 | [ '' => $raw ], 67 | [ iso => $iso ], 68 | [ iso8601 => $iso ], 69 | [ rfc => $rfc ], 70 | [ rfc2822 => $rfc ], 71 | [ q{cldr:HH'h' mm'm'} => $ldt->format_cldr( q{HH'h' mm'm'} ) ], 72 | [ 'strftime:%a at %H:%M:%S' => $ldt->strftime('%a at %H:%M:%S') ], 73 | ) { 74 | my $clone = $dt->clone; 75 | $clone->set_time_zone('UTC'); 76 | is $dt->as_string( format => $spec->[0] ), $spec->[1], 77 | sprintf 'Date format "%s" should yield "%s"', $spec->[0], encode_utf8 $spec->[1]; 78 | ok $dt->validate_as_string_format($spec->[0]), 79 | qq{Format "$spec->[0]" should be valid} if $spec->[0]; 80 | } 81 | 82 | throws_ok { $dt->validate_as_string_format('nonesuch') } 'App::Sqitch::X', 83 | 'Should get error for invalid date format'; 84 | is $@->ident, 'datetime', 'Invalid date format error ident should be "datetime"'; 85 | is $@->message, __x( 86 | 'Unknown date format "{format}"', 87 | format => 'nonesuch', 88 | ), 'Invalid date format error message should be correct'; 89 | 90 | throws_ok { $dt->as_string( format => 'nonesuch' ) } 'App::Sqitch::X', 91 | 'Should get error for invalid as_string format param'; 92 | is $@->ident, 'datetime', 'Invalid date format error ident should be "datetime"'; 93 | is $@->message, __x( 94 | 'Unknown date format "{format}"', 95 | format => 'nonesuch', 96 | ), 'Invalid date format error message should be correct'; 97 | -------------------------------------------------------------------------------- /t/dbiengine_role.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use 5.010; 6 | use utf8; 7 | use Test::More tests => 14; 8 | # use Test::More 'no_plan'; 9 | use Test::MockModule; 10 | use Test::Exception; 11 | 12 | # For testing paths in App::Sqitch::Role::DBIEngine that are not implicictly 13 | # tested by the engines that use it. 14 | 15 | my $CLASS; 16 | 17 | BEGIN { 18 | $CLASS = 'App::Sqitch::Role::DBIEngine'; 19 | require_ok $CLASS or die; 20 | } 21 | 22 | can_ok $CLASS, qw( 23 | _dt 24 | _log_tags_param 25 | _log_requires_param 26 | _log_conflicts_param 27 | _ts_default 28 | _can_limit 29 | _limit_default 30 | _simple_from 31 | _quote_idents 32 | _in_expr 33 | _register_release 34 | _version_query 35 | _dsn 36 | registry_version 37 | _cid 38 | earliest_change_id 39 | latest_change_id 40 | _select_state 41 | current_state 42 | current_changes 43 | current_tags 44 | search_events 45 | _regex_expr 46 | _limit_offset 47 | registered_projects 48 | register_project 49 | is_deployed_change 50 | are_deployed_changes 51 | is_deployed_tag 52 | _multi_values 53 | _dependency_placeholders 54 | _tag_placeholders 55 | _tag_subselect_columns 56 | _prepare_to_log 57 | log_deploy_change 58 | log_fail_change 59 | _log_event 60 | changes_requiring_change 61 | name_for_change_id 62 | log_new_tags 63 | log_revert_change 64 | deployed_changes 65 | deployed_changes_since 66 | load_change 67 | _offset_op 68 | change_id_offset_from_id 69 | change_offset_from_id 70 | _cid_head 71 | change_id_for 72 | _update_script_hashes 73 | begin_work 74 | finish_work 75 | rollback_work 76 | _eh 77 | error_handler 78 | ); 79 | 80 | is App::Sqitch::Role::DBIEngine::_ts_default, 'DEFAULT', 81 | '_ts_default should return DEFAULT'; 82 | 83 | # Test various failure modes. 84 | my $role = bless {} => $CLASS; 85 | FAILMOCKS: { 86 | # Set up mocks. 87 | my $mock = Test::MockModule->new($CLASS); 88 | my ($dbh_err, $no_table, $no_col, $init) = ('OW', 0, 0, 0); 89 | my ($state_err, $sel_state) = ('OOPS', -1); 90 | $mock->mock(dbh => sub { die $dbh_err }); 91 | $mock->mock(_no_table_error => sub { $no_table }); 92 | $mock->mock(initialized => sub { $init }); 93 | $mock->mock(_no_column_error => sub { $no_col }); 94 | $mock->mock(_select_state => sub { $sel_state = $_[2]; die $state_err }); 95 | 96 | # Test registry_version. 97 | throws_ok { $role->registry_version } qr/OW/, 98 | 'registry_version should propagate non-table error'; 99 | $no_table = 1; 100 | ok !$role->registry_version, 101 | 'registry_version should return false on no-table error'; 102 | $no_table = 0; 103 | 104 | # Test _cid 105 | throws_ok { $role->_cid(0, 0, 'foo') } qr/OW/, 106 | '_cid should propagate non-table error'; 107 | $no_table = 1; 108 | ok !$role->_cid(0, 0, 'foo'), 109 | '_cid should return false on no-table error and unititialized'; 110 | $no_table = 0; 111 | 112 | 113 | # Test current_state. 114 | throws_ok { $role->current_state('foo') } qr/OOPS/, 115 | 'curent_state should propagate _select_state error'; 116 | is $sel_state, 1, 'Should have passed 1 to _select_state'; 117 | ($sel_state, $no_table) = (-1, 1); 118 | ok !$role->current_state('foo'), 119 | 'curent_state should return false on no-table error'; 120 | is $sel_state, 1, 'Should again have passed 1 to _select_state'; 121 | ($sel_state, $init, $no_col) = (-1, 1, 1); 122 | throws_ok { $role->current_state('foo') } qr/OOPS/, 123 | 'curent_state should propagate second error on no-column error'; 124 | is $sel_state, 0, 'Should again have passed 0 to _select_state'; 125 | ($sel_state, $no_table, $init, $no_col) = (-1, 0, 0, 0); 126 | 127 | # Make sure change_id_for returns undef when no useful params. 128 | $mock->mock(dbh => 1); 129 | is $role->change_id_for(project => 'foo'), undef, 130 | 'Should get undef from change_id_for when no useful params'; 131 | } 132 | 133 | done_testing; 134 | -------------------------------------------------------------------------------- /t/die.pl: -------------------------------------------------------------------------------- 1 | use v5.10; 2 | 3 | say "@ARGV" if @ARGV; 4 | die 'OMGWTF'; 5 | 6 | -------------------------------------------------------------------------------- /t/echo.pl: -------------------------------------------------------------------------------- 1 | use 5.010; 2 | 3 | say "@ARGV"; 4 | -------------------------------------------------------------------------------- /t/editor.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | editor = config_specified_editor 4 | -------------------------------------------------------------------------------- /t/engine.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | 4 | [engine "mysql"] 5 | target = db:mysql://root@/foo 6 | client = /usr/sbin/mysql 7 | 8 | [engine "pg"] 9 | target = db:pg:try 10 | registry = meta 11 | client = /usr/sbin/psql 12 | 13 | [engine "sqlite"] 14 | target = widgets 15 | client = /usr/sbin/sqlite3 16 | 17 | [target "widgets"] 18 | uri = db:sqlite:widgets.db 19 | plan_file = foo.plan 20 | 21 | -------------------------------------------------------------------------------- /t/engine/deploy/func/add_user.sql: -------------------------------------------------------------------------------- 1 | -- Deploy func/add_user 2 | -- requires: users 3 | 4 | BEGIN; 5 | 6 | CREATE FUNCTION __myapp.add_user( 7 | nick TEXT, 8 | pass TEXT 9 | ) RETURNS VOID LANGUAGE SQL AS $$ 10 | INSERT INTO __myapp.users VALUES(nick, MD5(pass)); 11 | $$; 12 | 13 | COMMIT; 14 | -------------------------------------------------------------------------------- /t/engine/deploy/users.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | CREATE SCHEMA __myapp; 3 | CREATE TABLE __myapp.users ( 4 | nick TEXT PRIMARY KEY, 5 | name TEXT NOT NULL 6 | ); 7 | -------------------------------------------------------------------------------- /t/engine/deploy/widgets.sql: -------------------------------------------------------------------------------- 1 | -- requires: users 2 | -- conflicts: dr_evil 3 | SET client_min_messages = warning; 4 | CREATE TABLE __myapp.widgets ( 5 | name TEXT PRIMARY KEY, 6 | owner TEXT NOT NULL REFERENCES __myapp.users(nick) 7 | ); 8 | -------------------------------------------------------------------------------- /t/engine/revert/func/add_user.sql: -------------------------------------------------------------------------------- 1 | -- Revert func/add_user 2 | 3 | BEGIN; 4 | 5 | DROP FUNCTION __myapp.add_user(TEXT, TEXT); 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /t/engine/revert/users.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | DROP SCHEMA IF EXISTS __myapp CASCADE; 3 | -------------------------------------------------------------------------------- /t/engine/revert/widgets.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | DROP TABLE IF EXISTS __myapp.widgets; 3 | -------------------------------------------------------------------------------- /t/engine/reworked/deploy/users@alpha.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | CREATE SCHEMA __myapp; 3 | CREATE TABLE __myapp.users ( 4 | nick TEXT PRIMARY KEY, 5 | name TEXT NOT NULL 6 | ); 7 | -------------------------------------------------------------------------------- /t/engine/reworked/revert/users@alpha.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | DROP SCHEMA IF EXISTS __myapp CASCADE; 3 | -------------------------------------------------------------------------------- /t/engine/sqitch.plan: -------------------------------------------------------------------------------- 1 | %project=engine 2 | 3 | + users 2012-07-16T17:25:07Z Barack Obama # User roles 4 | @alpha 2012-07-16T17:25:07Z Barack Obama # Good to go! 5 | + widgets [users !dr_evil] 2012-07-16T17:25:07Z Barack Obama # All in 6 | + func/add_user [users] 2012-10-09T18:28:29Z Barack Obama # Add users. 7 | + users [users@alpha] 2012-10-09T19:28:29Z Barack Obama # Add users. 8 | -------------------------------------------------------------------------------- /t/help.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use utf8; 6 | use Test::More tests => 20; 7 | #use Test::More 'no_plan'; 8 | use App::Sqitch; 9 | use Locale::TextDomain qw(App-Sqitch); 10 | use Test::Exception; 11 | use Test::Warn; 12 | use Config; 13 | use File::Spec; 14 | use Test::MockModule; 15 | use Test::NoWarnings; 16 | use lib 't/lib'; 17 | use TestConfig; 18 | 19 | my $CLASS = 'App::Sqitch::Command::help'; 20 | 21 | ok my $sqitch = App::Sqitch->new, 'Load a sqitch sqitch object'; 22 | my $config = TestConfig->new; 23 | 24 | isa_ok my $help = App::Sqitch::Command->load({ 25 | sqitch => $sqitch, 26 | command => 'help', 27 | config => $config, 28 | }), $CLASS, 'Load help command'; 29 | isa_ok $help, 'App::Sqitch::Command', 'Help command'; 30 | 31 | can_ok $help, qw( 32 | options 33 | execute 34 | find_and_show 35 | ); 36 | 37 | is_deeply [$CLASS->options], [qw( 38 | guide|g 39 | )], 'Options should be correct'; 40 | 41 | warning_is { 42 | Getopt::Long::Configure(qw(bundling pass_through)); 43 | ok Getopt::Long::GetOptionsFromArray( 44 | [], {}, App::Sqitch->_core_opts, $CLASS->options, 45 | ), 'Should parse options'; 46 | } undef, 'Options should not conflict with core options'; 47 | 48 | my $mock = Test::MockModule->new($CLASS); 49 | my @args; 50 | $mock->mock(_pod2usage => sub { @args = @_} ); 51 | 52 | ok $help->execute, 'Execute help'; 53 | is_deeply \@args, [ 54 | $help, 55 | '-input' => Pod::Find::pod_where({'-inc' => 1 }, 'sqitchcommands'), 56 | '-verbose' => 2, 57 | '-exitval' => 0, 58 | ], 'Should show sqitch app docs'; 59 | 60 | ok $help->execute('config'), 'Execute "config" help'; 61 | is_deeply \@args, [ 62 | $help, 63 | '-input' => Pod::Find::pod_where({'-inc' => 1 }, 'sqitch-config'), 64 | '-verbose' => 2, 65 | '-exitval' => 0, 66 | ], 'Should show "config" command docs'; 67 | 68 | ok $help->execute('changes'), 'Execute "changes" help'; 69 | is_deeply \@args, [ 70 | $help, 71 | '-input' => Pod::Find::pod_where({'-inc' => 1 }, 'sqitchchanges'), 72 | '-verbose' => 2, 73 | '-exitval' => 0, 74 | ], 'Should show "changes" command docs'; 75 | 76 | ok $help->execute('tutorial'), 'Execute "tutorial" help'; 77 | is_deeply \@args, [ 78 | $help, 79 | '-input' => Pod::Find::pod_where({'-inc' => 1 }, 'sqitchtutorial'), 80 | '-verbose' => 2, 81 | '-exitval' => 0, 82 | ], 'Should show "tutorial" command docs'; 83 | 84 | my @fail; 85 | $mock->mock(fail => sub { @fail = @_ }); 86 | throws_ok { $help->execute('nonexistent') } 'App::Sqitch::X', 87 | 'Should get an exception for "nonexistent" help'; 88 | is $@->ident, 'help', 'Exception ident should be "help"'; 89 | is $@->message, __x( 90 | 'No manual entry for {command}', 91 | command => 'sqitch-nonexistent', 92 | ), 'Should get failure message for nonexistent command'; 93 | is $@->exitval, 1, 'Exception exit val should be 1'; 94 | -------------------------------------------------------------------------------- /t/lib/App/Sqitch/Command/bad.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Command::bad; 2 | use Moo; 3 | die 'LOL BADZ'; 4 | -------------------------------------------------------------------------------- /t/lib/App/Sqitch/Command/good.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Command::good; 2 | use Moo; 3 | extends 'App::Sqitch::Command'; 4 | 5 | 1; 6 | 7 | =head1 NAME 8 | 9 | good - Good stuff. 10 | 11 | =head1 SYNOPSIS 12 | 13 | 14 | 15 | =head1 DESCRIPTION 16 | 17 | 18 | 19 | =cut 20 | 21 | -------------------------------------------------------------------------------- /t/lib/App/Sqitch/Engine/bad.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Engine::bad; 2 | 3 | die 'LOL BADZ'; 4 | -------------------------------------------------------------------------------- /t/lib/App/Sqitch/Engine/good.pm: -------------------------------------------------------------------------------- 1 | package App::Sqitch::Engine::good; 2 | extends 'App::Sqitch::Engine'; 3 | 1; 4 | 5 | =head1 NAME 6 | 7 | good - Good stuff. 8 | 9 | =head1 SYNOPSIS 10 | 11 | 12 | 13 | =head1 DESCRIPTION 14 | 15 | 16 | 17 | =cut 18 | 19 | -------------------------------------------------------------------------------- /t/lib/LC.pm: -------------------------------------------------------------------------------- 1 | package LC; 2 | 3 | our $TIME = do { 4 | if ($^O eq 'MSWin32') { 5 | require Win32::Locale; 6 | Win32::Locale::get_locale(); 7 | } else { 8 | require POSIX; 9 | POSIX::setlocale( POSIX::LC_TIME() ); 10 | } 11 | }; 12 | 13 | # https://github.com/sqitchers/sqitch/issues/230#issuecomment-103946451 14 | # https://rt.cpan.org/Ticket/Display.html?id=104574 15 | $TIME = 'en_US_POSIX' if $TIME eq 'C.UTF-8'; 16 | 17 | 1; 18 | -------------------------------------------------------------------------------- /t/lib/MockOutput.pm: -------------------------------------------------------------------------------- 1 | package MockOutput; 2 | 3 | use 5.010; 4 | use strict; 5 | use warnings; 6 | use utf8; 7 | use Test::MockModule 0.05; 8 | 9 | our $MOCK = Test::MockModule->new('App::Sqitch'); 10 | 11 | my @mocked = qw( 12 | trace 13 | trace_literal 14 | debug 15 | debug_literal 16 | info 17 | info_literal 18 | comment 19 | comment_literal 20 | emit 21 | emit_literal 22 | vent 23 | vent_literal 24 | warn 25 | warn_literal 26 | page 27 | page_literal 28 | prompt 29 | ask_yes_no 30 | ); 31 | 32 | my $INPUT; 33 | sub prompt_returns { $INPUT = $_[1]; } 34 | 35 | my $Y_N; 36 | sub ask_yes_no_returns { $Y_N = $_[1]; } 37 | 38 | my %CAPTURED; 39 | 40 | __PACKAGE__->clear; 41 | 42 | for my $meth (@mocked) { 43 | $MOCK->mock($meth => sub { 44 | shift; 45 | push @{ $CAPTURED{$meth} } => [@_]; 46 | }); 47 | 48 | my $get = sub { 49 | my $ret = $CAPTURED{$meth}; 50 | $CAPTURED{$meth} = []; 51 | return $ret; 52 | }; 53 | 54 | no strict 'refs'; 55 | *{"get_$meth"} = $get; 56 | } 57 | 58 | $MOCK->mock(prompt => sub { 59 | shift; 60 | push @{ $CAPTURED{prompt} } => [@_]; 61 | return $INPUT; 62 | }); 63 | 64 | $MOCK->mock(ask_yes_no => sub { 65 | shift; 66 | push @{ $CAPTURED{ask_yes_no} } => [@_]; 67 | return $Y_N; 68 | }); 69 | 70 | sub clear { 71 | %CAPTURED = map { $_ => [] } @mocked; 72 | } 73 | 74 | 1; 75 | -------------------------------------------------------------------------------- /t/lib/upgradable_registries/sqlite.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | CREATE TABLE releases ( 4 | version FLOAT PRIMARY KEY, 5 | installed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 6 | installer_name TEXT NOT NULL, 7 | installer_email TEXT NOT NULL 8 | ); 9 | 10 | CREATE TABLE projects ( 11 | project TEXT PRIMARY KEY, 12 | uri TEXT NULL UNIQUE, 13 | created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 14 | creator_name TEXT NOT NULL, 15 | creator_email TEXT NOT NULL 16 | ); 17 | 18 | CREATE TABLE changes ( 19 | change_id TEXT PRIMARY KEY, 20 | change TEXT NOT NULL, 21 | project TEXT NOT NULL REFERENCES projects(project) ON UPDATE CASCADE, 22 | note TEXT NOT NULL DEFAULT '', 23 | committed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 24 | committer_name TEXT NOT NULL, 25 | committer_email TEXT NOT NULL, 26 | planned_at DATETIME NOT NULL, 27 | planner_name TEXT NOT NULL, 28 | planner_email TEXT NOT NULL 29 | ); 30 | 31 | CREATE TABLE tags ( 32 | tag_id TEXT PRIMARY KEY, 33 | tag TEXT NOT NULL, 34 | project TEXT NOT NULL REFERENCES projects(project) ON UPDATE CASCADE, 35 | change_id TEXT NOT NULL REFERENCES changes(change_id) ON UPDATE CASCADE, 36 | note TEXT NOT NULL DEFAULT '', 37 | committed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 38 | committer_name TEXT NOT NULL, 39 | committer_email TEXT NOT NULL, 40 | planned_at DATETIME NOT NULL, 41 | planner_name TEXT NOT NULL, 42 | planner_email TEXT NOT NULL, 43 | UNIQUE(project, tag) 44 | ); 45 | 46 | CREATE TABLE dependencies ( 47 | change_id TEXT NOT NULL REFERENCES changes(change_id) ON UPDATE CASCADE ON DELETE CASCADE, 48 | type TEXT NOT NULL, 49 | dependency TEXT NOT NULL, 50 | dependency_id TEXT NULL REFERENCES changes(change_id) ON UPDATE CASCADE CHECK ( 51 | (type = 'require' AND dependency_id IS NOT NULL) 52 | OR (type = 'conflict' AND dependency_id IS NULL) 53 | ), 54 | PRIMARY KEY (change_id, dependency) 55 | ); 56 | 57 | CREATE TABLE events ( 58 | event TEXT NOT NULL CHECK (event IN ('deploy', 'revert', 'fail')), 59 | change_id TEXT NOT NULL, 60 | change TEXT NOT NULL, 61 | project TEXT NOT NULL REFERENCES projects(project) ON UPDATE CASCADE, 62 | note TEXT NOT NULL DEFAULT '', 63 | requires TEXT NOT NULL DEFAULT '', 64 | conflicts TEXT NOT NULL DEFAULT '', 65 | tags TEXT NOT NULL DEFAULT '', 66 | committed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 67 | committer_name TEXT NOT NULL, 68 | committer_email TEXT NOT NULL, 69 | planned_at DATETIME NOT NULL, 70 | planner_name TEXT NOT NULL, 71 | planner_email TEXT NOT NULL, 72 | PRIMARY KEY (change_id, committed_at) 73 | ); 74 | 75 | COMMIT; 76 | -------------------------------------------------------------------------------- /t/lib/upgradable_registries/vertica.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA :"registry"; 2 | 3 | COMMENT ON SCHEMA :"registry" IS 'Sqitch database deployment metadata v1.0.'; 4 | 5 | CREATE TABLE :"registry".releases ( 6 | version FLOAT PRIMARY KEY ENABLED, 7 | installed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 8 | installer_name VARCHAR(1024) NOT NULL, 9 | installer_email VARCHAR(1024) NOT NULL 10 | ); 11 | 12 | COMMENT ON TABLE :"registry".releases IS 'Sqitch registry releases.'; 13 | 14 | CREATE TABLE :"registry".projects ( 15 | project VARCHAR(1024) PRIMARY KEY ENABLED ENCODING AUTO, 16 | uri VARCHAR(1024) NULL UNIQUE ENABLED, 17 | created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 18 | creator_name VARCHAR(1024) NOT NULL, 19 | creator_email VARCHAR(1024) NOT NULL 20 | ); 21 | 22 | COMMENT ON TABLE :"registry".projects IS 'Sqitch projects deployed to this database.'; 23 | 24 | CREATE TABLE :"registry".changes ( 25 | change_id CHAR(40) PRIMARY KEY ENABLED ENCODING AUTO, 26 | change VARCHAR(1024) NOT NULL, 27 | project VARCHAR(1024) NOT NULL REFERENCES :"registry".projects(project), 28 | note VARCHAR(65000) NOT NULL DEFAULT '', 29 | committed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 30 | committer_name VARCHAR(1024) NOT NULL, 31 | committer_email VARCHAR(1024) NOT NULL, 32 | planned_at TIMESTAMPTZ NOT NULL, 33 | planner_name VARCHAR(1024) NOT NULL, 34 | planner_email VARCHAR(1024) NOT NULL 35 | ); 36 | 37 | COMMENT ON TABLE :"registry".changes IS 'Tracks the changes currently deployed to the database.'; 38 | 39 | CREATE TABLE :"registry".tags ( 40 | tag_id CHAR(40) PRIMARY KEY ENABLED ENCODING AUTO, 41 | tag VARCHAR(1024) NOT NULL, 42 | project VARCHAR(1024) NOT NULL REFERENCES :"registry".projects(project), 43 | change_id CHAR(40) NOT NULL REFERENCES :"registry".changes(change_id), 44 | note VARCHAR(65000) NOT NULL DEFAULT '', 45 | committed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 46 | committer_name VARCHAR(1024) NOT NULL, 47 | committer_email VARCHAR(1024) NOT NULL, 48 | planned_at TIMESTAMPTZ NOT NULL, 49 | planner_name VARCHAR(1024) NOT NULL, 50 | planner_email VARCHAR(1024) NOT NULL, 51 | UNIQUE(project, tag) ENABLED 52 | ); 53 | 54 | COMMENT ON TABLE :"registry".tags IS 'Tracks the tags currently applied to the database.'; 55 | 56 | CREATE TABLE :"registry".dependencies ( 57 | change_id CHAR(40) NOT NULL REFERENCES :"registry".changes(change_id), 58 | type VARCHAR(8) NOT NULL ENCODING AUTO, 59 | dependency VARCHAR(2048) NOT NULL, 60 | dependency_id CHAR(40) NULL REFERENCES :"registry".changes(change_id), 61 | PRIMARY KEY (change_id, dependency) ENABLED 62 | ); 63 | 64 | COMMENT ON TABLE :"registry".dependencies IS 'Tracks the currently satisfied dependencies.'; 65 | 66 | CREATE TABLE :"registry".events ( 67 | event VARCHAR(6) NOT NULL ENCODING AUTO, 68 | change_id CHAR(40) NOT NULL, 69 | change VARCHAR(1024) NOT NULL, 70 | project VARCHAR(1024) NOT NULL REFERENCES :"registry".projects(project), 71 | note VARCHAR(65000) NOT NULL DEFAULT '', 72 | requires LONG VARCHAR NOT NULL DEFAULT '{}', 73 | conflicts LONG VARCHAR NOT NULL DEFAULT '{}', 74 | tags LONG VARCHAR NOT NULL DEFAULT '{}', 75 | committed_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), 76 | committer_name VARCHAR(1024) NOT NULL, 77 | committer_email VARCHAR(1024) NOT NULL, 78 | planned_at TIMESTAMPTZ NOT NULL, 79 | planner_name VARCHAR(1024) NOT NULL, 80 | planner_email VARCHAR(1024) NOT NULL, 81 | PRIMARY KEY (change_id, committed_at) ENABLED 82 | ); 83 | 84 | COMMENT ON TABLE :"registry".events IS 'Contains full history of all deployment events.'; 85 | -------------------------------------------------------------------------------- /t/linelist.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use 5.010; 6 | use utf8; 7 | use Test::More tests => 28; 8 | #use Test::More 'no_plan'; 9 | use Test::NoWarnings; 10 | use Test::Exception; 11 | use App::Sqitch; 12 | use App::Sqitch::Target; 13 | use App::Sqitch::Plan; 14 | use lib 't/lib'; 15 | use TestConfig; 16 | 17 | BEGIN { require_ok 'App::Sqitch::Plan::LineList' or die } 18 | 19 | my $sqitch = App::Sqitch->new(config => TestConfig->new('core.engine' => 'sqlite')); 20 | my $target = App::Sqitch::Target->new(sqitch => $sqitch); 21 | my $plan = App::Sqitch::Plan->new(sqitch => $sqitch, target => $target); 22 | 23 | my $foo = App::Sqitch::Plan::Change->new(plan => $plan, name => 'foo'); 24 | my $bar = App::Sqitch::Plan::Change->new(plan => $plan, name => 'bar'); 25 | my $baz = App::Sqitch::Plan::Change->new(plan => $plan, name => 'baz'); 26 | my $yo1 = App::Sqitch::Plan::Change->new(plan => $plan, name => 'yo'); 27 | my $yo2 = App::Sqitch::Plan::Change->new(plan => $plan, name => 'yo'); 28 | 29 | my $blank = App::Sqitch::Plan::Blank->new(plan => $plan); 30 | my $alpha = App::Sqitch::Plan::Tag->new( 31 | plan => $plan, 32 | change => $yo1, 33 | name => 'alpha', 34 | ); 35 | 36 | my $lines = App::Sqitch::Plan::LineList->new( 37 | $foo, 38 | $bar, 39 | $yo1, 40 | $alpha, 41 | $blank, 42 | $baz, 43 | $yo2, 44 | ); 45 | 46 | is $lines->count, 7, 'Count should be six'; 47 | is_deeply [$lines->items], [$foo, $bar, $yo1, $alpha, $blank, $baz, $yo2], 48 | 'Lines should be in order'; 49 | is $lines->item_at(0), $foo, 'Should have foo at 0'; 50 | is $lines->item_at(1), $bar, 'Should have bar at 1'; 51 | is $lines->item_at(2), $yo1, 'Should have yo1 at 2'; 52 | is $lines->item_at(3), $alpha, 'Should have @alpha at 3'; 53 | is $lines->item_at(4), $blank, 'Should have blank at 4'; 54 | is $lines->item_at(5), $baz, 'Should have baz at 5'; 55 | is $lines->item_at(6), $yo2, 'Should have yo2 at 6'; 56 | 57 | is $lines->index_of('non'), undef, 'Should not find "non"'; 58 | is $lines->index_of($foo), 0, 'Should find foo at 0'; 59 | is $lines->index_of($bar), 1, 'Should find bar at 1'; 60 | is $lines->index_of($yo1), 2, 'Should find yo1 at 2'; 61 | is $lines->index_of($alpha), 3, 'Should find @alpha at 3'; 62 | is $lines->index_of($blank), 4, 'Should find blank at 4'; 63 | is $lines->index_of($baz), 5, 'Should find baz at 5'; 64 | is $lines->index_of($yo2), 6, 'Should find yo2 at 6'; 65 | 66 | my $hi = App::Sqitch::Plan::Change->new(plan => $plan, name => 'hi'); 67 | ok $lines->append($hi), 'Append hi'; 68 | is $lines->count, 8, 'Count should now be eight'; 69 | is_deeply [$lines->items], [$foo, $bar, $yo1, $alpha, $blank, $baz, $yo2, $hi], 70 | 'Lines should be in order with $hi at the end'; 71 | 72 | # Try inserting. 73 | my $oy = App::Sqitch::Plan::Change->new(plan => $plan, name => 'oy'); 74 | ok $lines->insert_at($oy, 3), 'Insert a change at index 3'; 75 | is $lines->count, 9, 'Count should now be nine'; 76 | is_deeply [$lines->items], [$foo, $bar, $yo1, $oy, $alpha, $blank, $baz, $yo2, $hi], 77 | 'Lines should be in order with $oy at index 3'; 78 | is $lines->index_of($oy), 3, 'Should find oy at 3'; 79 | is $lines->index_of($alpha), 4, 'Should find @alpha at 4'; 80 | is $lines->index_of($hi), 8, 'Should find hi at 8'; 81 | 82 | -------------------------------------------------------------------------------- /t/local.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | 4 | [engine "pg"] 5 | target = mydb 6 | 7 | [engine "sqlite"] 8 | target = devdb 9 | 10 | [target "devdb"] 11 | uri = db:sqlite: 12 | 13 | [target "mydb"] 14 | uri = db:pg:mydb 15 | plan_file = t/plans/dependencies.plan 16 | -------------------------------------------------------------------------------- /t/mooseless.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use utf8; 6 | 7 | use Test::More; 8 | use File::Find qw(find); 9 | use Module::Runtime qw(use_module); 10 | 11 | my $test = sub { 12 | return unless $_ =~ /\.pm$/; 13 | 14 | my $module = $File::Find::name; 15 | $module =~ s!^(blib[/\\])?lib[/\\]!!; 16 | $module =~ s![/\\]!::!g; 17 | $module =~ s/\.pm$//; 18 | 19 | eval { use_module $module; }; 20 | if ($@) { 21 | diag "Couldn't load $module: $@"; 22 | undef $@; 23 | return; 24 | } 25 | 26 | ok ! $INC{'Moose.pm'}, "No moose in $module"; 27 | }; 28 | 29 | find($test, 'lib'); 30 | 31 | done_testing(); 32 | -------------------------------------------------------------------------------- /t/multiplan.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | 4 | [engine "pg"] 5 | top_dir = engine 6 | reworked_dir = engine/reworked 7 | 8 | [engine "sqlite"] 9 | top_dir = engine 10 | reworked_dir = engine/reworked 11 | 12 | [engine "mysql"] 13 | top_dir = sql 14 | -------------------------------------------------------------------------------- /t/odbc/odbcinst.ini: -------------------------------------------------------------------------------- 1 | [Exasol] 2 | Description = ODBC for Exasol 3 | Driver = /opt/exasol/lib/libexaodbc.so 4 | 5 | [Vertica] 6 | Description = ODBC for Vertica 7 | Driver = /opt/vertica/lib64/libverticaodbc.so 8 | 9 | [Snowflake] 10 | Description = ODBC for Snowflake 11 | Driver = /opt/snowflake/lib/libSnowflake.so 12 | -------------------------------------------------------------------------------- /t/odbc/snowflake.ini: -------------------------------------------------------------------------------- 1 | [ODBC Data Sources] 2 | sqitch = Snowflake 3 | 4 | [sqitch] 5 | Driver = /opt/snowflake/lib/libSnowflake.so 6 | ACCOUNT = YOHTWZV-ZSA24461 7 | AUTHENTICATOR = SNOWFLAKE_JWT 8 | PRIV_KEY_FILE = /opt/snowflake/rsa_key.p8 9 | PRIV_KEY_FILE_PWD = KEY_PASSWORD 10 | -------------------------------------------------------------------------------- /t/odbc/vertica.ini: -------------------------------------------------------------------------------- 1 | [Driver] 2 | DriverManagerEncoding=UTF-16 3 | ODBCInstLib=/usr/lib/x86_64-linux-gnu/libodbcinst.so 4 | ErrorMessagesPath=/opt/vertica/lib64 5 | -------------------------------------------------------------------------------- /t/plans/bad-change.plan: -------------------------------------------------------------------------------- 1 | %project=bad_change 2 | # This is a note 3 | 4 | # And there was a blank line. 5 | what what what 2012-07-16T17:25:07Z Barack Obama # OHNOEZ, No white space allowed! 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /t/plans/changes-only.plan: -------------------------------------------------------------------------------- 1 | %project=changes_only 2 | # This is a note 3 | 4 | # And there was a blank line. 5 | 6 | hey 2012-07-16T17:25:07Z Barack Obama 7 | you 2012-07-16T17:25:07Z Barack Obama 8 | whatwhatwhat 2012-07-16T17:25:07Z Barack Obama 9 | -------------------------------------------------------------------------------- /t/plans/dependencies.plan: -------------------------------------------------------------------------------- 1 | %project=dependencies 2 | 3 | +roles 2012-07-16T17:25:07Z Barack Obama 4 | +users [roles] 2012-07-16T17:25:07Z Barack Obama 5 | +add_user [users roles] 2012-07-16T17:25:07Z Barack Obama 6 | +dr_evil 2012-07-16T17:25:07Z Barack Obama 7 | @alpha 2012-07-16T17:25:07Z Barack Obama 8 | 9 | +users [users@alpha] 2012-07-16T17:25:07Z Barack Obama 10 | -dr_evil 2012-07-16T17:25:07Z Barack Obama 11 | +del_user [!dr_evil users] 2012-07-16T17:25:07Z Barack Obama 12 | 13 | -------------------------------------------------------------------------------- /t/plans/deploy-and-revert.plan: -------------------------------------------------------------------------------- 1 | %project=deploy_and_revert 2 | 3 | +hey 2012-07-16T17:25:07Z Barack Obama 4 | +you 2012-07-16T17:25:07Z Barack Obama 5 | + dr_evil 2012-07-16T17:25:07Z Barack Obama 6 | @foo 2012-07-16T17:25:07Z Barack Obama 7 | 8 | +this/rocks 2012-07-16T17:25:07Z Barack Obama 9 | hey-there 2012-07-16T17:25:07Z Barack Obama 10 | -dr_evil 2012-07-16T17:25:07Z Barack Obama # revert! 11 | @bar 2012-07-16T17:25:07Z Barack Obama 12 | -------------------------------------------------------------------------------- /t/plans/dos.plan: -------------------------------------------------------------------------------- 1 | %project=dos 2 | # This is a note 3 | 4 | # And there was a blank line. 5 | 6 | hey 2012-07-16T17:25:07Z Barack Obama 7 | you 2012-07-16T17:25:07Z Barack Obama 8 | whatwhatwhat 2012-07-16T17:25:07Z Barack Obama 9 | -------------------------------------------------------------------------------- /t/plans/dupe-change-diff-tag.plan: -------------------------------------------------------------------------------- 1 | %project=dupe_change_diff_tag 2 | 3 | whatever 2012-07-16T17:25:07Z Barack Obama 4 | @foo 2012-07-16T17:25:07Z Barack Obama 5 | 6 | hi 2012-07-16T17:25:07Z Barack Obama 7 | @bar 2012-07-16T17:25:07Z Barack Obama 8 | 9 | greets 2012-07-16T17:25:07Z Barack Obama 10 | whatever 2012-07-16T17:25:07Z Barack Obama 11 | -------------------------------------------------------------------------------- /t/plans/dupe-change.plan: -------------------------------------------------------------------------------- 1 | %project=dupe_change 2 | 3 | whatever 2012-07-16T17:25:07Z Barack Obama 4 | @foo 2012-07-16T17:25:07Z Barack Obama 5 | 6 | hi 2012-07-16T17:25:07Z Barack Obama 7 | greets 2012-07-16T17:25:07Z Barack Obama 8 | tallyho 2012-07-16T17:25:07Z Barack Obama 9 | greets 2012-07-16T17:25:07Z Barack Obama 10 | @bar 2012-07-16T17:25:07Z Barack Obama 11 | -------------------------------------------------------------------------------- /t/plans/dupe-tag.plan: -------------------------------------------------------------------------------- 1 | %project=dupe_tag 2 | 3 | whatever 2012-07-16T17:25:07Z Barack Obama 4 | @foo 2012-07-16T17:25:07Z Barack Obama 5 | 6 | hi 2012-07-16T17:25:07Z Barack Obama 7 | @bar 2012-07-16T17:25:07Z Barack Obama 8 | 9 | @stink 2012-07-16T17:25:07Z Barack Obama 10 | 11 | @blah 2012-07-16T17:25:07Z Barack Obama 12 | @bar 2012-07-16T17:25:07Z Barack Obama 13 | @w00t 2012-07-16T17:25:07Z Barack Obama 14 | OHNOEZ 2012-07-16T17:25:07Z Barack Obama 15 | -------------------------------------------------------------------------------- /t/plans/multi.plan: -------------------------------------------------------------------------------- 1 | %project=multi 2 | # This is a note 3 | 4 | # And there was a blank line. 5 | 6 | hey 2012-07-16T17:25:07Z theory 7 | you 2012-07-16T17:25:07Z anna 8 | @foo 2012-07-16T17:24:07Z julie # look, a tag! 9 | 10 | this/rocks 2012-07-16T17:25:07Z Barack Obama 11 | hey-there 2012-07-16T17:25:07Z Barack Obama # trailing note! 12 | @bar 2012-07-16T17:25:07Z Barack Obama 13 | @baz 2012-07-16T17:25:07Z Barack Obama 14 | -------------------------------------------------------------------------------- /t/plans/pragmas.plan: -------------------------------------------------------------------------------- 1 | % syntax-version=1.0.0 2 | %foo = bar # lolz 3 | % project=pragmata 4 | % uri=https://github.com/sqitchers/sqitch/ 5 | % strict 6 | 7 | hey 2012-07-16T17:25:07Z Barack Obama 8 | you 2012-07-16T17:25:07Z Barack Obama 9 | 10 | -------------------------------------------------------------------------------- /t/plans/project_deps.plan: -------------------------------------------------------------------------------- 1 | %project=dependencies 2 | 3 | +roles 2012-07-16T17:25:07Z Barack Obama 4 | +users [roles] 2012-07-16T17:25:07Z Barack Obama 5 | +add_user [users roles log:logger] 2012-07-16T17:25:07Z Barack Obama 6 | +dr_evil 2012-07-16T17:25:07Z Barack Obama 7 | @alpha 2012-07-16T17:25:07Z Barack Obama 8 | 9 | +users [users@alpha] 2012-07-16T17:25:07Z Barack Obama 10 | -dr_evil 2012-07-16T17:25:07Z Barack Obama 11 | +del_user [!dr_evil users log:logger@beta1] 2012-07-16T17:25:07Z Barack Obama 12 | 13 | -------------------------------------------------------------------------------- /t/plans/reserved-tag.plan: -------------------------------------------------------------------------------- 1 | %project=reserved_tag 2 | 3 | hey 2012-07-16T17:25:07Z Barack Obama 4 | @foo 2012-07-16T17:25:07Z Barack Obama 5 | 6 | @bar 2012-07-16T17:25:07Z Barack Obama 7 | @HEAD 2012-07-16T17:25:07Z Barack Obama 8 | @whatever 2012-07-16T17:25:07Z Barack Obama 9 | ruh-roh 2012-07-16T17:25:07Z Barack Obama 10 | 11 | -------------------------------------------------------------------------------- /t/plans/widgets.plan: -------------------------------------------------------------------------------- 1 | %project=widgets 2 | # This is a note 3 | 4 | # And there was a blank line. 5 | 6 | hey 2012-07-16T14:01:20Z Barack Obama 7 | you 2012-07-16T14:01:35Z Barack Obama 8 | @foo 2012-07-16T14:02:05Z Barack Obama # look, a tag! 9 | -------------------------------------------------------------------------------- /t/pragma.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use 5.010; 6 | use utf8; 7 | use Test::More tests => 10; 8 | #use Test::More 'no_plan'; 9 | use Test::NoWarnings; 10 | use App::Sqitch; 11 | use App::Sqitch::Target; 12 | use App::Sqitch::Plan; 13 | use lib 't/lib'; 14 | use TestConfig; 15 | 16 | my $CLASS; 17 | 18 | BEGIN { 19 | $CLASS = 'App::Sqitch::Plan::Pragma'; 20 | require_ok $CLASS or die; 21 | } 22 | 23 | can_ok $CLASS, qw( 24 | name 25 | lspace 26 | rspace 27 | hspace 28 | ropspace 29 | lopspace 30 | note 31 | plan 32 | value 33 | ); 34 | 35 | my $config = TestConfig->new('core.engine' => 'sqlite'); 36 | my $sqitch = App::Sqitch->new(config => $config); 37 | my $target = App::Sqitch::Target->new(sqitch => $sqitch); 38 | my $plan = App::Sqitch::Plan->new(sqitch => $sqitch, target => $target); 39 | isa_ok my $dir = $CLASS->new( 40 | name => 'foo', 41 | plan => $plan, 42 | ), $CLASS; 43 | isa_ok $dir, 'App::Sqitch::Plan::Line'; 44 | 45 | is $dir->format_name, '%foo', 'Name should format as "%foo"'; 46 | is $dir->format_value, '', 'Value should format as ""'; 47 | is $dir->as_string, '%foo', 'should stringify to "%foo"'; 48 | 49 | ok $dir = $CLASS->new( 50 | name => 'howdy', 51 | value => 'woody', 52 | plan => $plan, 53 | lspace => ' ', 54 | hspace => ' ', 55 | rspace => "\t", 56 | lopspace => ' ', 57 | operator => '=', 58 | ropspace => ' ', 59 | note => 'blah blah blah', 60 | ), 'Create pragma with more stuff'; 61 | 62 | is $dir->as_string, " % howdy = woody\t# blah blah blah", 63 | 'It should stringify correctly'; 64 | -------------------------------------------------------------------------------- /t/read.pl: -------------------------------------------------------------------------------- 1 | use 5.010; 2 | 3 | print while ; 4 | -------------------------------------------------------------------------------- /t/rework.conf: -------------------------------------------------------------------------------- 1 | [rework] 2 | open_editor = true 3 | -------------------------------------------------------------------------------- /t/sqitch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl -CAS 2 | 3 | use locale; 4 | use FindBin; 5 | use lib "$FindBin::Bin/../lib"; 6 | use App::Sqitch; 7 | 8 | exit App::Sqitch->go; 9 | -------------------------------------------------------------------------------- /t/sqitch.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | uri = https://github.com/sqitchers/sqitch/ 3 | engine = pg 4 | top_dir = migrations 5 | extension = ddl 6 | pager = less -r 7 | 8 | [engine "pg"] 9 | client = /usr/local/pgsql/bin/psql 10 | 11 | [revert] 12 | to = gamma 13 | count = 2 14 | revision = 1.1 15 | 16 | [bundle] 17 | from = gamma 18 | tags_only = true 19 | dest_dir = _build/sql 20 | [foo "BAR"] 21 | baz = hello 22 | yep 23 | [guess "Yes.No"] 24 | red = true 25 | Calico = false 26 | -------------------------------------------------------------------------------- /t/sql/deploy/curry.sql: -------------------------------------------------------------------------------- 1 | -- Just for curry. 2 | -------------------------------------------------------------------------------- /t/sql/deploy/dr_evil.sql: -------------------------------------------------------------------------------- 1 | -- Dr. Evil. 2 | -------------------------------------------------------------------------------- /t/sql/deploy/lolz.sql: -------------------------------------------------------------------------------- 1 | -- Just for the lolz 2 | -------------------------------------------------------------------------------- /t/sql/deploy/oops.sql: -------------------------------------------------------------------------------- 1 | -- Has no corresponding revert script. 2 | -------------------------------------------------------------------------------- /t/sql/deploy/roles.sql: -------------------------------------------------------------------------------- 1 | -- Create roles. -------------------------------------------------------------------------------- /t/sql/deploy/tacos.sql: -------------------------------------------------------------------------------- 1 | -- Just for tacos. 2 | -------------------------------------------------------------------------------- /t/sql/deploy/users.sql: -------------------------------------------------------------------------------- 1 | -- Create users. 2 | -- requires: roles 3 | -------------------------------------------------------------------------------- /t/sql/deploy/widgets.sql: -------------------------------------------------------------------------------- 1 | -- Create widgets. 2 | -- requires: users 3 | -------------------------------------------------------------------------------- /t/sql/revert/curry.sql: -------------------------------------------------------------------------------- 1 | -- Just for curry. 2 | -------------------------------------------------------------------------------- /t/sql/revert/dr_evil.sql: -------------------------------------------------------------------------------- 1 | -- Dr. Evil. 2 | -------------------------------------------------------------------------------- /t/sql/revert/lolz.sql: -------------------------------------------------------------------------------- 1 | -- Just for the lolz 2 | -------------------------------------------------------------------------------- /t/sql/revert/roles.sql: -------------------------------------------------------------------------------- 1 | -- Remove roles. -------------------------------------------------------------------------------- /t/sql/revert/tacos.sql: -------------------------------------------------------------------------------- 1 | -- Just for tacos. 2 | -------------------------------------------------------------------------------- /t/sql/revert/users.sql: -------------------------------------------------------------------------------- 1 | -- Remove users. 2 | -------------------------------------------------------------------------------- /t/sql/revert/widgets.sql: -------------------------------------------------------------------------------- 1 | -- Remove widgets. 2 | -------------------------------------------------------------------------------- /t/sql/sqitch.plan: -------------------------------------------------------------------------------- 1 | %project=sql 2 | 3 | roles 2012-07-16T17:25:07Z Barack Obama 4 | users 2012-07-16T17:25:07Z Barack Obama 5 | @alpha 2012-07-16T17:25:07Z Barack Obama 6 | 7 | widgets 2012-07-16T17:25:07Z Barack Obama 8 | @beta 2012-07-16T17:25:07Z Barack Obama 9 | -------------------------------------------------------------------------------- /t/sql/verify/users.sql: -------------------------------------------------------------------------------- 1 | SELECT nick, name FROM __myapp.users WHERE FALSE; 2 | -------------------------------------------------------------------------------- /t/target.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | 4 | [target "dev"] 5 | uri = db:pg:widgets 6 | 7 | [target "qa"] 8 | uri = db:pg://qa.example.com/qa_widgets 9 | registry = meta 10 | client = /usr/sbin/psql 11 | 12 | [target "prod"] 13 | uri = db:pg://prod.example.us/pr_widgets 14 | -------------------------------------------------------------------------------- /t/templates.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | 4 | [add "templates"] 5 | deploy = etc/templates/deploy/pg.tmpl 6 | revert = etc/templates/revert/pg.tmpl 7 | test = etc/templates/verify/pg.tmpl 8 | verify = etc/templates/verify/pg.tmpl 9 | 10 | -------------------------------------------------------------------------------- /t/upgrade.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use utf8; 6 | use Test::More tests => 25; 7 | #use Test::More 'no_plan'; 8 | use App::Sqitch; 9 | use Locale::TextDomain qw(App-Sqitch); 10 | use Test::NoWarnings; 11 | use Test::Exception; 12 | use Test::Warn; 13 | use Test::MockModule; 14 | use Path::Class; 15 | use lib 't/lib'; 16 | use MockOutput; 17 | use TestConfig; 18 | 19 | my $CLASS = 'App::Sqitch::Command::upgrade'; 20 | require_ok $CLASS; 21 | 22 | my $config = TestConfig->new( 23 | 'core.engine' => 'sqlite', 24 | 'core.top_dir' => dir->new('test-upgrade')->stringify, 25 | ); 26 | ok my $sqitch = App::Sqitch->new(config => $config), 'Load a sqitch object'; 27 | isa_ok my $upgrade = App::Sqitch::Command->load({ 28 | sqitch => $sqitch, 29 | command => 'upgrade', 30 | config => $config, 31 | }), $CLASS, 'upgrade command'; 32 | 33 | can_ok $upgrade, qw( 34 | target 35 | options 36 | execute 37 | configure 38 | does 39 | ); 40 | 41 | ok $CLASS->does("App::Sqitch::Role::ConnectingCommand"), 42 | "$CLASS does ConnectingCommand"; 43 | 44 | is_deeply [ $CLASS->options ], [qw( 45 | target|t=s 46 | registry=s 47 | client|db-client=s 48 | db-name|d=s 49 | db-user|db-username|u=s 50 | db-host|h=s 51 | db-port|p=i 52 | )], 'Options should be correct'; 53 | 54 | warning_is { 55 | Getopt::Long::Configure(qw(bundling pass_through)); 56 | ok Getopt::Long::GetOptionsFromArray( 57 | [], {}, App::Sqitch->_core_opts, $CLASS->options, 58 | ), 'Should parse options'; 59 | } undef, 'Options should not conflict with core options'; 60 | 61 | # Start with the engine up-to-date. 62 | my $engine_mocker = Test::MockModule->new('App::Sqitch::Engine::sqlite'); 63 | my $registry_version = App::Sqitch::Engine->registry_release; 64 | my $upgrade_called = 0; 65 | $engine_mocker->mock(registry_version => sub { $registry_version }); 66 | $engine_mocker->mock(upgrade_registry => sub { $upgrade_called = 1 }); 67 | 68 | ok $upgrade->execute, 'Execute upgrade'; 69 | ok !$upgrade_called, 'Upgrade should not have been called'; 70 | is_deeply +MockOutput->get_info, [[__x( 71 | 'Registry {registry} is up-to-date at version {version}', 72 | registry => 'db:sqlite:', 73 | version => App::Sqitch::Engine->registry_release, 74 | )]], 'Should get output for up-to-date registry'; 75 | 76 | # Pass in a different target. 77 | ok $upgrade->execute('db:sqlite:foo.db'), 'Execute upgrade with target'; 78 | ok !$upgrade_called, 'Upgrade should again not have been called'; 79 | is_deeply +MockOutput->get_info, [[__x( 80 | 'Registry {registry} is up-to-date at version {version}', 81 | registry => 'db:sqlite:sqitch.db', 82 | version => App::Sqitch::Engine->registry_release, 83 | )]], 'Should get output for up-to-date registry with target'; 84 | 85 | # Pass in an engine. 86 | ok $upgrade->execute('sqlite'), 'Execute upgrade with engine'; 87 | ok !$upgrade_called, 'Upgrade should again not have been called'; 88 | is_deeply +MockOutput->get_info, [[__x( 89 | 'Registry {registry} is up-to-date at version {version}', 90 | registry => 'db:sqlite:', 91 | version => App::Sqitch::Engine->registry_release, 92 | )]], 'Should get output for up-to-date registry with target'; 93 | 94 | # Specify a target as an option. 95 | isa_ok $upgrade = App::Sqitch::Command->load({ 96 | sqitch => $sqitch, 97 | command => 'upgrade', 98 | config => $config, 99 | args => [qw(--target db:sqlite:my.sqlite)], 100 | }), $CLASS, 'upgrade command with target'; 101 | 102 | ok $upgrade->execute, 'Execute upgrade with target option'; 103 | ok !$upgrade_called, 'Upgrade should still not have been called'; 104 | is_deeply +MockOutput->get_info, [[__x( 105 | 'Registry {registry} is up-to-date at version {version}', 106 | registry => 'db:sqlite:sqitch.sqlite', 107 | version => App::Sqitch::Engine->registry_release, 108 | )]], 'Should get output for up-to-date registry with target option'; 109 | 110 | # Now make it upgrade. 111 | $registry_version = 0.1; 112 | ok $upgrade->execute, 'Execute upgrade with out-of-date registry'; 113 | ok $upgrade_called, 'Upgrade should now have been called'; 114 | is_deeply +MockOutput->get_info, [[__x( 115 | 'Upgrading registry {registry} to version {version}', 116 | registry => 'db:sqlite:sqitch.sqlite', 117 | version => App::Sqitch::Engine->registry_release, 118 | )]], 'Should get output for the upgrade'; 119 | -------------------------------------------------------------------------------- /t/user.conf: -------------------------------------------------------------------------------- 1 | [user] 2 | name = Michael Stonebraker 3 | email = michael@example.com 4 | 5 | [engine "pg"] 6 | client = /opt/local/pgsql/bin/psql 7 | target = db:pg://postgres@localhost/thingies 8 | registry = meta 9 | 10 | [engine "mysql"] 11 | client = /opt/local/mysql/bin/mysql 12 | registry = meta 13 | 14 | [engine "mysql.variables"] 15 | prefix = foo_ 16 | 17 | [engine "sqlite"] 18 | client = /opt/local/bin/sqlite3 19 | registry = meta 20 | target = db:sqlite:my.db 21 | 22 | [engine "firebird"] 23 | client = /opt/firebird/bin/isql 24 | registry = meta 25 | -------------------------------------------------------------------------------- /t/win32.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # local *main::^O; 4 | BEGIN { 5 | $^O = 'MSWin32'; 6 | } 7 | 8 | use strict; 9 | use warnings; 10 | use Test::More tests => 2; 11 | use Try::Tiny; 12 | use App::Sqitch::ItemFormatter; 13 | 14 | is $^O, 'MSWin32', 'Should have "MSWin32"'; 15 | is App::Sqitch::ItemFormatter::CAN_OUTPUT_COLOR, 16 | try { require Win32::Console::ANSI }, 17 | 'CAN_OUTPUT_COLOR should be set properly'; 18 | -------------------------------------------------------------------------------- /t/x.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use Test::More; 5 | use Test::Exception; 6 | use Try::Tiny; 7 | use Path::Class; 8 | use lib 't/lib'; 9 | use TestConfig; 10 | 11 | my $CLASS; 12 | BEGIN { 13 | $CLASS = 'App::Sqitch::X'; 14 | require_ok $CLASS or die; 15 | $CLASS->import(':all'); 16 | } 17 | 18 | isa_ok my $x = $CLASS->new(ident => 'test', message => 'Die'), $CLASS, 'X object'; 19 | 20 | for my $role(qw( 21 | Throwable 22 | StackTrace::Auto 23 | )) { 24 | ok $x->does($role), "X object does $role"; 25 | } 26 | 27 | # Make sure default ident works. 28 | ok $x = $CLASS->new(message => 'whatever'), 'Create X without ident'; 29 | is $x->ident, 'DEV', 'Default ident should be "DEV"'; 30 | 31 | throws_ok { hurl basic => 'OMFG!' } $CLASS; 32 | isa_ok $x = $@, $CLASS, 'Thrown object'; 33 | is $x->ident, 'basic', 'Ident should be "basic"'; 34 | is $x->message, 'OMFG!', 'The message should have been passed'; 35 | ok $x->stack_trace->frames, 'It should have a stack trace'; 36 | is $x->exitval, 2, 'Exit val should be 2'; 37 | is +($x->stack_trace->frames)[0]->filename, file(qw(t x.t)), 38 | 'The trace should start in this file'; 39 | 40 | # NB: Don't use `local $@`, as it does not work on Perls < 5.14. 41 | throws_ok { $@ = 'Yo dawg'; hurl 'OMFG!' } $CLASS; 42 | isa_ok $x = $@, $CLASS, 'Thrown object'; 43 | is $x->ident, 'DEV', 'Ident should be "DEV"'; 44 | is $x->message, 'OMFG!', 'The message should have been passed'; 45 | is $x->exitval, 2, 'Exit val should again be 2'; 46 | is $x->previous_exception, 'Yo dawg', 47 | 'Previous exception should have been passed'; 48 | is $x->as_string, join("\n", 49 | $x->message, 50 | $x->previous_exception, 51 | $x->stack_trace 52 | ), 'Stringification should work'; 53 | 54 | is $x->as_string, "$x", 'Stringification should work'; 55 | 56 | is $x->details_string, join("\n", 57 | $x->previous_exception, 58 | $x->stack_trace 59 | ), 'Details string should work'; 60 | 61 | throws_ok { hurl {ident => 'blah', message => 'OMFG!', exitval => 1} } $CLASS; 62 | isa_ok $x = $@, $CLASS, 'Thrown object'; 63 | is $x->message, 'OMFG!', 'The params should have been passed'; 64 | is $x->exitval, 1, 'Exit val should be 1'; 65 | is $x->as_string, join("\n", 66 | $x->message, 67 | $x->stack_trace 68 | ), 'Stringification should work'; 69 | 70 | is $x->as_string, "$x", 'Stringification should work'; 71 | 72 | is $x->details_string, join("\n", 73 | $x->stack_trace 74 | ), 'Details string should work'; 75 | 76 | # Do some actual exception handling. 77 | try { 78 | hurl io => 'Cannot open file'; 79 | } catch { 80 | return fail "Not a Sqitch::X: $_" unless eval { $_->isa('App::Sqitch::X') }; 81 | is $_->ident, 'io', 'Should be an "io" exception'; 82 | }; 83 | 84 | # Make sure we can goto hurl. 85 | try { 86 | @_ = (io => 'Cannot open file'); 87 | goto &hurl; 88 | } catch { 89 | return fail "Not a Sqitch::X: $_" unless eval { $_->isa('App::Sqitch::X') }; 90 | is $_->ident, 'io', 'Should catch error called via &goto'; 91 | }; 92 | 93 | done_testing; 94 | -------------------------------------------------------------------------------- /xt/gen_release_changes: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | # This script is used by .github/workflow/release.yml to generate a list of 7 | # changes to apply to a release on GitHub. The latest_changes.md file contains 8 | # the changes. 9 | 10 | open my $in, '<:raw', 'Changes' or die "Cannot open Changes: $!\n"; 11 | open my $out, '>:raw', 'latest_changes.md' or die "Cannot open latest_changes.md: $!\n"; 12 | my $dv; 13 | my $version_re = qr/^(\d+[.]\d+[.]\d+)\b/; 14 | while (<$in>) { 15 | if (/$version_re/) { 16 | $dv = $1; 17 | last; 18 | } 19 | } 20 | 21 | # XXX This is over-simplified. Fine for now, but if we use headings and/or 22 | # indented bullets again, as in 0.9999, this will need some tweakings. 23 | 24 | print {$out} "Changes for v$dv\n"; 25 | while (<$in>) { 26 | last if /$version_re/; 27 | chomp; 28 | if (s/^\s+-/- /) { 29 | print {$out} "\n"; 30 | } else { 31 | s/^\s+/ /; 32 | } 33 | print {$out} $_; 34 | } 35 | 36 | print {$out} "\n"; 37 | -------------------------------------------------------------------------------- /xt/locale/LocaleData/de_DE/LC_MESSAGES/App-Sqitch.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqitchers/sqitch/138658889f824eaf59abd5fff96c46ff6f4842a5/xt/locale/LocaleData/de_DE/LC_MESSAGES/App-Sqitch.mo -------------------------------------------------------------------------------- /xt/locale/LocaleData/fr_FR/LC_MESSAGES/App-Sqitch.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqitchers/sqitch/138658889f824eaf59abd5fff96c46ff6f4842a5/xt/locale/LocaleData/fr_FR/LC_MESSAGES/App-Sqitch.mo -------------------------------------------------------------------------------- /xt/locale/LocaleData/it_IT/LC_MESSAGES/App-Sqitch.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqitchers/sqitch/138658889f824eaf59abd5fff96c46ff6f4842a5/xt/locale/LocaleData/it_IT/LC_MESSAGES/App-Sqitch.mo -------------------------------------------------------------------------------- /xt/locale/README.md: -------------------------------------------------------------------------------- 1 | Sqitch Locale Test 2 | ================== 3 | 4 | This directory contains the files necessary to test the Sqitch CLI to ensure it 5 | properly detects locale settings and emits translated messages. The 6 | [`po` directory here](./po/), unlike the canonical translations in the root `po` 7 | directory, contains only a few languages translating a single message: 8 | 9 | ``` 10 | "{command}" is not a valid command 11 | ``` 12 | 13 | The `LocaleData` directory contains the compiled forms of these dictionaries, 14 | and unlike the main dictionaries, these are committed to the repository. This 15 | allows the [OS](.github/workflows/os.yml) and [Perl](.github/workflows/os.yml) 16 | workflows to run without the overhead of compiling them (a PITA since `gettext` 17 | is hard to get on Windows and Dist::Zilla supports only more recent versions of 18 | Perl). If the messages need to change, recompile the dictionaries with these 19 | commands: 20 | 21 | ```sh 22 | cpanm Dist::Zilla --notest 23 | dzil authordeps --missing | cpanm --notest 24 | dzil msg-compile -d xt/locale xt/locale/po/*.po 25 | ``` 26 | 27 | For errors where it can't find `msgformat` or `gettext`, be sure that [gettext] 28 | is installed (readily available via `apt-get`, `yum`, or `brew`). 29 | 30 | Now run the test, which validates the output from [`bin/sqitch`](bin/sqitch): 31 | 32 | ```sh 33 | prove -lv xt/locale/test-cli.t 34 | ``` 35 | 36 | If tests fail, be sure each of the locales is installed on your system. 37 | Apt-based systems, for example, require the relevant language packs: 38 | 39 | ```sh 40 | sudo apt-get install -qq language-pack-fr language-pack-en language-pack-de language-pack-it 41 | ``` 42 | 43 | [gettext]: https://www.gnu.org/software/gettext/ 44 | -------------------------------------------------------------------------------- /xt/locale/po/de_DE.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: de\n" 4 | "Project-Id-Version: Sqitch 1.4.1\n" 5 | "PO-Revision-Date: 22024-01-06T21:10:06Z\n" 6 | "Last-Translator: Sqitch Hackers \n" 7 | "Language-Team: Sqitch Hackers \n" 8 | "MIME-Version: 1.0\n" 9 | "Content-Type: text/plain; charset=UTF-8\n" 10 | "Content-Transfer-Encoding: 8bit\n" 11 | msgid "\"{command}\" is not a valid command" 12 | msgstr "\"{command}\" ist ein ungültiger Befehl" 13 | -------------------------------------------------------------------------------- /xt/locale/po/fr_FR.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: fr\n" 4 | "Project-Id-Version: Sqitch 1.4.1\n" 5 | "PO-Revision-Date: 22024-01-06T21:10:06Z\n" 6 | "Last-Translator: Sqitch Hackers \n" 7 | "Language-Team: Sqitch Hackers \n" 8 | "MIME-Version: 1.0\n" 9 | "Content-Type: text/plain; charset=UTF-8\n" 10 | "Content-Transfer-Encoding: 8bit\n" 11 | msgid "\"{command}\" is not a valid command" 12 | msgstr "\"{command}\" n'est pas une commande valide" 13 | -------------------------------------------------------------------------------- /xt/locale/po/it_IT.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Language: it\n" 4 | "Project-Id-Version: Sqitch 1.4.1\n" 5 | "PO-Revision-Date: 22024-01-06T21:10:06Z\n" 6 | "Last-Translator: Sqitch Hackers \n" 7 | "Language-Team: Sqitch Hackers \n" 8 | "MIME-Version: 1.0\n" 9 | "Content-Type: text/plain; charset=UTF-8\n" 10 | "Content-Transfer-Encoding: 8bit\n" 11 | msgid "\"{command}\" is not a valid command" 12 | msgstr "\"{command}\" non è un comando valido" 13 | -------------------------------------------------------------------------------- /xt/locale/test-cli.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use warnings; 5 | use Test::More tests => 4; 6 | use File::Spec; 7 | use Capture::Tiny qw(:all); 8 | 9 | # Requires xt/locale/LocaleData; see xt/locale/README.md for details. 10 | my @cli = (qw(-Ilib -CAS -Ixt/locale), File::Spec->catfile(qw(bin sqitch))); 11 | 12 | # Windows has its own locale names for some reason. 13 | # https://stackoverflow.com/q/77771097/79202 14 | my %lang_for = ( 15 | "en_US" => 'English_United States.1252', 16 | "fr_FR" => 'French_France.1252', 17 | "de_DE" => 'German_Germany.1252', 18 | "it_IT" => 'Italian_Italy.1252', 19 | ); 20 | 21 | # Other supported OSes just use the code name. 22 | if ($^O ne 'MSWin32') { 23 | $lang_for{$_} = "$_.UTF-8" for keys %lang_for; 24 | } 25 | 26 | # Each locale must be installed on the local system. Adding a new lang? Also add 27 | # the relevant language-pack-XX package to os.yml and perl.yml. 28 | for my $tc ( 29 | { lang => 'en_US', err => q{"nonesuch" is not a valid command} }, 30 | { lang => 'fr_FR', err => q{"nonesuch" n'est pas une commande valide} }, 31 | { lang => 'de_DE', err => q{"nonesuch" ist ein ungültiger Befehl} }, 32 | { lang => 'it_IT', err => q{"nonesuch" non è un comando valido} }, 33 | ) { 34 | subtest $tc->{lang} || 'default' => sub { 35 | local $ENV{LC_ALL} = $lang_for{$tc->{lang}}; 36 | 37 | # Test successful run. 38 | my ($stdout, $stderr, $exit) = capture { system $^X, @cli, 'help' }; 39 | is $exit >> 8, 0, 'Should have exited normally'; 40 | like $stdout, qr/\AUsage\b/, 'Should have usage statement in STDOUT'; 41 | is $stderr, '', 'Should have no STDERR'; 42 | 43 | # Test localized error. 44 | ($stdout, $stderr, $exit) = capture { system $^X, @cli, 'nonesuch' }; 45 | is $exit >> 8, 2, 'Should have exit val 2'; 46 | is $stdout, '', 'Should have no STDOUT'; 47 | TODO: { 48 | # The Windows locales don't translate into the language codes 49 | # recognized by Locale::TextDomain/gettext. Not at all sure how to 50 | # fix this. Some relevant notes in the FAQ: 51 | # https://metacpan.org/dist/libintl-perl/view/lib/Locale/libintlFAQ.pod#How-do-I-switch-languages-or-force-a-certain-language-independently-from-user-settings-read-from-the-environment? 52 | local $TODO = $^O eq 'MSWin32' ? 'localization fails on Windows' : ''; 53 | like $stderr, qr/\A\Q$tc->{err}/, 54 | 'Should have localized error message in STDERR'; 55 | } 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /xt/release/pod-coverage.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use Test::More; 5 | use Test::Pod::Coverage 1.08; 6 | 7 | Test::Pod::Coverage::all_pod_coverage_ok({ 8 | also_private => [qw(BUILDARGS BUILD CAN_OUTPUT_COLOR OUTPUT_TO_PIPE)], 9 | coverage_class => 'Pod::Coverage::CountParents', 10 | }); 11 | -------------------------------------------------------------------------------- /xt/release/pod-spelling.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use Test::More; 5 | use Test::Spelling; 6 | 7 | # Suppress `Wide character in print`, which is emitted because 8 | # Pod::Spelling::invalid_words_in sets no encoding $handle. Would go away with: 9 | # open my $handle, '>:utf8', \$document; 10 | $SIG{__WARN__} = sub { warn @_ if $_[0] !~ /^Wide character in print/ }; 11 | 12 | add_stopwords(); 13 | all_pod_files_spelling_ok(); 14 | 15 | __DATA__ 16 | API 17 | Blockchain 18 | blog 19 | change's 20 | CLDR 21 | CockroachDB 22 | command's 23 | committer 24 | committers 25 | cryptographic 26 | DateTime 27 | DBA 28 | DDLs 29 | depesz 30 | disambiguating 31 | DML 32 | DSN 33 | Dunklau 34 | EBNF 35 | exaplus 36 | Exasol 37 | exasol 38 | findable 39 | Firebird 40 | firebird 41 | Firebird's 42 | Flipr 43 | flipr 44 | formatter 45 | ftw 46 | Gentoo 47 | GitHub 48 | GSS 49 | GSSAPI 50 | hashtags 51 | Hrm 52 | IDE 53 | ident 54 | incrementing 55 | init 56 | iovation 57 | lowercased 58 | MariaDB 59 | Matthieu 60 | MERCHANTABILITY 61 | Merkle 62 | multivalue 63 | MySQL 64 | MySQL's 65 | namespace 66 | NL 67 | NONINFRINGEMENT 68 | ODBC 69 | OpenID 70 | ORM 71 | other's 72 | overridable 73 | Overridable 74 | Oy 75 | passwordless 76 | PDX 77 | PDXPUG 78 | pgTAP 79 | postgres 80 | PostgreSQL 81 | PostgreSQL's 82 | queryable 83 | RDBMS 84 | RDBMSes 85 | rebase 86 | Rebase 87 | rebased 88 | rebases 89 | relatedly 90 | Relatedly 91 | Ronan 92 | schemas 93 | SDK 94 | SHA 95 | SnowSQL 96 | sqitch 97 | Sqitch's 98 | sqitchchanges 99 | sqitchtutorial 100 | sql 101 | SQLite 102 | sqlite 103 | SQLite's 104 | subdirectories 105 | sublicense 106 | Suciu 107 | sys 108 | timestamp 109 | TLS 110 | transactional 111 | undeployed 112 | unlocalized 113 | unsets 114 | Unsets 115 | untracked 116 | username 117 | UTC 118 | UTF 119 | VCS 120 | VCSes 121 | verifications 122 | Versioning 123 | Vertica 124 | vertica 125 | VirtualBox 126 | VM 127 | XC 128 | yay 129 | Yay 130 | Yugabyte 131 | YugabyteDB 132 | -------------------------------------------------------------------------------- /xt/release/pod.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use strict; 4 | use Test::More; 5 | use Test::Pod 1.41; 6 | all_pod_files_ok(); 7 | --------------------------------------------------------------------------------