Repository: readthedocs/readthedocs.org

Issue:
links to github are broken
## Details

* Project URL: sequana.readthedocs, bioservices.readthedocs, bioconvert.readtheodocs and more 
* Build URL (if applicable): http://sequana.readthedocs.io/en/master/
* Read the Docs username (if applicable):  cokelaer

## Expected Result

link should work (there were working)

## Actual Result

links broken due to additional "origin" added in the links to github. 



Discussion:
Broken here too: http://docs.ev3dev.org/en/ev3dev-stretch/index.html
We have the same issue

https://identityserver4.readthedocs.io/en/release/

any comment on this? Can we fix that somehow ourselves?
AFAIC, the problem is still there for the projects mentioned above.
I think this is the PR that fixes this issue: https://github.com/rtfd/readthedocs.org/pull/3302
@humitos I think this issue is specifically about the local remote alias being added to the version name, Github knows nothing of `origin/` which is currently part of `github_version` being used in the template.
I've trying to reproduce this bug in my local instance using the `sequana` project but I wasn't able yet. On one hand, the `commit_name` property used in all the Version objects is correct and on the other hand, I wasn't able to build the documentation because the project fail with an issue that's not related to RTD. @cokelaer please, let me know when I can get a success build and I will try again with this project.

I will try to debug this issue again with the other projects linked in this ticket (probably tomorrow) and I will comment here the results. Thanks for the reports.
@humitos here are some examples of live projects with broken Edit buttons:

http://django-wiki.readthedocs.io/en/master/
http://discretize.simpeg.xyz/en/master/
Bioservices project has the Same issue and may be easier to install or one of the projet that @benjaoming just mentionned. I believe the issues are all related. Could be pbl with à newer version of sphinx maybe?
OK, I think I have "something to say" after my little research.

It seems that this _only happens_ with the `master` branch. I just built `django-wiki` and `discretize` both using `latest` version and links works properly. Then I activated the `master` branch on those projects and the Github link start pointing to the wrong link (adding the "origin" to the URL).

This is happening because in the `Version.commit_name` the value of `self.type` is `unknown` and it doesn't enter to this if, https://github.com/rtfd/readthedocs.org/blob/6fd828216fede4a64259c5d5f199f8e4fd5163e1/readthedocs/builds/models.py#L139
so it returns `self.identifier` which is `origin/master`.

Now, I need to find/understand why the `Version` is detected as `unknown` instead of a `branch`.
Sorry, I got confused with `discrete`. It's using the `dev` branch as `latest` and it's has the problem with the links to GH on that branch. It doesn't have the problem in `stable`.

Resolving patch:
diff --git a/readthedocs/builds/models.py b/readthedocs/builds/models.py
--- a/readthedocs/builds/models.py
+++ b/readthedocs/builds/models.py
@@ -146,6 +146,7 @@ def commit_name(self):
 
         # If we came that far it's not a special version nor a branch or tag.
         # Therefore just return the identifier to make a safe guess.
+        log.error('TODO: Raise an exception here. Testing what cases it happens')
         return self.identifier
 
     def get_absolute_url(self):
diff --git a/readthedocs/restapi/serializers.py b/readthedocs/restapi/serializers.py
--- a/readthedocs/restapi/serializers.py
+++ b/readthedocs/restapi/serializers.py
@@ -73,6 +73,7 @@ class Meta(object):
             'identifier', 'verbose_name',
             'active', 'built',
             'downloads',
+            'type',
         )
 
 


Test patch:
diff --git a/readthedocs/rtd_tests/tests/test_api.py b/readthedocs/rtd_tests/tests/test_api.py
--- a/readthedocs/rtd_tests/tests/test_api.py
+++ b/readthedocs/rtd_tests/tests/test_api.py
@@ -1,23 +1,25 @@
-from __future__ import absolute_import
+# -*- coding: utf-8 -*-
+from __future__ import (
+    absolute_import, division, print_function, unicode_literals)
 
-import json
 import base64
 import datetime
+import json
+from builtins import str
 
 import mock
-from builtins import str
-from django.test import TestCase
+from allauth.socialaccount.models import SocialAccount
 from django.contrib.auth.models import User
+from django.core.urlresolvers import reverse
+from django.test import TestCase
 from django_dynamic_fixture import get
 from rest_framework import status
 from rest_framework.test import APIClient
