File Coverage

blib/lib/App/Sqitch/Command/revert.pm
Criterion Covered Total %
statement 56 56 100.0
branch 10 10 100.0
condition 6 6 100.0
subroutine 12 12 100.0
pod 1 1 100.0
total 85 85 100.0


line stmt bran cond sub pod time code
1             package App::Sqitch::Command::revert;
2              
3 2     2   1824 use 5.010;
  2         8  
4 2     2   11 use strict;
  2         4  
  2         53  
5 2     2   11 use warnings;
  2         4  
  2         49  
6 2     2   10 use utf8;
  2         13  
  2         12  
7 2     2   47 use Moo;
  2         4  
  2         12  
8 2     2   733 use Types::Standard qw(Int Str Bool HashRef);
  2         5  
  2         22  
9 2     2   2413 use List::Util qw(first);
  2         6  
  2         127  
10 2     2   13 use App::Sqitch::X qw(hurl);
  2         4  
  2         16  
11 2     2   584 use Locale::TextDomain qw(App-Sqitch);
  2         4  
  2         15  
12 2     2   378 use namespace::autoclean;
  2         6  
  2         17  
13              
14             extends 'App::Sqitch::Command';
15             with 'App::Sqitch::Role::ContextCommand';
16             with 'App::Sqitch::Role::ConnectingCommand';
17              
18             our $VERSION = 'v1.4.0'; # VERSION
19              
20             has target => (
21             is => 'ro',
22             isa => Str,
23             );
24              
25             has to_change => (
26             is => 'ro',
27             isa => Str,
28             );
29              
30             has modified => (
31             is => 'ro',
32             isa => Bool,
33             default => 0,
34             );
35              
36             has no_prompt => (
37             is => 'ro',
38             isa => Bool
39             );
40              
41             has prompt_accept => (
42             is => 'ro',
43             isa => Bool
44             );
45              
46             has strict => (
47             is => 'ro',
48             lazy => 1,
49             default => sub {
50             my $self = shift;
51             return $self->sqitch->config->get( key => 'revert.strict' ) // 0;
52             }
53             );
54              
55             has log_only => (
56             is => 'ro',
57             isa => Bool,
58             default => 0,
59             );
60              
61             has lock_timeout => (
62             is => 'ro',
63             isa => Int,
64             lazy => 1,
65             default => sub { App::Sqitch::Engine::default_lock_timeout() },
66             );
67              
68             has variables => (
69             is => 'ro',
70             isa => HashRef,
71             lazy => 1,
72             default => sub { {} },
73             );
74              
75             sub options {
76             return qw(
77             target|t=s
78             to-change|to|change=s
79             set|s=s%
80             log-only
81             lock-timeout=i
82             modified|m
83             y
84             );
85             }
86              
87             sub configure {
88             my ( $class, $config, $opt ) = @_;
89              
90             my %params = map { $_ => $opt->{$_} } grep { exists $opt->{$_} } qw(
91             to_change
92             log_only
93             lock_timeout
94             target
95             modified
96             );
97              
98             if ( my $vars = $opt->{set} ) {
99             $params{variables} = $vars
100             }
101              
102             $params{no_prompt} = delete $opt->{y} // $config->get(
103             key => 'revert.no_prompt',
104             as => 'bool',
105             ) // 0;
106              
107             $params{prompt_accept} = $config->get(
108             key => 'revert.prompt_accept',
109             as => 'bool',
110             ) // 1;
111              
112             return \%params;
113             }
114              
115             sub _collect_vars {
116 15     15   651 my ($self, $target) = @_;
117 15         288 my $cfg = $self->sqitch->config;
118             return (
119 15         81 %{ $cfg->get_section(section => 'core.variables') },
120 15         65 %{ $cfg->get_section(section => 'deploy.variables') },
121 15         48 %{ $cfg->get_section(section => 'revert.variables') },
122 15         334 %{ $target->variables }, # includes engine
123 15         119 %{ $self->variables }, # --set
  15         689  
124             );
125             }
126              
127             sub execute {
128 12     12 1 31538 my $self = shift;
129 12         70 my ($targets, $changes) = $self->parse_args(
130             target => $self->target,
131             args => \@_,
132             );
133              
134             # Warn on multiple targets.
135 10         580 my $target = shift @{ $targets };
  10         27  
136             $self->warn(__x(
137             'Too many targets specified; connecting to {target}',
138             target => $target->name,
139 10 100       20 )) if @{ $targets };
  10         63  
140              
141             # Warn on too many changes.
142 10         963 my $engine = $target->engine;
143             my $change = $self->modified
144             ? $engine->planned_deployed_common_ancestor_id
145 10 100 100     1926 : $self->to_change // shift @{ $changes };
  7         28  
146              
147             # Require a change to revert to in strict mode.
148 10 100 100     100 hurl {
149             ident => 'revert:strict',
150             message => __ 'Must specify a target revision in strict mode',
151             exitval => 1,
152             } if !defined $change && $self->strict;
153              
154 9 100       168 if (@{ $changes }) {
  9         28  
155             # Only one change allowed currently; fatal in strict mode.
156 2 100       43 hurl {
157             ident => 'revert:strict',
158             message => __ 'Too many changes specified',
159             exitval => 2,
160             } if $self->strict;
161              
162 1         145 $self->warn(__x(
163             'Too many changes specified; reverting to "{change}"',
164             change => $change,
165             ));
166             }
167              
168             # Now get to work.
169 8         297 $engine->log_only( $self->log_only );
170 8         361 $engine->lock_timeout( $self->lock_timeout );
171 8         484 $engine->set_variables( $self->_collect_vars($target) );
172 8         281 $engine->revert( $change, ! ($self->no_prompt), $self->prompt_accept );
173 8         132 return $self;
174             }
175              
176             1;
177              
178             __END__
179              
180             =head1 Name
181              
182             App::Sqitch::Command::revert - Revert Sqitch changes from a database
183              
184             =head1 Synopsis
185              
186             my $cmd = App::Sqitch::Command::revert->new(%params);
187             $cmd->execute;
188              
189             =head1 Description
190              
191             If you want to know how to use the C<revert> command, you probably want to be
192             reading C<sqitch-revert>. But if you really want to know how the C<revert> command
193             works, read on.
194              
195             =head1 Interface
196              
197             =head2 Class Methods
198              
199             =head3 C<options>
200              
201             my @opts = App::Sqitch::Command::revert->options;
202              
203             Returns a list of L<Getopt::Long> option specifications for the command-line
204             options for the C<revert> command.
205              
206             =head2 Attributes
207              
208             =head3 C<log_only>
209              
210             Boolean indicating whether to log the deploy without running the scripts.
211              
212             =head3 C<lock_timeout>
213              
214             The number of seconds to wait for an exclusive advisory lock on the target,
215             for engines that support the feature.
216              
217             =head3 C<modified>
218              
219             Boolean to revert to the change prior to earliest change with a revised
220             deploy script.
221              
222             =head3 C<no_prompt>
223              
224             Boolean indicating whether or not to prompt the user to really go through with
225             the revert.
226              
227             =head3 C<prompt_accept>
228              
229             Boolean value to indicate whether or not the default value for the prompt,
230             should the user hit C<return>, is to accept the prompt or deny it.
231              
232             =head3 C<strict>
233              
234             Boolean to indicate whether or not a change to revert to is required.
235              
236             =head3 C<target>
237              
238             The deployment target URI.
239              
240             =head3 C<to_change>
241              
242             Change to revert to.
243              
244             =head2 Instance Methods
245              
246             =head3 C<execute>
247              
248             $revert->execute;
249              
250             Executes the revert command.
251              
252             =head1 See Also
253              
254             =over
255              
256             =item L<sqitch-revert>
257              
258             Documentation for the C<revert> command to the Sqitch command-line client.
259              
260             =item L<sqitch>
261              
262             The Sqitch command-line client.
263              
264             =back
265              
266             =head1 Author
267              
268             David E. Wheeler <david@justatheory.com>
269              
270             =head1 License
271              
272             Copyright (c) 2012-2023 iovation Inc., David E. Wheeler
273              
274             Permission is hereby granted, free of charge, to any person obtaining a copy
275             of this software and associated documentation files (the "Software"), to deal
276             in the Software without restriction, including without limitation the rights
277             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
278             copies of the Software, and to permit persons to whom the Software is
279             furnished to do so, subject to the following conditions:
280              
281             The above copyright notice and this permission notice shall be included in all
282             copies or substantial portions of the Software.
283              
284             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
285             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
286             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
287             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
288             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
289             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
290             SOFTWARE.
291              
292             =cut