airbyte-source-github 1.6.0__py3-none-any.whl → 1.6.1__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.6.1.dist-info/METADATA +111 -0
- {airbyte_source_github-1.6.0.dist-info → airbyte_source_github-1.6.1.dist-info}/RECORD +17 -43
- {airbyte_source_github-1.6.0.dist-info → airbyte_source_github-1.6.1.dist-info}/WHEEL +1 -2
- airbyte_source_github-1.6.1.dist-info/entry_points.txt +3 -0
- airbyte_source_github-1.6.0.dist-info/METADATA +0 -144
- airbyte_source_github-1.6.0.dist-info/entry_points.txt +0 -2
- airbyte_source_github-1.6.0.dist-info/top_level.txt +0 -3
- integration_tests/__init__.py +0 -0
- integration_tests/abnormal_state.json +0 -237
- integration_tests/acceptance.py +0 -16
- integration_tests/configured_catalog.json +0 -435
- integration_tests/configured_catalog_full_refresh_test.json +0 -415
- integration_tests/invalid_config.json +0 -5
- integration_tests/sample_config.json +0 -5
- integration_tests/sample_state.json +0 -137
- unit_tests/__init__.py +0 -3
- unit_tests/conftest.py +0 -29
- unit_tests/projects_v2_pull_requests_query.json +0 -3
- unit_tests/pull_request_stats_query.json +0 -3
- unit_tests/responses/contributor_activity_response.json +0 -33
- unit_tests/responses/graphql_reviews_responses.json +0 -405
- unit_tests/responses/issue_timeline_events.json +0 -166
- unit_tests/responses/issue_timeline_events_response.json +0 -170
- unit_tests/responses/projects_v2_response.json +0 -45
- unit_tests/responses/pull_request_comment_reactions.json +0 -744
- unit_tests/responses/pull_request_stats_response.json +0 -317
- unit_tests/test_migrations/test_config.json +0 -8
- unit_tests/test_migrations/test_new_config.json +0 -8
- unit_tests/test_multiple_token_authenticator.py +0 -163
- unit_tests/test_source.py +0 -331
- unit_tests/test_stream.py +0 -1471
- unit_tests/utils.py +0 -78
@@ -1,317 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"data": {
|
3
|
-
"repository": {
|
4
|
-
"name": "integration-test",
|
5
|
-
"owner": {
|
6
|
-
"login": "airbytehq"
|
7
|
-
},
|
8
|
-
"pullRequests": {
|
9
|
-
"nodes": [
|
10
|
-
{
|
11
|
-
"node_id": "MDExOlB1bGxSZXF1ZXN0NzIxNDM1NTA2",
|
12
|
-
"id": 721435506,
|
13
|
-
"number": 5,
|
14
|
-
"updated_at": "2021-08-27T15:53:14Z",
|
15
|
-
"changed_files": 5,
|
16
|
-
"deletions": 0,
|
17
|
-
"additions": 5,
|
18
|
-
"merged": false,
|
19
|
-
"mergeable": "MERGEABLE",
|
20
|
-
"can_be_rebased": true,
|
21
|
-
"maintainer_can_modify": false,
|
22
|
-
"merge_state_status": "BLOCKED",
|
23
|
-
"comments": {
|
24
|
-
"totalCount": 0
|
25
|
-
},
|
26
|
-
"commits": {
|
27
|
-
"totalCount": 5
|
28
|
-
},
|
29
|
-
"review_comments": {
|
30
|
-
"totalCount": 1,
|
31
|
-
"nodes": [
|
32
|
-
{
|
33
|
-
"comments": {
|
34
|
-
"totalCount": 0
|
35
|
-
}
|
36
|
-
}
|
37
|
-
]
|
38
|
-
},
|
39
|
-
"merged_by": null
|
40
|
-
},
|
41
|
-
{
|
42
|
-
"node_id": "MDExOlB1bGxSZXF1ZXN0NzIxNDM1NDA3",
|
43
|
-
"id": 721435407,
|
44
|
-
"number": 2,
|
45
|
-
"updated_at": "2021-08-27T15:53:27Z",
|
46
|
-
"changed_files": 5,
|
47
|
-
"deletions": 0,
|
48
|
-
"additions": 5,
|
49
|
-
"merged": false,
|
50
|
-
"mergeable": "MERGEABLE",
|
51
|
-
"can_be_rebased": true,
|
52
|
-
"maintainer_can_modify": false,
|
53
|
-
"merge_state_status": "BLOCKED",
|
54
|
-
"comments": {
|
55
|
-
"totalCount": 0
|
56
|
-
},
|
57
|
-
"commits": {
|
58
|
-
"totalCount": 5
|
59
|
-
},
|
60
|
-
"review_comments": {
|
61
|
-
"totalCount": 1,
|
62
|
-
"nodes": [
|
63
|
-
{
|
64
|
-
"comments": {
|
65
|
-
"totalCount": 0
|
66
|
-
}
|
67
|
-
}
|
68
|
-
]
|
69
|
-
},
|
70
|
-
"merged_by": null
|
71
|
-
},
|
72
|
-
{
|
73
|
-
"node_id": "MDExOlB1bGxSZXF1ZXN0NzIxNDM1NDQw",
|
74
|
-
"id": 721435440,
|
75
|
-
"number": 3,
|
76
|
-
"updated_at": "2021-08-27T16:02:49Z",
|
77
|
-
"changed_files": 5,
|
78
|
-
"deletions": 0,
|
79
|
-
"additions": 5,
|
80
|
-
"merged": true,
|
81
|
-
"mergeable": "UNKNOWN",
|
82
|
-
"can_be_rebased": false,
|
83
|
-
"maintainer_can_modify": false,
|
84
|
-
"merge_state_status": "UNKNOWN",
|
85
|
-
"comments": {
|
86
|
-
"totalCount": 0
|
87
|
-
},
|
88
|
-
"commits": {
|
89
|
-
"totalCount": 5
|
90
|
-
},
|
91
|
-
"review_comments": {
|
92
|
-
"totalCount": 1,
|
93
|
-
"nodes": [
|
94
|
-
{
|
95
|
-
"comments": {
|
96
|
-
"totalCount": 0
|
97
|
-
}
|
98
|
-
}
|
99
|
-
]
|
100
|
-
},
|
101
|
-
"merged_by": {
|
102
|
-
"__typename": "User",
|
103
|
-
"node_id": "MDQ6VXNlcjc0MzkwMQ==",
|
104
|
-
"id": 743901,
|
105
|
-
"login": "gaart",
|
106
|
-
"avatar_url": "https://avatars.githubusercontent.com/u/743901?v=4",
|
107
|
-
"html_url": "https://github.com/gaart",
|
108
|
-
"site_admin": false
|
109
|
-
}
|
110
|
-
},
|
111
|
-
{
|
112
|
-
"node_id": "MDExOlB1bGxSZXF1ZXN0NzIxNDM1NDY2",
|
113
|
-
"id": 721435466,
|
114
|
-
"number": 4,
|
115
|
-
"updated_at": "2021-08-31T12:01:15Z",
|
116
|
-
"changed_files": 5,
|
117
|
-
"deletions": 0,
|
118
|
-
"additions": 5,
|
119
|
-
"merged": false,
|
120
|
-
"mergeable": "MERGEABLE",
|
121
|
-
"can_be_rebased": true,
|
122
|
-
"maintainer_can_modify": false,
|
123
|
-
"merge_state_status": "BLOCKED",
|
124
|
-
"comments": {
|
125
|
-
"totalCount": 0
|
126
|
-
},
|
127
|
-
"commits": {
|
128
|
-
"totalCount": 5
|
129
|
-
},
|
130
|
-
"review_comments": {
|
131
|
-
"totalCount": 3,
|
132
|
-
"nodes": [
|
133
|
-
{
|
134
|
-
"comments": {
|
135
|
-
"totalCount": 0
|
136
|
-
}
|
137
|
-
},
|
138
|
-
{
|
139
|
-
"comments": {
|
140
|
-
"totalCount": 0
|
141
|
-
}
|
142
|
-
},
|
143
|
-
{
|
144
|
-
"comments": {
|
145
|
-
"totalCount": 1
|
146
|
-
}
|
147
|
-
}
|
148
|
-
]
|
149
|
-
},
|
150
|
-
"merged_by": null
|
151
|
-
},
|
152
|
-
{
|
153
|
-
"node_id": "PR_kwDOF9hP9c4xmEi6",
|
154
|
-
"id": 832063674,
|
155
|
-
"number": 12,
|
156
|
-
"updated_at": "2022-01-26T03:46:56Z",
|
157
|
-
"changed_files": 1,
|
158
|
-
"deletions": 0,
|
159
|
-
"additions": 2,
|
160
|
-
"merged": true,
|
161
|
-
"mergeable": "UNKNOWN",
|
162
|
-
"can_be_rebased": false,
|
163
|
-
"maintainer_can_modify": false,
|
164
|
-
"merge_state_status": "UNKNOWN",
|
165
|
-
"comments": {
|
166
|
-
"totalCount": 0
|
167
|
-
},
|
168
|
-
"commits": {
|
169
|
-
"totalCount": 1
|
170
|
-
},
|
171
|
-
"review_comments": {
|
172
|
-
"totalCount": 1,
|
173
|
-
"nodes": [
|
174
|
-
{
|
175
|
-
"comments": {
|
176
|
-
"totalCount": 0
|
177
|
-
}
|
178
|
-
}
|
179
|
-
]
|
180
|
-
},
|
181
|
-
"merged_by": {
|
182
|
-
"__typename": "User",
|
183
|
-
"node_id": "MDQ6VXNlcjUxNTQzMjI=",
|
184
|
-
"id": 5154322,
|
185
|
-
"login": "marcosmarxm",
|
186
|
-
"avatar_url": "https://avatars.githubusercontent.com/u/5154322?u=92c89b82271d48f41fad03923b0a24083e049038&v=4",
|
187
|
-
"html_url": "https://github.com/marcosmarxm",
|
188
|
-
"site_admin": false
|
189
|
-
}
|
190
|
-
},
|
191
|
-
{
|
192
|
-
"node_id": "MDExOlB1bGxSZXF1ZXN0NzIxNDM1Mzcz",
|
193
|
-
"id": 721435373,
|
194
|
-
"number": 1,
|
195
|
-
"updated_at": "2022-03-31T11:06:06Z",
|
196
|
-
"changed_files": 5,
|
197
|
-
"deletions": 0,
|
198
|
-
"additions": 5,
|
199
|
-
"merged": false,
|
200
|
-
"mergeable": "MERGEABLE",
|
201
|
-
"can_be_rebased": true,
|
202
|
-
"maintainer_can_modify": false,
|
203
|
-
"merge_state_status": "BLOCKED",
|
204
|
-
"comments": {
|
205
|
-
"totalCount": 0
|
206
|
-
},
|
207
|
-
"commits": {
|
208
|
-
"totalCount": 5
|
209
|
-
},
|
210
|
-
"review_comments": {
|
211
|
-
"totalCount": 1,
|
212
|
-
"nodes": [
|
213
|
-
{
|
214
|
-
"comments": {
|
215
|
-
"totalCount": 0
|
216
|
-
}
|
217
|
-
}
|
218
|
-
]
|
219
|
-
},
|
220
|
-
"merged_by": null
|
221
|
-
},
|
222
|
-
{
|
223
|
-
"node_id": "PR_kwDOF9hP9c46s2Qa",
|
224
|
-
"id": 984835098,
|
225
|
-
"number": 14,
|
226
|
-
"updated_at": "2022-10-04T17:41:29Z",
|
227
|
-
"changed_files": 1,
|
228
|
-
"deletions": 0,
|
229
|
-
"additions": 1,
|
230
|
-
"merged": false,
|
231
|
-
"mergeable": "MERGEABLE",
|
232
|
-
"can_be_rebased": true,
|
233
|
-
"maintainer_can_modify": false,
|
234
|
-
"merge_state_status": "BLOCKED",
|
235
|
-
"comments": {
|
236
|
-
"totalCount": 0
|
237
|
-
},
|
238
|
-
"commits": {
|
239
|
-
"totalCount": 2
|
240
|
-
},
|
241
|
-
"review_comments": {
|
242
|
-
"totalCount": 1,
|
243
|
-
"nodes": [
|
244
|
-
{
|
245
|
-
"comments": {
|
246
|
-
"totalCount": 0
|
247
|
-
}
|
248
|
-
}
|
249
|
-
]
|
250
|
-
},
|
251
|
-
"merged_by": null
|
252
|
-
},
|
253
|
-
{
|
254
|
-
"node_id": "PR_kwDOF9hP9c41Vftv",
|
255
|
-
"id": 894827375,
|
256
|
-
"number": 13,
|
257
|
-
"updated_at": "2023-05-03T06:50:23Z",
|
258
|
-
"changed_files": 1,
|
259
|
-
"deletions": 1,
|
260
|
-
"additions": 1,
|
261
|
-
"merged": false,
|
262
|
-
"mergeable": "MERGEABLE",
|
263
|
-
"can_be_rebased": true,
|
264
|
-
"maintainer_can_modify": false,
|
265
|
-
"merge_state_status": "BLOCKED",
|
266
|
-
"comments": {
|
267
|
-
"totalCount": 0
|
268
|
-
},
|
269
|
-
"commits": {
|
270
|
-
"totalCount": 1
|
271
|
-
},
|
272
|
-
"review_comments": {
|
273
|
-
"totalCount": 0,
|
274
|
-
"nodes": []
|
275
|
-
},
|
276
|
-
"merged_by": null
|
277
|
-
},
|
278
|
-
{
|
279
|
-
"node_id": "PR_kwDOF9hP9c5PqZhG",
|
280
|
-
"id": 1336514630,
|
281
|
-
"number": 15,
|
282
|
-
"updated_at": "2023-05-04T10:07:46Z",
|
283
|
-
"changed_files": 1,
|
284
|
-
"deletions": 0,
|
285
|
-
"additions": 1,
|
286
|
-
"merged": false,
|
287
|
-
"mergeable": "MERGEABLE",
|
288
|
-
"can_be_rebased": false,
|
289
|
-
"maintainer_can_modify": false,
|
290
|
-
"merge_state_status": "BLOCKED",
|
291
|
-
"comments": {
|
292
|
-
"totalCount": 1
|
293
|
-
},
|
294
|
-
"commits": {
|
295
|
-
"totalCount": 1
|
296
|
-
},
|
297
|
-
"review_comments": {
|
298
|
-
"totalCount": 1,
|
299
|
-
"nodes": [
|
300
|
-
{
|
301
|
-
"comments": {
|
302
|
-
"totalCount": 0
|
303
|
-
}
|
304
|
-
}
|
305
|
-
]
|
306
|
-
},
|
307
|
-
"merged_by": null
|
308
|
-
}
|
309
|
-
],
|
310
|
-
"pageInfo": {
|
311
|
-
"hasNextPage": false,
|
312
|
-
"endCursor": "Y3Vyc29yOnYyOpK5MjAyMy0wNS0wNFQxMzowNzo0NiswMzowMM5PqZhG"
|
313
|
-
}
|
314
|
-
}
|
315
|
-
}
|
316
|
-
}
|
317
|
-
}
|
@@ -1,8 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"credentials": {
|
3
|
-
"personal_access_token": "personal_access_token"
|
4
|
-
},
|
5
|
-
"repositories": ["airbytehq/airbyte", "airbytehq/airbyte-platform"],
|
6
|
-
"start_date": "2000-01-01T00:00:00Z",
|
7
|
-
"branches": ["airbytehq/airbyte/master", "airbytehq/airbyte-platform/main"]
|
8
|
-
}
|
@@ -1,163 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
3
|
-
#
|
4
|
-
|
5
|
-
import json
|
6
|
-
from unittest.mock import patch
|
7
|
-
|
8
|
-
import pendulum
|
9
|
-
import pytest
|
10
|
-
import responses
|
11
|
-
from airbyte_cdk.utils import AirbyteTracedException
|
12
|
-
from freezegun import freeze_time
|
13
|
-
from source_github import SourceGithub
|
14
|
-
from source_github.streams import Organizations
|
15
|
-
from source_github.utils import MultipleTokenAuthenticatorWithRateLimiter, read_full_refresh
|
16
|
-
|
17
|
-
|
18
|
-
@responses.activate
|
19
|
-
def test_multiple_tokens(rate_limit_mock_response):
|
20
|
-
authenticator = SourceGithub()._get_authenticator({"access_token": "token_1, token_2, token_3"})
|
21
|
-
assert isinstance(authenticator, MultipleTokenAuthenticatorWithRateLimiter)
|
22
|
-
assert ["token_1", "token_2", "token_3"] == list(authenticator._tokens)
|
23
|
-
|
24
|
-
|
25
|
-
@responses.activate
|
26
|
-
def test_authenticator_counter(rate_limit_mock_response):
|
27
|
-
"""
|
28
|
-
This test ensures that the rate limiter:
|
29
|
-
1. correctly handles the available limits from GitHub API and saves it.
|
30
|
-
2. correctly counts the number of requests made.
|
31
|
-
"""
|
32
|
-
authenticator = MultipleTokenAuthenticatorWithRateLimiter(tokens=["token1", "token2", "token3"])
|
33
|
-
|
34
|
-
assert [(x.count_rest, x.count_graphql) for x in authenticator._tokens.values()] == [(5000, 5000), (5000, 5000), (5000, 5000)]
|
35
|
-
organization_args = {"organizations": ["org1", "org2"], "authenticator": authenticator}
|
36
|
-
stream = Organizations(**organization_args)
|
37
|
-
responses.add("GET", "https://api.github.com/orgs/org1", json={"id": 1})
|
38
|
-
responses.add("GET", "https://api.github.com/orgs/org2", json={"id": 2})
|
39
|
-
list(read_full_refresh(stream))
|
40
|
-
assert authenticator._tokens["token1"].count_rest == 4998
|
41
|
-
|
42
|
-
|
43
|
-
@responses.activate
|
44
|
-
def test_multiple_token_authenticator_with_rate_limiter():
|
45
|
-
"""
|
46
|
-
This test ensures that:
|
47
|
-
1. The rate limiter iterates over all tokens one-by-one after the previous is fully drained.
|
48
|
-
2. Counter is set to zero after 1500 requests were made. (500 available requests per key were set as default)
|
49
|
-
3. Exception is handled and log warning message could be found in output. Connector does not raise AirbyteTracedException because there might be GraphQL streams with remaining request we still can read.
|
50
|
-
"""
|
51
|
-
|
52
|
-
counter_rate_limits = 0
|
53
|
-
counter_orgs = 0
|
54
|
-
|
55
|
-
def request_callback_rate_limits(request):
|
56
|
-
nonlocal counter_rate_limits
|
57
|
-
while counter_rate_limits < 3:
|
58
|
-
counter_rate_limits += 1
|
59
|
-
resp_body = {
|
60
|
-
"resources": {
|
61
|
-
"core": {
|
62
|
-
"limit": 500,
|
63
|
-
"used": 0,
|
64
|
-
"remaining": 500,
|
65
|
-
"reset": 4070908800
|
66
|
-
},
|
67
|
-
"graphql": {
|
68
|
-
"limit": 500,
|
69
|
-
"used": 0,
|
70
|
-
"remaining": 500,
|
71
|
-
"reset": 4070908800
|
72
|
-
}
|
73
|
-
}
|
74
|
-
}
|
75
|
-
return (200, {}, json.dumps(resp_body))
|
76
|
-
|
77
|
-
responses.add_callback(responses.GET, "https://api.github.com/rate_limit", callback=request_callback_rate_limits)
|
78
|
-
authenticator = MultipleTokenAuthenticatorWithRateLimiter(tokens=["token1", "token2", "token3"])
|
79
|
-
organization_args = {"organizations": ["org1"], "authenticator": authenticator}
|
80
|
-
stream = Organizations(**organization_args)
|
81
|
-
|
82
|
-
def request_callback_orgs(request):
|
83
|
-
nonlocal counter_orgs
|
84
|
-
while counter_orgs < 1_501:
|
85
|
-
counter_orgs += 1
|
86
|
-
resp_body = {"id": 1}
|
87
|
-
headers = {"Link": '<https://api.github.com/orgs/org1?page=2>; rel="next"'}
|
88
|
-
return (200, headers, json.dumps(resp_body))
|
89
|
-
|
90
|
-
responses.add_callback(
|
91
|
-
responses.GET,
|
92
|
-
"https://api.github.com/orgs/org1",
|
93
|
-
callback=request_callback_orgs,
|
94
|
-
content_type="application/json",
|
95
|
-
)
|
96
|
-
with pytest.raises(AirbyteTracedException) as e:
|
97
|
-
list(read_full_refresh(stream))
|
98
|
-
assert [(x.count_rest, x.count_graphql) for x in authenticator._tokens.values()] == [(0, 500), (0, 500), (0, 500)]
|
99
|
-
message = "Stream: `organizations`, slice: `{'organization': 'org1'}`. Limits for all provided tokens are reached, please try again later"
|
100
|
-
assert e.value.internal_message == message
|
101
|
-
|
102
|
-
|
103
|
-
@freeze_time("2021-01-01 12:00:00")
|
104
|
-
@responses.activate
|
105
|
-
@patch("time.sleep")
|
106
|
-
def test_multiple_token_authenticator_with_rate_limiter_and_sleep(sleep_mock, caplog):
|
107
|
-
"""
|
108
|
-
This test ensures that:
|
109
|
-
1. The rate limiter will only wait (sleep) for token availability if the nearest available token appears within 600 seconds (see max_time).
|
110
|
-
2. Token Counter is reset to new values after 1500 requests were made and last token is still in use.
|
111
|
-
"""
|
112
|
-
|
113
|
-
counter_rate_limits = 0
|
114
|
-
counter_orgs = 0
|
115
|
-
ACCEPTED_WAITING_TIME_IN_SECONDS = 595
|
116
|
-
reset_time = (pendulum.now() + pendulum.duration(seconds=ACCEPTED_WAITING_TIME_IN_SECONDS)).int_timestamp
|
117
|
-
|
118
|
-
def request_callback_rate_limits(request):
|
119
|
-
nonlocal counter_rate_limits
|
120
|
-
while counter_rate_limits < 6:
|
121
|
-
counter_rate_limits += 1
|
122
|
-
resp_body = {
|
123
|
-
"resources": {
|
124
|
-
"core": {
|
125
|
-
"limit": 500,
|
126
|
-
"used": 0,
|
127
|
-
"remaining": 500,
|
128
|
-
"reset": reset_time
|
129
|
-
},
|
130
|
-
"graphql": {
|
131
|
-
"limit": 500,
|
132
|
-
"used": 0,
|
133
|
-
"remaining": 500,
|
134
|
-
"reset": reset_time
|
135
|
-
}
|
136
|
-
}
|
137
|
-
}
|
138
|
-
return (200, {}, json.dumps(resp_body))
|
139
|
-
|
140
|
-
responses.add_callback(responses.GET, "https://api.github.com/rate_limit", callback=request_callback_rate_limits)
|
141
|
-
authenticator = MultipleTokenAuthenticatorWithRateLimiter(tokens=["token1", "token2", "token3"])
|
142
|
-
organization_args = {"organizations": ["org1"], "authenticator": authenticator}
|
143
|
-
stream = Organizations(**organization_args)
|
144
|
-
|
145
|
-
def request_callback_orgs(request):
|
146
|
-
nonlocal counter_orgs
|
147
|
-
while counter_orgs < 1_501:
|
148
|
-
counter_orgs += 1
|
149
|
-
resp_body = {"id": 1}
|
150
|
-
headers = {"Link": '<https://api.github.com/orgs/org1?page=2>; rel="next"'}
|
151
|
-
return (200, headers, json.dumps(resp_body))
|
152
|
-
return (200, {}, json.dumps({"id": 2}))
|
153
|
-
|
154
|
-
responses.add_callback(
|
155
|
-
responses.GET,
|
156
|
-
"https://api.github.com/orgs/org1",
|
157
|
-
callback=request_callback_orgs,
|
158
|
-
content_type="application/json",
|
159
|
-
)
|
160
|
-
|
161
|
-
list(read_full_refresh(stream))
|
162
|
-
sleep_mock.assert_called_once_with(ACCEPTED_WAITING_TIME_IN_SECONDS)
|
163
|
-
assert [(x.count_rest, x.count_graphql) for x in authenticator._tokens.values()] == [(500, 500), (500, 500), (498, 500)]
|