diff --git a/api/poetry.lock b/api/poetry.lock index 8d8785f96..bec40c748 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1871,6 +1871,23 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +[[package]] +name = "pytest-mock" +version = "3.12.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.12.0.tar.gz", hash = "sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9"}, + {file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"}, +] + +[package.dependencies] +pytest = ">=5.0" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -2586,4 +2603,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "236963249ab752c29ae5a0d5f5a8db5a0143b161ce3ef52b04fda0ddb4d2fcc3" +content-hash = "57d4d95e636e026446f832e8a94e599ff6c6dcf081a385ad30adb47dc689f85b" diff --git a/api/pyproject.toml b/api/pyproject.toml index 97af8484a..a6cf9b7b2 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -93,6 +93,7 @@ responses = "*" pytest = "*" pytest-asyncio = "*" pytest-cov = "*" +pytest-mock = "*" black = "*" check-manifest = "*" isort = "*" diff --git a/api/src/shipit_api/admin/github.py b/api/src/shipit_api/admin/github.py index 8a4198b43..17024f33b 100644 --- a/api/src/shipit_api/admin/github.py +++ b/api/src/shipit_api/admin/github.py @@ -114,27 +114,46 @@ def ref_to_commit(owner, repo, ref): def list_github_branches(owner, repo, limit=100): - query = """ - { - repository(name: "%(repo)s", owner: "%(owner)s") { - refs(first: %(limit)s, refPrefix: "refs/heads/") { - nodes { - name - target { - ... on Commit { - committedDate + page = { + "hasNextPage": True, + "endCursor": None, + } + + branches = [] + while page["hasNextPage"]: + after = "" + if page["endCursor"]: + after = f", after: \"{page['endCursor']}\"" + + query = """ + { + repository(name: "%(repo)s", owner: "%(owner)s") { + refs(first: %(limit)s%(after)s, refPrefix: "refs/heads/") { + nodes { + name + target { + ... on Commit { + committedDate + } + } + } + pageInfo { + endCursor + hasNextPage } } } } - } - } - """ % dict( - owner=owner, repo=repo, limit=limit - ) - content = query_api(query) - nodes = content["data"]["repository"]["refs"]["nodes"] - return [{"committer_date": node["target"]["committedDate"], "name": node["name"]} for node in nodes] + """ % dict( + owner=owner, repo=repo, limit=limit, after=after + ) + content = query_api(query) + page = content["data"]["repository"]["refs"]["pageInfo"] + + nodes = content["data"]["repository"]["refs"]["nodes"] + branches.extend([{"committer_date": node["target"]["committedDate"], "name": node["name"]} for node in nodes]) + + return branches def list_github_commits(owner, repo, branch, limit=10): diff --git a/api/tests/conftest.py b/api/tests/conftest.py index cf0c38808..57de9f4e2 100644 --- a/api/tests/conftest.py +++ b/api/tests/conftest.py @@ -6,11 +6,18 @@ import os import pytest +import responses as rsps import backend_common.testing from shipit_api.common.models import XPI, XPIRelease +@pytest.fixture +def responses(): + with rsps.RequestsMock() as req_mock: + yield req_mock + + @pytest.fixture(scope="session") def app(): """Load shipit_api in test mode""" diff --git a/api/tests/test_github.py b/api/tests/test_github.py new file mode 100644 index 000000000..a4290bc9f --- /dev/null +++ b/api/tests/test_github.py @@ -0,0 +1,52 @@ +from pprint import pprint + +import pytest +from flask import Flask + +from shipit_api.admin import github + + +@pytest.fixture(autouse=True) +def setup(monkeypatch, mocker): + app = Flask(__name__) + app.config["GITHUB_TOKEN"] = "token" + with app.app_context(): + monkeypatch.setattr(github, "current_app", app) + mocker.patch("shipit_api.admin.github._require_auth", return_value=None) + yield + + +def test_list_github_branches(responses): + rsp1 = responses.post( + "https://api.github.com/graphql", + json={ + "data": { + "repository": { + "refs": { + "nodes": [{"name": "foo", "target": {"committedDate": "1"}}, {"name": "bar", "target": {"committedDate": "2"}}], + "pageInfo": {"hasNextPage": True, "endCursor": "abc"}, + } + } + } + }, + ) + rsp2 = responses.post( + "https://api.github.com/graphql", + json={ + "data": { + "repository": { + "refs": { + "nodes": [{"name": "baz", "target": {"committedDate": "3"}}], + "pageInfo": {"hasNextPage": False, "endCursor": "def"}, + } + } + } + }, + ) + repos = github.list_github_branches("org", "repo", limit=2) + assert b"after" not in rsp1.calls[0].request.body + assert b'after: \\"abc\\",' in rsp2.calls[0].request.body + + print("Dumping for copy/paste:") + pprint(repos) + assert repos == [{"committer_date": "1", "name": "foo"}, {"committer_date": "2", "name": "bar"}, {"committer_date": "3", "name": "baz"}]