-from allauth.socialaccount.models import SocialAccount
 
 from readthedocs.builds.models import Build, Version
 from readthedocs.integrations.models import Integration
-from readthedocs.projects.models import Project, Feature
-from readthedocs.oauth.models import RemoteRepository, RemoteOrganization
-
+from readthedocs.oauth.models import RemoteOrganization, RemoteRepository
+from readthedocs.projects.models import Feature, Project
 
 super_auth = base64.b64encode(b'super:test').decode('utf-8')
 eric_auth = base64.b64encode(b'eric:test').decode('utf-8')
@@ -27,9 +29,7 @@ class APIBuildTests(TestCase):
     fixtures = ['eric.json', 'test_data.json']
 
     def test_make_build(self):
-        """
-        Test that a superuser can use the API
-        """
+        """Test that a superuser can use the API."""
         client = APIClient()
         client.login(username='super', password='test')
         resp = client.post(
@@ -42,7 +42,8 @@ def test_make_build(self):
                 'error': 'Test Error',
                 'state': 'cloning',
             },
-            format='json')
+            format='json',
+        )
         self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
         build = resp.data
         self.assertEqual(build['state_display'], 'Cloning')
@@ -54,7 +55,7 @@ def test_make_build(self):
         self.assertEqual(build['state_display'], 'Cloning')
 
     def test_make_build_without_permission(self):
-        """Ensure anonymous/non-staff users cannot write the build endpoint"""
+        """Ensure anonymous/non-staff users cannot write the build endpoint."""
         client = APIClient()
 
         def _try_post():
@@ -67,7 +68,8 @@ def _try_post():
                     'output': 'Test Output',
                     'error': 'Test Error',
                 },
-                format='json')
+                format='json',
+            )
             self.assertEqual(resp.status_code, 403)
 
         _try_post()
@@ -78,7 +80,7 @@ def _try_post():
         _try_post()
 
     def test_update_build_without_permission(self):
-        """Ensure anonymous/non-staff users cannot update build endpoints"""
+        """Ensure anonymous/non-staff users cannot update build endpoints."""
         client = APIClient()
         api_user = get(User, staff=False, password='test')
         client.force_authenticate(user=api_user)
@@ -88,13 +90,15 @@ def test_update_build_without_permission(self):
             {
                 'project': 1,
                 'version': 1,
-                'state': 'finished'
+                'state': 'finished',
             },
-            format='json')
+            format='json',
+        )
         self.assertEqual(resp.status_code, 403)
 
     def test_make_build_protected_fields(self):
-        """Ensure build api view delegates correct serializer
+        """
+        Ensure build api view delegates correct serializer.
 
         Super users should be able to read/write the `builder` property, but we
         don't expose this to end users via the API
@@ -113,7 +117,7 @@ def test_make_build_protected_fields(self):
         self.assertIn('builder', resp.data)
 
     def test_make_build_commands(self):
-        """Create build and build commands"""
+        """Create build and build commands."""
         client = APIClient()
         client.login(username='super', password='test')
         resp = client.post(
@@ -123,7 +127,8 @@ def test_make_build_commands(self):
                 'version': 1,
                 'success': True,
             },
-            format='json')
+            format='json',
+        )
         self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
         build = resp.data
         now = datetime.datetime.utcnow()
@@ -137,7 +142,8 @@ def test_make_build_commands(self):
                 'start_time': str(now - datetime.timedelta(seconds=5)),
                 'end_time': str(now),
             },
-            format='json')
+            format='json',
+        )
         self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
         resp = client.get('/api/v2/build/%s/' % build['id'])
         self.assertEqual(resp.status_code, 200)
@@ -151,20 +157,24 @@ class APITests(TestCase):
     fixtures = ['eric.json', 'test_data.json']
 
     def test_make_project(self):
-        """
-        Test that a superuser can use the API
-        """
-        post_data = {"name": "awesome-project",
-                     "repo": "https://github.com/ericholscher/django-kong.git"}
-        resp = self.client.post('/api/v1/project/',
-                                data=json.dumps(post_data),
-                                content_type='application/json',
-                                HTTP_AUTHORIZATION=u'Basic %s' % super_auth)
+        """Test that a superuser can use the API."""
+        post_data = {
+            'name': 'awesome-project',
+            'repo': 'https://github.com/ericholscher/django-kong.git',
+        }
+        resp = self.client.post(
+            '/api/v1/project/',
+            data=json.dumps(post_data),
+            content_type='application/json',
+            HTTP_AUTHORIZATION='Basic %s' % super_auth,
+        )
         self.assertEqual(resp.status_code, 201)
-        self.assertEqual(resp['location'],
-                         '/api/v1/project/24/')
-        resp = self.client.get('/api/v1/project/24/', data={'format': 'json'},
-                               HTTP_AUTHORIZATION=u'Basic %s' % eric_auth)
+        self.assertEqual(resp['location'], '/api/v1/project/24/')
+        resp = self.client.get(
+            '/api/v1/project/24/',
+            data={'format': 'json'},
+            HTTP_AUTHORIZATION='Basic %s' % eric_auth,
+        )
         self.assertEqual(resp.status_code, 200)
         obj = json.loads(resp.content)
         self.assertEqual(obj['slug'], 'awesome-project')
@@ -187,44 +197,41 @@ def test_user_doesnt_get_full_api_return(self):
         self.assertEqual(resp.data['conf_py_file'], 'foo')
 
     def test_invalid_make_project(self):
-        """
-        Test that the authentication is turned on.
-        """
-        post_data = {"user": "/api/v1/user/2/",
-                     "name": "awesome-project-2",
-                     "repo": "https://github.com/ericholscher/django-bob.git"
-                     }
+        """Test that the authentication is turned on."""
+        post_data = {
+            'user': '/api/v1/user/2/',
+            'name': 'awesome-project-2',
+            'repo': 'https://github.com/ericholscher/django-bob.git',
+        }
         resp = self.client.post(
-            '/api/v1/project/', data=json.dumps(post_data),
+            '/api/v1/project/',
+            data=json.dumps(post_data),
             content_type='application/json',
-            HTTP_AUTHORIZATION=u'Basic %s' % base64.b64encode(b'tester:notapass').decode('utf-8')
+            HTTP_AUTHORIZATION='Basic %s' %
+            base64.b64encode(b'tester:notapass').decode('utf-8'),
         )
         self.assertEqual(resp.status_code, 401)
 
     def test_make_project_dishonest_user(self):
-        """
-        Test that you can't create a project for another user
-        """
+        """Test that you can't create a project for another user."""
         # represents dishonest data input, authentication happens for user 2
         post_data = {
-            "users": ["/api/v1/user/1/"],
-            "name": "awesome-project-2",
-            "repo": "https://github.com/ericholscher/django-bob.git"
+            'users': ['/api/v1/user/1/'],
+            'name': 'awesome-project-2',
+            'repo': 'https://github.com/ericholscher/django-bob.git',
         }
         resp = self.client.post(
             '/api/v1/project/',
             data=json.dumps(post_data),
             content_type='application/json',
-            HTTP_AUTHORIZATION=u'Basic %s' % base64.b64encode(b'tester:test').decode('utf-8')
+            HTTP_AUTHORIZATION='Basic %s' %
+            base64.b64encode(b'tester:test').decode('utf-8'),
         )
         self.assertEqual(resp.status_code, 401)
 
     def test_ensure_get_unauth(self):
-        """
-        Test that GET requests work without authenticating.
-        """
-
-        resp = self.client.get("/api/v1/project/", data={"format": "json"})
+        """Test that GET requests work without authenticating."""
+        resp = self.client.get('/api/v1/project/', data={'format': 'json'})
         self.assertEqual(resp.status_code, 200)
 
     def test_project_features(self):
@@ -233,7 +240,7 @@ def test_project_features(self):
         # One explicit, one implicit feature
         feature1 = get(Feature, projects=[project])
         feature2 = get(Feature, projects=[], default_true=True)
-        feature3 = get(Feature, projects=[], default_true=False)
+        feature3 = get(Feature, projects=[], default_true=False)  # noqa
         client = APIClient()
 
         client.force_authenticate(user=user)
@@ -242,7 +249,7 @@ def test_project_features(self):
         self.assertIn('features', resp.data)
         self.assertEqual(
             resp.data['features'],
-            [feature1.feature_id, feature2.feature_id]
+            [feature1.feature_id, feature2.feature_id],
         )
 
     def test_project_features_multiple_projects(self):
@@ -256,20 +263,17 @@ def test_project_features_multiple_projects(self):
         resp = client.get('/api/v2/project/%s/' % (project1.pk))
         self.assertEqual(resp.status_code, 200)
         self.assertIn('features', resp.data)
-        self.assertEqual(
-            resp.data['features'],
-            [feature.feature_id]
-        )
+        self.assertEqual(resp.data['features'], [feature.feature_id])
 
 
 class APIImportTests(TestCase):
 
-    """Import API endpoint tests"""
+    """Import API endpoint tests."""
 
     fixtures = ['eric.json', 'test_data.json']
 
     def test_permissions(self):
-        """Ensure user repositories aren't leaked to other users"""
+        """Ensure user repositories aren't leaked to other users."""
         client = APIClient()
 
         account_a = get(SocialAccount, provider='github')
@@ -279,33 +283,35 @@ def test_permissions(self):
         user_b = get(User, password='test', socialaccount_set=[account_b])
         user_c = get(User, password='test', socialaccount_set=[account_c])
         org_a = get(RemoteOrganization, users=[user_a], account=account_a)
-        repo_a = get(RemoteRepository, users=[user_a], organization=org_a,
-                     account=account_a)
-        repo_b = get(RemoteRepository, users=[user_b], organization=None,
-                     account=account_b)
+        repo_a = get(
+            RemoteRepository,
+            users=[user_a],
+            organization=org_a,
+            account=account_a,
+        )
+        repo_b = get(
+            RemoteRepository,
+            users=[user_b],
+            organization=None,
+            account=account_b,
+        )
 
         client.force_authenticate(user=user_a)
-        resp = client.get(
-            '/api/v2/remote/repo/',
-            format='json')
+        resp = client.get('/api/v2/remote/repo/', format='json')
         self.assertEqual(resp.status_code, status.HTTP_200_OK)
         repos = resp.data['results']
         self.assertEqual(repos[0]['id'], repo_a.id)
         self.assertEqual(repos[0]['organization']['id'], org_a.id)
         self.assertEqual(len(repos), 1)
 
-        resp = client.get(
-            '/api/v2/remote/org/',
-            format='json')
+        resp = client.get('/api/v2/remote/org/', format='json')
         self.assertEqual(resp.status_code, status.HTTP_200_OK)
         orgs = resp.data['results']
         self.assertEqual(orgs[0]['id'], org_a.id)
         self.assertEqual(len(orgs), 1)
 
         client.force_authenticate(user=user_b)
-        resp = client.get(
-            '/api/v2/remote/repo/',
-            format='json')
+        resp = client.get('/api/v2/remote/repo/', format='json')
         self.assertEqual(resp.status_code, status.HTTP_200_OK)
         repos = resp.data['results']
         self.assertEqual(repos[0]['id'], repo_b.id)
@@ -313,9 +319,7 @@ def test_permissions(self):
         self.assertEqual(len(repos), 1)
 
         client.force_authenticate(user=user_c)
-        resp = client.get(
-            '/api/v2/remote/repo/',
-            format='json')
+        resp = client.get('/api/v2/remote/repo/', format='json')
         self.assertEqual(resp.status_code, status.HTTP_200_OK)
         repos = resp.data['results']
         self.assertEqual(len(repos), 0)
@@ -324,7 +328,7 @@ def test_permissions(self):
 @mock.patch('readthedocs.core.views.hooks.trigger_build')
 class IntegrationsTests(TestCase):
 
-    """Integration for webhooks, etc"""
+    """Integration for webhooks, etc."""
 
     fixtures = ['eric.json', 'test_data.json']
 
@@ -333,27 +337,25 @@ def setUp(self):
         self.version = get(Version, verbose_name='master', project=self.project)
 
     def test_github_webhook(self, trigger_build):
-        """GitHub webhook API"""
+        """GitHub webhook API."""
         client = APIClient()
