File Coverage

blib/lib/Liquibase/Git.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Liquibase::Git;
2              
3 1     1   635 use strict;
  1         2  
  1         34  
4 1     1   4 use warnings;
  1         1  
  1         34  
5 1     1   12 use feature 'say';
  1         1  
  1         79  
6 1     1   3293 use Moo;
  1         13112  
  1         5  
7 1     1   1291 use File::Temp qw/tempdir/;
  1         1  
  1         67  
8 1     1   209 use DateTime;
  0            
  0            
9             use IPC::Cmd qw/run/;
10             use IO::Handle;
11             use Data::Dumper;
12              
13             our $VERSION = '0.01';
14              
15             # ABSTRACT: API and CLI to apply sql scripts from a git repo using Liquibase
16              
17              
18              
19             has username => (
20             is => 'ro',
21             required => 1,
22             );
23              
24              
25             has password => (
26             is => 'ro',
27             required => 1,
28             );
29              
30              
31             has db => (
32             is => 'ro',
33             required => 1,
34             );
35              
36             has hostname => (
37             is => 'ro',
38             required => 1,
39             );
40              
41             # something like mydb1
42             has git_changeset_dir => (
43             is => 'ro',
44             required => 1,
45             );
46              
47             has git_repo => (
48             is => 'ro', # eg. ssh://git@github.com/foo/myapp.git
49             required => 1,
50             );
51              
52             has git_identifier => (
53             is => 'ro', # something like 'master', 'branchname' or a commit hash
54             required => 1,
55             );
56              
57             has temp_dir => (
58             # create a temp directory
59             is => 'ro',
60             default => sub { tempdir(CLEANUP => 1); },
61             );
62              
63             has db_type => (
64             is => 'ro',
65             required => 1,
66             isa => sub {
67             die 'Only types available are postgresql and mysql'
68             unless $_[0] eq 'postgresql' || $_[0] eq 'mysql';
69             }
70             );
71              
72             # filename relative to the changeset_dir
73             has git_changeset_file => (
74             is => 'ro',
75             required => 1,
76             );
77              
78             my %default_db_drivers = (
79             postgresql => {
80             classpath => '/usr/share/java/postgresql-jdbc.jar',
81             port => '5432',
82             },
83             mysql => {
84             classpath => '/usr/share/java/mysql-connector-java.jar',
85             port => '3306',
86             },
87             );
88              
89              
90             has classpath => (
91             is => 'lazy',
92             default => sub {
93             my $self = shift;
94              
95             return $default_db_drivers{$self->db_type}->{classpath};
96             }
97             );
98              
99             has port => (
100             is => 'lazy',
101             default => sub {
102             my $self = shift;
103              
104             return $default_db_drivers{$self->db_type}->{port};
105             }
106             );
107              
108              
109             sub liquibase_command_stem {
110             my $self = shift;
111              
112             my $command = "CLASSPATH=".$self->classpath.
113             ' /usr/bin/liquibase --changeLogFile='.$self->git_changeset_dir.'/'.$self->git_changeset_file.' '.
114             '--url="jdbc:'.$self->db_type.
115             '://'.$self->hostname.':'.$self->port.'/'.
116             $self->db.'" --username='.$self->username.' --password='.$self->password;
117              
118             return $command;
119             }
120              
121              
122              
123             # return the buffer (stderr+stdout) only, and die if things go badly
124             sub run_command {
125             my %args = (
126             cmd => undef,
127             @_
128             );
129              
130             my $buffer;
131              
132             my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf) = run (command => $args{cmd}, buffer => \$buffer);
133              
134             STDERR->autoflush(1);
135             STDOUT->autoflush(1);
136              
137             my $censored_cmd = $args{cmd};
138             $censored_cmd =~ s/--password=(\w*)/--password=__CENSORED__/;
139              
140             say '=================================================';
141             say 'COMMAND: '.$censored_cmd;
142             say '=================================================';
143             say $buffer if $buffer;
144             unless ($success) {
145             say '=================================================';
146             say 'FAILED';
147             }
148             unless ($success) {
149             say STDERR "ERROR CODE: $error_code";
150             say STDERR "ERROR BUF: ".Dumper($stderr_buf);
151             exit 1;
152             }
153              
154             return $buffer;
155             }
156              
157              
158             sub retrieve_changeset_from_git {
159             my $self = shift;
160              
161              
162             my $cmd_git_clone = "git clone ".$self->git_repo." ".$self->temp_dir;
163             run_command(cmd => $cmd_git_clone);
164              
165             chdir $self->temp_dir;
166             my $cmd_git_checkout = "git checkout ".$self->git_identifier;
167             run_command(cmd => $cmd_git_checkout);
168              
169             my $git_commit_id = run_command(cmd => 'git log --format="%H" -n 1');
170             chomp $git_commit_id;
171              
172             my $dt_now = DateTime->now;
173             my $description = $dt_now.'.'.$self->git_identifier.'.'.$$.".".$git_commit_id;
174             run_command(cmd => "echo PATCH_RUN_SIGNATURE: ${description}");
175             }
176              
177             sub dryrun {
178             my $self = shift;
179              
180             run_command(cmd => $self->liquibase_command_stem." updateSQL");
181             }
182              
183             sub wetrun {
184             my $self = shift;
185              
186             run_command(cmd => $self->liquibase_command_stem." update");
187             run_command(cmd => 'echo PASSED');
188             }
189              
190             sub update {
191             my $self = shift;
192              
193             $self->retrieve_changeset_from_git;
194             chdir $self->temp_dir;
195             $self->dryrun;
196             $self->wetrun;
197             }
198              
199             sub updateSQL {
200             my $self = shift;
201              
202             $self->retrieve_changeset_from_git;
203             chdir $self->temp_dir;
204             $self->dryrun;
205             }
206              
207              
208             1;
209              
210             __END__