From 7d32c174f34132bf79abbef6a397a07f20bf5ecd Mon Sep 17 00:00:00 2001 From: Siddharth Anand Date: Mon, 16 May 2016 22:36:09 +0000 Subject: [PATCH] Add a version view to display airflow version info --- .gitignore | 1 + airflow/www/app.py | 2 + airflow/www/templates/airflow/version.html | 30 +++ airflow/www/views.py | 29 +++ setup.py | 224 +++++++++++++-------- 5 files changed, 198 insertions(+), 88 deletions(-) create mode 100644 airflow/www/templates/airflow/version.html diff --git a/.gitignore b/.gitignore index 4f5b5d3c89305..48af479ee14a9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ .DS_Store .ipynb* .coverage +airflow/git_version airflow/www/static/coverage/ airflow.db airflow.cfg diff --git a/airflow/www/app.py b/airflow/www/app.py index 0af625baa457e..17260465ee209 100644 --- a/airflow/www/app.py +++ b/airflow/www/app.py @@ -95,6 +95,8 @@ def create_app(config=None): base.MenuLink(category='Docs', name='Github',url='https://github.com/airbnb/airflow')) + av(vs.VersionView(name='Version', category="About")) + av(vs.DagRunModelView( models.DagRun, Session, name="DAG Runs", category="Browse")) av(vs.DagModelView(models.DagModel, Session, name=None)) diff --git a/airflow/www/templates/airflow/version.html b/airflow/www/templates/airflow/version.html new file mode 100644 index 0000000000000..f294635fda654 --- /dev/null +++ b/airflow/www/templates/airflow/version.html @@ -0,0 +1,30 @@ +{# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#} +{% extends "airflow/master.html" %} + +{% block body %} + {{ super() }} +

{{ title }}

+ {% set version_label = 'Version' %} + {% if airflow_version %} +

{{ version_label }} : {{ airflow_version }}

+ {% else %} +

{{ version_label }} : Not Available

+ {% endif %} +

Git Version :{% if git_version %} {{ git_version }} {% else %} Not Available {% endif %}

+
+ +{% endblock %} diff --git a/airflow/www/views.py b/airflow/www/views.py index b4d4cfa95bea6..3a0e2854aa4b4 100644 --- a/airflow/www/views.py +++ b/airflow/www/views.py @@ -15,6 +15,7 @@ import sys import os +import pkg_resources import socket import importlib @@ -28,6 +29,7 @@ from past.builtins import basestring import inspect +import subprocess import traceback import sqlalchemy as sqla @@ -61,6 +63,7 @@ from airflow.operators import BaseOperator, SubDagOperator +from airflow.utils.logging import LoggingMixin from airflow.utils.json import json_ser from airflow.utils.state import State from airflow.utils.db import provide_session @@ -2291,6 +2294,32 @@ class UserModelView(wwwutils.SuperUserMixin, AirflowModelView): column_default_sort = 'username' +class VersionView(wwwutils.SuperUserMixin, LoggingMixin, BaseView): + @expose('/') + def version(self): + # Look at the version from setup.py + try: + airflow_version = pkg_resources.require("airflow")[0].version + except Exception as e: + airflow_version = None + self.logger.error(e) + + # Get the Git repo and git hash + git_version = None + try: + with open("airflow/git_version") as f: + git_version = f.readline() + except Exception as e: + self.logger.error(e) + + # Render information + title = "Version Info" + return self.render('airflow/version.html', + title=title, + airflow_version=airflow_version, + git_version=git_version) + + class ConfigurationView(wwwutils.SuperUserMixin, BaseView): @expose('/') def conf(self): diff --git a/setup.py b/setup.py index 7d88f00dfa3d5..4d596ee4c1e83 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,12 @@ from setuptools import setup, find_packages, Command from setuptools.command.test import test as TestCommand +import logging import os import sys +logger = logging.getLogger(__name__) + # Kept manually in sync with airflow.__version__ version = '1.7.0' @@ -35,6 +38,44 @@ def run(self): os.system('rm -vrf ./build ./dist ./*.pyc ./*.tgz ./*.egg-info') +def git_version(version): + try: + import git + except ImportError: + logger.warn('gitpython not found: Cannot compute the git version.') + return '' + try: + repo = git.Repo('.git') + except ImportError: + logger.warn('Git repo not found: Cannot compute the git version.') + return '' + sha = repo.head.commit.hexsha + if repo.is_dirty(): + return '.dev0+{sha}.dirty'.format(sha=sha) + # commit is clean + # is it release of `version` ? + try: + tag = repo.git.describe( + match='[0-9]*', exact_match=True, + tags=True, dirty=True) + assert tag == version, (tag, version) + return '.release:{version}+{sha}'.format(version=version, + sha=sha) + except git.GitCommandError: + return '.dev0+{sha}'.format(sha=sha) + + +def write_version(filename=os.path.join('airflow', 'git_version')): + cnt = """%(git_revision)s""" + text = cnt % {'git_revision': + git_version(version)} + try: + with open(filename, 'w') as a: + a.write(text) + except Exception as e: + logger.error(e) + + async = [ 'greenlet>=0.4.9', 'eventlet>= 0.9.7', @@ -100,91 +141,98 @@ def run(self): devel_hadoop = devel_minreq + hive + hdfs + webhdfs + kerberos devel_all = devel + all_dbs + doc + samba + s3 + slack + crypto + oracle + docker -setup( - name='airflow', - description='Programmatically author, schedule and monitor data pipelines', - license='Apache License 2.0', - version=version, - packages=find_packages(), - package_data={'': ['airflow/alembic.ini']}, - include_package_data=True, - zip_safe=False, - scripts=['airflow/bin/airflow'], - install_requires=[ - 'alembic>=0.8.3, <0.9', - 'babel>=1.3, <2.0', - 'chartkick>=0.4.2, < 0.5', - 'croniter>=0.3.8, <0.4', - 'dill>=0.2.2, <0.3', - 'python-daemon>=2.1.1, <2.2', - 'flask>=0.10.1, <0.11', - 'flask-admin>=1.4.0, <2.0.0', - 'flask-cache>=0.13.1, <0.14', - 'flask-login==0.2.11', - 'future>=0.15.0, <0.16', - 'funcsigs>=0.4, <1', - 'gunicorn>=19.3.0, <19.4.0', # 19.4.? seemed to have issues - 'jinja2>=2.7.3, <3.0', - 'markdown>=2.5.2, <3.0', - 'pandas>=0.15.2, <1.0.0', - 'pygments>=2.0.1, <3.0', - 'python-dateutil>=2.3, <3', - 'requests>=2.5.1, <3', - 'setproctitle>=1.1.8, <2', - 'sqlalchemy>=0.9.8', - 'thrift>=0.9.2, <0.10', - 'Flask-WTF==0.12' - ], - extras_require={ - 'all': devel_all, - 'all_dbs': all_dbs, - 'async': async, - 'celery': celery, - 'crypto': crypto, - 'devel': devel_minreq, - 'devel_hadoop': devel_hadoop, - 'doc': doc, - 'docker': docker, - 'druid': druid, - 'gcp_api': gcp_api, - 'hdfs': hdfs, - 'hive': hive, - 'jdbc': jdbc, - 'mssql': mssql, - 'mysql': mysql, - 'oracle': oracle, - 'postgres': postgres, - 'rabbitmq': rabbitmq, - 's3': s3, - 'samba': samba, - 'slack': slack, - 'statsd': statsd, - 'vertica': vertica, - 'ldap': ldap, - 'webhdfs': webhdfs, - 'kerberos': kerberos, - 'password': password, - 'github_enterprise': github_enterprise, - 'qds': qds, - 'cloudant': cloudant - }, - classifiers={ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Console', - 'Environment :: Web Environment', - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.4', - 'Topic :: System :: Monitoring', - }, - author='Maxime Beauchemin', - author_email='maximebeauchemin@gmail.com', - url='https://github.com/airbnb/airflow', - download_url=( - 'https://github.com/airbnb/airflow/tarball/' + version), - cmdclass={'test': Tox, - 'extra_clean': CleanCommand, - }, -) +def do_setup(): + write_version() + setup( + name='airflow', + description='Programmatically author, schedule and monitor data pipelines', + license='Apache License 2.0', + version=version, + packages=find_packages(), + package_data={'': ['airflow/alembic.ini', "airflow/git_version"]}, + include_package_data=True, + zip_safe=False, + scripts=['airflow/bin/airflow'], + install_requires=[ + 'alembic>=0.8.3, <0.9', + 'babel>=1.3, <2.0', + 'chartkick>=0.4.2, < 0.5', + 'croniter>=0.3.8, <0.4', + 'dill>=0.2.2, <0.3', + 'python-daemon>=2.1.1, <2.2', + 'flask>=0.10.1, <0.11', + 'flask-admin>=1.4.0, <2.0.0', + 'flask-cache>=0.13.1, <0.14', + 'flask-login==0.2.11', + 'future>=0.15.0, <0.16', + 'funcsigs>=0.4, <1', + 'gitpython>=2.0.2', + 'gunicorn>=19.3.0, <19.4.0', # 19.4.? seemed to have issues + 'jinja2>=2.7.3, <3.0', + 'markdown>=2.5.2, <3.0', + 'pandas>=0.15.2, <1.0.0', + 'pygments>=2.0.1, <3.0', + 'python-dateutil>=2.3, <3', + 'requests>=2.5.1, <3', + 'setproctitle>=1.1.8, <2', + 'sqlalchemy>=0.9.8', + 'thrift>=0.9.2, <0.10', + 'Flask-WTF==0.12' + ], + extras_require={ + 'all': devel_all, + 'all_dbs': all_dbs, + 'async': async, + 'celery': celery, + 'crypto': crypto, + 'devel': devel_minreq, + 'devel_hadoop': devel_hadoop, + 'doc': doc, + 'docker': docker, + 'druid': druid, + 'gcp_api': gcp_api, + 'hdfs': hdfs, + 'hive': hive, + 'jdbc': jdbc, + 'mssql': mssql, + 'mysql': mysql, + 'oracle': oracle, + 'postgres': postgres, + 'rabbitmq': rabbitmq, + 's3': s3, + 'samba': samba, + 'slack': slack, + 'statsd': statsd, + 'vertica': vertica, + 'ldap': ldap, + 'webhdfs': webhdfs, + 'kerberos': kerberos, + 'password': password, + 'github_enterprise': github_enterprise, + 'qds': qds, + 'cloudant': cloudant + }, + classifiers={ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Environment :: Web Environment', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.4', + 'Topic :: System :: Monitoring', + }, + author='Maxime Beauchemin', + author_email='maximebeauchemin@gmail.com', + url='https://github.com/airbnb/airflow', + download_url=( + 'https://github.com/airbnb/airflow/tarball/' + version), + cmdclass={'test': Tox, + 'extra_clean': CleanCommand, + }, + ) + + +if __name__ == "__main__": + do_setup()