File Coverage

blib/lib/App/Sqitch/Command/init.pm
Criterion Covered Total %
statement 94 94 100.0
branch 30 32 93.7
condition 7 13 53.8
subroutine 16 16 100.0
pod 2 2 100.0
total 149 157 94.9


line stmt bran cond sub pod time code
1              
2             use 5.010;
3 2     2   46448 use strict;
  2         7  
4 2     2   8 use warnings;
  2         4  
  2         58  
5 2     2   13 use utf8;
  2         2  
  2         55  
6 2     2   9 use Moo;
  2         4  
  2         8  
7 2     2   47 use App::Sqitch::Types qw(URI Maybe);
  2         6  
  2         8  
8 2     2   625 use Locale::TextDomain qw(App-Sqitch);
  2         5  
  2         29  
9 2     2   1401 use App::Sqitch::X qw(hurl);
  2         4  
  2         14  
10 2     2   314 use List::MoreUtils qw(natatime);
  2         3  
  2         15  
11 2     2   508 use Path::Class;
  2         6  
  2         15  
12 2     2   1825 use App::Sqitch::Plan;
  2         4  
  2         85  
13 2     2   10 use namespace::autoclean;
  2         4  
  2         36  
14 2     2   8 use constant extra_target_keys => qw(engine target);
  2         4  
  2         13  
15 2     2   124  
  2         3  
  2         1916  
16             extends 'App::Sqitch::Command';
17             with 'App::Sqitch::Role::TargetConfigCommand';
18              
19             our $VERSION = 'v1.3.1'; # VERSION
20              
21             my ( $self, $project ) = @_;
22             $self->_validate_project($project);
23 1     1 1 2843 $self->write_config;
24 1         5 my $target = $self->config_target;
25 1         5 $self->write_plan(
26 1         6 project => $project,
27 1         81 uri => $self->uri,
28             target => $target,
29             );
30             $self->make_directories_for($target);
31             return $self;
32 1         6 }
33 1         18  
34             has uri => (
35             is => 'ro',
36             isa => Maybe[URI],
37             );
38              
39             return qw(uri=s);
40             }
41              
42             my ( $self, $project ) = @_;
43             $self->usage unless $project;
44             my $name_re = 'App::Sqitch::Plan'->name_regex;
45             hurl init => __x(
46 13     13   29721 qq{invalid project name "{project}": project names must not }
47 13 100       40 . 'begin with punctuation, contain "@", ":", "#", or blanks, or end in '
48 12         48 . 'punctuation or digits following punctuation',
49 12 100       210 project => $project
50             ) unless $project =~ /\A$name_re\z/;
51             }
52              
53             my ( $class, $config, $opt ) = @_;
54              
55             if ( my $uri = $opt->{uri} ) {
56             require URI;
57             $opt->{uri} = 'URI'->new($uri);
58             }
59              
60             return $opt;
61             }
62              
63             my $self = shift;
64             my $sqitch = $self->sqitch;
65             my $config = $sqitch->config;
66             my $file = $config->local_file;
67             if ( -f $file ) {
68              
69 12     12 1 12535 # Do nothing? Update config?
70 12         104 return $self;
71 12         368 }
72 12         201  
73 12 100       1109 my ( @vars, @comments );
74              
75             # Get the props, and make sure the target can find the engine.
76 1         48 my $props = $self->properties;
77             my $target = $self->config_target;
78              
79 11         222 # Write the engine from --engine or core.engine.
80             my $ekey = $props->{engine} || $target->engine_key;
81             if ($ekey) {
82 11         70 push @vars => {
83 11         79 key => "core.engine",
84             value => $ekey,
85             };
86 11   100     1506 }
87 11 100       378 else {
88 7         57 push @comments => "\tengine = ";
89             }
90              
91             # Add core properties.
92             for my $name (qw(
93             plan_file
94 4         8 top_dir
95             )) {
96             # Set properties passed on the command-line.
97             if ( my $val = $props->{$name} ) {
98 11         52 push @vars => {
99             key => "core.$name",
100             value => $val,
101             };
102             }
103 22 100       172 else {
104 3         31 my $val //= $target->$name // '';
105             push @comments => "\t$name = $val";
106             }
107             }
108              
109             # Add script options passed to the init command. No comments if not set.
110 19   50     515 for my $attr (qw(
      33        
111 19         5270 extension
112             deploy_dir
113             revert_dir
114             verify_dir
115             reworked_dir
116 11         161 reworked_deploy_dir
117             reworked_revert_dir
118             reworked_verify_dir
119             )) {
120             push @vars => { key => "core.$attr", value => $props->{$attr} }
121             if defined $props->{$attr};
122             }
123              
124             # Add variables.
125             if (my $vars = $props->{variables}) {
126             push @vars => map {{
127 88 100       194 key => "core.variables.$_",
128             value => $vars->{$_},
129             }} keys %{ $vars };
130             }
131 11 100       30  
132             # Emit them.
133             if (@vars) {
134 2         18 $config->group_set( $file => \@vars );
135 1         2 }
  1         8  
136             else {
137             unshift @comments => '[core]';
138             }
139 11 100       34  
140 10         59 # Emit the comments.
141             $config->add_comment(
142             filename => $file,
143 1         5 indented => 1,
144             comment => join "\n" => @comments,
145             ) if @comments;
146              
147 11 100       15897 if ($ekey) {
148             # Write out the engine.$engine section.
149             my $config_key = "engine.$ekey";
150             @comments = @vars = ();
151              
152             for my $key (qw(target registry client)) {
153 11 100       8231 # Was it passed as an option?
154             if ( my $val = $props->{$key} ) {
155 7         36 push @vars => {
156 7         35 key => "$config_key.$key",
157             value => $val,
158 7         44 };
159             # We're good on this one.
160 21 100       75 next;
161 4         21 }
162              
163             # No value, but add it as a comment, possibly with a default.
164             my $def = $target->$key
165             // $config->get( key => "$config_key.$key" )
166 4         17 // '';
167             push @comments => "\t$key = $def";
168             }
169              
170 17   33     307 if (@vars) {
      50        
171             # Emit them.
172             $config->group_set( $file => \@vars ) if @vars;
173 17         1315 }
174             else {
175             # Still want the section, emit it as a comment.
176 7 100       28 unshift @comments => qq{[engine "$ekey"]};
177             }
178 2 50       29  
179             # Emit the comments.
180             $config->add_comment(
181             filename => $file,
182 5         23 indented => 1,
183             comment => join "\n" => @comments,
184             ) if @comments;
185             }
186 7 100       5190  
187             # Is there are target?
188             if (my $target_name = $props->{target}) {
189             # If it's a named target, add it to the configuration.
190             $config->set(
191             filename => $file,
192             key => "target.$target_name.uri",
193             value => $target->uri,
194 11 100       4724 ) if $target_name !~ /:/
195             }
196 1 50       16  
197             $self->info( __x 'Created {file}', file => $file );
198             return $self;
199             }
200              
201             1;
202              
203 11         119  
204 11         2043 =head1 Name
205              
206             App::Sqitch::Command::init - Initialize a Sqitch project
207              
208             =head1 Synopsis
209              
210             my $cmd = App::Sqitch::Command::init->new(%params);
211             $cmd->execute;
212              
213             =head1 Description
214              
215             This command creates the files and directories for a new Sqitch project -
216             basically a F<sqitch.conf> file and directories for deploy and revert
217             scripts.
218              
219             =head1 Interface
220              
221             =head2 Class Methods
222              
223             =head3 C<options>
224              
225             my @opts = App::Sqitch::Command::init->options;
226              
227             Returns a list of L<Getopt::Long> option specifications for the command-line
228             options for the C<config> command.
229              
230             =head3 C<extra_target_keys>
231              
232             Returns a list of additional option keys to be specified via options.
233              
234             =head2 Attributes
235              
236             =head3 C<uri>
237              
238             URI for the project.
239              
240             =head3 C<properties>
241              
242             Hash of property values to set.
243              
244             =head2 Instance Methods
245              
246             =head3 C<execute>
247              
248             $init->execute($project);
249              
250             Executes the C<init> command.
251              
252             =head3 C<write_config>
253              
254             $init->write_config;
255              
256             Writes out the configuration file. Called by C<execute()>.
257              
258             =head1 Author
259              
260             David E. Wheeler <david@justatheory.com>
261              
262             =head1 License
263              
264             Copyright (c) 2012-2022 iovation Inc., David E. Wheeler
265              
266             Permission is hereby granted, free of charge, to any person obtaining a copy
267             of this software and associated documentation files (the "Software"), to deal
268             in the Software without restriction, including without limitation the rights
269             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
270             copies of the Software, and to permit persons to whom the Software is
271             furnished to do so, subject to the following conditions:
272              
273             The above copyright notice and this permission notice shall be included in all
274             copies or substantial portions of the Software.
275              
276             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
277             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
278             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
279             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
280             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
281             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
282             SOFTWARE.
283              
284             =cut
285