hgweb: report v-c-t changeset in page footer
authorGregory Szorc <gps@mozilla.com>
Thu, 23 Apr 2015 16:01:01 -0700
changeset 360725 b289eb470ad4ed25a251c1ed38c5e5556a23e293
parent 360724 d16c9567b6ac211843f89a0e728d9e11b8e72091
child 360726 4f8c93e418c7bfa89636d423824b038e73958acf
push id16998
push userrwood@mozilla.com
push dateMon, 02 May 2016 19:42:03 +0000
hgweb: report v-c-t changeset in page footer It is useful to know what version of the repository is deployed on the server. We now advertise it in the page footer in hgweb.
.hgignore
ansible/tasks/hgmo-extensions.yml
hgtemplates/gitweb_mozilla/footer.tmpl
testing/vcttesting/deploy.py
testing/vcttesting/docker.py
testing/vcttesting/util.py
--- a/.hgignore
+++ b/.hgignore
@@ -12,8 +12,9 @@ testing/vcttesting.egg-info/
 venv/
 \.pyc$
 \.pyo$
 \.swp$
 \.t.err$
 ~$
 \.vagrant/*
 \.docker-state.json$
+\.vctnode$
--- a/ansible/tasks/hgmo-extensions.yml
+++ b/ansible/tasks/hgmo-extensions.yml
@@ -44,10 +44,15 @@
     - treeclosure_comm_central.py
     - try_mandatory.py
     - whitelist_qa.py
     - whitelist_releng.py
 
 - name: synchronize hg templates
   synchronize: src={{ vct }}/hgtemplates/ dest=/repo/hg/hg_templates/ recursive=yes delete=yes
 
+- name: advertise current v-c-t changeset in hgweb
+  replace: dest=/repo/hg/hg_templates/gitweb_mozilla/footer.tmpl
+           regexp='VCTNODE'
+           replace={{ lookup('file', '../../.vctnode') }}
+
 - name: adjust file permissions for hg templates
   command: /bin/chown -R hg:hg /repo/hg/hg_templates
--- a/hgtemplates/gitweb_mozilla/footer.tmpl
+++ b/hgtemplates/gitweb_mozilla/footer.tmpl
@@ -1,10 +1,11 @@
 <div class="page_footer">
 <div class="page_footer_text">{repo|escape}</div>
+<div class="page_footer_text" style="padding-left: 10px">Deployed from <a href="https://hg.mozilla.org/hgcustom/version-control-tools/rev/VCTNODE">VCTNODE</a>.</div>
 <div class="feed">
 <a href="{url|urlescape}atom-log"><img src="{staticurl}livemarks16.png" alt="Feed" title="Feed of repository changes"/></a>
 </div>
 <br />
 {motd}
 </div>
 </body>
 </html>
--- a/testing/vcttesting/deploy.py
+++ b/testing/vcttesting/deploy.py
@@ -5,25 +5,28 @@
 from __future__ import absolute_import, unicode_literals
 
 import json
 import logging
 import os
 from pipes import quote
 import subprocess
 
+from .util import get_and_write_vct_node
 
 HERE = os.path.abspath(os.path.dirname(__file__))
 ROOT = os.path.normpath(os.path.join(HERE, '..', '..'))
 ANSIBLE = os.path.join(ROOT, 'ansible')
 
 logger = logging.getLogger(__name__)
 
 
 def run_playbook(name, extra_vars=None, verbosity=0):
+    get_and_write_vct_node()
+
     extra_vars = extra_vars or {}
 
     args = [
         'ansible-playbook',
         '-i', os.path.join(ANSIBLE, 'hosts'),
         '-f', '20',
         '%s.yml' % name,
         '--extra-vars', json.dumps(extra_vars),
--- a/testing/vcttesting/docker.py
+++ b/testing/vcttesting/docker.py
@@ -25,16 +25,17 @@ import warnings
 from docker.errors import APIError as DockerAPIError
 from contextlib import contextmanager
 from io import BytesIO
 
 import concurrent.futures as futures
 from coverage.data import CoverageData
 
 from .util import (
+    get_and_write_vct_node,
     wait_for_amqp,
     wait_for_http,
     wait_for_ssh,
 )
 
 
 HERE = os.path.abspath(os.path.dirname(__file__))
 DOCKER_DIR = os.path.normpath(os.path.join(HERE, '..', 'docker'))
@@ -1107,20 +1108,22 @@ class Docker(object):
 
         try:
             if start:
                 self.client.start(cid, port_bindings={873: None})
                 state = self.client.inspect_container(cid)
                 port = state['NetworkSettings']['Ports']['873/tcp'][0]['HostPort']
                 url = 'rsync://%s:%s/vct-mount/' % (self.docker_hostname, port)
 
+                get_and_write_vct_node()
                 vct_paths = self._get_vct_files()
                 with tempfile.NamedTemporaryFile() as fh:
                     for f in sorted(vct_paths.keys()):
                         fh.write('%s\n' % f)
+                    fh.write('.vctnode\n')
                     fh.flush()
 
                     rsync('-a', '--delete-before', '--files-from', fh.name, ROOT, url)
 
                 self.state['last-vct-id'] = image
                 self.state['vct-cid'] = cid
                 self.save_state()
 
--- a/testing/vcttesting/util.py
+++ b/testing/vcttesting/util.py
@@ -1,22 +1,28 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, unicode_literals
 
+import os
 import socket
+import subprocess
 import time
 
 import kombu
 import paramiko
 import requests
 
 
+HERE = os.path.abspath(os.path.dirname(__file__))
+ROOT = os.path.normpath(os.path.join(HERE, '..', '..'))
+
+
 def get_available_port():
     """Obtain a port number available for binding."""
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     s.bind(('', 0))
     host, port = s.getsockname()
     s.close()
 
     return port
@@ -83,8 +89,22 @@ def wait_for_ssh(hostname, port, timeout
             # and wait for an explicit auth failed instead of a generic
             # error.
             return
 
         if time.time() - start > timeout:
             raise Exception('Timeout reached waiting for SSH')
 
         time.sleep(0.1)
+
+
+def get_and_write_vct_node():
+    hg = os.path.join(ROOT, 'venv', 'bin', 'hg')
+    env = dict(os.environ)
+    env['HGRCPATH'] = '/dev/null'
+    args = [hg, '-R', ROOT, 'log', '-r', '.', '-T', '{node|short}']
+    with open(os.devnull, 'wb') as null:
+        node = subprocess.check_output(args, env=env, cwd='/', stderr=null)
+
+    with open(os.path.join(ROOT, '.vctnode'), 'wb') as fh:
+        fh.write(node)
+
+    return node