blib/lib/SVN/Notify/HTML.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 128 | 128 | 100.0 |
branch | 51 | 56 | 91.0 |
condition | 21 | 24 | 87.5 |
subroutine | 14 | 14 | 100.0 |
pod | 9 | 9 | 100.0 |
total | 223 | 231 | 96.5 |
line | stmt | bran | cond | sub | pod | time | code | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | package SVN::Notify::HTML; | |||||||||||||
2 | ||||||||||||||
3 | 198 | 198 | 384114 | use strict; | ||||||||||
198 | 366 | |||||||||||||
198 | 5903 | |||||||||||||
4 | 198 | 198 | 1022 | use HTML::Entities; | ||||||||||
198 | 450 | |||||||||||||
198 | 12327 | |||||||||||||
5 | 198 | 198 | 65306 | use SVN::Notify (); | ||||||||||
198 | 576 | |||||||||||||
198 | 440223 | |||||||||||||
6 | ||||||||||||||
7 | $SVN::Notify::HTML::VERSION = '2.87'; | |||||||||||||
8 | @SVN::Notify::HTML::ISA = qw(SVN::Notify); | |||||||||||||
9 | ||||||||||||||
10 | __PACKAGE__->register_attributes( | |||||||||||||
11 | linkize => 'linkize', | |||||||||||||
12 | css_url => 'css-url=s', | |||||||||||||
13 | wrap_log => 'wrap-log', | |||||||||||||
14 | ); | |||||||||||||
15 | ||||||||||||||
16 | =head1 Name | |||||||||||||
17 | ||||||||||||||
18 | SVN::Notify::HTML - Subversion activity HTML notification | |||||||||||||
19 | ||||||||||||||
20 | =head1 Synopsis | |||||||||||||
21 | ||||||||||||||
22 | Use F |
|||||||||||||
23 | ||||||||||||||
24 | svnnotify --repos-path "$1" --revision "$2" \ | |||||||||||||
25 | --to developers@example.com --handler HTML [options] | |||||||||||||
26 | ||||||||||||||
27 | Use the class in a custom script: | |||||||||||||
28 | ||||||||||||||
29 | use SVN::Notify::HTML; | |||||||||||||
30 | ||||||||||||||
31 | my $notifier = SVN::Notify::HTML->new(%params); | |||||||||||||
32 | $notifier->prepare; | |||||||||||||
33 | $notifier->execute; | |||||||||||||
34 | ||||||||||||||
35 | =head1 Description | |||||||||||||
36 | ||||||||||||||
37 | This subclass of L |
|||||||||||||
38 | messages for Subversion activity, rather than the default plain text. | |||||||||||||
39 | ||||||||||||||
40 | =head1 Prerequisites | |||||||||||||
41 | ||||||||||||||
42 | In addition to the modules required by SVN::Notify, this class requires: | |||||||||||||
43 | ||||||||||||||
44 | =over | |||||||||||||
45 | ||||||||||||||
46 | =item HTML::Entities | |||||||||||||
47 | ||||||||||||||
48 | =back | |||||||||||||
49 | ||||||||||||||
50 | =head1 Usage | |||||||||||||
51 | ||||||||||||||
52 | To use SVN::Notify::HTML, simply follow the L |
|||||||||||||
53 | in SVN::Notify, but when using F |
|||||||||||||
54 | ||||||||||||||
55 | =cut | |||||||||||||
56 | ||||||||||||||
57 | ############################################################################## | |||||||||||||
58 | ||||||||||||||
59 | =head1 Class Interface | |||||||||||||
60 | ||||||||||||||
61 | =head2 Constructor | |||||||||||||
62 | ||||||||||||||
63 | =head3 new | |||||||||||||
64 | ||||||||||||||
65 | my $notifier = SVN::Notify::HTML->new(%params); | |||||||||||||
66 | ||||||||||||||
67 | Constructs and returns a new SVN::Notify object. All parameters supported by | |||||||||||||
68 | SVN::Notity are supported here, but SVN::Notify::HTML supports a few | |||||||||||||
69 | additional parameters: | |||||||||||||
70 | ||||||||||||||
71 | =over | |||||||||||||
72 | ||||||||||||||
73 | =item linkize | |||||||||||||
74 | ||||||||||||||
75 | svnnotify --linkize | |||||||||||||
76 | ||||||||||||||
77 | A boolean attribute to specify whether or not to "linkize" the SVN log | |||||||||||||
78 | message--that is, to turn any URLs or email addresses in the log message into | |||||||||||||
79 | links. | |||||||||||||
80 | ||||||||||||||
81 | =item css_url | |||||||||||||
82 | ||||||||||||||
83 | svnnotify --css-url http://example.com/svnnotify.css | |||||||||||||
84 | ||||||||||||||
85 | URL for a CSS file that will can style the HTML output by SVN::Notify::HTML or | |||||||||||||
86 | its subclasses. Note that the URL will be added to the output via a | |||||||||||||
87 | C<< >> tag I |
|||||||||||||
88 | SVN::Notify::HTML or its subclasses. What that means is that the CSS file | |||||||||||||
89 | specified by C |
|||||||||||||
90 | override the default settings. This approach nicely takes advantage of the | |||||||||||||
91 | "cascading" abilities of CSS. | |||||||||||||
92 | ||||||||||||||
93 | =item ticket_map | |||||||||||||
94 | ||||||||||||||
95 | svnnotify --ticket-map '(BUG-(\d+))=http://bugs.example.com/?show=%s' | |||||||||||||
96 | ||||||||||||||
97 | This attribute is inherited from L |
|||||||||||||
98 | are slightly different: the regular expression passed as the regular | |||||||||||||
99 | expression used for the key should return I |
|||||||||||||
100 | text to link and the ticket ID itself. For example, '(BUG-(\d+))' will match | |||||||||||||
101 | "BUG-1234567", and "BUG-1234567" will be used for the link text, while | |||||||||||||
102 | "1234567" will be used to fill in the C |
|||||||||||||
103 | set of parentheses capture the whole string, while the parentheses around | |||||||||||||
104 | C<\d+> match the number only. Also note that it is wise to use "\b" on either | |||||||||||||
105 | side of the regular expression to insure that you don't get spurious matches. | |||||||||||||
106 | So a better version would be '\b(BUG-(\d+))\b'. | |||||||||||||
107 | ||||||||||||||
108 | As a fallback, if your regular expression returns only a single match string, | |||||||||||||
109 | it will be used both for the link text and for the the ticket URL generated | |||||||||||||
110 | from C |
|||||||||||||
111 | number in 'BUG-1234567', as only the number has been captured by the regular | |||||||||||||
112 | expression. But two matches are of course recommended (and likely to work | |||||||||||||
113 | better, as well). | |||||||||||||
114 | ||||||||||||||
115 | You can use more complicated regular expressions if commit messages are likely | |||||||||||||
116 | to format ticket numbers in various ways. For example, this regular | |||||||||||||
117 | expression: | |||||||||||||
118 | ||||||||||||||
119 | \b\[?\s*(Ticket\s*#\s*(\d+))\s*\]?\b' | |||||||||||||
120 | ||||||||||||||
121 | Will match: | |||||||||||||
122 | ||||||||||||||
123 | String Matched Link Text Ticket Number | |||||||||||||
124 | --------------------|--------------------|--------------- | |||||||||||||
125 | [Ticket#1234] [Ticket#1234] 1234 | |||||||||||||
126 | [ Ticket # 1234 ] [ Ticket # 1234 ] 1234 | |||||||||||||
127 | Ticket #1234 Ticket #1234 1234 | |||||||||||||
128 | Ticket # 1234 Ticket #1234 1234 | |||||||||||||
129 | ||||||||||||||
130 | In any of these cases, you can see that the match is successful, properly | |||||||||||||
131 | creates the link text (simply using the text as typed in by the committer, and | |||||||||||||
132 | correctly extracts the ticket number for use in the URL. | |||||||||||||
133 | ||||||||||||||
134 | To learn more about the power of Regular expressions, I highly recommend | |||||||||||||
135 | _Mastering Regular Expressions, Second Edition_, by Jeffrey Friedl. | |||||||||||||
136 | ||||||||||||||
137 | =item wrap_log | |||||||||||||
138 | ||||||||||||||
139 | svnnotify --wrap-log | |||||||||||||
140 | ||||||||||||||
141 | A boolean attribute to specify whether or not to wrap the log message in the | |||||||||||||
142 | output HTML. By default, log messages are I |
|||||||||||||
143 | that they should appear exactly as typed. But if that's not the case, specify | |||||||||||||
144 | this option to wrap the log message. | |||||||||||||
145 | ||||||||||||||
146 | =back | |||||||||||||
147 | ||||||||||||||
148 | =cut | |||||||||||||
149 | ||||||||||||||
150 | ############################################################################## | |||||||||||||
151 | ||||||||||||||
152 | =head2 Class Methods | |||||||||||||
153 | ||||||||||||||
154 | =head3 content_type | |||||||||||||
155 | ||||||||||||||
156 | Returns the content type of the notification message, "text/html". Used to set | |||||||||||||
157 | the Content-Type header for the message. | |||||||||||||
158 | ||||||||||||||
159 | =cut | |||||||||||||
160 | ||||||||||||||
161 | 1139 | 1139 | 1 | 12249 | sub content_type { 'text/html' } | |||||||||
162 | ||||||||||||||
163 | ############################################################################## | |||||||||||||
164 | ||||||||||||||
165 | =head1 Instance Interface | |||||||||||||
166 | ||||||||||||||
167 | =head2 Instance Methods | |||||||||||||
168 | ||||||||||||||
169 | =head3 start_html | |||||||||||||
170 | ||||||||||||||
171 | $notifier->start_html($file_handle); | |||||||||||||
172 | ||||||||||||||
173 | This method starts the HTML of the notification message. It outputs the | |||||||||||||
174 | opening C<< >>, C<< >>, and C<< >> tags. Note that if the | |||||||||||||
175 | C |
|||||||||||||
176 | C<< >> tag. | |||||||||||||
177 | ||||||||||||||
178 | All of the HTML will be passed to any "start_html" output filters. See | |||||||||||||
179 | L |
|||||||||||||
180 | filters. | |||||||||||||
181 | ||||||||||||||
182 | =cut | |||||||||||||
183 | ||||||||||||||
184 | sub start_html { | |||||||||||||
185 | 1077 | 1077 | 1 | 11514 | my ($self, $out) = @_; | |||||||||
186 | 1077 | 22754 | my $lang = $self->language; | |||||||||||
187 | 1077 | 11565 | my $char = lc $self->encoding; | |||||||||||
188 | ||||||||||||||
189 | my @html = ( | |||||||||||||
190 | qq{ | |||||||||||||
191 | qq{"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n}, | |||||||||||||
192 | qq{ | |||||||||||||
193 | ($lang ? qq{ xml:lang="$lang"} : ()), | |||||||||||||
194 | qq{>\n 195 | qq{charset=$char" />\n}, | ||||||||||||
196 | ( $self->{css_url} | |||||||||||||
197 | ? ( | |||||||||||||
198 | ' 199 | 1077 | 100 | 30575 | encode_entities($self->{css_url}), | |||||||||
100 | ||||||||||||||
200 | qq{" />\n} | |||||||||||||
201 | ) : () | |||||||||||||
202 | ), | |||||||||||||
203 | ' |
|||||||||||||
204 | qq{\n\n\n\n} | |||||||||||||
205 | ); | |||||||||||||
206 | ||||||||||||||
207 | 1077 | 185454 | print $out @{ $self->run_filters( start_html => \@html ) }; | |||||||||||
1077 | 5791 | |||||||||||||
208 | 1077 | 3904 | return $self; | |||||||||||
209 | } | |||||||||||||
210 | ||||||||||||||
211 | ############################################################################## | |||||||||||||
212 | ||||||||||||||
213 | =head3 start_body | |||||||||||||
214 | ||||||||||||||
215 | This method starts the body of the HTML notification message. It first calls | |||||||||||||
216 | C |
|||||||||||||
238 | ||||||||||||||
239 | 1077 | 7235 | my @html = ( qq{ \n} ); |
|||||||||||
240 | 1077 | 100 | 9613 | if (my $header = $self->header) { | ||||||||||
241 | 13 | 100 | 439 | push @html, ( | ||||||||||
242 | ' ', |
|||||||||||||
243 | ( $header =~ /^ ? $header : encode_entities($header, '<>&"') ), | |||||||||||||
244 | "\n", | |||||||||||||
245 | ); | |||||||||||||
246 | } | |||||||||||||
247 | ||||||||||||||
248 | 1077 | 3633 | print $out @{ $self->run_filters( start_body => \@html ) }; | |||||||||||
1077 | 3991 | |||||||||||||
249 | 1077 | 3634 | return $self; | |||||||||||
250 | } | |||||||||||||
251 | ||||||||||||||
252 | ############################################################################## | |||||||||||||
253 | ||||||||||||||
254 | =head3 output_css | |||||||||||||
255 | ||||||||||||||
256 | $notifier->output_css($file_handle); | |||||||||||||
257 | ||||||||||||||
258 | This method starts outputs the CSS for the HTML message. It is called by | |||||||||||||
259 | C |
|||||||||||||
260 | appropriate C<< |