Skip to content

Commit ed82e79

Browse files
committed
Merge branch 'master' into embed-test-def-lists
2 parents 039859a + b56ccae commit ed82e79

File tree

7 files changed

+58
-67
lines changed

7 files changed

+58
-67
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 2.2.19 on 2021-03-17 15:23
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('projects', '0069_migrate_protected_projects'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='importedfile',
15+
name='md5',
16+
field=models.CharField(max_length=255, null=True, verbose_name='MD5 checksum'),
17+
),
18+
]

readthedocs/projects/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,7 @@ class ImportedFile(models.Model):
13661366
# of 4096 characters for most filesystems (including EXT4).
13671367
# https://github.com/rtfd/readthedocs.org/issues/5061
13681368
path = models.CharField(_('Path'), max_length=4096)
1369-
md5 = models.CharField(_('MD5 checksum'), max_length=255)
1369+
md5 = models.CharField(_('MD5 checksum'), max_length=255, null=True)
13701370
commit = models.CharField(_('Commit'), max_length=255)
13711371
build = models.IntegerField(_('Build id'), null=True)
13721372
modified_date = models.DateTimeField(_('Modified date'), auto_now=True)

readthedocs/projects/signals.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import django.dispatch
44

5-
65
before_vcs = django.dispatch.Signal(providing_args=['version', 'environmemt'])
76
after_vcs = django.dispatch.Signal(providing_args=['version'])
87

@@ -12,4 +11,4 @@
1211
project_import = django.dispatch.Signal(providing_args=['project'])
1312

1413
# Used to purge files from the CDN
15-
files_changed = django.dispatch.Signal(providing_args=['project', 'version', 'files'])
14+
files_changed = django.dispatch.Signal(providing_args=['project', 'version'])

readthedocs/projects/tasks.py

