Giuseppe Lavagetto has submitted this change and it was merged. Change subject: Use jinja2 templates, various fixes. ......................................................................
Use jinja2 templates, various fixes. Now I create an index page for the html status pages we generate; also some corrections to provision.sh and other parts of the scripts have been implemented. The code is now slightly less ugly, and it happily runs in labs. Change-Id: I6a70c5fdea282f3922bdf9c4012e9ea09d8c1a75 Signed-off-by: Giuseppe Lavagetto <glavage...@wikimedia.org> --- M compare-puppet-catalogs/comparator M compare-puppet-catalogs/provision.sh M compare-puppet-catalogs/puppet_compare/diff2html.py M compare-puppet-catalogs/puppet_compare/generator.py A compare-puppet-catalogs/puppet_compare/templates/compile_error.jinja2 A compare-puppet-catalogs/puppet_compare/templates/htmldiff.jinja2 A compare-puppet-catalogs/puppet_compare/templates/index.jinja2 A compare-puppet-catalogs/puppet_compare/templates/node_ok.jinja2 M compare-puppet-catalogs/shell/helper 9 files changed, 261 insertions(+), 182 deletions(-) Approvals: Giuseppe Lavagetto: Looks good to me, approved jenkins-bot: Verified diff --git a/compare-puppet-catalogs/comparator b/compare-puppet-catalogs/comparator index aa1c477..a78bc12 100755 --- a/compare-puppet-catalogs/comparator +++ b/compare-puppet-catalogs/comparator @@ -7,4 +7,4 @@ except IndexError: arg = None -generator.main(node=arg) +generator.main(nodes=arg) diff --git a/compare-puppet-catalogs/provision.sh b/compare-puppet-catalogs/provision.sh index 002f957..d411efc 100755 --- a/compare-puppet-catalogs/provision.sh +++ b/compare-puppet-catalogs/provision.sh @@ -33,6 +33,7 @@ popd sudo pip install simplediff +sudo pip install jinja2 for dir in compiled diff html; do sudo -u vagrant mkdir -p /vagrant/output/${dir} diff --git a/compare-puppet-catalogs/puppet_compare/diff2html.py b/compare-puppet-catalogs/puppet_compare/diff2html.py index f41e198..878e47e 100755 --- a/compare-puppet-catalogs/puppet_compare/diff2html.py +++ b/compare-puppet-catalogs/puppet_compare/diff2html.py @@ -40,11 +40,10 @@ import sys import re import htmlentitydefs -import getopt import StringIO -import codecs import datetime from functools import reduce + try: from simplediff import diff, string_diff except ImportError: @@ -66,70 +65,6 @@ dtnow = datetime.datetime.now() modified_date = "%s+01:00" % dtnow.isoformat() -html_hdr = """<!DOCTYPE html> -<html lang="{5}" dir="ltr" - xmlns:dc="http://purl.org/dc/terms/"> -<head> - <meta charset="{1}" /> - <meta name="generator" content="diff2html.py (http://git.droids-corp.org/gitweb/?p=diff2html)" /> - <!--meta name="author" content="Fill in" /--> - <title>HTML Diff{0}</title> - <link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEXAAAAAgAD///+K/HwIAAAAJUlEQVQI12NYBQQM2IgGBQ4mCIEQW7oyK4phampkGIQAc1G1AQCRxCNbyW92oQAAAABJRU5ErkJggg==" type="image/png" /> - <meta property="dc:language" content="{5}" /> - <!--meta property="dc:date" content="{3}" /--> - <meta property="dc:modified" content="{4}" /> - <meta name="description" content="Differences in catalogs for {2}" /> - <meta property="dc:abstract" content="{2}" /> - <style> - table {{ border:0px; border-collapse:collapse; width: 100%; font-size:0.75em; font-family: Lucida Console, monospace }} - td.line {{ color:#8080a0 }} - th {{ background: black; color: white }} - tr.diffunmodified td {{ background: #D0D0E0 }} - tr.diffhunk td {{ background: #A0A0A0 }} - tr.diffadded td {{ background: #CCFFCC }} - tr.diffdeleted td {{ background: #FFCCCC }} - tr.diffchanged td {{ background: #FFFFA0 }} - span.diffchanged2 {{ background: #E0C880 }} - span.diffponct {{ color: #B08080 }} - tr.diffmisc td {{}} - tr.diffseparator td {{}} - </style> -</head> -<body> -<h1>Catalog compilation for <span style="color: #EA3030">{2}</span></h1> - -<div class="hero-unit"> -<h2>Puppet 3</h2> -<ul> - <li><a href="../compiled/puppet_catalogs_3/{2}.pson">Compiled catalog</a></li> - <li><a href="../compiled/puppet_catalogs_3/{2}.warnings">Compilation errors and warnings</a></li> -</ul> -</div> -<div class="hero-unit"> -<h2>Puppet 2.7</h2> -<ul> - <li><a href="../compiled/puppet_catalogs_2.7/{2}.pson">Compiled catalog</a></li> - <li><a href="../compiled/puppet_catalogs_2.7/{2}.warnings">Compilation errors and warnings</a></li> -</ul> -</div> -<h2>Diffs</h2> - -""" - -html_footer = """ -<footer> - <p>Modified at {1}. HTML formatting created by <a href="http://git.droids-corp.org/gitweb/?p=diff2html;a=summary">diff2html</a>. </p> -</footer> -</body></html> -""" - -table_hdr = """ - <table class="diff"> -""" - -table_footer = """ -</table> -""" DIFFON = "\x01" DIFFOFF = "\x02" @@ -142,6 +77,8 @@ # Characters we're willing to word wrap on WORDBREAK = " \t;.,/):-" + +output = [] def sane(x): @@ -318,31 +255,20 @@ return t -def add_comment(s, output_file): - output_file.write( - ('<tr class="diffmisc"><td colspan="4">%s</td></tr>\n' % convert(s)).encode(encoding)) +def add_comment(s): + return ('comment', convert(s)) -def add_filename(f1, f2, output_file): - output_file.write(("<tr><th colspan='2'>%s</th>" % - convert(f1, linesize=linesize)).encode(encoding)) - output_file.write(("<th colspan='2'>%s</th></tr>\n" % - convert(f2, linesize=linesize)).encode(encoding)) +def add_filename(f1, f2): + return ('filename', convert(f1,linesize=linesize), convert(f2,linesize=linesize)) - -def add_hunk(output_file, show_hunk_infos): +def add_hunk(show_hunk_infos): if show_hunk_infos: - output_file.write( - '<tr class="diffhunk"><td colspan="2">Offset %d, %d lines modified</td>' % (hunk_off1, hunk_size1)) - output_file.write( - '<td colspan="2">Offset %d, %d lines modified</td></tr>\n' % (hunk_off2, hunk_size2)) + return ('hunk', (hunk_off1, hunk_size1), (hunk_off2, hunk_size2)) else: - # ⋮ - vertical ellipsis - output_file.write( - '<tr class="diffhunk"><td colspan="2">⋮</td><td colspan="2">⋮</td></tr>') + return ('empty_hunk') - -def add_line(s1, s2, output_file): +def add_line(s1, s2): global line1 global line2 @@ -366,45 +292,41 @@ else: # default s1, s2 = linediff(orig1, orig2) - output_file.write(('<tr class="diff%s">' % type_name).encode(encoding)) + res = {'type': type_name} + if s1 is not None and s1 != "": - output_file.write( - ('<td class="diffline">%d </td>' % line1).encode(encoding)) - output_file.write('<td class="diffpresent">'.encode(encoding)) - output_file.write( - convert(s1, linesize=linesize, ponct=1).encode(encoding)) - output_file.write('</td>') + res['line1'] = ( + line1, + convert(s1, linesize=linesize, ponct=1).encode(encoding) + ) else: + res['line1'] = '' s1 = "" - output_file.write('<td colspan="2"> </td>') if s2 is not None and s2 != "": - output_file.write( - ('<td class="diffline">%d </td>' % line2).encode(encoding)) - output_file.write('<td class="diffpresent">') - output_file.write( - convert(s2, linesize=linesize, ponct=1).encode(encoding)) - output_file.write('</td>') + res['line2'] = ( + line2, + convert(s2, linesize=linesize, ponct=1).encode(encoding) + ) else: + res['line2'] = '' s2 = "" - output_file.write('<td colspan="2"></td>') - output_file.write('</tr>\n') - + return ('diffline', res) if s1 != "": line1 += 1 if s2 != "": line2 += 1 -def empty_buffer(output_file): +def empty_buffer(output): global buf global add_cpt global del_cpt if del_cpt == 0 or add_cpt == 0: for l in buf: - add_line(l[0], l[1], output_file) + output.append(add_line(l[0], l[1])) elif del_cpt != 0 and add_cpt != 0: l0, l1 = [], [] @@ -420,23 +342,19 @@ s0 = l0[i] if i < len(l1): s1 = l1[i] - add_line(s0, s1, output_file) + output.append(add_line(s0, s1)) add_cpt, del_cpt = 0, 0 buf = [] -def parse_input(input_file, output_file, input_file_name, output_file_name, - exclude_headers, show_hunk_infos, desc): +def parse_input(txt, output_file_name, + show_hunk_infos): global add_cpt, del_cpt global line1, line2 global hunk_off1, hunk_size1, hunk_off2, hunk_size2 - - if not exclude_headers: - title_suffix = ' ' + input_file_name - output_file.write(html_hdr.format( - title_suffix, encoding, desc, "", modified_date, lang).encode(encoding)) - output_file.write(table_hdr.encode(encoding)) + output = [] + input_file = StringIO.StringIO(txt) while True: l = input_file.readline() @@ -445,7 +363,7 @@ m = re.match('^--- ([^\s]*)', l) if m: - empty_buffer(output_file) + empty_buffer(output) file1 = m.groups()[0] while True: l = input_file.readline() @@ -453,22 +371,22 @@ if m: file2 = m.groups()[0] break - add_filename(file1, file2, output_file) + output.append(add_filename(file1, file2)) hunk_off1, hunk_size1, hunk_off2, hunk_size2 = 0, 0, 0, 0 continue m = re.match("@@ -(\d+),?(\d*) \+(\d+),?(\d*)", l) if m: - empty_buffer(output_file) + empty_buffer(output) hunk_data = map(lambda x: x == "" and 1 or int(x), m.groups()) hunk_off1, hunk_size1, hunk_off2, hunk_size2 = hunk_data line1, line2 = hunk_off1, hunk_off2 - add_hunk(output_file, show_hunk_infos) + output.append(add_hunk(show_hunk_infos)) continue if hunk_size1 == 0 and hunk_size2 == 0: - empty_buffer(output_file) - add_comment(l, output_file) + empty_buffer(output) + output.append(add_comment(l)) continue if re.match("^\+", l): @@ -484,48 +402,14 @@ continue if re.match("^\ ", l) and hunk_size1 and hunk_size2: - empty_buffer(output_file) + empty_buffer(output) hunk_size1 -= 1 hunk_size2 -= 1 buf.append((l[1:], l[1:])) continue - empty_buffer(output_file) - add_comment(l, output_file) + empty_buffer(output) + output.append(add_comment(l)) - empty_buffer(output_file) - output_file.write(table_footer.encode(encoding)) - if not exclude_headers: - output_file.write( - html_footer.format("", dtnow.strftime("%d.%m.%Y")).encode(encoding)) - - -def stream_parse(txt=None, output_file_name='', enc=None, - show_cr=False, show_hunk_infos=True, verbose=False, fqdn=None): - global linesize, tabsize - global show_CR - global encoding - global algorithm - - exclude_headers = False - - if enc is not None: - encoding = enc - - if show_cr is not None: - show_CR = show_cr - - input_file = StringIO.StringIO(txt) - - if output_file_name: - output_file = codecs.open(output_file_name, "w") - else: - output_file = codecs.getwriter(encoding)(sys.stdout) - - if fqdn: - desc = fqdn - else: - desc = 'Catalog differences' - - parse_input(input_file, output_file, '', output_file_name, - exclude_headers, show_hunk_infos, desc) + empty_buffer(output) + return output diff --git a/compare-puppet-catalogs/puppet_compare/generator.py b/compare-puppet-catalogs/puppet_compare/generator.py index 711e976..8285c03 100644 --- a/compare-puppet-catalogs/puppet_compare/generator.py +++ b/compare-puppet-catalogs/puppet_compare/generator.py @@ -4,7 +4,9 @@ import shlex from collections import defaultdict from subprocess import CalledProcessError +from jinja2 import Environment, PackageLoader +env = Environment(loader=PackageLoader('puppet_compare', 'templates')) def bootstrap(): # initialize things here @@ -40,6 +42,11 @@ def compile_and_diff_node(nodename): + node_compile(nodename) + return node_diff(nodename) + + +def node_compile(nodename): for puppet_version in app.config.get('PUPPET_VERSIONS'): print "Compiling node %s under puppet %s" % (nodename, puppet_version) # Compile @@ -50,6 +57,8 @@ app.config.get('COMPILE_OUTPUT_DIR') ) ruby(cmd) + +def node_diff(nodename): print "Building diffs for node %s" % nodename diff_cmd = '{} {} {} {}'.format( app.config.get('DIFF_SCRIPT'), @@ -61,50 +70,89 @@ ruby(diff_cmd) return os.path.join(app.config.get('DIFF_DIR'), nodename + '.diff') +def update_index(nodelist): -def main(node=None): - if node is not None: - gen = lambda: [n for n in node.split(',')] + t = env.get_template('index.jinja2') + with open(os.path.join(app.config.get('HTML_DIR'), 'index.html'), 'w') as f: + f.write(t.render(nodes=nodelist)) + +def write_node_page(node, txt, is_error=False, is_ok=False, **kwdargs): + html = os.path.join(app.config.get('HTML_DIR'), node + '.html') + template = 'htmldiff.jinja2' + output = None + + if is_error: + template = 'compile_error.jinja2' + elif is_ok: + template = 'node_ok.jinja2' + else: + output = diff2html.parse_input(txt, html, True) + + t = env.get_template(template) + with open(html, 'w') as fh: + fh.write( + t.render( + lang=diff2html.lang, + charset='utf-8', + fqdn=node, + data=output + ) + ) + + +def diff_save(fname, diff): + with open(fname + '.formatted', 'w') as f: + for (resource_diff, content_diff) in diff: + f.write("-- \n\n") + f.write(resource_diff) + if content_diff != '': + f.write("\nContent Diff:\n") + f.write(content_diff) + + +def main(nodes=None): + count = 0 + if nodes is not None: + gen = lambda: [n for n in nodes.split(',')] else: gen = get_nodes nodelist = defaultdict(list) for node in gen(): + count += 1 + if not count % 10: + update_index(nodelist) print "Doing node {}".format(node) + # If compilation or diff fails, build a report page + # for a node with errors. try: - filename = compile_and_diff_node(node) + node_compile(node) + filename = node_diff(node) p = parser.DiffParser(filename) diff = p.run() - except CalledProcessError as e: - print "Error running on node %s" % node + except CalledProcessError: + print "Error in compilation on node %s" % node + write_node_page(node, '', is_error=True) nodelist['ERROR'].append(node) continue + + # If compilation is successful and no diffs, go on. if not diff: print "No differences for node %s" % node + write_node_page(node, '', is_ok=True) nodelist['OK'].append(node) continue + + # If diff is present, render it. nodelist['DIFF'].append(node) - with open(filename + '.formatted', 'w') as f: - for (resource_diff, content_diff) in diff: - f.write("-- \n\n") - f.write(resource_diff) - if content_diff != '': - f.write("\nContent Diff:\n") - f.write(content_diff) + diff_save(filename, diff) # Also save the html rendering text_diff = "\n".join([a + b for (a, b) in diff]) - html = os.path.join(app.config.get('HTML_DIR'), node + '.html') - diff2html.stream_parse( - txt=text_diff, - output_file_name=html, - enc='utf-8', - show_cr=True, - show_hunk_infos=True, - fqdn=node - ) + write_node_page(node, text_diff) + print "###\nRUN RESULTS:" for (k,v) in nodelist.items(): print "%s => %d" % (k, len(v)) - + update_index(nodelist) if __name__ == '__main__': main() diff --git a/compare-puppet-catalogs/puppet_compare/templates/compile_error.jinja2 b/compare-puppet-catalogs/puppet_compare/templates/compile_error.jinja2 new file mode 100644 index 0000000..2b332a6 --- /dev/null +++ b/compare-puppet-catalogs/puppet_compare/templates/compile_error.jinja2 @@ -0,0 +1,7 @@ +{% extends "htmldiff.jinja2" %} +{% block diffs %} +{% endblock %} +{% block summary %} +<h1>Catalog compilation result for <span style="color: #EA3030">{{ fqdn }}</span>: <span style="color: #EA3030">FAIL</span></h1> +<p>See reports for detailed compilation errors</p> +{% endblock %} diff --git a/compare-puppet-catalogs/puppet_compare/templates/htmldiff.jinja2 b/compare-puppet-catalogs/puppet_compare/templates/htmldiff.jinja2 new file mode 100644 index 0000000..4ef90e5 --- /dev/null +++ b/compare-puppet-catalogs/puppet_compare/templates/htmldiff.jinja2 @@ -0,0 +1,92 @@ +<!DOCTYPE html> +<html lang="{{ lang }}" dir="ltr" + xmlns:dc="http://purl.org/dc/terms/"> +<head> + <meta charset="{{ charset }}" /> + <meta name="generator" content="diff2html.py (http://git.droids-corp.org/gitweb/?p=diff2html)" /> + <!--meta name="author" content="Fill in" /--> + <title>Diff for node {{ fqdn }}</title> + <link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEXAAAAAgAD///+K/HwIAAAAJUlEQVQI12NYBQQM2IgGBQ4mCIEQW7oyK4phampkGIQAc1G1AQCRxCNbyW92oQAAAABJRU5ErkJggg==" type="image/png" /> + <meta property="dc:language" content="{{ lang }}" /> + <meta property="dc:modified" content="" /> + <meta name="description" content="Diffs between puppet 2 and puppet 3 catalogs for {{ fqdn }}" /> + <style> + table { border:0px; border-collapse:collapse; width: 100%; font-size:0.75em; font-family: Lucida Console, monospace } + td.line { color:#8080a0 } + th { background: black; color: white } + tr.diffunmodified td { background: #D0D0E0 } + tr.diffhunk td { background: #A0A0A0 } + tr.diffadded td { background: #CCFFCC } + tr.diffdeleted td { background: #FFCCCC } + tr.diffchanged td { background: #FFFFA0 } + span.diffchanged2 { background: #E0C880 } + span.diffponct { color: #B08080 } + tr.diffmisc td {} + tr.diffseparator td {} + </style> +</head> +<body> +{% block summary %} +<h1>Catalog compilation result for <span style="color: #EA3030">{{ fqdn }}</span>: <span style="color: #EA3030">NOT OK</span></h1> +{% endblock %} +<div class="hero-unit"> +<h2>Puppet 3</h2> +<ul> + <li><a href="../compiled/puppet_catalogs_3/{{ fqdn }}.pson">Compiled catalog</a></li> + <li><a href="../compiled/puppet_catalogs_3/{{ fqdn }}.warnings">Compilation errors and warnings</a></li> +</ul> +</div> +<div class="hero-unit"> +<h2>Puppet 2.7</h2> +<ul> + <li><a href="../compiled/puppet_catalogs_2.7/{{ fqdn }}.pson">Compiled catalog</a></li> + <li><a href="../compiled/puppet_catalogs_2.7/{{ fqdn }}.warnings">Compilation errors and warnings</a></li> +</ul> +</div> + +{% block diffs %} +<div id="diffs"> +<h2>Diffs</h2> +<table class="diff"> + {% for line in data %} + {% if line[0] == 'comment' %} + <tr class="diffmisc"><td colspan="4">{{ line[1] }}</td></tr> + {% endif %} + {% if line[0] == 'filename' %} + <tr><th colspan='2'>{{ line[1] }}</th><th colspan='2'>{{ line[2] }}</th></tr> + {% endif %} + {% if line[0] == 'hunk' %} + <tr class="diffhunk"> + <td colspan="2">Offset {{ line[1][0] }}, {{ line[1][1] }} lines modified</td> + <td colspan="2">Offset {{ line[2][0] }}, {{ line[2][1] }} lines modified</td> + </tr> + {% endif %} + {% if line[0] == 'empty_hunk' %} + <tr class="diffhunk"><td colspan="2">⋮</td><td colspan="2">⋮</td></tr> + {% endif %} + {% if line[0] == 'diffline' %} + <tr class="diff{{ line[1].type }}"> + {% if line[1].line1 != '' %} + <td class="diffline">{{ line[1].line1[0] }}</td> + <td class="diffpresent">{{ line[1].line1[1] }}</td> + {% else %} + <td colspan="2"> </td> + {% endif %} + {% if line[1].line2 != '' %} + <td class="diffline">{{ line[1].line2[0] }}</td> + <td class="diffpresent">{{ line[1].line2[1] }}</td> + {% else %} + <td colspan="2"> </td> + {% endif %} + </tr> + {% endif %} + {% endfor %} +</table> +</div> +{% endblock %} +<footer> + <p>HTML formatting studied to show my non-proficiency with CSS.</p> +</footer> +</table> +</body> +</html> diff --git a/compare-puppet-catalogs/puppet_compare/templates/index.jinja2 b/compare-puppet-catalogs/puppet_compare/templates/index.jinja2 new file mode 100644 index 0000000..b743acd --- /dev/null +++ b/compare-puppet-catalogs/puppet_compare/templates/index.jinja2 @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<html lang="en" dir="ltr" xmlns:dc="http://purl.org/dc/terms/"> + <head> + <meta charset="utf-8" /> + <link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEXAAAAAgAD///+K/HwIAAAAJUlEQVQI12NYBQQM2IgGBQ4mCIEQW7oyK4phampkGIQAc1G1AQCRxCNbyW92oQAAAABJRU5ErkJggg==" type="image/png" /> + <meta name="description" content="Diffs between puppet 2 and puppet 3 catalogs" /> + <style> + a { font-weight: bold; text-decoration: none;} + </style> + </head> + <body> + <div class="hostgroup"> + <h2>Hosts where compilation is failing:</h2> + <ul> + {% for host in nodes.ERROR %} + <li><a href="{{ host }}.html"><span style="color: #EA3030">{{ host }}</span></a></li> + {% endfor %} + </ul> + </div> + <div class="hostgroup"> + <h2>Hosts where compilation differs:</h2> + <ul> + {% for host in nodes.DIFF %} + <li><a href="{{ host }}.html"><span style="color: #3030EA">{{ host }}</span></a></li> + {% endfor %} + </ul> + </div> + <div class="hostgroup"> + <h2>Hosts where compilation is identical:</h2> + <ul> + {% for host in nodes.OK %} + <li><a href="{{ host }}.html"><span style="color: #30EA30">{{ host }}</span></a></li> + {% endfor %} + </ul> + </div> + </body> +</html> diff --git a/compare-puppet-catalogs/puppet_compare/templates/node_ok.jinja2 b/compare-puppet-catalogs/puppet_compare/templates/node_ok.jinja2 new file mode 100644 index 0000000..26d8cde --- /dev/null +++ b/compare-puppet-catalogs/puppet_compare/templates/node_ok.jinja2 @@ -0,0 +1,6 @@ +{% extends "htmldiff.jinja2" %} +{% block diffs %} +{% endblock %} +{% block summary %} +<h1>Catalog compilation result for <span style="color: #30AF30">{{ fqdn }}</span>: <span style="color: #30AF30">OK</span></h1> +{% endblock %} diff --git a/compare-puppet-catalogs/shell/helper b/compare-puppet-catalogs/shell/helper index 88fa357..debf3bb 100755 --- a/compare-puppet-catalogs/shell/helper +++ b/compare-puppet-catalogs/shell/helper @@ -23,6 +23,9 @@ cp -ax ${subdir}/* ${PUPPETDIR}/${subdir}/; done popd + pushd ${PUPPETDIR} + git submodule update --init + popd popd } @@ -30,6 +33,7 @@ log "Updating repositories" pushd ${PUPPETDIR} git pull --rebase + git submodule update --init # use --init here in case something went wrong the first time. popd pushd ${PRIVATEDIR} git pull --rebase -- To view, visit https://gerrit.wikimedia.org/r/129456 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I6a70c5fdea282f3922bdf9c4012e9ea09d8c1a75 Gerrit-PatchSet: 2 Gerrit-Project: operations/software Gerrit-Branch: master Gerrit-Owner: Giuseppe Lavagetto <glavage...@wikimedia.org> Gerrit-Reviewer: Giuseppe Lavagetto <glavage...@wikimedia.org> Gerrit-Reviewer: Hashar <has...@free.fr> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits