Skip to content

Commit a489572

Browse files
authored
Merge pull request #8259 from readthedocs/humitos/remoterepository-project-fk
2 parents db0c0e2 + e5fccce commit a489572

16 files changed

+99
-51
lines changed

docs/api/v3.rst

+7-7
Original file line numberDiff line numberDiff line change
@@ -1713,12 +1713,12 @@ Remote Repository listing
17131713

17141714
.. code-tab:: bash
17151715

1716-
$ curl -H "Authorization: Token <token>" https://readthedocs.org/api/v3/remote/repositories/?expand=project,organization
1716+
$ curl -H "Authorization: Token <token>" https://readthedocs.org/api/v3/remote/repositories/?expand=projects,remote_organization
17171717

17181718
.. code-tab:: python
17191719

17201720
import requests
1721-
URL = 'https://readthedocs.org/api/v3/remote/repositories/?expand=project,organization'
1721+
URL = 'https://readthedocs.org/api/v3/remote/repositories/?expand=projects,remote_organization'
17221722
TOKEN = '<token>'
17231723
HEADERS = {'Authorization': f'token {TOKEN}'}
17241724
response = requests.get(URL, headers=HEADERS)
@@ -1730,11 +1730,11 @@ Remote Repository listing
17301730

17311731
{
17321732
"count": 20,
1733-
"next": "api/v3/remote/repositories/?expand=project,organization&limit=10&offset=10",
1733+
"next": "api/v3/remote/repositories/?expand=projects,remote_organization&limit=10&offset=10",
17341734
"previous": null,
17351735
"results": [
17361736
{
1737-
"organization": {
1737+
"remote_organization": {
17381738
"avatar_url": "https://avatars.githubusercontent.com/u/12345?v=4",
17391739
"created": "2019-04-29T10:00:00Z",
17401740
"modified": "2019-04-29T12:00:00Z",
@@ -1744,7 +1744,7 @@ Remote Repository listing
17441744
"url": "https://github.com/organization",
17451745
"vcs_provider": "github"
17461746
},
1747-
"project": {
1747+
"project": [{
17481748
"id": 12345,
17491749
"name": "project",
17501750
"slug": "project",
@@ -1787,7 +1787,7 @@ Remote Repository listing
17871787
"redirects": "/api/v3/projects/project/redirects/",
17881788
"translations": "/api/v3/projects/project/translations/"
17891789
}
1790-
}
1790+
}],
17911791
"avatar_url": "https://avatars3.githubusercontent.com/u/test-organization?v=4",
17921792
"clone_url": "https://github.com/organization/project.git",
17931793
"created": "2019-04-29T10:00:00Z",
@@ -1814,7 +1814,7 @@ Remote Repository listing
18141814
:query string vcs_provider: return remote repositories for specific vcs provider (``github``, ``gitlab`` or ``bitbucket``)
18151815
:query string organization: return remote repositories for specific remote organization (using remote organization ``slug``)
18161816
:query string expand: allows to add/expand some extra fields in the response.
1817-
Allowed values are ``project`` and ``organization``.
1817+
Allowed values are ``projects`` and ``remote_organization``.
18181818
Multiple fields can be passed separated by commas.
18191819

18201820
:requestheader Authorization: token to authenticate.

readthedocs/api/v3/serializers.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -950,11 +950,11 @@ class Meta:
950950
]
951951
read_only_fields = fields
952952
expandable_fields = {
953-
'organization': (
953+
'remote_organization': (
954954
RemoteOrganizationSerializer, {'source': 'organization'}
955955
),
956-
'project': (
957-
ProjectSerializer, {'source': 'project'}
956+
'projects': (
957+
ProjectSerializer, {'source': 'projects', 'many': True}
958958
)
959959
}
960960

readthedocs/api/v3/tests/responses/remoterepositories-list.json

+11-11
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,9 @@
1414
"html_url": "https://github.com/rtd/project",
1515
"modified": "2019-04-29T12:00:00Z",
1616
"name": "project",
17-
"organization": {
18-
"avatar_url": "https://avatars.githubusercontent.com/u/366329?v=4",
19-
"created": "2019-04-29T10:00:00Z",
20-
"modified": "2019-04-29T12:00:00Z",
21-
"name": "Read the Docs",
22-
"pk": 1,
23-
"slug": "readthedocs",
24-
"url": "https://github.com/readthedocs",
25-
"vcs_provider": "github"
26-
},
2717
"pk": 1,
2818
"private": false,
29-
"project": {
19+
"projects": [{
3020
"_links": {
3121
"_self": "https://readthedocs.org/api/v3/projects/project/",
3222
"builds": "https://readthedocs.org/api/v3/projects/project/builds/",
@@ -58,6 +48,16 @@
5848
"versions": "https://readthedocs.org/projects/project/versions/"
5949
},
6050
"users": [{ "username": "testuser" }]
51+
}],
52+
"remote_organization": {
53+
"avatar_url": "https://avatars.githubusercontent.com/u/366329?v=4",
54+
"created": "2019-04-29T10:00:00Z",
55+
"modified": "2019-04-29T12:00:00Z",
56+
"name": "Read the Docs",
57+
"pk": 1,
58+
"slug": "readthedocs",
59+
"url": "https://github.com/readthedocs",
60+
"vcs_provider": "github"
6161
},
6262
"ssh_url": "[email protected]:rtd/project.git",
6363
"vcs": "git",

readthedocs/api/v3/tests/test_remoterepositories.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ def setUp(self):
3333

3434
self.remote_repository = fixture.get(
3535
RemoteRepository,
36-
project=self.project,
3736
organization=self.remote_organization,
3837
created=self.created,
3938
modified=self.modified,
@@ -49,6 +48,8 @@ def setUp(self):
4948
default_branch="master",
5049
private=False
5150
)
51+
self.remote_repository.projects.add(self.project)
52+
5253
social_account = fixture.get(SocialAccount, user=self.me, provider=GITHUB)
5354
fixture.get(
5455
RemoteRepositoryRelation,
@@ -70,8 +71,8 @@ def test_remote_repository_list(self):
7071
reverse('remoterepositories-list'),
7172
{
7273
'expand': (
73-
'project,'
74-
'organization'
74+
'projects,'
75+
'remote_organization'
7576
)
7677
}
7778
)
@@ -88,8 +89,8 @@ def test_remote_repository_list_name_filter(self):
8889
reverse('remoterepositories-list'),
8990
{
9091
'expand': (
91-
'project,'
92-
'organization'
92+
'projects,'
93+
'remote_organization'
9394
),
9495
'name': 'proj'
9596
}

readthedocs/api/v3/views.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,8 @@ class RemoteRepositoryViewSet(
451451
queryset = RemoteRepository.objects.all()
452452
permission_classes = (IsAuthenticated,)
453453
permit_list_expands = [
454-
'organization',
455-
'project'
454+
'remote_organization',
455+
'projects'
456456
]
457457

458458
def get_queryset(self):
@@ -466,13 +466,11 @@ def get_queryset(self):
466466
)
467467
)
468468

469-
if is_expanded(self.request, 'organization'):
469+
if is_expanded(self.request, 'remote_organization'):
470470
queryset = queryset.select_related('organization')
471471

472-
if is_expanded(self.request, 'project'):
473-
queryset = queryset.select_related('project').prefetch_related(
474-
'project__users',
475-
)
472+
if is_expanded(self.request, 'projects'):
473+
queryset = queryset.prefetch_related('projects__users')
476474

477475
return queryset.order_by('organization__name', 'full_name').distinct()
478476

readthedocs/builds/tasks.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ def send_build_status(build_pk, commit, status, link_to_build=False):
374374
service_class = build.project.git_service_class()
375375
users = build.project.users.all()
376376

377-
try:
377+
if build.project.remote_repository:
378378
remote_repository = build.project.remote_repository
379379
remote_repository_relations = (
380380
remote_repository.remote_repository_relations.filter(
@@ -409,8 +409,7 @@ def send_build_status(build_pk, commit, status, link_to_build=False):
409409
relation.user.username,
410410
)
411411
return True
412-
413-
except RemoteRepository.DoesNotExist:
412+
else:
414413
log.warning(
415414
'Project does not have a RemoteRepository. project=%s',
416415
build.project.slug,

readthedocs/oauth/admin.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class RemoteRepositoryAdmin(admin.ModelAdmin):
1616

1717
"""Admin configuration for the RemoteRepository model."""
1818

19-
raw_id_fields = ('project', 'organization',)
19+
raw_id_fields = ('organization',)
2020

2121

2222
class RemoteRepositoryRelationAdmin(admin.ModelAdmin):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Generated by Django 2.2.22 on 2021-06-14 15:42
2+
3+
from django.db import migrations
4+
5+
6+
def migrate_data(apps, schema_editor):
7+
RemoteRepository = apps.get_model('oauth', 'RemoteRepository')
8+
queryset = RemoteRepository.objects.filter(project__isnull=False).select_related('project')
9+
for rr in queryset.iterator():
10+
rr.project.remote_repository = rr
11+
rr.save()
12+
13+
14+
class Migration(migrations.Migration):
15+
16+
dependencies = [
17+
('oauth', '0013_create_new_table_for_remote_repository_normalization'),
18+
('projects', '0076_project_remote_repository'),
19+
]
20+
21+
operations = [
22+
migrations.RunPython(migrate_data),
23+
migrations.RemoveField(
24+
model_name='remoterepository',
25+
name='project',
26+
),
27+
]

readthedocs/oauth/models.py

-7
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,6 @@ class RemoteRepository(TimeStampedModel):
124124
blank=True,
125125
on_delete=models.CASCADE,
126126
)
127-
project = models.OneToOneField(
128-
Project,
129-
on_delete=models.SET_NULL,
130-
related_name='remote_repository',
131-
null=True,
132-
blank=True,
133-
)
134127
name = models.CharField(_('Name'), max_length=255)
135128
full_name = models.CharField(
136129
_('Full Name'),

readthedocs/oauth/services/gitlab.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ class GitLabService(Service):
5454
def _get_repo_id(self, project):
5555
# The ID or URL-encoded path of the project
5656
# https://docs.gitlab.com/ce/api/README.html#namespaced-path-encoding
57-
try:
57+
if project.remote_repository:
5858
repo_id = project.remote_repository.remote_id
59-
except Project.remote_repository.RelatedObjectDoesNotExist:
59+
else:
6060
# Handle "Manual Import" when there is no RemoteRepository
6161
# associated with the project. It only works with gitlab.com at the
6262
# moment (doesn't support custom gitlab installations)

readthedocs/projects/admin.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class ProjectAdmin(admin.ModelAdmin):
165165
DomainInline,
166166
]
167167
readonly_fields = ('pub_date', 'feature_flags',)
168-
raw_id_fields = ('users', 'main_language_project')
168+
raw_id_fields = ('users', 'main_language_project', 'remote_repository')
169169
actions = [
170170
'send_owner_email',
171171
'ban_owner',

readthedocs/projects/forms.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def save(self, commit=True):
107107
remote_repo = self.cleaned_data.get('remote_repository', None)
108108
if remote_repo:
109109
if commit:
110-
remote_repo.project = self.instance
110+
remote_repo.projects.add(self.instance)
111111
remote_repo.save()
112112
else:
113113
instance.remote_repository = remote_repo
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Generated by Django 2.2.22 on 2021-06-14 15:42
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('oauth', '0013_create_new_table_for_remote_repository_normalization'),
11+
('projects', '0075_change_mkdocs_name'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='project',
17+
name='remote_repository',
18+
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='projects', to='oauth.RemoteRepository'),
19+
),
20+
]

readthedocs/projects/models.py

+8
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,14 @@ class Project(models.Model):
423423
objects = ProjectQuerySet.as_manager()
424424
all_objects = models.Manager()
425425

426+
remote_repository = models.ForeignKey(
427+
'oauth.RemoteRepository',
428+
on_delete=models.SET_NULL,
429+
related_name='projects',
430+
null=True,
431+
blank=True,
432+
)
433+
426434
# Property used for storing the latest build for a project when prefetching
427435
LATEST_BUILD_CACHE = '_latest_build'
428436

readthedocs/rtd_tests/tests/test_celery.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,8 @@ def test_send_build_status_with_remote_repo_github(self, send_build_status):
352352
self.project.save()
353353

354354
social_account = get(SocialAccount, user=self.eric, provider='gitlab')
355-
remote_repo = get(RemoteRepository, project=self.project)
355+
remote_repo = get(RemoteRepository)
356+
remote_repo.projects.add(self.project)
356357
get(
357358
RemoteRepositoryRelation,
358359
remote_repository=remote_repo,
@@ -417,7 +418,8 @@ def test_send_build_status_with_remote_repo_gitlab(self, send_build_status):
417418
self.project.save()
418419

419420
social_account = get(SocialAccount, user=self.eric, provider='gitlab')
420-
remote_repo = get(RemoteRepository, project=self.project)
421+
remote_repo = get(RemoteRepository)
422+
remote_repo.projects.add(self.project)
421423
get(
422424
RemoteRepositoryRelation,
423425
remote_repository=remote_repo,

readthedocs/rtd_tests/tests/test_oauth_sync.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ def test_sync_delete_stale(self, mock_request):
109109
project = fixture.get(Project)
110110
repo_3 = fixture.get(
111111
RemoteRepository,
112-
project=project,
113112
full_name='organization/project-linked-repository',
114113
remote_id='54321',
115114
vcs_provider=GITHUB
116115
)
116+
repo_3.projects.add(project)
117117
fixture.get(
118118
RemoteRepositoryRelation,
119119
remote_repository=repo_3,

0 commit comments

Comments
 (0)