+7-49
Original file line numberDiff line numberDiff line change
@@ -1340,15 +1340,14 @@ def fileify(version_pk, commit, build, search_ranking, search_ignore):
13401340
},
13411341
)
13421342
try:
1343-
changed_files = _create_imported_files(
1343+
_create_imported_files(
13441344
version=version,
13451345
commit=commit,
13461346
build=build,
13471347
search_ranking=search_ranking,
13481348
search_ignore=search_ignore,
13491349
)
13501350
except Exception:
1351-
changed_files = set()
13521351
log.exception('Failed during ImportedFile creation')
13531352

13541353
try:
@@ -1357,7 +1356,7 @@ def fileify(version_pk, commit, build, search_ranking, search_ignore):
13571356
log.exception('Failed during SphinxDomain creation')
13581357

13591358
try:
1360-
_sync_imported_files(version, build, changed_files)
1359+
_sync_imported_files(version, build)
13611360
except Exception:
13621361
log.exception('Failed during ImportedFile syncing')
13631362

@@ -1530,57 +1529,22 @@ def _create_imported_files(*, version, commit, build, search_ranking, search_ign
15301529
:param version: Version instance
15311530
:param commit: Commit that updated path
15321531
:param build: Build id
1533-
:returns: paths of changed files
1534-
:rtype: set
15351532
"""
1536-
changed_files = set()
1537-
15381533
# Re-create all objects from the new build of the version
15391534
storage_path = version.project.get_storage_path(
15401535
type_='html', version_slug=version.slug, include_file=False
15411536
)
15421537
for root, __, filenames in build_media_storage.walk(storage_path):
15431538
for filename in filenames:
1544-
if filename.endswith('.html'):
1545-
model_class = HTMLFile
1546-
elif version.project.cdn_enabled:
1547-
# We need to track all files for CDN enabled projects so the files can be purged
1548-
model_class = ImportedFile
1549-
else:
1550-
# For projects not behind a CDN, we don't care about non-HTML
1539+
# We don't care about non-HTML files
1540+
if not filename.endswith('.html'):
15511541
continue
15521542

15531543
full_path = build_media_storage.join(root, filename)
15541544

15551545
# Generate a relative path for storage similar to os.path.relpath
15561546
relpath = full_path.replace(storage_path, '', 1).lstrip('/')
15571547

1558-
try:
1559-
md5 = hashlib.md5(build_media_storage.open(full_path, 'rb').read()).hexdigest()
1560-
except Exception:
1561-
log.exception(
1562-
'Error while generating md5 for %s:%s:%s. Don\'t stop.',
1563-
version.project.slug,
1564-
version.slug,
1565-
relpath,
1566-
)
1567-
md5 = ''
1568-
# Keep track of changed files to be purged in the CDN
1569-
obj = (
1570-
model_class.objects
1571-
.filter(project=version.project, version=version, path=relpath)
1572-
.order_by('-modified_date')
1573-
.first()
1574-
)
1575-
if obj and md5 and obj.md5 != md5:
1576-
changed_files.add(
1577-
resolve_path(
1578-
version.project,
1579-
filename=relpath,
1580-
version_slug=version.slug,
1581-
),
1582-
)
1583-
15841548
page_rank = 0
15851549
# Last pattern to match takes precedence
15861550
# XXX: see if we can implement another type of precedence,
@@ -1598,37 +1562,31 @@ def _create_imported_files(*, version, commit, build, search_ranking, search_ign
15981562
break
15991563

16001564
# Create imported files from new build
1601-
model_class.objects.create(
1565+
HTMLFile.objects.create(
16021566
project=version.project,
16031567
version=version,
16041568
path=relpath,
16051569
name=filename,
1606-
md5=md5,
16071570
rank=page_rank,
16081571
commit=commit,
16091572
build=build,
16101573
ignore=ignore,
16111574
)
16121575

1613-
# This signal is used for clearing the CDN,
1614-
# so send it as soon as we have the list of changed files
1576+
# This signal is used for purging the CDN.
16151577
files_changed.send(
16161578
sender=Project,
16171579
project=version.project,
16181580
version=version,
1619-
files=changed_files,
16201581
)
16211582

1622-
return changed_files
1623-
16241583

1625-
def _sync_imported_files(version, build, changed_files):
1584+
def _sync_imported_files(version, build):
16261585
"""
16271586
Sync/Update/Delete ImportedFiles objects of this version.
16281587
16291588
:param version: Version instance
16301589
:param build: Build id
1631-
:param changed_files: path of changed files
16321590
"""
16331591

16341592
# Index new HTMLFiles to ElasticSearch

readthedocs/projects/views/public.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
from readthedocs.analytics.tasks import analytics_event
2828
from readthedocs.analytics.utils import get_client_ip
29-
from readthedocs.builds.constants import LATEST
29+
from readthedocs.builds.constants import LATEST, BUILD_STATUS_DUPLICATED
3030
from readthedocs.builds.models import Version
3131
from readthedocs.builds.views import BuildTriggerMixin
3232
from readthedocs.core.permissions import AdminPermission
@@ -177,10 +177,13 @@ def get(self, request, project_slug, *args, **kwargs):
177177
).first()
178178

179179
if version:
180-
last_build = version.builds.filter(
181-
type='html',
182-
state='finished',
183-
).order_by('-date').first()
180+
last_build = (
181+
version.builds
182+
.filter(type='html', state='finished')
183+
.exclude(status=BUILD_STATUS_DUPLICATED)
184+
.order_by('-date')
185+
.first()
186+
)
184187
if last_build:
185188
if last_build.success:
186189
status = self.STATUS_PASSING

readthedocs/rtd_tests/tests/test_imported_file.py

+3-9
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def _manage_imported_files(
4747
search_ranking=search_ranking,
4848
search_ignore=search_ignore,
4949
)
50-
_sync_imported_files(version, build, set())
50+
_sync_imported_files(version, build)
5151

5252
def _copy_storage_dir(self):
5353
"""Copy the test directory (rtd_tests/files) to storage"""
@@ -63,18 +63,14 @@ def _copy_storage_dir(self):
6363
def test_properly_created(self):
6464
# Only 2 files in the directory is HTML (test.html, api/index.html)
6565
self.assertEqual(ImportedFile.objects.count(), 0)
66-
self._manage_imported_files(self.version, 'commit01', 1)
66+
self._manage_imported_files(version=self.version, commit='commit01', build=1)
6767
self.assertEqual(ImportedFile.objects.count(), 2)
68-
self._manage_imported_files(self.version, 'commit01', 2)
68+
self._manage_imported_files(version=self.version, commit='commit01', build=2)
6969
self.assertEqual(ImportedFile.objects.count(), 2)
7070

7171
self.project.cdn_enabled = True
7272
self.project.save()
7373

74-
# CDN enabled projects => save all files
75-
self._manage_imported_files(self.version, 'commit01', 3)
76-
self.assertEqual(ImportedFile.objects.count(), 4)
77-
7874
def test_update_commit(self):
7975
self.assertEqual(ImportedFile.objects.count(), 0)
8076
self._manage_imported_files(self.version, 'commit01', 1)
@@ -168,7 +164,6 @@ def test_update_content(self):
168164
self._copy_storage_dir()
169165

170166
self._manage_imported_files(self.version, 'commit01', 1)
171-
self.assertEqual(ImportedFile.objects.get(name='test.html').md5, 'c7532f22a052d716f7b2310fb52ad981')
172167
self.assertEqual(ImportedFile.objects.count(), 2)
173168

174169
with open(os.path.join(test_dir, 'test.html'), 'w+') as f:
@@ -177,7 +172,6 @@ def test_update_content(self):
177172
self._copy_storage_dir()
178173

179174
self._manage_imported_files(self.version, 'commit02', 2)
180-
self.assertNotEqual(ImportedFile.objects.get(name='test.html').md5, 'c7532f22a052d716f7b2310fb52ad981')
181175
self.assertEqual(ImportedFile.objects.count(), 2)
182176

183177
@override_settings(PRODUCTION_DOMAIN='readthedocs.org')

readthedocs/rtd_tests/tests/test_project_views.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from django.views.generic.base import ContextMixin
1212
from django_dynamic_fixture import get, new
1313

14-
from readthedocs.builds.constants import EXTERNAL
14+
from readthedocs.builds.constants import BUILD_STATUS_DUPLICATED, EXTERNAL
1515
from readthedocs.builds.models import Build, Version
1616
from readthedocs.integrations.models import GenericAPIWebhook, GitHubWebhook
1717
from readthedocs.oauth.models import RemoteRepository
@@ -611,6 +611,25 @@ def test_passing_badge(self):
611611
self.assertContains(res, 'passing')
612612
self.assertEqual(res['Content-Type'], 'image/svg+xml')
613613

614+
def test_ignore_duplicated_build(self):
615+
"""Ignore builds marked as duplicate from the badge status."""
616+
get(
617+
Build,
618+
project=self.project,
619+
version=self.version,
620+
success=True,
621+
)
622+
get(
623+
Build,
624+
project=self.project,
625+
version=self.version,
626+
success=False,
627+
status=BUILD_STATUS_DUPLICATED,
628+
)
629+
res = self.client.get(self.badge_url, {'version': self.version.slug})
630+
self.assertContains(res, 'passing')
631+
self.assertEqual(res['Content-Type'], 'image/svg+xml')
632+
614633
def test_failing_badge(self):
615634
get(Build, project=self.project, version=self.version, success=False)
616635
res = self.client.get(self.badge_url, {'version': self.version.slug})

0 commit comments

Comments
 (0)