airbyte-source-github 1.5.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- airbyte_source_github-1.5.7.dist-info/METADATA +144 -0
- airbyte_source_github-1.5.7.dist-info/RECORD +88 -0
- airbyte_source_github-1.5.7.dist-info/WHEEL +5 -0
- airbyte_source_github-1.5.7.dist-info/entry_points.txt +2 -0
- airbyte_source_github-1.5.7.dist-info/top_level.txt +3 -0
- integration_tests/__init__.py +0 -0
- integration_tests/abnormal_state.json +237 -0
- integration_tests/acceptance.py +16 -0
- integration_tests/configured_catalog.json +435 -0
- integration_tests/configured_catalog_full_refresh_test.json +415 -0
- integration_tests/invalid_config.json +5 -0
- integration_tests/sample_config.json +5 -0
- integration_tests/sample_state.json +137 -0
- source_github/__init__.py +27 -0
- source_github/config_migrations.py +106 -0
- source_github/constants.py +9 -0
- source_github/github_schema.py +41034 -0
- source_github/graphql.py +327 -0
- source_github/run.py +17 -0
- source_github/schemas/assignees.json +63 -0
- source_github/schemas/branches.json +48 -0
- source_github/schemas/collaborators.json +80 -0
- source_github/schemas/comments.json +104 -0
- source_github/schemas/commit_comment_reactions.json +4 -0
- source_github/schemas/commit_comments.json +53 -0
- source_github/schemas/commits.json +126 -0
- source_github/schemas/contributor_activity.json +109 -0
- source_github/schemas/deployments.json +77 -0
- source_github/schemas/events.json +63 -0
- source_github/schemas/issue_comment_reactions.json +4 -0
- source_github/schemas/issue_events.json +335 -0
- source_github/schemas/issue_labels.json +30 -0
- source_github/schemas/issue_milestones.json +61 -0
- source_github/schemas/issue_reactions.json +28 -0
- source_github/schemas/issue_timeline_events.json +1056 -0
- source_github/schemas/issues.json +281 -0
- source_github/schemas/organizations.json +197 -0
- source_github/schemas/project_cards.json +50 -0
- source_github/schemas/project_columns.json +38 -0
- source_github/schemas/projects.json +50 -0
- source_github/schemas/projects_v2.json +80 -0
- source_github/schemas/pull_request_comment_reactions.json +28 -0
- source_github/schemas/pull_request_commits.json +122 -0
- source_github/schemas/pull_request_stats.json +84 -0
- source_github/schemas/pull_requests.json +363 -0
- source_github/schemas/releases.json +126 -0
- source_github/schemas/repositories.json +313 -0
- source_github/schemas/review_comments.json +118 -0
- source_github/schemas/reviews.json +69 -0
- source_github/schemas/shared/events/comment.json +188 -0
- source_github/schemas/shared/events/commented.json +118 -0
- source_github/schemas/shared/events/committed.json +56 -0
- source_github/schemas/shared/events/cross_referenced.json +784 -0
- source_github/schemas/shared/events/reviewed.json +139 -0
- source_github/schemas/shared/reaction.json +27 -0
- source_github/schemas/shared/reactions.json +35 -0
- source_github/schemas/shared/user.json +59 -0
- source_github/schemas/shared/user_graphql.json +26 -0
- source_github/schemas/stargazers.json +19 -0
- source_github/schemas/tags.json +32 -0
- source_github/schemas/team_members.json +66 -0
- source_github/schemas/team_memberships.json +24 -0
- source_github/schemas/teams.json +50 -0
- source_github/schemas/users.json +63 -0
- source_github/schemas/workflow_jobs.json +109 -0
- source_github/schemas/workflow_runs.json +449 -0
- source_github/schemas/workflows.json +41 -0
- source_github/source.py +339 -0
- source_github/spec.json +179 -0
- source_github/streams.py +1678 -0
- source_github/utils.py +152 -0
- unit_tests/__init__.py +3 -0
- unit_tests/conftest.py +29 -0
- unit_tests/projects_v2_pull_requests_query.json +3 -0
- unit_tests/pull_request_stats_query.json +3 -0
- unit_tests/responses/contributor_activity_response.json +33 -0
- unit_tests/responses/graphql_reviews_responses.json +405 -0
- unit_tests/responses/issue_timeline_events.json +166 -0
- unit_tests/responses/issue_timeline_events_response.json +170 -0
- unit_tests/responses/projects_v2_response.json +45 -0
- unit_tests/responses/pull_request_comment_reactions.json +744 -0
- unit_tests/responses/pull_request_stats_response.json +317 -0
- unit_tests/test_migrations/test_config.json +8 -0
- unit_tests/test_migrations/test_new_config.json +8 -0
- unit_tests/test_multiple_token_authenticator.py +160 -0
- unit_tests/test_source.py +326 -0
- unit_tests/test_stream.py +1471 -0
- unit_tests/utils.py +78 -0
source_github/utils.py
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
3
|
+
#
|
4
|
+
|
5
|
+
import time
|
6
|
+
from dataclasses import dataclass
|
7
|
+
from itertools import cycle
|
8
|
+
from typing import Any, List, Mapping
|
9
|
+
|
10
|
+
import pendulum
|
11
|
+
import requests
|
12
|
+
from airbyte_cdk.models import SyncMode
|
13
|
+
from airbyte_cdk.sources.streams import Stream
|
14
|
+
from airbyte_cdk.sources.streams.http.requests_native_auth import TokenAuthenticator
|
15
|
+
from airbyte_cdk.sources.streams.http.requests_native_auth.abstract_token import AbstractHeaderAuthenticator
|
16
|
+
|
17
|
+
|
18
|
+
def getter(D: dict, key_or_keys, strict=True):
|
19
|
+
if not isinstance(key_or_keys, list):
|
20
|
+
key_or_keys = [key_or_keys]
|
21
|
+
for k in key_or_keys:
|
22
|
+
if strict:
|
23
|
+
D = D[k]
|
24
|
+
else:
|
25
|
+
D = D.get(k, {})
|
26
|
+
return D
|
27
|
+
|
28
|
+
|
29
|
+
def read_full_refresh(stream_instance: Stream):
|
30
|
+
slices = stream_instance.stream_slices(sync_mode=SyncMode.full_refresh)
|
31
|
+
for _slice in slices:
|
32
|
+
records = stream_instance.read_records(stream_slice=_slice, sync_mode=SyncMode.full_refresh)
|
33
|
+
for record in records:
|
34
|
+
yield record
|
35
|
+
|
36
|
+
|
37
|
+
class GitHubAPILimitException(Exception):
|
38
|
+
"""General class for Rate Limits errors"""
|
39
|
+
|
40
|
+
|
41
|
+
@dataclass
|
42
|
+
class Token:
|
43
|
+
count_rest: int = 5000
|
44
|
+
count_graphql: int = 5000
|
45
|
+
reset_at_rest: pendulum.DateTime = pendulum.now()
|
46
|
+
reset_at_graphql: pendulum.DateTime = pendulum.now()
|
47
|
+
|
48
|
+
|
49
|
+
class MultipleTokenAuthenticatorWithRateLimiter(AbstractHeaderAuthenticator):
|
50
|
+
"""
|
51
|
+
Each token in the cycle is checked against the rate limiter.
|
52
|
+
If a token exceeds the capacity limit, the system switches to another token.
|
53
|
+
If all tokens are exhausted, the system will enter a sleep state until
|
54
|
+
the first token becomes available again.
|
55
|
+
"""
|
56
|
+
|
57
|
+
DURATION = pendulum.duration(seconds=3600) # Duration at which the current rate limit window resets
|
58
|
+
|
59
|
+
def __init__(self, tokens: List[str], auth_method: str = "token", auth_header: str = "Authorization"):
|
60
|
+
self._auth_method = auth_method
|
61
|
+
self._auth_header = auth_header
|
62
|
+
self._tokens = {t: Token() for t in tokens}
|
63
|
+
self.check_all_tokens()
|
64
|
+
self._tokens_iter = cycle(self._tokens)
|
65
|
+
self._active_token = next(self._tokens_iter)
|
66
|
+
self._max_time = 60 * 10 # 10 minutes as default
|
67
|
+
|
68
|
+
@property
|
69
|
+
def auth_header(self) -> str:
|
70
|
+
return self._auth_header
|
71
|
+
|
72
|
+
def get_auth_header(self) -> Mapping[str, Any]:
|
73
|
+
"""The header to set on outgoing HTTP requests"""
|
74
|
+
if self.auth_header:
|
75
|
+
return {self.auth_header: self.token}
|
76
|
+
return {}
|
77
|
+
|
78
|
+
def __call__(self, request):
|
79
|
+
"""Attach the HTTP headers required to authenticate on the HTTP request"""
|
80
|
+
while True:
|
81
|
+
current_token = self._tokens[self.current_active_token]
|
82
|
+
if "graphql" in request.path_url:
|
83
|
+
if self.process_token(current_token, "count_graphql", "reset_at_graphql"):
|
84
|
+
break
|
85
|
+
else:
|
86
|
+
if self.process_token(current_token, "count_rest", "reset_at_rest"):
|
87
|
+
break
|
88
|
+
|
89
|
+
request.headers.update(self.get_auth_header())
|
90
|
+
|
91
|
+
return request
|
92
|
+
|
93
|
+
@property
|
94
|
+
def current_active_token(self) -> str:
|
95
|
+
return self._active_token
|
96
|
+
|
97
|
+
def update_token(self) -> None:
|
98
|
+
self._active_token = next(self._tokens_iter)
|
99
|
+
|
100
|
+
@property
|
101
|
+
def token(self) -> str:
|
102
|
+
|
103
|
+
token = self.current_active_token
|
104
|
+
return f"{self._auth_method} {token}"
|
105
|
+
|
106
|
+
@property
|
107
|
+
def max_time(self) -> int:
|
108
|
+
return self._max_time
|
109
|
+
|
110
|
+
@max_time.setter
|
111
|
+
def max_time(self, value: int) -> None:
|
112
|
+
self._max_time = value
|
113
|
+
|
114
|
+
def _check_token_limits(self, token: str):
|
115
|
+
"""check that token is not limited"""
|
116
|
+
headers = {"Accept": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28"}
|
117
|
+
rate_limit_info = (
|
118
|
+
requests.get(
|
119
|
+
"https://api.github.com/rate_limit", headers=headers, auth=TokenAuthenticator(token, auth_method=self._auth_method)
|
120
|
+
)
|
121
|
+
.json()
|
122
|
+
.get("resources")
|
123
|
+
)
|
124
|
+
token_info = self._tokens[token]
|
125
|
+
remaining_info_core = rate_limit_info.get("core")
|
126
|
+
token_info.count_rest, token_info.reset_at_rest = remaining_info_core.get("remaining"), pendulum.from_timestamp(
|
127
|
+
remaining_info_core.get("reset")
|
128
|
+
)
|
129
|
+
|
130
|
+
remaining_info_graphql = rate_limit_info.get("graphql")
|
131
|
+
token_info.count_graphql, token_info.reset_at_graphql = remaining_info_graphql.get("remaining"), pendulum.from_timestamp(
|
132
|
+
remaining_info_graphql.get("reset")
|
133
|
+
)
|
134
|
+
|
135
|
+
def check_all_tokens(self):
|
136
|
+
for token in self._tokens:
|
137
|
+
self._check_token_limits(token)
|
138
|
+
|
139
|
+
def process_token(self, current_token, count_attr, reset_attr):
|
140
|
+
if getattr(current_token, count_attr) > 0:
|
141
|
+
setattr(current_token, count_attr, getattr(current_token, count_attr) - 1)
|
142
|
+
return True
|
143
|
+
elif all(getattr(x, count_attr) == 0 for x in self._tokens.values()):
|
144
|
+
min_time_to_wait = min((getattr(x, reset_attr) - pendulum.now()).in_seconds() for x in self._tokens.values())
|
145
|
+
if min_time_to_wait < self.max_time:
|
146
|
+
time.sleep(min_time_to_wait if min_time_to_wait > 0 else 0)
|
147
|
+
self.check_all_tokens()
|
148
|
+
else:
|
149
|
+
raise GitHubAPILimitException(f"Rate limits for all tokens ({count_attr}) were reached")
|
150
|
+
else:
|
151
|
+
self.update_token()
|
152
|
+
return False
|
unit_tests/__init__.py
ADDED
unit_tests/conftest.py
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
2
|
+
|
3
|
+
import os
|
4
|
+
|
5
|
+
import pytest
|
6
|
+
import responses
|
7
|
+
|
8
|
+
os.environ["REQUEST_CACHE_PATH"] = "REQUEST_CACHE_PATH"
|
9
|
+
|
10
|
+
|
11
|
+
@pytest.fixture(name="rate_limit_mock_response")
|
12
|
+
def rate_limit_mock_response():
|
13
|
+
rate_limit_response = {
|
14
|
+
"resources": {
|
15
|
+
"core": {
|
16
|
+
"limit": 5000,
|
17
|
+
"used": 0,
|
18
|
+
"remaining": 5000,
|
19
|
+
"reset": 4070908800
|
20
|
+
},
|
21
|
+
"graphql": {
|
22
|
+
"limit": 5000,
|
23
|
+
"used": 0,
|
24
|
+
"remaining": 5000,
|
25
|
+
"reset": 4070908800
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
responses.add(responses.GET, "https://api.github.com/rate_limit", json=rate_limit_response)
|
@@ -0,0 +1,3 @@
|
|
1
|
+
{
|
2
|
+
"query": "query {\n repository(owner: \"airbytehq\", name: \"airbyte\") {\n name\n owner {\n login\n }\n projectsV2(first: 100, orderBy: {field: UPDATED_AT, direction: ASC}) {\n nodes {\n closed\n created_at: createdAt\n closed_at: closedAt\n updated_at: updatedAt\n creator: creator {\n avatarUrl\n login\n resourcePath\n url\n }\n node_id: id\n id: databaseId\n number\n public\n readme: readme\n short_description: shortDescription\n template\n title: title\n url: url\n viewerCanClose\n viewerCanReopen\n viewerCanUpdate\n owner {\n id: id\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n}"
|
3
|
+
}
|
@@ -0,0 +1,3 @@
|
|
1
|
+
{
|
2
|
+
"query": "query {\n repository(owner: \"airbytehq\", name: \"airbyte\") {\n name\n owner {\n login\n }\n pullRequests(first: 10, orderBy: {field: UPDATED_AT, direction: ASC}) {\n nodes {\n node_id: id\n id: databaseId\n number\n updated_at: updatedAt\n changed_files: changedFiles\n deletions\n additions\n merged\n mergeable\n can_be_rebased: canBeRebased\n maintainer_can_modify: maintainerCanModify\n merge_state_status: mergeStateStatus\n comments {\n totalCount\n }\n commits {\n totalCount\n }\n review_comments: reviews(first: 100) {\n totalCount\n nodes {\n comments {\n totalCount\n }\n }\n }\n merged_by: mergedBy {\n __typename\n ... on User {\n node_id: id\n id: databaseId\n login\n avatar_url: avatarUrl\n html_url: url\n site_admin: isSiteAdmin\n }\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n}"
|
3
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"author": {
|
4
|
+
"login": "octocat",
|
5
|
+
"id": 1,
|
6
|
+
"node_id": "MDQ6VXNlcjE=",
|
7
|
+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
|
8
|
+
"gravatar_id": "",
|
9
|
+
"url": "https://api.github.com/users/octocat",
|
10
|
+
"html_url": "https://github.com/octocat",
|
11
|
+
"followers_url": "https://api.github.com/users/octocat/followers",
|
12
|
+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
|
13
|
+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
|
14
|
+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
|
15
|
+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
|
16
|
+
"organizations_url": "https://api.github.com/users/octocat/orgs",
|
17
|
+
"repos_url": "https://api.github.com/users/octocat/repos",
|
18
|
+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
|
19
|
+
"received_events_url": "https://api.github.com/users/octocat/received_events",
|
20
|
+
"type": "User",
|
21
|
+
"site_admin": false
|
22
|
+
},
|
23
|
+
"total": 135,
|
24
|
+
"weeks": [
|
25
|
+
{
|
26
|
+
"w": 1367712000,
|
27
|
+
"a": 6898,
|
28
|
+
"d": 77,
|
29
|
+
"c": 10
|
30
|
+
}
|
31
|
+
]
|
32
|
+
}
|
33
|
+
]
|
@@ -0,0 +1,405 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"data": {
|
4
|
+
"repository": {
|
5
|
+
"owner": {
|
6
|
+
"login": "airbytehq"
|
7
|
+
},
|
8
|
+
"name": "airbyte",
|
9
|
+
"pullRequests": {
|
10
|
+
"nodes": [
|
11
|
+
{
|
12
|
+
"number": 1,
|
13
|
+
"url": "https://github.com/airbytehq/airbyte/pull/1",
|
14
|
+
"reviews": {
|
15
|
+
"nodes": [
|
16
|
+
{
|
17
|
+
"id": 1000,
|
18
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
19
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/1#pullrequestreview-1000",
|
20
|
+
"commit": null,
|
21
|
+
"user": {
|
22
|
+
"__typename": "User"
|
23
|
+
}
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"id": 1001,
|
27
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
28
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/1#pullrequestreview-1001",
|
29
|
+
"commit": null,
|
30
|
+
"user": {
|
31
|
+
"__typename": "User"
|
32
|
+
}
|
33
|
+
}
|
34
|
+
],
|
35
|
+
"pageInfo": {
|
36
|
+
"endCursor": "cursor",
|
37
|
+
"hasNextPage": true
|
38
|
+
}
|
39
|
+
}
|
40
|
+
},
|
41
|
+
{
|
42
|
+
"number": 2,
|
43
|
+
"url": "https://github.com/airbytehq/airbyte/pull/2",
|
44
|
+
"reviews": {
|
45
|
+
"nodes": [
|
46
|
+
{
|
47
|
+
"id": 1002,
|
48
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
49
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/2#pullrequestreview-1002",
|
50
|
+
"commit": null,
|
51
|
+
"user": {
|
52
|
+
"__typename": "User"
|
53
|
+
}
|
54
|
+
},
|
55
|
+
{
|
56
|
+
"id": 1003,
|
57
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
58
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/2#pullrequestreview-1003",
|
59
|
+
"commit": null,
|
60
|
+
"user": {
|
61
|
+
"__typename": "User"
|
62
|
+
}
|
63
|
+
}
|
64
|
+
],
|
65
|
+
"pageInfo": {
|
66
|
+
"endCursor": "cursor",
|
67
|
+
"hasNextPage": true
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
],
|
72
|
+
"pageInfo": {
|
73
|
+
"endCursor": "cursor",
|
74
|
+
"hasNextPage": true
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
},
|
80
|
+
{
|
81
|
+
"data": {
|
82
|
+
"repository": {
|
83
|
+
"owner": {
|
84
|
+
"login": "airbytehq"
|
85
|
+
},
|
86
|
+
"name": "airbyte",
|
87
|
+
"pullRequest": {
|
88
|
+
"number": 1,
|
89
|
+
"url": "https://github.com/airbytehq/airbyte/pull/1",
|
90
|
+
"reviews": {
|
91
|
+
"nodes": [
|
92
|
+
{
|
93
|
+
"id": 1004,
|
94
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
95
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/1#pullrequestreview-1004",
|
96
|
+
"commit": null,
|
97
|
+
"user": {
|
98
|
+
"__typename": "User"
|
99
|
+
}
|
100
|
+
},
|
101
|
+
{
|
102
|
+
"id": 1005,
|
103
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
104
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/1#pullrequestreview-1005",
|
105
|
+
"commit": null,
|
106
|
+
"user": {
|
107
|
+
"__typename": "User"
|
108
|
+
}
|
109
|
+
}
|
110
|
+
],
|
111
|
+
"pageInfo": {
|
112
|
+
"endCursor": null,
|
113
|
+
"hasNextPage": false
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
},
|
120
|
+
{
|
121
|
+
"data": {
|
122
|
+
"repository": {
|
123
|
+
"owner": {
|
124
|
+
"login": "airbytehq"
|
125
|
+
},
|
126
|
+
"name": "airbyte",
|
127
|
+
"pullRequest": {
|
128
|
+
"number": 2,
|
129
|
+
"url": "https://github.com/airbytehq/airbyte/pull/2",
|
130
|
+
"reviews": {
|
131
|
+
"nodes": [
|
132
|
+
{
|
133
|
+
"id": 1006,
|
134
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
135
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/2#pullrequestreview-1006",
|
136
|
+
"commit": null,
|
137
|
+
"user": {
|
138
|
+
"__typename": "User"
|
139
|
+
}
|
140
|
+
},
|
141
|
+
{
|
142
|
+
"id": 1007,
|
143
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
144
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/2#pullrequestreview-1007",
|
145
|
+
"commit": null,
|
146
|
+
"user": {
|
147
|
+
"__typename": "User"
|
148
|
+
}
|
149
|
+
}
|
150
|
+
],
|
151
|
+
"pageInfo": {
|
152
|
+
"endCursor": null,
|
153
|
+
"hasNextPage": false
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
},
|
160
|
+
{
|
161
|
+
"data": {
|
162
|
+
"repository": {
|
163
|
+
"owner": {
|
164
|
+
"login": "airbytehq"
|
165
|
+
},
|
166
|
+
"name": "airbyte",
|
167
|
+
"pullRequests": {
|
168
|
+
"nodes": [
|
169
|
+
{
|
170
|
+
"number": 3,
|
171
|
+
"url": "https://github.com/airbytehq/airbyte/pull/3",
|
172
|
+
"reviews": {
|
173
|
+
"nodes": [
|
174
|
+
{
|
175
|
+
"id": 1008,
|
176
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
177
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/3#pullrequestreview-1008",
|
178
|
+
"commit": null,
|
179
|
+
"user": {
|
180
|
+
"__typename": "User"
|
181
|
+
}
|
182
|
+
}
|
183
|
+
],
|
184
|
+
"pageInfo": {
|
185
|
+
"endCursor": null,
|
186
|
+
"hasNextPage": false
|
187
|
+
}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
],
|
191
|
+
"pageInfo": {
|
192
|
+
"endCursor": null,
|
193
|
+
"hasNextPage": false
|
194
|
+
}
|
195
|
+
}
|
196
|
+
}
|
197
|
+
}
|
198
|
+
},
|
199
|
+
{
|
200
|
+
"data": {
|
201
|
+
"repository": {
|
202
|
+
"owner": {
|
203
|
+
"login": "airbytehq"
|
204
|
+
},
|
205
|
+
"name": "airbyte",
|
206
|
+
"pullRequests": {
|
207
|
+
"nodes": [
|
208
|
+
{
|
209
|
+
"number": 1,
|
210
|
+
"url": "https://github.com/airbytehq/airbyte/pull/1",
|
211
|
+
"reviews": {
|
212
|
+
"nodes": [
|
213
|
+
{
|
214
|
+
"id": 1000,
|
215
|
+
"updated_at": "2000-01-01T00:00:02Z",
|
216
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/1#pullrequestreview-1000",
|
217
|
+
"commit": null,
|
218
|
+
"user": {
|
219
|
+
"__typename": "User"
|
220
|
+
}
|
221
|
+
},
|
222
|
+
{
|
223
|
+
"id": 1001,
|
224
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
225
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/1#pullrequestreview-1001",
|
226
|
+
"commit": null,
|
227
|
+
"user": {
|
228
|
+
"__typename": "User"
|
229
|
+
}
|
230
|
+
}
|
231
|
+
],
|
232
|
+
"pageInfo": {
|
233
|
+
"endCursor": "cursor",
|
234
|
+
"hasNextPage": true
|
235
|
+
}
|
236
|
+
}
|
237
|
+
},
|
238
|
+
{
|
239
|
+
"number": 2,
|
240
|
+
"url": "https://github.com/airbytehq/airbyte/pull/2",
|
241
|
+
"reviews": {
|
242
|
+
"nodes": [
|
243
|
+
{
|
244
|
+
"id": 1002,
|
245
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
246
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/2#pullrequestreview-1002",
|
247
|
+
"commit": null,
|
248
|
+
"user": {
|
249
|
+
"__typename": "User"
|
250
|
+
}
|
251
|
+
},
|
252
|
+
{
|
253
|
+
"id": 1003,
|
254
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
255
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/2#pullrequestreview-1003",
|
256
|
+
"commit": null,
|
257
|
+
"user": {
|
258
|
+
"__typename": "User"
|
259
|
+
}
|
260
|
+
}
|
261
|
+
],
|
262
|
+
"pageInfo": {
|
263
|
+
"endCursor": "cursor",
|
264
|
+
"hasNextPage": true
|
265
|
+
}
|
266
|
+
}
|
267
|
+
}
|
268
|
+
],
|
269
|
+
"pageInfo": {
|
270
|
+
"endCursor": "cursor",
|
271
|
+
"hasNextPage": true
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}
|
275
|
+
}
|
276
|
+
},
|
277
|
+
{
|
278
|
+
"data": {
|
279
|
+
"repository": {
|
280
|
+
"owner": {
|
281
|
+
"login": "airbytehq"
|
282
|
+
},
|
283
|
+
"name": "airbyte",
|
284
|
+
"pullRequest": {
|
285
|
+
"number": 1,
|
286
|
+
"url": "https://github.com/airbytehq/airbyte/pull/1",
|
287
|
+
"reviews": {
|
288
|
+
"nodes": [
|
289
|
+
{
|
290
|
+
"id": 1004,
|
291
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
292
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/1#pullrequestreview-1004",
|
293
|
+
"commit": null,
|
294
|
+
"user": {
|
295
|
+
"__typename": "User"
|
296
|
+
}
|
297
|
+
},
|
298
|
+
{
|
299
|
+
"id": 1005,
|
300
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
301
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/1#pullrequestreview-1005",
|
302
|
+
"commit": null,
|
303
|
+
"user": {
|
304
|
+
"__typename": "User"
|
305
|
+
}
|
306
|
+
}
|
307
|
+
],
|
308
|
+
"pageInfo": {
|
309
|
+
"endCursor": null,
|
310
|
+
"hasNextPage": false
|
311
|
+
}
|
312
|
+
}
|
313
|
+
}
|
314
|
+
}
|
315
|
+
}
|
316
|
+
},
|
317
|
+
{
|
318
|
+
"data": {
|
319
|
+
"repository": {
|
320
|
+
"owner": {
|
321
|
+
"login": "airbytehq"
|
322
|
+
},
|
323
|
+
"name": "airbyte",
|
324
|
+
"pullRequest": {
|
325
|
+
"number": 2,
|
326
|
+
"url": "https://github.com/airbytehq/airbyte/pull/2",
|
327
|
+
"reviews": {
|
328
|
+
"nodes": [
|
329
|
+
{
|
330
|
+
"id": 1006,
|
331
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
332
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/2#pullrequestreview-1006",
|
333
|
+
"commit": null,
|
334
|
+
"user": {
|
335
|
+
"__typename": "User"
|
336
|
+
}
|
337
|
+
},
|
338
|
+
{
|
339
|
+
"id": 1007,
|
340
|
+
"updated_at": "2000-01-01T00:00:02Z",
|
341
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/2#pullrequestreview-1007",
|
342
|
+
"commit": null,
|
343
|
+
"user": {
|
344
|
+
"__typename": "User"
|
345
|
+
}
|
346
|
+
}
|
347
|
+
],
|
348
|
+
"pageInfo": {
|
349
|
+
"endCursor": null,
|
350
|
+
"hasNextPage": false
|
351
|
+
}
|
352
|
+
}
|
353
|
+
}
|
354
|
+
}
|
355
|
+
}
|
356
|
+
},
|
357
|
+
{
|
358
|
+
"data": {
|
359
|
+
"repository": {
|
360
|
+
"owner": {
|
361
|
+
"login": "airbytehq"
|
362
|
+
},
|
363
|
+
"name": "airbyte",
|
364
|
+
"pullRequests": {
|
365
|
+
"nodes": [
|
366
|
+
{
|
367
|
+
"number": 3,
|
368
|
+
"url": "https://github.com/airbytehq/airbyte/pull/3",
|
369
|
+
"reviews": {
|
370
|
+
"nodes": [
|
371
|
+
{
|
372
|
+
"id": 1008,
|
373
|
+
"updated_at": "2000-01-01T00:00:01Z",
|
374
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/3#pullrequestreview-1008",
|
375
|
+
"commit": null,
|
376
|
+
"user": {
|
377
|
+
"__typename": "User"
|
378
|
+
}
|
379
|
+
},
|
380
|
+
{
|
381
|
+
"id": 1009,
|
382
|
+
"updated_at": "2000-01-01T00:00:02Z",
|
383
|
+
"html_url": "https://github.com/airbytehq/airbyte/pull/3#pullrequestreview-1009",
|
384
|
+
"commit": null,
|
385
|
+
"user": {
|
386
|
+
"__typename": "User"
|
387
|
+
}
|
388
|
+
}
|
389
|
+
],
|
390
|
+
"pageInfo": {
|
391
|
+
"endCursor": null,
|
392
|
+
"hasNextPage": false
|
393
|
+
}
|
394
|
+
}
|
395
|
+
}
|
396
|
+
],
|
397
|
+
"pageInfo": {
|
398
|
+
"endCursor": null,
|
399
|
+
"hasNextPage": false
|
400
|
+
}
|
401
|
+
}
|
402
|
+
}
|
403
|
+
}
|
404
|
+
}
|
405
|
+
]
|