Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix github build status reporting bug #5985

Merged
merged 7 commits into from
Jul 31, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion readthedocs/core/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ def prepare_build(

if build:
# Send pending Build Status using Git Status API for External Builds.
send_external_build_status(version=version, build_pk=build.id, status=BUILD_STATUS_PENDING)
send_external_build_status(
version_type=version.type, build_pk=build.id,
commit=version.identifier, status=BUILD_STATUS_PENDING
saadmk11 marked this conversation as resolved.
Show resolved Hide resolved
)

return (
update_docs_task.signature(
Expand Down
4 changes: 3 additions & 1 deletion readthedocs/oauth/services/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,14 @@ def update_webhook(self, project, integration):
"""
raise NotImplementedError

def send_build_status(self, build, state):
def send_build_status(self, build, commit, state):
"""
Create commit status for project.

:param build: Build to set up commit status for
:type build: Build
:param commit: commit sha of the pull/merge request
:type commit: str
:param state: build state failure, pending, or success.
:type state: str
:returns: boolean based on commit status creation was successful or not.
Expand Down
7 changes: 4 additions & 3 deletions readthedocs/oauth/services/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,21 +315,22 @@ def update_webhook(self, project, integration):
)
return (False, resp)

def send_build_status(self, build, state):
def send_build_status(self, build, commit, state):
"""
Create GitHub 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
:param commit: commit sha of the pull request
:type commit: 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']
Expand All @@ -346,7 +347,7 @@ def send_build_status(self, build, state):

try:
resp = session.post(
f'https://api.github.com/repos/{owner}/{repo}/statuses/{build_sha}',
f'https://api.github.com/repos/{owner}/{repo}/statuses/{commit}',
data=json.dumps(data),
headers={'content-type': 'application/json'},
)
Expand Down
29 changes: 20 additions & 9 deletions readthedocs/projects/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,16 +579,25 @@ def run_build(self, docker, record):
if self.build_env.failed:
self.send_notifications(self.version.pk, self.build['id'])
send_external_build_status(
version=self.version, build_pk=self.build['id'], status=BUILD_STATUS_FAILURE
version_type=self.version.type,
build_pk=self.build['id'],
commit=self.build['commit'],
status=BUILD_STATUS_FAILURE
)
elif self.build_env.successful:
send_external_build_status(
version=self.version, build_pk=self.build['id'], status=BUILD_STATUS_SUCCESS
version_type=self.version.type,
build_pk=self.build['id'],
commit=self.build['commit'],
status=BUILD_STATUS_SUCCESS
)
else:
msg = 'Unhandled Build Status'
send_external_build_status(
version=self.version, build_pk=self.build['id'], status=BUILD_STATUS_FAILURE
version_type=self.version.type,
build_pk=self.build['id'],
commit=self.build['commit'],
status=BUILD_STATUS_FAILURE
)
log.warning(
LOG_TEMPLATE,
Expand Down Expand Up @@ -1822,11 +1831,12 @@ def retry_domain_verification(domain_pk):


@app.task(queue='web')
def send_build_status(build_pk, status):
def send_build_status(build_pk, commit, status):
"""
Send Build Status to Git Status API for project external versions.

:param build_pk: Build primary key
:param commit: commit sha of the pull/merge request
:param status: build status failed, pending, or success to be sent.
"""
build = Build.objects.get(pk=build_pk)
Expand All @@ -1838,7 +1848,7 @@ def send_build_status(build_pk, status):
)

# send Status report using the API.
service.send_build_status(build, status)
service.send_build_status(build, commit, status)

except RemoteRepository.DoesNotExist:
log.info('Remote repository does not exist for %s', build.project)
Expand All @@ -1849,16 +1859,17 @@ def send_build_status(build_pk, status):
# TODO: Send build status for other providers.


def send_external_build_status(version, build_pk, status):
def send_external_build_status(version_type, build_pk, commit, status):
"""
Check if build is external and Send Build Status for project external versions.

:param version: Version instance
:param version_type: Version type e.g EXTERNAL, BRANCH, TAG
:param build_pk: Build pk
:param commit: commit sha of the pull/merge request
:param status: build status failed, pending, or success to be sent.
"""

# Send status reports for only External (pull/merge request) Versions.
if version.type == EXTERNAL:
if version_type == EXTERNAL:
# call the task that actually send the build status.
send_build_status.delay(build_pk, status)
send_build_status.delay(build_pk, commit, status)
12 changes: 9 additions & 3 deletions readthedocs/rtd_tests/tests/test_celery.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,16 +343,22 @@ def test_send_build_status_task(self, send_build_status):
external_build = get(
Build, project=self.project, version=external_version
)
tasks.send_build_status(external_build.id, BUILD_STATUS_SUCCESS)
tasks.send_build_status(
external_build.id, external_build.commit, BUILD_STATUS_SUCCESS
)

send_build_status.assert_called_once_with(external_build, BUILD_STATUS_SUCCESS)
send_build_status.assert_called_once_with(
external_build, external_build.commit, BUILD_STATUS_SUCCESS
)

@patch('readthedocs.projects.tasks.GitHubService.send_build_status')
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
)
tasks.send_build_status(external_build.id, BUILD_STATUS_SUCCESS)
tasks.send_build_status(
external_build.id, external_build.commit, BUILD_STATUS_SUCCESS
)

send_build_status.assert_not_called()
6 changes: 5 additions & 1 deletion readthedocs/rtd_tests/tests/test_config_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,11 @@ def get_update_docs_task(self):
config=load_yaml_config(self.version),
project=self.project,
version=self.version,
build={'id': 99, 'state': BUILD_STATE_TRIGGERED}
build={
'id': 99,
'state': BUILD_STATE_TRIGGERED,
'commit': 'abc859dada4faf'
}
)
return update_docs

Expand Down
4 changes: 3 additions & 1 deletion readthedocs/rtd_tests/tests/test_oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ 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,
self.external_build.commit,
BUILD_STATUS_SUCCESS
)

Expand All @@ -172,6 +173,7 @@ 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,
self.external_build.commit,
BUILD_STATUS_SUCCESS
)

Expand All @@ -187,7 +189,7 @@ def test_send_build_status_404_error(self, session, mock_logger):
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.external_build, self.external_build.commit, BUILD_STATUS_SUCCESS
)

self.assertFalse(success)
Expand Down
18 changes: 13 additions & 5 deletions readthedocs/rtd_tests/tests/test_projects_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,22 @@ def setUp(self):

@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_version,
self.external_build.id, BUILD_STATUS_SUCCESS)
send_external_build_status(
self.external_version.type, self.external_build.id,
self.external_build.commit, BUILD_STATUS_SUCCESS
)

send_build_status.delay.assert_called_once_with(self.external_build.id, BUILD_STATUS_SUCCESS)
send_build_status.delay.assert_called_once_with(
self.external_build.id,
self.external_build.commit,
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_version,
self.internal_build.id, BUILD_STATUS_SUCCESS)
send_external_build_status(
self.internal_version.type, self.internal_build.id,
self.external_build.commit, BUILD_STATUS_SUCCESS
)

send_build_status.delay.assert_not_called()