App-Sqitch
view release on metacpan or search on metacpan
- Removed `local` directory from the distribution, accidentally included
in v1.2.0. Thanks to gregor herrmann for the report (#600).
1.2.0 2021-11-20T22:45:00Z
- Fixed partitioned search for deployed changes on Oracle and Exasol to
correctly support plans with more than 250 changes. Thanks to @Nicqu
for the report (#521).
- DBI connections to the registry will now be set to trace level one
when a verbosity level of three or higher is passed to Sqitch
(i.e., `sqitch -vvv`). Thanks to @wkoszek for the suggestion (#155).
- Renamed the "master" branch to "main" and updated all relevant
references.
- Fixed the parsing of the Snowflake account name from the target URL
to that it no longer strips out the region and cloud platform parts.
Also deprecated the use of the region, host, and port config and
environment variables. This is to comply with the new account name
format. Thanks to @ldsingh00 for the report (#544).
- The checkout command will now show a usage statement when no branch
name is passed to it, rather than a series of warnings and a Git error.
Thanks to François Beausoleil for the report (#561).
- The checkout command now works when operating on a Sqitch project in
the database name and no default for the role.
- Switched to using a constant internally to optimize windows-specific
code paths at compile time.
- When `deploy` detects undeployed dependencies, it now eliminates
duplicates before listing them in the error message.
- Now requiring IO::Pager v0.34 or later for its more consistent
interface.
- Added notes about creating databases to the tutorials. Thanks to Dave
Rolsky for the prompt (#315).
- Added a status message to tell the user when the registry is being
updated, rather than just show each individual update. Thanks to Ben
Hutton for the suggestion (#276).
- Added support for a `$SQITCH_TARGET` environment variable, which takes
precedence over all other target specifications except for command-line
options and arguments. Thanks to @mvgrimes for the suggestion (#203).
- Fixed target/engine/change argument parsing so it won't automatically
fail when `core.engine` isn't set unless no targets are found. This
lets engines be determined strictly from command-line arguments --
derived from targets, or just listed on their own -- whether or not
`core.engine` is set. This change eliminates the need for the
`no_default` parameter to the `parse_args()` method of App::Sqitch
such as `--to-target`, `--upto-target`, which have been deprecated with
warnings in in favor of options containing the string "change", such as
`--to-change` and `--upto-change`, since v0.997 (November 2014).
- Remove the `engine` and `target` command `set-*` actions and their
corresponding methods, which have been deprecated in favor of the
`alter` action since v0.9993 (August 2015).
- Removed the automatic updating of change and tag IDs in the Postgres
engine. This functionality was added in v0.940 (December 2012), when
Postgres was the only engine, and the SHA-1 hash for change and tag IDs
was changed. There were very few deployments at the time, and all
should long since have been updated.
[API Changes]
- Added the URI-overriding parameters `user`, `host`, `port`, and
`dbname` to App::Sqitch::Target so that command options can be used to
easily set them.
- Added support for passing attribute parameters to the `all_targets`
group constructor on App::Sqitch::Target, so that command-line options
can be used to assign attributes to all targets read from the
configuration.
- Aded the `target_params` method to App::Sqitch::Command and updated all
commands to use it when constructing targets. This allows commands to
define options for Target parameters, as required for moving options to
commands as described above.
- Added the `class_for` method to App::Sqitch::Command so that the new
options parser described above can load a command class without
instantiating an instance. Useful for searching command-line arguments
for a command name.
- Added the `create` constructor to App::Sqitch::Command to let Sqitch
instantiate an instance of a command once it finds one via `class_for`.
Previously, Sqitch used the `load` method, which handled the
- Removed documentation for the optional `config` parameter to the
`all_targets` constructor of App::Sqitch::Target, since it was never
used by Sqitch. It always fetched the config from the required `sqitch`
parameter. Support for the `config` parameter has not been removed,
since third-parties might use it.
- Removed the `set_*` methods in the `engine` and `target` commands,
which have been deprecated in favor of the new `alter` method since
v0.9993 (August 2015).
- Removed the `old_id` and `old_info` methods from Change and Tag, which
date from v0.940 (December 2012), and were provided only to allow
existing Postgres databases to be updated from the old to new ID
format, now removed. There should be no other use case for these
methods.
0.9998 2018-10-03T20:53:58Z
- Fixed an issue where Sqitch would sometimes truncate the registry
version number fetched from MySQL, most likely because the Perl runtime
was using 32-bit integers. Fixed by casting the version to CHAR in the
query, before Perl ever see it. Thanks to Allen Godfrey David for the
report.
- Added the Snowflake engine.
tables are distributed by replication to all data nodes.
- Added support to MariaDB 5.3 and higher to the MySQL engine, thanks to
Ed Silva.
0.991 2014-01-16T23:24:33Z
- Greatly simplified determining the Firebird ISQL client. It no longer
tries so hard to find a full path, but does search through the path list
for a likely candidate between fbsql, isql-fb, and isql (or equivalents
ending in .exe on Windows).
- Removed a bunch of inappropriately pasted stuff from the Firebird
tutorial, and updated it a bit.
- `HEAD` and `ROOT` are now recognized as aliases for `@HEAD` and
`@ROOT`, when querying the database, too. That means that `revert --to
HEAD` now works the same as `revert --to @HEAD`, as had been expected
in v0.990.
- Eliminated "use of uninitialized value" warnings when database
connections fail.
- Reduced the minimum required DBD::Firebird to v1.11.
- Fixed the `--verbose` option to the `target` command.
- Eliminated more user-configuration issues in tests, thanks to
chromatic.
- Improved error handling when deploying and reverting a change. If the
change successfully deployed but the logging of the deployment to the
database failed, there was just a rollback message. Sqitch will now
emit the underlying error *and* run the revert script for the
just-deployed change.
- Modified the text hashed for change and tag IDs. Both now include the
note, if present, the ID of the preceding change, and the list of
dependencies. The result is that, when a change is modified or moved in
the plan, it gets a new ID ID. The upshot is that things *must* be in
order for a deploy to succeed. Existing deployments will automatically
have their IDs updated by the `deploy` command.
- Changed the `revert` command so that it *only* fetches information about
changes to be reverted from the database, rather than the plan.
- Deprecated the `@LAST` and `@FIRST` symbolic tags. With `revert` now
fetching change information from the database, there is no longer a
need to specify that changes be found in the database. It's possible
some other way to search database changes will be added in the future,
but if so, it will be less limiting than `@LAST` and `@FIRST`, because
it will likely allow searches by literal tags.
- Added the `rebase` command. This command combines a `revert` and a
`deploy` into a single command, which should allow for more natural
There have also been a number of presentations on Sqitch:
* [PDX.pm Presentation]: Slides from "Sane Database Management with Sqitch",
presented to the Portland Perl Mongers in January, 2013.
* [PDXPUG Presentation]: Movie of "Sane Database Management with Sqitch",
presented to the Portland PostgreSQL Users Group in September, 2012.
* [Agile Database Development]: Slides from a three-hour tutorial session on
using [Git], test-driven development with [pgTAP], and change management with
Sqitch, updated in January, 2014.
Installation
------------
To install Sqitch from a distribution download, type the following:
perl Build.PL
./Build installdeps
./Build
./Build test
inc/Module/Build/Sqitch.pm view on Meta::CPAN
}
$self->log_verbose("Unlinking $file\n");
unlink $file;
$notify = 1;
}
}
}
# If we moved any files, nofify the user that custom templates will need
# to be updated, too.
if ($notify) {
$self->log_warn(q{
#################################################################
# WARNING #
# #
# As of v0.980, the location of script templates has changed. #
# The system-wide templates have been moved to their new #
# locations as described above. However, user-specific #
# templates have not been moved. #
# #
lib/App/Sqitch/Engine.pm view on Meta::CPAN
);
# Upgrade the registry if there is no script_hash column.
unless ( exists $state->{script_hash} ) {
$self->upgrade_registry;
$state->{script_hash} = $state->{change_id};
}
# Update the script hashes if they're the same as the change ID.
# DEPRECATTION: Added in v0.998 (Jan 2015, c86cba61c); consider removing
# in the future when all databases are likely to be updated already.
$self->_update_script_hashes if $state->{script_hash}
&& $state->{script_hash} eq $state->{change_id};
$plan->position($idx);
my $change = $plan->change_at($idx);
if (my @tags = $change->tags) {
$self->log_new_tags($change);
$self->start_at( $change->format_name . $tags[-1]->format_name );
} else {
$self->start_at( $change->format_name );
lib/App/Sqitch/Engine/Upgrade/sqlite-1.1.sql view on Meta::CPAN
BEGIN;
-- Create a new changes table with updated unique constraint.
CREATE TABLE new_changes (
change_id TEXT PRIMARY KEY,
script_hash TEXT NULL,
change TEXT NOT NULL,
project TEXT NOT NULL REFERENCES projects(project) ON UPDATE CASCADE,
note TEXT NOT NULL DEFAULT '',
committed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
committer_name TEXT NOT NULL,
committer_email TEXT NOT NULL,
planned_at DATETIME NOT NULL,
lib/App/Sqitch/Plan/ChangeList.pm view on Meta::CPAN
Append one or more changes to the list. Does not check for duplicates, so
use with care.
=head3 C<index_tag>
$changelist->index_tag($index, $tag);
Index the tag at the specified index. That is, the tag is assumed to be
associated with the change at the specified index, and so the internal look up
table is updated so that the change at that index can be found via the tag's
name and ID.
=head1 See Also
=over
=item L<App::Sqitch::Plan>
The Sqitch plan.
lib/sqitch-config.pod view on Meta::CPAN
=head1 Description
You can query/set/replace/unset Sqitch options with this command. The name is
actually the section and the key separated by a dot, and the value will be
escaped.
Multiple lines can be added to an option by using the C<--add> option. If you
want to update or unset an option which can occur on multiple lines, a Perl
regular expression C<value_regex> needs to be given. Only the existing values
that match the regex will be updated or unset. If you want to handle lines
that do not match the regex, just prepend a single C<!> (exclamation point) in
front (see L<Examples>).
The C<type> specifier can be C<--int>, C<--num>, or C<--bool>, to ensure that
the variable(s) are of the given type and convert the value to the canonical
form (simple integer for C<--int>, decimal number for C<--num>, a "true" or
"false" string for C<--bool>) If no type specifier is passed, no checks or
transformations are performed on the value.
The C<file-option> can be one of C<--local>, C<--user>, C<--system>, or
lib/sqitch.pod view on Meta::CPAN
distribution. Sqitch can read your VCS history and write out a plan file along
with the appropriate deployment and reversion scripts. Once the bundle is
installed on a new system, Sqitch can use the plan file to deploy or the
changes in the proper order.
=item Reduced Duplication
If you're using a VCS to track your changes, you don't have to duplicate
entire change scripts for simple changes. As long as the changes are
L<idempotent|https://en.wikipedia.org/wiki/Idempotence>, you can change
your code directly, and Sqitch will know it needs to be updated.
=end comment
=back
Ready to get started? Here's where:
=over
=item Sqitch Tutorials
lib/sqitchtutorial-exasol.pod view on Meta::CPAN
* deploy/userflips.sql
* revert/userflips.sql
* verify/userflips.sql
Oh, so we can edit those files in place. Nice! How does Sqitch do it? Well, in
point of fact, it has copied the files to stand in for the previous instance
of the C<userflips> change, which we can see via C<git status>:
> git status
# On branch main
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: revert/userflips.sql
# modified: sqitch.plan
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# deploy/userflips@v1.0.0-dev2.sql
lib/sqitchtutorial-sqlite.pod view on Meta::CPAN
The other thing to notice is that F<revert/userflips.sql> has changed. Sqitch
replaced it with the original deploy script. As of now,
F<deploy/userflips.sql> and F<revert/userflips.sql> are identical. This is on
the assumption that the deploy script will be changed (we're reworking it,
remember?), and that the revert script should actually change things back to
how they were before. Of course, the original deploy script won't be
L<idempotent|https://en.wikipedia.org/wiki/Idempotence> -- that is, able to be
applied multiple times without changing the result beyond the initial
application. It could be if SQLite supported C<CREATE OR REPLACE VIEW>, but
since it doesn't, we will have to edit the script to drop the view before
creating it. Or, more simply, it needs to be updated to revert changes back to
how they were as-of the deployment of F<deploy/userflips@v1.0.0-dev2.sql>.
Modify F<deploy/userflips.sql> to add the C<twitter> column; in fact, let's
also add a C<DROP VIEW IF EXISTS> statement, in case we need to rework this
change again in the future:
@@ -4,8 +4,9 @@
BEGIN;
lib/sqitchtutorial-vertica.pod view on Meta::CPAN
* deploy/userflips.sql
* revert/userflips.sql
* verify/userflips.sql
Oh, so we can edit those files in place. Nice! How does Sqitch do it? Well, in
point of fact, it has copied the files to stand in for the previous instance
of the C<userflips> change, which we can see via C<git status>:
> git status
# On branch main
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: revert/userflips.sql
# modified: sqitch.plan
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# deploy/userflips@v1.0.0-dev2.sql
$engine->seen;
is $plan->position, -1, 'Plan should start at position -1';
is $engine->start_at, undef, 'start_at should be undef';
ok $engine->_sync_plan, 'Sync the plan';
is $plan->position, -1, 'Plan should still be at position -1';
is $engine->start_at, undef, 'start_at should still be undef';
$plan->position(4);
is_deeply $engine->seen, [['current_state', undef]],
'Should not have updated IDs or hashes';
ok $engine->_sync_plan, 'Sync the plan again';
is $plan->position, -1, 'Plan should again be at position -1';
is $engine->start_at, undef, 'start_at should again be undef';
is_deeply $engine->seen, [['current_state', undef]],
'Still should not have updated IDs or hashes';
# Have latest_item return a tag.
$latest_change_id = $changes[2]->id;
ok $engine->_sync_plan, 'Sync the plan to a tag';
is $plan->position, 2, 'Plan should now be at position 2';
is $engine->start_at, 'widgets@beta', 'start_at should now be widgets@beta';
is_deeply $engine->seen, [
['current_state', undef],
['log_new_tags' => $plan->change_at(2)],
], 'Should have updated IDs';
# Have current_state return a script hash.
$script_hash = '550aeeab2ae39cba45840888b12a70820a2d6f83';
ok $engine->_sync_plan, 'Sync the plan with a random script hash';
is $plan->position, 2, 'Plan should now be at position 1';
is $engine->start_at, 'widgets@beta', 'start_at should now be widgets@beta';
is_deeply $engine->seen, [
['current_state', undef],
['log_new_tags' => $plan->change_at(2)],
], 'Should have updated IDs but not hashes';
# Have current_state return the last deployed ID as script_hash.
$script_hash = $latest_change_id;
ok $engine->_sync_plan, 'Sync the plan with a random script hash';
is $plan->position, 2, 'Plan should now be at position 1';
is $engine->start_at, 'widgets@beta', 'start_at should now be widgets@beta';
is_deeply $engine->seen, [
['current_state', undef],
['_update_script_hashes'],
['log_new_tags' => $plan->change_at(2)],
], 'Should have updated IDs and hashes';
# Return no change ID, now.
$script_hash = $latest_change_id = $changes[1]->id;
ok $engine->_sync_plan, 'Sync the plan';
is $plan->position, 1, 'Plan should be at position 1';
is $engine->start_at, 'users@alpha', 'start_at should be users@alpha';
is_deeply $engine->seen, [
['current_state', undef],
['_update_script_hashes'],
['log_new_tags' => $plan->change_at(1)],
], 'Should have updated hashes but not IDs';
# Have current_state return no script hash.
my $mock_whu = Test::MockModule->new('App::Sqitch::Engine::whu');
my $state = {change_id => $latest_change_id};
$mock_whu->mock(current_state => $state);
ok $engine->_sync_plan, 'Sync the plan with no script hash';
$mock_whu->unmock('current_state');
is $plan->position, 1, 'Plan should now be at position 1';
is $engine->start_at, 'users@alpha', 'start_at should still be users@alpha';
is_deeply $engine->seen, [
t/lib/DBIEngineTest.pm view on Meta::CPAN
# Unmock everything and call it a day.
$mock_dbh->unmock_all;
$mock_sqitch->unmock_all;
######################################################################
# Let's make sure script_hash upgrades work.
$engine->dbh->do('UPDATE changes SET script_hash = change_id');
ok $engine->_update_script_hashes, 'Update script hashes';
# Make sure they were updated properly.
my $sth = $engine->dbh->prepare(
'SELECT change_id, script_hash FROM changes WHERE project = ?',
);
$sth->execute($plan->project);
while (my $row = $sth->fetch) {
my $change = $plan->get($row->[0]);
is $row->[1], $change->script_hash,
'Should have updated script hash for ' . $change->name;
}
# Make sure no other projects were updated.
$sth = $engine->dbh->prepare(
'SELECT change_id, script_hash FROM changes WHERE project <> ?',
);
$sth->execute($plan->project);
while (my $row = $sth->fetch) {
is $row->[1], $row->[0],
'Change ID and script hash should be ' . substr $row->[0], 0, 6;
}
######################################################################
COMMIT;
EOF
# The note should have been required.
is_deeply \%request_params, {
for => __ 'rework',
scripts => [$deploy_file, $revert_file, $verify_file],
}, 'It should have prompted for a note';
# The plan file should have been updated.
ok $plan->load, 'Reload the plan file';
ok my @steps = $plan->changes, 'Get the steps';
is @steps, 2, 'Should have two steps';
is $steps[0]->name, 'foo', 'First step should be "foo"';
is $steps[1]->name, 'foo', 'Second step should also be "foo"';
is_deeply [$steps[1]->requires], [dep 'foo@alpha'],
'Reworked step should require the previous step';
is_deeply +MockOutput->get_info, [
[__x(
file_not_exists_ok($_) for ($revert_file, $verify_file);
file_exists_ok($deploy_file3);
file_not_exists_ok($_) for ($revert_file3, $verify_file3);
# The note should have been required.
is_deeply \%request_params, {
for => __ 'rework',
scripts => [$deploy_file],
}, 'It should have prompted for a note';
# The plan file should have been updated.
ok $plan->load, 'Reload the plan file again';
ok @steps = $plan->changes, 'Get the steps';
is @steps, 4, 'Should have four steps';
is $steps[0]->name, 'foo', 'First step should be "foo"';
is $steps[1]->name, 'foo', 'Second step should also be "foo"';
is $steps[2]->name, 'bar', 'First step should be "bar"';
is $steps[3]->name, 'bar', 'Second step should also be "bar"';
is_deeply [$steps[3]->requires], [dep 'bar@beta', dep 'foo'],
'Requires should have been passed to reworked change';
is_deeply [$steps[3]->conflicts], [dep '!dr_evil'],
( run in 0.560 second using v1.01-cache-2.11-cpan-05444aca049 )