Skip to content
This repository has been archived by the owner on Aug 10, 2023. It is now read-only.

Commit

Permalink
Add wait-for-deployments feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Surya Teja authored Sep 28, 2019
1 parent 3796025 commit f85d33f
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 21 deletions.
9 changes: 0 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
FROM python:3.7-alpine

LABEL version="1.0.1" \
repository="https://github.com/niteoweb/reviewapps-deploy-status" \
homepage="https://github.com/niteoweb" \
maintainer="niteo.co" \
"com.github.actions.name"="Heroku Review App Deployment Status" \
"com.github.actions.description"="A Github Action to test the deployment status of a Heroku Review App." \
"com.github.actions.icon"="git-pull-request" \
"com.github.actions.color"="orange"

RUN pip install --upgrade pip
RUN pip install requests==2.22.0

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ A Github Action that tests the deployment status of a Heroku Review App.

steps:
- name: Run review-app test
uses: niteoweb/[email protected].1
uses: niteoweb/[email protected].2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
interval: 10 # in seconds, optional, default is 10
accepted_responses: 200 # comma separated status codes, optional, default is 200
deployments_timeout: 120 # in seconds, optional, default is 120
```
> Note: Work flow should include `pull_request` event.
Expand All @@ -40,6 +41,7 @@ A Github Action that tests the deployment status of a Heroku Review App.
|---|---|---|
| interval | Wait for this amount of seconds before retrying the build check | 10 |
| accepted_responses | Allow/Accept the specified status codes | 200 |
| deployments_timeout | Maximum waiting time (in seconds) to fetch the deployments | 120 |

## Local Development
* Create a Python virtual environment(version > 3.6).
Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ inputs:
description: Status(es) which can be accepted. Separated by comma.
required: false
default: 200 # All OK status
deployments_timeout:
description: Maximum waiting time to fetch the deployments.
required: false
default: 120 # 120 seconds
24 changes: 19 additions & 5 deletions review_app_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,29 @@ def _make_github_api_request(url):
return r.json()


def _get_github_deployment_status_url(deployments_url, commit_sha):
def _get_github_deployment_status_url(deployments_url, commit_sha, timeout, interval):
"""Get deployment_status URL for the head commit.
Inputs:
deployments_url: This can be obtained from `pull_request` event payload.
commit_sha: SHA of head/latest commit. This also can be obtained from `pull_request` event payload.
timeout: Maximum waiting time to fetch the deployments.
interval: Amount of time (in seconds) to check the deployments
if the deployments are not available.
Output:
Github deployment_status URL.
"""
deployments = _make_github_api_request(deployments_url)
for deployment in deployments:
if deployment["sha"] == commit_sha:
return deployment["statuses_url"]

if interval > timeout:
raise ValueError("Interval can't be greater than deployments_timeout.")

while timeout > 0:
deployments = _make_github_api_request(deployments_url)
for deployment in deployments:
if deployment["sha"] == commit_sha:
return deployment["statuses_url"]
time.sleep(interval)
timeout = timeout - interval
logger.info(f"Waiting for deployments. Will check after {interval} seconds.")

raise ValueError("No deployment found for the lastest commit.")

Expand Down Expand Up @@ -102,6 +113,7 @@ def main():
All the inputs are received from workflow as environment variables.
"""
interval_arg = int(os.environ["INPUT_INTERVAL"])
deployments_timeout_arg = int(os.environ["INPUT_DEPLOYMENTS_TIMEOUT"])
accepted_responses_arg = os.environ["INPUT_ACCEPTED_RESPONSES"]
event_payload_path = os.environ["GITHUB_EVENT_PATH"]

Expand All @@ -115,6 +127,8 @@ def main():
github_deployment_status_url = _get_github_deployment_status_url(
pull_request_data["repository"]["deployments_url"],
pull_request_data["pull_request"]["head"]["sha"],
deployments_timeout_arg,
interval_arg,
)

reviewapp_build_data = _get_build_data(github_deployment_status_url, interval_arg)
Expand Down
63 changes: 57 additions & 6 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ def test_make_github_api_request_failure():
)


@mock.patch("review_app_status._make_github_api_request")
def test_get_deployment_status_interval_greater_failure(mock_github_request):

from review_app_status import _get_github_deployment_status_url

with pytest.raises(ValueError) as excinfo:
url = _get_github_deployment_status_url(
"https://foo.bar/deployments", "commitsha12345", 3, 4
)
assert "Interval can't be greater than deployments_timeout." in str(excinfo.value)


@mock.patch("review_app_status._make_github_api_request")
def test_get_deployment_status_url_success(mock_github_request):

Expand All @@ -65,14 +77,14 @@ def test_get_deployment_status_url_success(mock_github_request):
}
]
url = _get_github_deployment_status_url(
"https://foo.bar/deployments", "commitsha12345"
"https://foo.bar/deployments", "commitsha12345", 2, 1
)
assert url == "https://foo.bar/deployment/statuses/1"
mock_github_request.assert_called_once_with("https://foo.bar/deployments")


@mock.patch("review_app_status._make_github_api_request")
def test_get_deployment_status_url_failure(mock_github_request):
def test_get_deployment_status_url_failure(mock_github_request, caplog):

from review_app_status import _get_github_deployment_status_url

Expand All @@ -81,11 +93,48 @@ def test_get_deployment_status_url_failure(mock_github_request):
]
with pytest.raises(ValueError) as excinfo:
url = _get_github_deployment_status_url(
"https://foo.bar/deployments", "commitsha12345"
"https://foo.bar/deployments", "commitsha12345", 2, 1
)

assert (
caplog.records[0].message
== "Waiting for deployments. Will check after 1 seconds."
)
assert "No deployment found for the lastest commit." in str(excinfo.value)
mock_github_request.assert_called_once_with("https://foo.bar/deployments")
mock_github_request.call_count == 2


@mock.patch(
"review_app_status._make_github_api_request",
side_effect=[
[],
[
{
"sha": "commitsha12345",
"statuses_url": "https://foo.bar/deployment/statuses/1",
}
],
],
)
def test_get_deployment_pending_status(mock_github_request, caplog):

from review_app_status import _get_github_deployment_status_url

url = _get_github_deployment_status_url(
"https://foo.bar/deployments", "commitsha12345", 2, 1
)

assert url == "https://foo.bar/deployment/statuses/1"
assert (
caplog.records[0].message
== "Waiting for deployments. Will check after 1 seconds."
)
assert mock_github_request.call_count == 2
expected = [
mock.call("https://foo.bar/deployments"),
mock.call("https://foo.bar/deployments"),
]
assert mock_github_request.call_args_list == expected


@mock.patch("review_app_status._make_github_api_request")
Expand Down Expand Up @@ -181,6 +230,7 @@ def test_check_review_app_custom_status_success(caplog):
@mock.patch.dict(
os.environ,
{
"INPUT_DEPLOYMENTS_TIMEOUT": "20",
"INPUT_INTERVAL": "10",
"INPUT_ACCEPTED_RESPONSES": "200, 302",
"GITHUB_EVENT_PATH": "./test_path",
Expand Down Expand Up @@ -212,7 +262,7 @@ def test_main_success(

mock_file.assert_called_with("./test_path")
mock_deployment_status_url.assert_called_once_with(
"http://foo.bar/deployments", "commit12345"
"http://foo.bar/deployments", "commit12345", 20, 10
)
mock_build_data.assert_called_once_with("http://foo.bar/deployment_status", 10)
mock_review_app_deployment.assert_called_once_with(
Expand All @@ -226,6 +276,7 @@ def test_main_success(
@mock.patch.dict(
os.environ,
{
"INPUT_DEPLOYMENTS_TIMEOUT": "20",
"INPUT_INTERVAL": "10",
"INPUT_ACCEPTED_RESPONSES": "200, 302",
"GITHUB_EVENT_PATH": "./test_path",
Expand Down Expand Up @@ -254,7 +305,7 @@ def test_main_failure(

mock_file.assert_called_with("./test_path")
mock_deployment_status_url.assert_called_once_with(
"http://foo.bar/deployments", "commit12345"
"http://foo.bar/deployments", "commit12345", 20, 10
)
mock_build_data.assert_called_once_with("http://foo.bar/deployment_status", 10)

Expand Down

0 comments on commit f85d33f

Please sign in to comment.