Repository: dbt-labs/dbt-core

Issue:
don't rely on master branch for latest version number
## Feature

### Feature description
The `master` branch of dbt isn't really a thing anymore. Instead of relying on the [master](https://github.com/fishtown-analytics/dbt/blob/51f68e3aabcda57afbe5051983d1d17e092be665/dbt/version.py#L12) branch to grab the latest release number, we should pull it from PyPi.

We can use [this api](https://warehouse.readthedocs.io/api-reference/json/) to fetch [some JSON info](https://pypi.org/pypi/dbt/json) about dbt releases.

We need to confirm that pre-releases are not shown as the latest version for a package on PyPi.

### Who will this benefit?
dbt maintainers :) 


Discussion:

Resolving patch:
diff --git a/dbt/version.py b/dbt/version.py
--- a/dbt/version.py
+++ b/dbt/version.py
@@ -1,43 +1,23 @@
+import json
 import re
 
-import dbt.semver
-
-try:
-    # For Python 3.0 and later
-    from urllib.request import urlopen
-except ImportError:
-    # Fall back to Python 2's urllib2
-    from urllib2 import urlopen
-
-REMOTE_VERSION_FILE = \
-    'https://raw.githubusercontent.com/fishtown-analytics/dbt/' \
-    'master/.bumpversion.cfg'
-
+import requests
 
-def get_version_string_from_text(contents):
-    matches = re.search(r"current_version = ([\.0-9a-z]+)", contents)
-    if matches is None or len(matches.groups()) != 1:
-        return ""
-    version = matches.groups()[0]
-    return version
+import dbt.exceptions
+import dbt.semver
 
 
-def get_remote_version_file_contents(url=REMOTE_VERSION_FILE):
-    try:
-        f = urlopen(url)
-        contents = f.read()
-    except Exception:
-        contents = ''
-    if hasattr(contents, 'decode'):
-        contents = contents.decode('utf-8')
-    return contents
+PYPI_VERSION_URL = 'https://pypi.org/pypi/dbt/json'
 
 
 def get_latest_version():
-    contents = get_remote_version_file_contents()
-    if contents == '':
+    try:
+        resp = requests.get(PYPI_VERSION_URL)
+        data = resp.json()
+        version_string = data['info']['version']
+    except (json.JSONDecodeError, KeyError, requests.RequestException):
         return None
-    version_string = get_version_string_from_text(contents)
+
     return dbt.semver.VersionSpecifier.from_version_string(version_string)
 
 
@@ -61,7 +41,7 @@ def get_version_information():
     if latest is None:
         return ("{}The latest version of dbt could not be determined!\n"
                 "Make sure that the following URL is accessible:\n{}"
-                .format(version_msg, REMOTE_VERSION_FILE))
+                .format(version_msg, PYPI_VERSION_URL))
 
     if installed == latest:
         return "{}Up to date!".format(version_msg)


Test patch:
diff --git a/test/unit/test_version.py b/test/unit/test_version.py
--- a/test/unit/test_version.py
+++ b/test/unit/test_version.py
@@ -9,19 +9,9 @@
 class VersionTest(unittest.TestCase):
 
     @patch("dbt.version.__version__", "0.10.0")
-    def test_versions_equal(self):
-
-        dbt.version.get_remote_version_file_contents = MagicMock(
-            return_value="""
-                [bumpversion]
-                current_version = 0.10.0
-                commit = True
-                tag = True
-
-                [bumpversion:file:setup.py]
-
-                [bumpversion:file:dbt/version.py]
-            """)
+    @patch('dbt.version.requests.get')
+    def test_versions_equal(self, mock_get):
+        mock_get.return_value.json.return_value = {'info': {'version': '0.10.0'}}
 
         latest_version = dbt.version.get_latest_version()
         installed_version = dbt.version.get_installed_version()
@@ -37,18 +27,9 @@ def test_versions_equal(self):
                                   expected_version_information)
 
     @patch("dbt.version.__version__", "0.10.2-a1")
-    def test_installed_version_greater(self):
-        dbt.version.get_remote_version_file_contents = MagicMock(
-            return_value="""
-                [bumpversion]
-                current_version = 0.10.1
-                commit = True
-                tag = True
-
-                [bumpversion:file:setup.py]
-
-                [bumpversion:file:dbt/version.py]
-            """)
+    @patch('dbt.version.requests.get')
+    def test_installed_version_greater(self, mock_get):
+        mock_get.return_value.json.return_value = {'info': {'version': '0.10.1'}}
 
         latest_version = dbt.version.get_latest_version()
         installed_version = dbt.version.get_installed_version()
@@ -63,18 +44,9 @@ def test_installed_version_greater(self):
                                   expected_version_information)
 
     @patch("dbt.version.__version__", "0.9.5")
-    def test_installed_version_lower(self):
-        dbt.version.get_remote_version_file_contents = MagicMock(
-            return_value="""
-                [bumpversion]
-                current_version = 0.10.0
-                commit = True
-                tag = True
-
-                [bumpversion:file:setup.py]
-
-                [bumpversion:file:dbt/version.py]
-            """)
+    @patch('dbt.version.requests.get')
+    def test_installed_version_lower(self, mock_get):
+        mock_get.return_value.json.return_value = {'info': {'version': '0.10.0'}}
 
         latest_version = dbt.version.get_latest_version()
         installed_version = dbt.version.get_installed_version()
@@ -92,20 +64,10 @@ def test_installed_version_lower(self):
 
     # suppress having version info printed to the screen during tests.
     @patch('sys.stderr')
-    def test_dbt_version_flag(self, stderr):
-        dbt.version.get_remote_version_file_contents = MagicMock(
-            return_value="""
-                [bumpversion]
-                current_version = 0.10.1
-                commit = True
-                tag = True
-
-                [bumpversion:file:setup.py]
-
-                [bumpversion:file:dbt/version.py]
-            """)
+    @patch('dbt.version.requests.get')
+    def test_dbt_version_flag(self, mock_get, stderr):
+        mock_get.return_value.json.return_value = {'info': {'version': '0.10.1'}}
 
         with self.assertRaises(SystemExit) as exc:
             dbt.main.handle_and_check(['--version'])
         self.assertEqual(exc.exception.code, 0)
-