-        resp = client.post(
+        client.post(
             '/api/v2/webhook/github/{0}/'.format(self.project.slug),
             {'ref': 'master'},
             format='json',
         )
-        trigger_build.assert_has_calls([
-            mock.call(force=True, version=mock.ANY, project=self.project)
-        ])
-        resp = client.post(
+        trigger_build.assert_has_calls(
+            [mock.call(force=True, version=mock.ANY, project=self.project)])
+        client.post(
             '/api/v2/webhook/github/{0}/'.format(self.project.slug),
             {'ref': 'non-existent'},
             format='json',
         )
-        trigger_build.assert_has_calls([
-            mock.call(force=True, version=mock.ANY, project=self.project)
-        ])
+        trigger_build.assert_has_calls(
+            [mock.call(force=True, version=mock.ANY, project=self.project)])
 
     def test_github_invalid_webhook(self, trigger_build):
-        """GitHub webhook unhandled event"""
+        """GitHub webhook unhandled event."""
         client = APIClient()
         resp = client.post(
             '/api/v2/webhook/github/{0}/'.format(self.project.slug),
@@ -365,27 +367,25 @@ def test_github_invalid_webhook(self, trigger_build):
         self.assertEqual(resp.data['detail'], 'Unhandled webhook event')
 
     def test_gitlab_webhook(self, trigger_build):
-        """GitLab webhook API"""
+        """GitLab webhook API."""
         client = APIClient()
-        resp = client.post(
+        client.post(
             '/api/v2/webhook/gitlab/{0}/'.format(self.project.slug),
             {'object_kind': 'push', 'ref': 'master'},
             format='json',
         )
-        trigger_build.assert_has_calls([
-            mock.call(force=True, version=mock.ANY, project=self.project)
-        ])
-        resp = client.post(
+        trigger_build.assert_has_calls(
+            [mock.call(force=True, version=mock.ANY, project=self.project)])
+        client.post(
             '/api/v2/webhook/gitlab/{0}/'.format(self.project.slug),
             {'object_kind': 'push', 'ref': 'non-existent'},
             format='json',
         )
-        trigger_build.assert_has_calls([
-            mock.call(force=True, version=mock.ANY, project=self.project)
-        ])
+        trigger_build.assert_has_calls(
+            [mock.call(force=True, version=mock.ANY, project=self.project)])
 
     def test_gitlab_invalid_webhook(self, trigger_build):
-        """GitLab webhook unhandled event"""
+        """GitLab webhook unhandled event."""
         client = APIClient()
         resp = client.post(
             '/api/v2/webhook/gitlab/{0}/'.format(self.project.slug),
@@ -396,50 +396,45 @@ def test_gitlab_invalid_webhook(self, trigger_build):
         self.assertEqual(resp.data['detail'], 'Unhandled webhook event')
 
     def test_bitbucket_webhook(self, trigger_build):
-        """Bitbucket webhook API"""
+        """Bitbucket webhook API."""
         client = APIClient()
-        resp = client.post(
+        client.post(
             '/api/v2/webhook/bitbucket/{0}/'.format(self.project.slug),
             {
                 'push': {
                     'changes': [{
                         'new': {
-                            'name': 'master'
-                        }
-                    }]
-                }
+                            'name': 'master',
+                        },
+                    }],
+                },
             },
             format='json',
         )
-        trigger_build.assert_has_calls([
-            mock.call(force=True, version=mock.ANY, project=self.project)
-        ])
-        resp = client.post(
+        trigger_build.assert_has_calls(
+            [mock.call(force=True, version=mock.ANY, project=self.project)])
+        client.post(
             '/api/v2/webhook/bitbucket/{0}/'.format(self.project.slug),
             {
                 'push': {
-                    'changes': [{
-                        'new': {
-                            'name': 'non-existent'
-                        }
-                    }]
-                }
+                    'changes': [
+                        {
+                            'new': {'name': 'non-existent'},
+                        },
+                    ],
+                },
             },
             format='json',
         )
-        trigger_build.assert_has_calls([
-            mock.call(force=True, version=mock.ANY, project=self.project)
-        ])
+        trigger_build.assert_has_calls(
+            [mock.call(force=True, version=mock.ANY, project=self.project)])
 
     def test_bitbucket_invalid_webhook(self, trigger_build):
-        """Bitbucket webhook unhandled event"""
+        """Bitbucket webhook unhandled event."""
         client = APIClient()
         resp = client.post(
             '/api/v2/webhook/bitbucket/{0}/'.format(self.project.slug),
-            {'foo': 'bar'},
-            format='json',
-            HTTP_X_EVENT_KEY='pull_request'
-        )
+            {'foo': 'bar'}, format='json', HTTP_X_EVENT_KEY='pull_request')
         self.assertEqual(resp.status_code, 200)
         self.assertEqual(resp.data['detail'], 'Unhandled webhook event')
 
@@ -453,18 +448,21 @@ def test_generic_api_fails_without_auth(self, trigger_build):
         self.assertEqual(resp.status_code, 403)
         self.assertEqual(
             resp.data['detail'],
-            'Authentication credentials were not provided.'
+            'Authentication credentials were not provided.',
         )
 
     def test_generic_api_respects_token_auth(self, trigger_build):
         client = APIClient()
         integration = Integration.objects.create(
             project=self.project,
-            integration_type=Integration.API_WEBHOOK
+            integration_type=Integration.API_WEBHOOK,
         )
         self.assertIsNotNone(integration.token)
         resp = client.post(
-            '/api/v2/webhook/{0}/{1}/'.format(self.project.slug, integration.pk),
+            '/api/v2/webhook/{0}/{1}/'.format(
+                self.project.slug,
+                integration.pk,
+            ),
             {'token': integration.token},
             format='json',
         )
@@ -472,7 +470,10 @@ def test_generic_api_respects_token_auth(self, trigger_build):
         self.assertTrue(resp.data['build_triggered'])
         # Test nonexistent branch
         resp = client.post(
-            '/api/v2/webhook/{0}/{1}/'.format(self.project.slug, integration.pk),
+            '/api/v2/webhook/{0}/{1}/'.format(
+                self.project.slug,
+                integration.pk,
+            ),
             {'token': integration.token, 'branches': 'nonexistent'},
             format='json',
         )
@@ -497,14 +498,84 @@ def test_generic_api_falls_back_to_token_auth(self, trigger_build):
         user = get(User)
         client.force_authenticate(user=user)
         integration = Integration.objects.create(
-            project=self.project,
-            integration_type=Integration.API_WEBHOOK
-        )
+            project=self.project, integration_type=Integration.API_WEBHOOK)
         self.assertIsNotNone(integration.token)
         resp = client.post(
-            '/api/v2/webhook/{0}/{1}/'.format(self.project.slug, integration.pk),
+            '/api/v2/webhook/{0}/{1}/'.format(
+                self.project.slug,
+                integration.pk,
+            ),
             {'token': integration.token},
             format='json',
         )
         self.assertEqual(resp.status_code, 200)
         self.assertTrue(resp.data['build_triggered'])
+
+
+class APIVersionTests(TestCase):
+    fixtures = ['eric', 'test_data']
+
+    def test_get_version_by_id(self):
+        """
+        Test the full response of ``/api/v2/version/{pk}`` is what we expects.
+
+        Allows us to notice changes in the fields returned by the endpoint
+        instead of let them pass silently.
+        """
+        pip = Project.objects.get(slug='pip')
+        version = pip.versions.get(slug='0.8')
+
+        data = {
+            'pk': version.pk,
+        }
+        resp = self.client.get(
+            reverse('version-detail', kwargs=data),
+            content_type='application/json',
+            HTTP_AUTHORIZATION='Basic {}'.format(eric_auth),
+        )
+        self.assertEqual(resp.status_code, 200)
+
+        version_data = {
+            'type': 'tag',
+            'verbose_name': '0.8',
+            'built': False,
+            'id': 18,
+            'active': True,
+            'project': {
+                'analytics_code': None,
+                'canonical_url': 'http://readthedocs.org/docs/pip/en/latest/',
+                'cdn_enabled': False,
+                'conf_py_file': '',
+                'container_image': None,
+                'container_mem_limit': None,
+                'container_time_limit': None,
+                'default_branch': None,
+                'default_version': 'latest',
+                'description': '',
+                'documentation_type': 'sphinx',
+                'enable_epub_build': True,
+                'enable_pdf_build': True,
+                'features': ['allow_deprecated_webhooks'],
+                'id': 6,
+                'install_project': False,
+                'language': 'en',
+                'name': 'Pip',
+                'python_interpreter': 'python',
+                'repo': 'https://github.com/pypa/pip',
+                'repo_type': 'git',
+                'requirements_file': None,
+                'skip': False,
+                'slug': 'pip',
+                'suffix': '.rst',
+                'use_system_packages': False,
+                'users': [1],
+            },
+            'downloads': {},
+            'identifier': '2404a34eba4ee9c48cc8bc4055b99a48354f4950',
+            'slug': '0.8',
+        }
+
+        self.assertDictEqual(
+            resp.data,
+            version_data,
+        )