From 40fb6eebd73e0dc4eabe231f3f2cec9fc265549d Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Sat, 29 Jun 2019 03:08:41 +0600 Subject: [PATCH 01/18] Send Build Status using Github Status API --- readthedocs/builds/constants.py | 31 +++++++++ readthedocs/builds/models.py | 8 +++ readthedocs/core/utils/__init__.py | 11 +++- readthedocs/doc_builder/environments.py | 2 +- readthedocs/oauth/services/base.py | 3 + readthedocs/oauth/services/github.py | 86 +++++++++++++++++++++++++ readthedocs/projects/tasks.py | 49 ++++++++++++++ 7 files changed, 187 insertions(+), 3 deletions(-) diff --git a/readthedocs/builds/constants.py b/readthedocs/builds/constants.py index bdc9a70fe79..2b7c179d2f6 100644 --- a/readthedocs/builds/constants.py +++ b/readthedocs/builds/constants.py @@ -61,3 +61,34 @@ LATEST, STABLE, ) + +# GitHub Build Statuses +GITHUB_BUILD_STATE_FAILURE = 'failure' +GITHUB_BUILD_STATE_PENDING = 'pending' +GITHUB_BUILD_STATE_SUCCESS = 'success' + +# GitHub Build Statuses +GITLAB_BUILD_STATE_FAILURE = 'failed' +GITLAB_BUILD_STATE_PENDING = 'pending' +GITLAB_BUILD_STATE_SUCCESS = 'success' + +# General Build Statuses +BUILD_STATUS_FAILURE = 'failed' +BUILD_STATUS_PENDING = 'pending' +BUILD_STATUS_SUCCESS = 'success' + +# Used to select correct Build status to be sent for each service +SELECT_BUILD_STATUS = { + BUILD_STATUS_FAILURE: { + 'github': GITHUB_BUILD_STATE_FAILURE, + 'gitlab': GITLAB_BUILD_STATE_FAILURE, + }, + BUILD_STATUS_PENDING: { + 'github': GITHUB_BUILD_STATE_PENDING, + 'gitlab': GITLAB_BUILD_STATE_PENDING, + }, + BUILD_STATUS_SUCCESS: { + 'github': GITHUB_BUILD_STATE_SUCCESS, + 'gitlab': GITLAB_BUILD_STATE_SUCCESS, + }, +} diff --git a/readthedocs/builds/models.py b/readthedocs/builds/models.py index 8e857d5c0e1..1163a078efb 100644 --- a/readthedocs/builds/models.py +++ b/readthedocs/builds/models.py @@ -734,6 +734,14 @@ def __str__(self): def get_absolute_url(self): return reverse('builds_detail', args=[self.project.slug, self.pk]) + def get_full_url(self): + """Get url including domain and scheme""" + full_url = '{domain}{absolute_url}'.format( + domain=settings.PUBLIC_API_URL, + absolute_url=self.get_absolute_url() + ) + return full_url + @property def finished(self): """Return if build has a finished state.""" diff --git a/readthedocs/core/utils/__init__.py b/readthedocs/core/utils/__init__.py index dbb8245c6fb..9fd917f095c 100644 --- a/readthedocs/core/utils/__init__.py +++ b/readthedocs/core/utils/__init__.py @@ -11,7 +11,10 @@ from django.utils.safestring import SafeText, mark_safe from django.utils.text import slugify as slugify_base -from readthedocs.builds.constants import BUILD_STATE_TRIGGERED +from readthedocs.builds.constants import ( + BUILD_STATE_TRIGGERED, + BUILD_STATUS_PENDING, +) from readthedocs.doc_builder.constants import DOCKER_LIMITS @@ -78,7 +81,7 @@ def prepare_build( # Avoid circular import from readthedocs.builds.models import Build from readthedocs.projects.models import Project - from readthedocs.projects.tasks import update_docs_task + from readthedocs.projects.tasks import update_docs_task, send_build_status build = None @@ -125,6 +128,10 @@ def prepare_build( options['soft_time_limit'] = time_limit options['time_limit'] = int(time_limit * 1.2) + if build: + # Send pending Build Status to Git Status API + send_build_status.delay(build.id, BUILD_STATUS_PENDING) + return ( update_docs_task.signature( args=(version.pk,), diff --git a/readthedocs/doc_builder/environments.py b/readthedocs/doc_builder/environments.py index 4d9fcb65e50..db47edf41cd 100644 --- a/readthedocs/doc_builder/environments.py +++ b/readthedocs/doc_builder/environments.py @@ -658,7 +658,7 @@ def failed(self): def done(self): """Is build in finished state.""" return ( - self.build is not None and + self.build and self.build['state'] == BUILD_STATE_FINISHED ) diff --git a/readthedocs/oauth/services/base.py b/readthedocs/oauth/services/base.py index 8bf95707b6c..6d9464c9ec9 100644 --- a/readthedocs/oauth/services/base.py +++ b/readthedocs/oauth/services/base.py @@ -216,6 +216,9 @@ def setup_webhook(self, project): def update_webhook(self, project, integration): raise NotImplementedError + def send_status(self, project, identifier, state, build_url): + raise NotImplementedError + @classmethod def is_project_service(cls, project): """ diff --git a/readthedocs/oauth/services/github.py b/readthedocs/oauth/services/github.py index ce0ed3b9163..3b8b0360b17 100644 --- a/readthedocs/oauth/services/github.py +++ b/readthedocs/oauth/services/github.py @@ -12,6 +12,11 @@ from readthedocs.api.v2.client import api from readthedocs.builds import utils as build_utils +from readthedocs.builds.constants import ( + GITHUB_BUILD_STATE_FAILURE, + GITHUB_BUILD_STATE_PENDING, + GITHUB_BUILD_STATE_SUCCESS, +) from readthedocs.integrations.models import Integration from ..models import RemoteOrganization, RemoteRepository @@ -311,6 +316,87 @@ def update_webhook(self, project, integration): ) return (False, resp) + def send_status(self, project, identifier, state, build_url): + """ + Create GitHub commit status for project. + + :param project: project to set up commit status for + :type project: Project + :param identifier: commit sha of the version + :type identifier: str + :param state: build state failure, pending, or success. + :type state: str + :param build_url: build url + :type build_url: str + :returns: boolean based on commit status creation was successful or not. + :rtype: Bool + """ + session = self.get_session() + owner, repo = build_utils.get_github_username_repo(url=project.repo) + + description = '' + if state == GITHUB_BUILD_STATE_SUCCESS: + description = 'The build succeeded!' + elif state == GITHUB_BUILD_STATE_FAILURE: + description = 'The build failed!' + elif state == GITHUB_BUILD_STATE_PENDING: + description = 'The build is pending!' + + data = { + "state": state, + "target_url": build_url, + "description": description, + "context": "continuous-documentation/read-the-docs" + } + + resp = None + try: + resp = session.post( + ( + 'https://api.github.com/repos/{owner}/{repo}/statuses/{sha}' + .format(owner=owner, repo=repo, sha=identifier) + ), + data=json.dumps(data), + headers={'content-type': 'application/json'}, + ) + if resp.status_code == 201: + log.info( + 'GitHub commit status for project: %s', + project, + ) + return True + + if resp.status_code in [401, 403, 404]: + log.info( + 'GitHub project does not exist or user does not have ' + 'permissions: project=%s', + project, + ) + return False + + # Catch exceptions with request or deserializing JSON + except (RequestException, ValueError): + log.exception( + 'GitHub commit status creation failed for project: %s', + project, + ) + else: + log.error( + 'GitHub commit status creation failed for project: %s', + project, + ) + # Response data should always be JSON, still try to log if not + # though + try: + debug_data = resp.json() + except ValueError: + debug_data = resp.content + log.debug( + 'GitHub commit status creation failure response: %s', + debug_data, + ) + return False + @classmethod def get_token_for_project(cls, project, force_local=False): """Get access token for project by iterating over project users.""" diff --git a/readthedocs/projects/tasks.py b/readthedocs/projects/tasks.py index 12fe740c600..c617a583e72 100644 --- a/readthedocs/projects/tasks.py +++ b/readthedocs/projects/tasks.py @@ -34,6 +34,10 @@ LATEST, LATEST_VERBOSE_NAME, STABLE_VERBOSE_NAME, + EXTERNAL, + BUILD_STATUS_SUCCESS, + BUILD_STATUS_FAILURE, + SELECT_BUILD_STATUS, ) from readthedocs.builds.models import APIVersion, Build, Version from readthedocs.builds.signals import build_complete @@ -59,6 +63,7 @@ ) from readthedocs.doc_builder.loader import get_builder_class from readthedocs.doc_builder.python_environments import Conda, Virtualenv +from readthedocs.oauth.services.github import GitHubService from readthedocs.projects.models import APIProject, Feature from readthedocs.search.utils import index_new_files, remove_indexed_files from readthedocs.sphinx_domains.models import SphinxDomain @@ -573,6 +578,16 @@ def run_build(self, docker, record): if self.build_env.failed: self.send_notifications(self.version.pk, self.build['id']) + # send build failure status to git Status API + self.send_build_status( + self.build['id'], BUILD_STATUS_FAILURE + ) + + if self.build_env.successful: + # send build successful status to git Status API + self.send_build_status( + self.build['id'], BUILD_STATUS_SUCCESS + ) build_complete.send(sender=Build, build=self.build_env.build) @@ -1008,6 +1023,10 @@ def is_type_sphinx(self): """Is documentation type Sphinx.""" return 'sphinx' in self.config.doctype + def send_build_status(self, build_pk, state): + """Send github build status for pull/merge requests.""" + send_build_status.delay(build_pk, state) + # Web tasks @app.task(queue='web') @@ -1773,3 +1792,33 @@ def retry_domain_verification(domain_pk): sender=domain.__class__, domain=domain, ) + + +@app.task(queue='web') +def send_build_status(build_pk, state): + """ + Send Build Status to Git Status API for project. + + :param build_pk: Build pk + :param state: build state failed, pending, or success to be sent. + """ + build = Build.objects.get(pk=build_pk) + version = build.version + project = build.project + + # Send status reports for only External (pull/merge request) Versions. + if version.type != EXTERNAL: + return + + if 'github.com' in project.repo: + account = project.remote_repository.account + service = GitHubService(project.users.first(), account) + # select the correct state. + state = SELECT_BUILD_STATUS[state]['github'] + + # send Status report using the API. + service.send_status( + project, version.identifier, state, build.get_full_url() + ) + + # TODO: Send build status for other providers. From c56148673a31fd0c9708b3855c6077123457103c Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Sat, 29 Jun 2019 03:28:14 +0600 Subject: [PATCH 02/18] docstring update --- readthedocs/builds/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/builds/models.py b/readthedocs/builds/models.py index 1163a078efb..771568039ff 100644 --- a/readthedocs/builds/models.py +++ b/readthedocs/builds/models.py @@ -735,7 +735,7 @@ def get_absolute_url(self): return reverse('builds_detail', args=[self.project.slug, self.pk]) def get_full_url(self): - """Get url including domain and scheme""" + """Get full url including domain""" full_url = '{domain}{absolute_url}'.format( domain=settings.PUBLIC_API_URL, absolute_url=self.get_absolute_url() From 3cf07f237e63be9d6f11345bb08f6d687b2f2c47 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Sat, 29 Jun 2019 14:55:27 +0600 Subject: [PATCH 03/18] Updated Constants and notification sending --- readthedocs/builds/constants.py | 5 ++++- readthedocs/oauth/services/github.py | 20 ++++++-------------- readthedocs/projects/tasks.py | 13 ++++++------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/readthedocs/builds/constants.py b/readthedocs/builds/constants.py index 2b7c179d2f6..ec56e8f8a60 100644 --- a/readthedocs/builds/constants.py +++ b/readthedocs/builds/constants.py @@ -77,18 +77,21 @@ BUILD_STATUS_PENDING = 'pending' BUILD_STATUS_SUCCESS = 'success' -# Used to select correct Build status to be sent for each service +# Used to select correct Build status and description to be sent to each service API SELECT_BUILD_STATUS = { BUILD_STATUS_FAILURE: { 'github': GITHUB_BUILD_STATE_FAILURE, 'gitlab': GITLAB_BUILD_STATE_FAILURE, + 'description': 'The build failed!', }, BUILD_STATUS_PENDING: { 'github': GITHUB_BUILD_STATE_PENDING, 'gitlab': GITLAB_BUILD_STATE_PENDING, + 'description': 'The build is pending!', }, BUILD_STATUS_SUCCESS: { 'github': GITHUB_BUILD_STATE_SUCCESS, 'gitlab': GITLAB_BUILD_STATE_SUCCESS, + 'description': 'The build succeeded!', }, } diff --git a/readthedocs/oauth/services/github.py b/readthedocs/oauth/services/github.py index 3b8b0360b17..114193677de 100644 --- a/readthedocs/oauth/services/github.py +++ b/readthedocs/oauth/services/github.py @@ -12,11 +12,7 @@ from readthedocs.api.v2.client import api from readthedocs.builds import utils as build_utils -from readthedocs.builds.constants import ( - GITHUB_BUILD_STATE_FAILURE, - GITHUB_BUILD_STATE_PENDING, - GITHUB_BUILD_STATE_SUCCESS, -) +from readthedocs.builds.constants import SELECT_BUILD_STATUS from readthedocs.integrations.models import Integration from ..models import RemoteOrganization, RemoteRepository @@ -316,7 +312,7 @@ def update_webhook(self, project, integration): ) return (False, resp) - def send_status(self, project, identifier, state, build_url): + def send_build_status(self, project, identifier, state, build_url): """ Create GitHub commit status for project. @@ -334,16 +330,12 @@ def send_status(self, project, identifier, state, build_url): session = self.get_session() owner, repo = build_utils.get_github_username_repo(url=project.repo) - description = '' - if state == GITHUB_BUILD_STATE_SUCCESS: - description = 'The build succeeded!' - elif state == GITHUB_BUILD_STATE_FAILURE: - description = 'The build failed!' - elif state == GITHUB_BUILD_STATE_PENDING: - description = 'The build is pending!' + # select the correct state and description. + github_build_state = SELECT_BUILD_STATUS[state]['github'] + description = SELECT_BUILD_STATUS[state]['description'] data = { - "state": state, + "state": github_build_state, "target_url": build_url, "description": description, "context": "continuous-documentation/read-the-docs" diff --git a/readthedocs/projects/tasks.py b/readthedocs/projects/tasks.py index c617a583e72..4c83ad36ae6 100644 --- a/readthedocs/projects/tasks.py +++ b/readthedocs/projects/tasks.py @@ -37,7 +37,6 @@ EXTERNAL, BUILD_STATUS_SUCCESS, BUILD_STATUS_FAILURE, - SELECT_BUILD_STATUS, ) from readthedocs.builds.models import APIVersion, Build, Version from readthedocs.builds.signals import build_complete @@ -1532,7 +1531,8 @@ def _manage_imported_files(version, path, commit, build): @app.task(queue='web') def send_notifications(version_pk, build_pk): version = Version.objects.get_object_or_log(pk=version_pk) - if not version: + # only send notification for Internal versions + if not version or version.type != EXTERNAL: return build = Build.objects.get(pk=build_pk) @@ -1797,7 +1797,7 @@ def retry_domain_verification(domain_pk): @app.task(queue='web') def send_build_status(build_pk, state): """ - Send Build Status to Git Status API for project. + Send Build Status to Git Status API for project external versions. :param build_pk: Build pk :param state: build state failed, pending, or success to be sent. @@ -1813,12 +1813,11 @@ def send_build_status(build_pk, state): if 'github.com' in project.repo: account = project.remote_repository.account service = GitHubService(project.users.first(), account) - # select the correct state. - state = SELECT_BUILD_STATUS[state]['github'] # send Status report using the API. - service.send_status( - project, version.identifier, state, build.get_full_url() + service.send_build_status( + project, version.identifier, state, + build.get_full_url() ) # TODO: Send build status for other providers. From d9a867bdf997516637fd178fad5a229dbe172bde Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Sat, 29 Jun 2019 14:56:18 +0600 Subject: [PATCH 04/18] cleanup --- readthedocs/projects/tasks.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readthedocs/projects/tasks.py b/readthedocs/projects/tasks.py index 4c83ad36ae6..2e4c63ee196 100644 --- a/readthedocs/projects/tasks.py +++ b/readthedocs/projects/tasks.py @@ -1531,9 +1531,11 @@ def _manage_imported_files(version, path, commit, build): @app.task(queue='web') def send_notifications(version_pk, build_pk): version = Version.objects.get_object_or_log(pk=version_pk) + # only send notification for Internal versions - if not version or version.type != EXTERNAL: + if not version or version.type == EXTERNAL: return + build = Build.objects.get(pk=build_pk) for hook in version.project.webhook_notifications.all(): From ef6707bffc10b35de71e13081f552ddaacecc617 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Tue, 2 Jul 2019 19:26:11 +0600 Subject: [PATCH 05/18] task update --- readthedocs/builds/constants.py | 2 +- readthedocs/oauth/services/base.py | 2 +- readthedocs/oauth/services/github.py | 31 ++++++++++------------------ readthedocs/projects/tasks.py | 21 ++++++++----------- 4 files changed, 22 insertions(+), 34 deletions(-) diff --git a/readthedocs/builds/constants.py b/readthedocs/builds/constants.py index ec56e8f8a60..7cb582fa448 100644 --- a/readthedocs/builds/constants.py +++ b/readthedocs/builds/constants.py @@ -67,7 +67,7 @@ GITHUB_BUILD_STATE_PENDING = 'pending' GITHUB_BUILD_STATE_SUCCESS = 'success' -# GitHub Build Statuses +# GitLab Build Statuses GITLAB_BUILD_STATE_FAILURE = 'failed' GITLAB_BUILD_STATE_PENDING = 'pending' GITLAB_BUILD_STATE_SUCCESS = 'success' diff --git a/readthedocs/oauth/services/base.py b/readthedocs/oauth/services/base.py index 6d9464c9ec9..99098f80487 100644 --- a/readthedocs/oauth/services/base.py +++ b/readthedocs/oauth/services/base.py @@ -216,7 +216,7 @@ def setup_webhook(self, project): def update_webhook(self, project, integration): raise NotImplementedError - def send_status(self, project, identifier, state, build_url): + def send_build_status(self, build, state): raise NotImplementedError @classmethod diff --git a/readthedocs/oauth/services/github.py b/readthedocs/oauth/services/github.py index 114193677de..21201286f89 100644 --- a/readthedocs/oauth/services/github.py +++ b/readthedocs/oauth/services/github.py @@ -312,42 +312,38 @@ def update_webhook(self, project, integration): ) return (False, resp) - def send_build_status(self, project, identifier, state, build_url): + def send_build_status(self, build, state): """ Create GitHub commit status for project. - :param project: project to set up commit status for - :type project: Project - :param identifier: commit sha of the version - :type identifier: str + :param build: Build to set up commit status for + :type build: Build :param state: build state failure, pending, or success. :type state: str - :param build_url: build url - :type build_url: str :returns: boolean based on commit status creation was successful or not. :rtype: Bool """ session = self.get_session() + project = build.project owner, repo = build_utils.get_github_username_repo(url=project.repo) + build_sha = build.version.identifier # select the correct state and description. github_build_state = SELECT_BUILD_STATUS[state]['github'] description = SELECT_BUILD_STATUS[state]['description'] data = { - "state": github_build_state, - "target_url": build_url, - "description": description, - "context": "continuous-documentation/read-the-docs" + 'state': github_build_state, + 'target_url': build.get_full_url(), + 'description': description, + 'context': 'continuous-documentation/read-the-docs' } resp = None try: + resp = session.post( - ( - 'https://api.github.com/repos/{owner}/{repo}/statuses/{sha}' - .format(owner=owner, repo=repo, sha=identifier) - ), + f'https://api.github.com/repos/{owner}/{repo}/statuses/{build_sha}', data=json.dumps(data), headers={'content-type': 'application/json'}, ) @@ -372,11 +368,6 @@ def send_build_status(self, project, identifier, state, build_url): 'GitHub commit status creation failed for project: %s', project, ) - else: - log.error( - 'GitHub commit status creation failed for project: %s', - project, - ) # Response data should always be JSON, still try to log if not # though try: diff --git a/readthedocs/projects/tasks.py b/readthedocs/projects/tasks.py index 2e4c63ee196..ffdbaff935f 100644 --- a/readthedocs/projects/tasks.py +++ b/readthedocs/projects/tasks.py @@ -581,8 +581,7 @@ def run_build(self, docker, record): self.send_build_status( self.build['id'], BUILD_STATUS_FAILURE ) - - if self.build_env.successful: + elif self.build_env.successful: # send build successful status to git Status API self.send_build_status( self.build['id'], BUILD_STATUS_SUCCESS @@ -1805,21 +1804,19 @@ def send_build_status(build_pk, state): :param state: build state failed, pending, or success to be sent. """ build = Build.objects.get(pk=build_pk) - version = build.version - project = build.project # Send status reports for only External (pull/merge request) Versions. - if version.type != EXTERNAL: + if build.version.type != EXTERNAL: return - if 'github.com' in project.repo: - account = project.remote_repository.account - service = GitHubService(project.users.first(), account) + if build.project.remote_repository.account.provider == 'github': + account = build.project.remote_repository.account + service = GitHubService( + build.project.remote_repository.users.first(), + account + ) # send Status report using the API. - service.send_build_status( - project, version.identifier, state, - build.get_full_url() - ) + service.send_build_status(build, state) # TODO: Send build status for other providers. From 66526be263149262f9217148809b02ec83224479 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Tue, 2 Jul 2019 20:49:27 +0600 Subject: [PATCH 06/18] send_build_status updated --- readthedocs/oauth/services/github.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/readthedocs/oauth/services/github.py b/readthedocs/oauth/services/github.py index 21201286f89..dad7592237f 100644 --- a/readthedocs/oauth/services/github.py +++ b/readthedocs/oauth/services/github.py @@ -340,8 +340,8 @@ def send_build_status(self, build, state): } resp = None - try: + try: resp = session.post( f'https://api.github.com/repos/{owner}/{repo}/statuses/{build_sha}', data=json.dumps(data), @@ -362,6 +362,8 @@ def send_build_status(self, build, state): ) return False + return False + # Catch exceptions with request or deserializing JSON except (RequestException, ValueError): log.exception( @@ -373,7 +375,10 @@ def send_build_status(self, build, state): try: debug_data = resp.json() except ValueError: - debug_data = resp.content + if resp is not None: + debug_data = resp.content + else: + debug_data = resp log.debug( 'GitHub commit status creation failure response: %s', debug_data, From 8f2505ae3bfc8bd937ce4a36505c861dff738871 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Tue, 2 Jul 2019 20:58:19 +0600 Subject: [PATCH 07/18] updated get full url --- readthedocs/builds/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/builds/models.py b/readthedocs/builds/models.py index 771568039ff..59c19dee225 100644 --- a/readthedocs/builds/models.py +++ b/readthedocs/builds/models.py @@ -736,7 +736,7 @@ def get_absolute_url(self): def get_full_url(self): """Get full url including domain""" - full_url = '{domain}{absolute_url}'.format( + full_url = 'https://{domain}{absolute_url}'.format( domain=settings.PUBLIC_API_URL, absolute_url=self.get_absolute_url() ) From ac67805a907a336f488c0705c7f4d0d190de602d Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Tue, 2 Jul 2019 21:01:17 +0600 Subject: [PATCH 08/18] changed to PRODUCTION_DOMAIN --- readthedocs/builds/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/builds/models.py b/readthedocs/builds/models.py index 59c19dee225..0663f81ae88 100644 --- a/readthedocs/builds/models.py +++ b/readthedocs/builds/models.py @@ -737,7 +737,7 @@ def get_absolute_url(self): def get_full_url(self): """Get full url including domain""" full_url = 'https://{domain}{absolute_url}'.format( - domain=settings.PUBLIC_API_URL, + domain=settings.PRODUCTION_DOMAIN, absolute_url=self.get_absolute_url() ) return full_url From 95264e0b260c957bbb1726adffa1b41447ee98f4 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Tue, 2 Jul 2019 21:47:47 +0600 Subject: [PATCH 09/18] tasks updated --- readthedocs/core/utils/__init__.py | 9 ++++++--- readthedocs/oauth/services/github.py | 13 ++++++------ readthedocs/projects/tasks.py | 30 ++++++++++++++++++---------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/readthedocs/core/utils/__init__.py b/readthedocs/core/utils/__init__.py index 9fd917f095c..8b8834d1f20 100644 --- a/readthedocs/core/utils/__init__.py +++ b/readthedocs/core/utils/__init__.py @@ -81,7 +81,10 @@ def prepare_build( # Avoid circular import from readthedocs.builds.models import Build from readthedocs.projects.models import Project - from readthedocs.projects.tasks import update_docs_task, send_build_status + from readthedocs.projects.tasks import ( + update_docs_task, + send_external_build_status, + ) build = None @@ -129,8 +132,8 @@ def prepare_build( options['time_limit'] = int(time_limit * 1.2) if build: - # Send pending Build Status to Git Status API - send_build_status.delay(build.id, BUILD_STATUS_PENDING) + # Send pending Build Status using Git Status API for External Builds. + send_external_build_status(build.id, BUILD_STATUS_PENDING) return ( update_docs_task.signature( diff --git a/readthedocs/oauth/services/github.py b/readthedocs/oauth/services/github.py index dad7592237f..ce978f99996 100644 --- a/readthedocs/oauth/services/github.py +++ b/readthedocs/oauth/services/github.py @@ -372,13 +372,14 @@ def send_build_status(self, build, state): ) # Response data should always be JSON, still try to log if not # though - try: - debug_data = resp.json() - except ValueError: - if resp is not None: + if resp is not None: + try: + debug_data = resp.json() + except ValueError: debug_data = resp.content - else: - debug_data = resp + else: + debug_data = resp + log.debug( 'GitHub commit status creation failure response: %s', debug_data, diff --git a/readthedocs/projects/tasks.py b/readthedocs/projects/tasks.py index ffdbaff935f..aa9afb26e1e 100644 --- a/readthedocs/projects/tasks.py +++ b/readthedocs/projects/tasks.py @@ -1023,7 +1023,7 @@ def is_type_sphinx(self): def send_build_status(self, build_pk, state): """Send github build status for pull/merge requests.""" - send_build_status.delay(build_pk, state) + send_external_build_status(build_pk, state) # Web tasks @@ -1796,27 +1796,35 @@ def retry_domain_verification(domain_pk): @app.task(queue='web') -def send_build_status(build_pk, state): +def send_build_status(build, state): """ Send Build Status to Git Status API for project external versions. - :param build_pk: Build pk + :param build: Build :param state: build state failed, pending, or success to be sent. """ - build = Build.objects.get(pk=build_pk) - - # Send status reports for only External (pull/merge request) Versions. - if build.version.type != EXTERNAL: - return - if build.project.remote_repository.account.provider == 'github': - account = build.project.remote_repository.account service = GitHubService( build.project.remote_repository.users.first(), - account + build.project.remote_repository.account ) # send Status report using the API. service.send_build_status(build, state) # TODO: Send build status for other providers. + + +def send_external_build_status(build_pk, state): + """ + Check if build is external and Send Build Status for project external versions. + + :param build_pk: Build pk + :param state: build state failed, pending, or success to be sent. + """ + build = Build.objects.get(pk=build_pk) + + # Send status reports for only External (pull/merge request) Versions. + if build.version.type == EXTERNAL: + # call the task that actually send the build status. + send_build_status.delay(build, state) From 1c0dda5febef7aadd30a95d96e3e7c46263f17c2 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Wed, 3 Jul 2019 18:39:34 +0600 Subject: [PATCH 10/18] some tests added --- readthedocs/rtd_tests/tests/test_api.py | 20 +++++++----- .../rtd_tests/tests/test_projects_tasks.py | 31 +++++++++++++++++-- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_api.py b/readthedocs/rtd_tests/tests/test_api.py index c1a78d496da..0cfa3de8721 100644 --- a/readthedocs/rtd_tests/tests/test_api.py +++ b/readthedocs/rtd_tests/tests/test_api.py @@ -906,7 +906,8 @@ def test_github_create_event(self, sync_repository_task, trigger_build): latest_version = self.project.versions.get(slug=LATEST) sync_repository_task.delay.assert_called_with(latest_version.pk) - def test_github_pull_request_opened_event(self, trigger_build): + @mock.patch('readthedocs.core.utils.trigger_build') + def test_github_pull_request_opened_event(self, trigger_build, core_trigger_build): client = APIClient() headers = {GITHUB_EVENT_HEADER: GITHUB_PULL_REQUEST} @@ -925,12 +926,13 @@ def test_github_pull_request_opened_event(self, trigger_build): self.assertTrue(resp.data['build_triggered']) self.assertEqual(resp.data['project'], self.project.slug) self.assertEqual(resp.data['versions'], [external_version.verbose_name]) - trigger_build.assert_called_once_with( + core_trigger_build.assert_called_once_with( force=True, project=self.project, version=external_version ) self.assertTrue(external_version) - def test_github_pull_request_reopened_event(self, trigger_build): + @mock.patch('readthedocs.core.utils.trigger_build') + def test_github_pull_request_reopened_event(self, trigger_build, core_trigger_build): client = APIClient() # Update the payload for `reopened` webhook event @@ -955,12 +957,13 @@ def test_github_pull_request_reopened_event(self, trigger_build): self.assertTrue(resp.data['build_triggered']) self.assertEqual(resp.data['project'], self.project.slug) self.assertEqual(resp.data['versions'], [external_version.verbose_name]) - trigger_build.assert_called_once_with( + core_trigger_build.assert_called_once_with( force=True, project=self.project, version=external_version ) self.assertTrue(external_version) - def test_github_pull_request_synchronize_event(self, trigger_build): + @mock.patch('readthedocs.core.utils.trigger_build') + def test_github_pull_request_synchronize_event(self, trigger_build, core_trigger_build): client = APIClient() pull_request_number = '6' @@ -998,13 +1001,14 @@ def test_github_pull_request_synchronize_event(self, trigger_build): self.assertTrue(resp.data['build_triggered']) self.assertEqual(resp.data['project'], self.project.slug) self.assertEqual(resp.data['versions'], [external_version.verbose_name]) - trigger_build.assert_called_once_with( + core_trigger_build.assert_called_once_with( force=True, project=self.project, version=external_version ) # `synchronize` webhook event updated the identifier (commit hash) self.assertNotEqual(prev_identifier, external_version.identifier) - def test_github_pull_request_closed_event(self, trigger_build): + @mock.patch('readthedocs.core.utils.trigger_build') + def test_github_pull_request_closed_event(self, trigger_build, core_trigger_build): client = APIClient() pull_request_number = '7' @@ -1044,7 +1048,7 @@ def test_github_pull_request_closed_event(self, trigger_build): self.assertTrue(resp.data['version_deleted']) self.assertEqual(resp.data['project'], self.project.slug) self.assertEqual(resp.data['versions'], [version.verbose_name]) - trigger_build.assert_not_called() + core_trigger_build.assert_not_called() def test_github_pull_request_no_action(self, trigger_build): client = APIClient() diff --git a/readthedocs/rtd_tests/tests/test_projects_tasks.py b/readthedocs/rtd_tests/tests/test_projects_tasks.py index c91f9b1534c..1ec1d8d0ae7 100644 --- a/readthedocs/rtd_tests/tests/test_projects_tasks.py +++ b/readthedocs/rtd_tests/tests/test_projects_tasks.py @@ -4,9 +4,14 @@ from django_dynamic_fixture import get from mock import patch -from readthedocs.builds.models import Version +from readthedocs.builds.constants import EXTERNAL, BUILD_STATUS_SUCCESS +from readthedocs.builds.models import Version, Build from readthedocs.projects.models import Project -from readthedocs.projects.tasks import sync_files +from readthedocs.projects.tasks import ( + sync_files, + send_external_build_status, + send_build_status, +) class SyncFilesTests(TestCase): @@ -121,3 +126,25 @@ def test_sync_files_search(self, rmtree, copy): self.assertIn('artifacts', args[0]) self.assertIn('sphinx_search', args[0]) self.assertIn('media/json', args[1]) + + +class SendBuildStatusTests(TestCase): + + def setUp(self): + self.project = get(Project) + self.internal_version = get(Version, project=self.project) + self.external_version = get(Version, project=self.project, type=EXTERNAL) + self.external_build = get(Build, project=self.project, version=self.external_version) + self.internal_build = get(Build, project=self.project, version=self.internal_version) + + @patch('readthedocs.projects.tasks.send_build_status') + def test_send_external_build_status_with_external_version(self, send_build_status): + send_external_build_status(self.external_build.id, BUILD_STATUS_SUCCESS) + + send_build_status.delay.assert_called_once_with(self.external_build, BUILD_STATUS_SUCCESS) + + @patch('readthedocs.projects.tasks.send_build_status') + def test_send_external_build_status_with_internal_version(self, send_build_status): + send_external_build_status(self.internal_build.id, BUILD_STATUS_SUCCESS) + + send_build_status.delay.assert_not_called() From 9b10ea6e5a7f4b45455b1ed2993bb9dfb39db4a6 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Thu, 4 Jul 2019 18:54:18 +0600 Subject: [PATCH 11/18] send_build_status tests added --- readthedocs/rtd_tests/tests/test_oauth.py | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/readthedocs/rtd_tests/tests/test_oauth.py b/readthedocs/rtd_tests/tests/test_oauth.py index 1ef675cc42c..49ac7bf64d4 100644 --- a/readthedocs/rtd_tests/tests/test_oauth.py +++ b/readthedocs/rtd_tests/tests/test_oauth.py @@ -5,6 +5,10 @@ from django.test import TestCase from django.test.utils import override_settings +from django_dynamic_fixture import get + +from readthedocs.builds.constants import EXTERNAL, BUILD_STATUS_SUCCESS +from readthedocs.builds.models import Version, Build from readthedocs.oauth.models import RemoteOrganization, RemoteRepository from readthedocs.oauth.services import ( BitbucketService, @@ -26,6 +30,10 @@ def setUp(self): self.org = RemoteOrganization.objects.create(slug='rtfd', json='') self.privacy = self.project.version_privacy_level self.service = GitHubService(user=self.user, account=None) + self.external_version = get(Version, project=self.project, type=EXTERNAL) + self.external_build = get( + Build, project=self.project, version=self.external_version + ) def test_make_project_pass(self): repo_json = { @@ -142,6 +150,51 @@ def test_multiple_users_same_repo(self): self.assertEqual(github_project, github_project_5) self.assertEqual(github_project_2, github_project_6) + @mock.patch('readthedocs.oauth.services.github.log') + @mock.patch('readthedocs.oauth.services.github.GitHubService.get_session') + def test_send_build_status_successful(self, session, mock_logger): + session().post.return_value.status_code = 201 + success = self.service.send_build_status( + self.external_build, + BUILD_STATUS_SUCCESS + ) + + self.assertTrue(success) + mock_logger.info.assert_called_with( + 'GitHub commit status for project: %s', + self.project + ) + + @mock.patch('readthedocs.oauth.services.github.log') + @mock.patch('readthedocs.oauth.services.github.GitHubService.get_session') + def test_send_build_status_404_error(self, session, mock_logger): + session().post.return_value.status_code = 404 + success = self.service.send_build_status( + self.external_build, + BUILD_STATUS_SUCCESS + ) + + self.assertFalse(success) + mock_logger.info.assert_called_with( + 'GitHub project does not exist or user does not have ' + 'permissions: project=%s', + self.project + ) + + @mock.patch('readthedocs.oauth.services.github.log') + @mock.patch('readthedocs.oauth.services.github.GitHubService.get_session') + def test_send_build_status_value_error(self, session, mock_logger): + session().post.side_effect = ValueError + success = self.service.send_build_status( + self.external_build, BUILD_STATUS_SUCCESS + ) + + self.assertFalse(success) + mock_logger.exception.assert_called_with( + 'GitHub commit status creation failed for project: %s', + self.project, + ) + @override_settings(DEFAULT_PRIVACY_LEVEL='private') def test_make_private_project(self): """ From e8098fbbd160f873db3d9ab4449badf8b3c23ba5 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Thu, 4 Jul 2019 20:09:42 +0600 Subject: [PATCH 12/18] tests for tasks added --- readthedocs/rtd_tests/tests/test_celery.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/readthedocs/rtd_tests/tests/test_celery.py b/readthedocs/rtd_tests/tests/test_celery.py index e3036367e57..301cc218dc5 100644 --- a/readthedocs/rtd_tests/tests/test_celery.py +++ b/readthedocs/rtd_tests/tests/test_celery.py @@ -7,11 +7,14 @@ from django_dynamic_fixture import get from mock import MagicMock, patch -from readthedocs.builds.constants import LATEST +from allauth.socialaccount.models import SocialAccount + +from readthedocs.builds.constants import LATEST, BUILD_STATUS_SUCCESS, EXTERNAL from readthedocs.builds.models import Build from readthedocs.doc_builder.exceptions import VersionLockedError from readthedocs.projects import tasks from readthedocs.builds.models import Version +from readthedocs.oauth.models import RemoteRepository from readthedocs.projects.exceptions import RepositoryError from readthedocs.projects.models import Project from readthedocs.rtd_tests.base import RTDTestCase @@ -329,3 +332,17 @@ def test_fileify_logging_when_wrong_version_pk(self, mock_logger): self.assertFalse(Version.objects.filter(pk=345343).exists()) tasks.fileify(version_pk=345343, commit=None, build=1) mock_logger.warning.assert_called_with("Version not found for given kwargs. {'pk': 345343}") + + @patch('readthedocs.projects.tasks.GitHubService.send_build_status') + def test_send_build_status_task(self, send_build_status): + social_account = get(SocialAccount, provider='github') + remote_repo = get(RemoteRepository, account=social_account, project=self.project) + remote_repo.users.add(self.eric) + + external_version = get(Version, project=self.project, type=EXTERNAL) + external_build = get( + Build, project=self.project, version=external_version + ) + tasks.send_build_status(external_build, BUILD_STATUS_SUCCESS) + + send_build_status.assert_called_once_with(external_build, BUILD_STATUS_SUCCESS) From e7a16410749f3a7d3ee8501c23881f60da7a30ab Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Fri, 5 Jul 2019 01:33:47 +0600 Subject: [PATCH 13/18] try catch added to task --- readthedocs/projects/tasks.py | 22 +++++++++++++++------- readthedocs/rtd_tests/tests/test_celery.py | 15 +++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/readthedocs/projects/tasks.py b/readthedocs/projects/tasks.py index aa9afb26e1e..7ac2d17b730 100644 --- a/readthedocs/projects/tasks.py +++ b/readthedocs/projects/tasks.py @@ -62,6 +62,7 @@ ) from readthedocs.doc_builder.loader import get_builder_class from readthedocs.doc_builder.python_environments import Conda, Virtualenv +from readthedocs.oauth.models import RemoteRepository from readthedocs.oauth.services.github import GitHubService from readthedocs.projects.models import APIProject, Feature from readthedocs.search.utils import index_new_files, remove_indexed_files @@ -1803,14 +1804,21 @@ def send_build_status(build, state): :param build: Build :param state: build state failed, pending, or success to be sent. """ - if build.project.remote_repository.account.provider == 'github': - service = GitHubService( - build.project.remote_repository.users.first(), - build.project.remote_repository.account - ) + try: + if build.project.remote_repository.account.provider == 'github': + service = GitHubService( + build.project.remote_repository.users.first(), + build.project.remote_repository.account + ) - # send Status report using the API. - service.send_build_status(build, state) + # send Status report using the API. + service.send_build_status(build, state) + + except RemoteRepository.DoesNotExist: + log.info('Remote repository does not exist for %s', build.project) + + except Exception: + log.exception('Send build status task failed.') # TODO: Send build status for other providers. diff --git a/readthedocs/rtd_tests/tests/test_celery.py b/readthedocs/rtd_tests/tests/test_celery.py index 301cc218dc5..f33c2892b77 100644 --- a/readthedocs/rtd_tests/tests/test_celery.py +++ b/readthedocs/rtd_tests/tests/test_celery.py @@ -346,3 +346,18 @@ def test_send_build_status_task(self, send_build_status): tasks.send_build_status(external_build, BUILD_STATUS_SUCCESS) send_build_status.assert_called_once_with(external_build, BUILD_STATUS_SUCCESS) + + @patch('readthedocs.projects.tasks.log') + @patch('readthedocs.projects.tasks.GitHubService.send_build_status') + def test_send_build_status_task_without_remote_repo(self, send_build_status, mock_logger): + external_version = get(Version, project=self.project, type=EXTERNAL) + external_build = get( + Build, project=self.project, version=external_version + ) + tasks.send_build_status(external_build, BUILD_STATUS_SUCCESS) + + send_build_status.assert_not_called() + mock_logger.info.assert_called_with( + 'Remote repository does not exist for %s', + self.project, + ) From 917b2e56196cf2c974ad5502b77bfa384fe912e8 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Fri, 5 Jul 2019 01:47:18 +0600 Subject: [PATCH 14/18] exception log updated --- readthedocs/projects/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/projects/tasks.py b/readthedocs/projects/tasks.py index 7ac2d17b730..a5aadb0b195 100644 --- a/readthedocs/projects/tasks.py +++ b/readthedocs/projects/tasks.py @@ -1818,7 +1818,7 @@ def send_build_status(build, state): log.info('Remote repository does not exist for %s', build.project) except Exception: - log.exception('Send build status task failed.') + log.exception('Send build status task failed for %s', build.project) # TODO: Send build status for other providers. From f9634b66c580b26e9f7e82701f7b5a0a60259fa7 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Tue, 9 Jul 2019 18:27:09 +0600 Subject: [PATCH 15/18] update send_build_status process --- readthedocs/builds/models.py | 4 ++- readthedocs/oauth/services/base.py | 44 ++++++++++++++++++++++++++++++ readthedocs/projects/tasks.py | 20 ++++++++++---- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/readthedocs/builds/models.py b/readthedocs/builds/models.py index 0663f81ae88..f4cb9310db0 100644 --- a/readthedocs/builds/models.py +++ b/readthedocs/builds/models.py @@ -736,7 +736,9 @@ def get_absolute_url(self): def get_full_url(self): """Get full url including domain""" - full_url = 'https://{domain}{absolute_url}'.format( + scheme = 'http' if settings.DEBUG else 'https' + full_url = '{scheme}://{domain}{absolute_url}'.format( + scheme=scheme, domain=settings.PRODUCTION_DOMAIN, absolute_url=self.get_absolute_url() ) diff --git a/readthedocs/oauth/services/base.py b/readthedocs/oauth/services/base.py index 99098f80487..ba21e56c085 100644 --- a/readthedocs/oauth/services/base.py +++ b/readthedocs/oauth/services/base.py @@ -184,12 +184,28 @@ def paginate(self, url, **kwargs): return [] def sync(self): + """Sync repositories and organizations.""" raise NotImplementedError def create_repository(self, fields, privacy=None, organization=None): + """ + Update or create a repository from API response. + + :param fields: dictionary of response data from API + :param privacy: privacy level to support + :param organization: remote organization to associate with + :type organization: RemoteOrganization + :rtype: RemoteRepository + """ raise NotImplementedError def create_organization(self, fields): + """ + Update or create remote organization from API response. + + :param fields: dictionary response of data from API + :rtype: RemoteOrganization + """ raise NotImplementedError def get_next_url_to_paginate(self, response): @@ -211,12 +227,40 @@ def get_paginated_results(self, response): raise NotImplementedError def setup_webhook(self, project): + """ + Setup webhook for project. + + :param project: project to set up webhook for + :type project: Project + :returns: boolean based on webhook set up success, and requests Response object + :rtype: (Bool, Response) + """ raise NotImplementedError def update_webhook(self, project, integration): + """ + Update webhook integration. + + :param project: project to set up webhook for + :type project: Project + :param integration: Webhook integration to update + :type integration: Integration + :returns: boolean based on webhook update success, and requests Response object + :rtype: (Bool, Response) + """ raise NotImplementedError def send_build_status(self, build, state): + """ + Create commit status for project. + + :param build: Build to set up commit status for + :type build: Build + :param state: build state failure, pending, or success. + :type state: str + :returns: boolean based on commit status creation was successful or not. + :rtype: Bool + """ raise NotImplementedError @classmethod diff --git a/readthedocs/projects/tasks.py b/readthedocs/projects/tasks.py index a5aadb0b195..e791f65a0ac 100644 --- a/readthedocs/projects/tasks.py +++ b/readthedocs/projects/tasks.py @@ -579,14 +579,26 @@ def run_build(self, docker, record): if self.build_env.failed: self.send_notifications(self.version.pk, self.build['id']) # send build failure status to git Status API - self.send_build_status( + send_external_build_status( self.build['id'], BUILD_STATUS_FAILURE ) elif self.build_env.successful: # send build successful status to git Status API - self.send_build_status( + send_external_build_status( self.build['id'], BUILD_STATUS_SUCCESS ) + else: + msg = 'Unhandled Build State: Build ID:'.format( + self.build['id'], + ) + log.warning( + LOG_TEMPLATE, + { + 'project': self.project.slug, + 'version': self.version.slug, + 'msg': msg, + } + ) build_complete.send(sender=Build, build=self.build_env.build) @@ -1022,10 +1034,6 @@ def is_type_sphinx(self): """Is documentation type Sphinx.""" return 'sphinx' in self.config.doctype - def send_build_status(self, build_pk, state): - """Send github build status for pull/merge requests.""" - send_external_build_status(build_pk, state) - # Web tasks @app.task(queue='web') From ec1c6a4190071ac7dde0cad591f39d8160aa2207 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Tue, 9 Jul 2019 18:29:41 +0600 Subject: [PATCH 16/18] removed gitlab build status constants --- readthedocs/builds/constants.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/readthedocs/builds/constants.py b/readthedocs/builds/constants.py index 7cb582fa448..3606bd7415b 100644 --- a/readthedocs/builds/constants.py +++ b/readthedocs/builds/constants.py @@ -67,11 +67,6 @@ GITHUB_BUILD_STATE_PENDING = 'pending' GITHUB_BUILD_STATE_SUCCESS = 'success' -# GitLab Build Statuses -GITLAB_BUILD_STATE_FAILURE = 'failed' -GITLAB_BUILD_STATE_PENDING = 'pending' -GITLAB_BUILD_STATE_SUCCESS = 'success' - # General Build Statuses BUILD_STATUS_FAILURE = 'failed' BUILD_STATUS_PENDING = 'pending' @@ -81,17 +76,14 @@ SELECT_BUILD_STATUS = { BUILD_STATUS_FAILURE: { 'github': GITHUB_BUILD_STATE_FAILURE, - 'gitlab': GITLAB_BUILD_STATE_FAILURE, 'description': 'The build failed!', }, BUILD_STATUS_PENDING: { 'github': GITHUB_BUILD_STATE_PENDING, - 'gitlab': GITLAB_BUILD_STATE_PENDING, 'description': 'The build is pending!', }, BUILD_STATUS_SUCCESS: { 'github': GITHUB_BUILD_STATE_SUCCESS, - 'gitlab': GITLAB_BUILD_STATE_SUCCESS, 'description': 'The build succeeded!', }, } From edab9b37a52c80c068b5a55e1a2cc96272bf9374 Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Tue, 9 Jul 2019 18:45:20 +0600 Subject: [PATCH 17/18] lint fix --- readthedocs/projects/tasks.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/readthedocs/projects/tasks.py b/readthedocs/projects/tasks.py index e791f65a0ac..8a68836e911 100644 --- a/readthedocs/projects/tasks.py +++ b/readthedocs/projects/tasks.py @@ -588,9 +588,7 @@ def run_build(self, docker, record): self.build['id'], BUILD_STATUS_SUCCESS ) else: - msg = 'Unhandled Build State: Build ID:'.format( - self.build['id'], - ) + msg = 'Unhandled Build State' log.warning( LOG_TEMPLATE, { From 1117caa917c5f10de583a828855ed1c763fecd6d Mon Sep 17 00:00:00 2001 From: saadmk11 Date: Wed, 10 Jul 2019 12:45:20 +0600 Subject: [PATCH 18/18] remove log test --- readthedocs/rtd_tests/tests/test_celery.py | 7 +------ readthedocs/rtd_tests/tests/test_oauth.py | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_celery.py b/readthedocs/rtd_tests/tests/test_celery.py index f33c2892b77..022c76a3294 100644 --- a/readthedocs/rtd_tests/tests/test_celery.py +++ b/readthedocs/rtd_tests/tests/test_celery.py @@ -347,9 +347,8 @@ def test_send_build_status_task(self, send_build_status): send_build_status.assert_called_once_with(external_build, BUILD_STATUS_SUCCESS) - @patch('readthedocs.projects.tasks.log') @patch('readthedocs.projects.tasks.GitHubService.send_build_status') - def test_send_build_status_task_without_remote_repo(self, send_build_status, mock_logger): + def test_send_build_status_task_without_remote_repo(self, send_build_status): external_version = get(Version, project=self.project, type=EXTERNAL) external_build = get( Build, project=self.project, version=external_version @@ -357,7 +356,3 @@ def test_send_build_status_task_without_remote_repo(self, send_build_status, moc tasks.send_build_status(external_build, BUILD_STATUS_SUCCESS) send_build_status.assert_not_called() - mock_logger.info.assert_called_with( - 'Remote repository does not exist for %s', - self.project, - ) diff --git a/readthedocs/rtd_tests/tests/test_oauth.py b/readthedocs/rtd_tests/tests/test_oauth.py index 49ac7bf64d4..b928e6b0aa5 100644 --- a/readthedocs/rtd_tests/tests/test_oauth.py +++ b/readthedocs/rtd_tests/tests/test_oauth.py @@ -191,8 +191,8 @@ def test_send_build_status_value_error(self, session, mock_logger): self.assertFalse(success) mock_logger.exception.assert_called_with( - 'GitHub commit status creation failed for project: %s', - self.project, + 'GitHub commit status creation failed for project: %s', + self.project, ) @override_settings(DEFAULT_PRIVACY_LEVEL='private')