-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathslack-subversion
executable file
·191 lines (136 loc) · 4.81 KB
/
slack-subversion
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#! /usr/local/bin/perl
# Time-stamp: "03 March 2014, 18:15:30 ([email protected])"
=head1 NAME
slack-subversion - Add svn commit log message to Slack channel
=head1 SYNOPSIS
slack-subversion --repos-path "$REPOS" --revision "$REV" \
--revision-url "http://projects/svnweb/index.cgi/rwde/revision?rev=%s" \
--slack-credentials domain,key
=head1 OPTIONS
Required:
--repos-path PATH Path to SVN repository.
--revision REV SVN commit rev number.
--slack-credentials dom,key Domain and Key for Slack integration.
Optional:
--revision-url URL Include link to specified Revision URL.
--svnlook PATH Location of the svnlook executable.
-V --verbose Incremental verbose mode.
-h --help Print this usage statement and exit.
-v --version Print the version number and exit.
=head1 DESCRIPTION
Add the commit message from the specified revision to Slack via the SVN
integration. The channel is specified by the configuration in Slack.
It is expected that this program be called from a post-commit hook script.
=head1 COPYRIGHT
Copyright 2014 Vick Khera <[email protected]>
=cut
use Getopt::Long;
use File::Which;
use HTTP::Request::Common qw(POST);
use LWP::UserAgent;
use JSON;
our $opts = get_options() or die "failed to process options";
# handle version
if (delete $opts->{version}) {
print "slack-subversion version $VERSION\n";
exit;
}
# display help message if not all params are given, or if asked.
require Pod::Usage && Pod::Usage::pod2usage(
'-verbose' => 99,
'-sections' => '(?i:(Synopsis|Options))',
'-exitval' => 0,
) if $opts->{help}
or not($opts->{'repos_path'} and $opts->{'revision'}
and $opts->{'slack_credentials'});
unless ($opts->{svnlook}) {
die "Unable to find svnlook binary. Specify --svnlook parameter.\n";
}
# now get the info we need, and prepare the message.
my $contents = prepare_contents();
my $view_url = '';
if ($opts->{revision_url}) {
$view_url = sprintf($opts->{revision_url},$opts->{revision});
}
# push notification to slack
my $payload = {
revision => $opts->{revision},
url => $view_url,
author => $contents->{author},
log => $contents->{message},
};
my $ua = LWP::UserAgent->new;
$ua->timeout(15);
my ($domain,$token) = split /,/,$opts->{slack_credentials};
my $req = POST("https://${domain}/services/hooks/subversion?token=${token}", ['payload' => encode_json($payload)]);
my $resp = $ua->request($req);
if ($resp->is_success) {
#print $resp->decoded_content;
}
else {
die $resp->status_line;
}
exit(0);
# parse the command line parameters
#
sub get_options {
my $opts = {};
# defaults
$opts->{svnlook} = which('svnlook') || $ENV{SVNLOOK};
GetOptions(
'repos-path|p=s' => \$opts->{repos_path},
'revision|r=s' => \$opts->{revision},
'revision-url=s' => \$opts->{revision_url},
'slack-credentials=s' => \$opts->{slack_credentials},
'svnlook=s' => \$opts->{svnlook},
'verbose|V+' => \$opts->{verbose},
'help|h' => \$opts->{help},
'version|v' => \$opts->{version},
) or return;
return $opts;
}
# _pipe() and _read_pipe() methods taken from SVN::Notify module
##############################################################################
# This method forks off a process to execute an external program and any
# associated arguments and returns a file handle that can be read from to
# fetch the output of the external program, or written to. Pass "-|" as the
# sole argument to read from another process (such as svnlook), and pass "|-"
# to write to another process (such as sendmail).
##############################################################################
sub _pipe {
my $mode = shift;
# Safer version of backtick (see perlipc(1)).
local *PIPE;
my $pid = open PIPE, $mode;
die "Cannot fork: $!\n" unless defined $pid;
if ($pid) {
# Parent process. Return the file handle.
return *PIPE;
} else {
# Child process. Execute the commands.
exec @_ or die "Cannot exec $_[0]: $!\n";
# Not reached.
}
}
##############################################################################
# This method passes its arguments to _pipe() in read mode, but then
# fetches each line of output from the returned file handle, safely
# strips out any newlines and carriage returns, and returns an array
# reference of those lines.
##############################################################################
sub _read_pipe {
my $fh = _pipe( '-|', @_ );
local $/; my @lines = split /(?:\r\n|\r|\n)/, <$fh>;
close $fh or warn "Child process exited: $?\n";
return \@lines;
}
sub prepare_contents {
my $c = {};
my $lines = _read_pipe($opts->{svnlook}, 'info', $opts->{repos_path},
'-r', $opts->{revision});
$c->{author} = shift @$lines;
$c->{date} = shift @$lines;
$c->{message_size} = shift @$lines;
$c->{message} = join("\n",@$lines);
return $c;
}