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.
Files changed (32) hide show
  1. airbyte_source_github-1.6.1.dist-info/METADATA +111 -0
  2. {airbyte_source_github-1.6.0.dist-info → airbyte_source_github-1.6.1.dist-info}/RECORD +17 -43
  3. {airbyte_source_github-1.6.0.dist-info → airbyte_source_github-1.6.1.dist-info}/WHEEL +1 -2
  4. airbyte_source_github-1.6.1.dist-info/entry_points.txt +3 -0
  5. airbyte_source_github-1.6.0.dist-info/METADATA +0 -144
  6. airbyte_source_github-1.6.0.dist-info/entry_points.txt +0 -2
  7. airbyte_source_github-1.6.0.dist-info/top_level.txt +0 -3
  8. integration_tests/__init__.py +0 -0
  9. integration_tests/abnormal_state.json +0 -237
  10. integration_tests/acceptance.py +0 -16
  11. integration_tests/configured_catalog.json +0 -435
  12. integration_tests/configured_catalog_full_refresh_test.json +0 -415
  13. integration_tests/invalid_config.json +0 -5
  14. integration_tests/sample_config.json +0 -5
  15. integration_tests/sample_state.json +0 -137
  16. unit_tests/__init__.py +0 -3
  17. unit_tests/conftest.py +0 -29
  18. unit_tests/projects_v2_pull_requests_query.json +0 -3
  19. unit_tests/pull_request_stats_query.json +0 -3
  20. unit_tests/responses/contributor_activity_response.json +0 -33
  21. unit_tests/responses/graphql_reviews_responses.json +0 -405
  22. unit_tests/responses/issue_timeline_events.json +0 -166
  23. unit_tests/responses/issue_timeline_events_response.json +0 -170
  24. unit_tests/responses/projects_v2_response.json +0 -45
  25. unit_tests/responses/pull_request_comment_reactions.json +0 -744
  26. unit_tests/responses/pull_request_stats_response.json +0 -317
  27. unit_tests/test_migrations/test_config.json +0 -8
  28. unit_tests/test_migrations/test_new_config.json +0 -8
  29. unit_tests/test_multiple_token_authenticator.py +0 -163
  30. unit_tests/test_source.py +0 -331
  31. unit_tests/test_stream.py +0 -1471
  32. unit_tests/utils.py +0 -78
unit_tests/test_source.py DELETED
@@ -1,331 +0,0 @@
1
- #
2
- # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
- #
4
-
5
- import logging
6
- import os
7
- from unittest.mock import MagicMock
8
-
9
- import pytest
10
- import responses
11
- from airbyte_cdk.models import AirbyteConnectionStatus, Status
12
- from airbyte_cdk.utils.traced_exception import AirbyteTracedException
13
- from source_github import constants
14
- from source_github.source import SourceGithub
15
-
16
- from .utils import command_check
17
-
18
-
19
- def check_source(repo_line: str) -> AirbyteConnectionStatus:
20
- source = SourceGithub()
21
- config = {"access_token": "test_token", "repository": repo_line}
22
- logger_mock = MagicMock()
23
- return source.check(logger_mock, config)
24
-
25
-
26
- def test_source_will_continue_sync_on_stream_failure():
27
- source = SourceGithub()
28
- assert source.continue_sync_on_stream_failure
29
-
30
-
31
- @responses.activate
32
- @pytest.mark.parametrize(
33
- "config, expected",
34
- (
35
- (
36
- {
37
- "start_date": "2021-08-27T00:00:46Z",
38
- "access_token": "test_token",
39
- "repository": "airbyte/test",
40
- },
41
- True,
42
- ),
43
- ({"access_token": "test_token", "repository": "airbyte/test"}, True),
44
- ),
45
- )
46
- def test_check_start_date(config, expected, rate_limit_mock_response):
47
- responses.add(responses.GET, "https://api.github.com/repos/airbyte/test?per_page=100", json={"full_name": "test_full_name"})
48
- source = SourceGithub()
49
- status, _ = source.check_connection(logger=logging.getLogger("airbyte"), config=config)
50
- assert status == expected
51
-
52
-
53
- @pytest.mark.parametrize(
54
- "api_url, deployment_env, expected_message",
55
- (
56
- ("github.my.company.org", "CLOUD", "Please enter a full url for `API URL` field starting with `http`"),
57
- (
58
- "http://github.my.company.org",
59
- "CLOUD",
60
- "HTTP connection is insecure and is not allowed in this environment. Please use `https` instead.",
61
- ),
62
- ("http:/github.my.company.org", "NOT_CLOUD", "Please provide a correct API URL."),
63
- ("https:/github.my.company.org", "CLOUD", "Please provide a correct API URL."),
64
- ),
65
- )
66
- def test_connection_fail_due_to_config_error(api_url, deployment_env, expected_message):
67
- os.environ["DEPLOYMENT_MODE"] = deployment_env
68
- source = SourceGithub()
69
- config = {"access_token": "test_token", "repository": "airbyte/test", "api_url": api_url}
70
-
71
- with pytest.raises(AirbyteTracedException) as e:
72
- source.check_connection(logging.getLogger(), config)
73
- assert e.value.message == expected_message
74
-
75
-
76
- @responses.activate
77
- def test_check_connection_repos_only(rate_limit_mock_response):
78
- responses.add("GET", "https://api.github.com/repos/airbytehq/airbyte", json={"full_name": "airbytehq/airbyte"})
79
-
80
- status = check_source("airbytehq/airbyte airbytehq/airbyte airbytehq/airbyte")
81
- assert not status.message
82
- assert status.status == Status.SUCCEEDED
83
- # Only one request since 3 repos have same name
84
- assert len(responses.calls) == 2
85
-
86
-
87
- @responses.activate
88
- def test_check_connection_repos_and_org_repos(rate_limit_mock_response):
89
- repos = [{"name": f"name {i}", "full_name": f"full name {i}", "updated_at": "2020-01-01T00:00:00Z"} for i in range(1000)]
90
- responses.add(
91
- "GET", "https://api.github.com/repos/airbyte/test", json={"full_name": "airbyte/test", "organization": {"login": "airbyte"}}
92
- )
93
- responses.add(
94
- "GET", "https://api.github.com/repos/airbyte/test2", json={"full_name": "airbyte/test2", "organization": {"login": "airbyte"}}
95
- )
96
- responses.add("GET", "https://api.github.com/orgs/airbytehq/repos", json=repos)
97
- responses.add("GET", "https://api.github.com/orgs/org/repos", json=repos)
98
-
99
- status = check_source("airbyte/test airbyte/test2 airbytehq/* org/*")
100
- assert not status.message
101
- assert status.status == Status.SUCCEEDED
102
- # Two requests for repos and two for organization
103
- assert len(responses.calls) == 5
104
-
105
-
106
- @responses.activate
107
- def test_check_connection_org_only(rate_limit_mock_response):
108
- repos = [{"name": f"name {i}", "full_name": f"full name {i}", "updated_at": "2020-01-01T00:00:00Z"} for i in range(1000)]
109
- responses.add("GET", "https://api.github.com/orgs/airbytehq/repos", json=repos)
110
-
111
- status = check_source("airbytehq/*")
112
- assert not status.message
113
- assert status.status == Status.SUCCEEDED
114
- # One request to check organization
115
- assert len(responses.calls) == 2
116
-
117
-
118
- @responses.activate
119
- def test_get_branches_data():
120
-
121
- repository_args = {"repositories": ["airbytehq/integration-test"], "page_size_for_large_streams": 10}
122
-
123
- source = SourceGithub()
124
-
125
- responses.add(
126
- "GET",
127
- "https://api.github.com/repos/airbytehq/integration-test",
128
- json={"full_name": "airbytehq/integration-test", "default_branch": "master"},
129
- )
130
-
131
- responses.add(
132
- "GET",
133
- "https://api.github.com/repos/airbytehq/integration-test/branches",
134
- json=[
135
- {"repository": "airbytehq/integration-test", "name": "feature/branch_0"},
136
- {"repository": "airbytehq/integration-test", "name": "feature/branch_1"},
137
- {"repository": "airbytehq/integration-test", "name": "feature/branch_2"},
138
- {"repository": "airbytehq/integration-test", "name": "master"},
139
- ],
140
- )
141
-
142
- default_branches, branches_to_pull = source._get_branches_data([], repository_args)
143
- assert default_branches == {"airbytehq/integration-test": "master"}
144
- assert branches_to_pull == {"airbytehq/integration-test": ["master"]}
145
-
146
- default_branches, branches_to_pull = source._get_branches_data(
147
- [
148
- "airbytehq/integration-test/feature/branch_0",
149
- "airbytehq/integration-test/feature/branch_1",
150
- "airbytehq/integration-test/feature/branch_3",
151
- ],
152
- repository_args,
153
- )
154
-
155
- assert default_branches == {"airbytehq/integration-test": "master"}
156
- assert len(branches_to_pull["airbytehq/integration-test"]) == 2
157
- assert "feature/branch_0" in branches_to_pull["airbytehq/integration-test"]
158
- assert "feature/branch_1" in branches_to_pull["airbytehq/integration-test"]
159
-
160
-
161
- @responses.activate
162
- def test_get_org_repositories():
163
- responses.add(
164
- "GET",
165
- "https://api.github.com/repos/airbytehq/integration-test",
166
- json={"full_name": "airbytehq/integration-test", "organization": {"login": "airbytehq"}},
167
- )
168
-
169
- responses.add(
170
- "GET",
171
- "https://api.github.com/orgs/docker/repos",
172
- json=[
173
- {"full_name": "docker/docker-py", "updated_at": "2020-01-01T00:00:00Z"},
174
- {"full_name": "docker/compose", "updated_at": "2020-01-01T00:00:00Z"},
175
- ],
176
- )
177
-
178
- config = {"repositories": ["airbytehq/integration-test", "docker/*"]}
179
- source = SourceGithub()
180
- config = source._ensure_default_values(config)
181
- organisations, repositories = source._get_org_repositories(config, authenticator=None)
182
-
183
- assert set(repositories) == {"airbytehq/integration-test", "docker/docker-py", "docker/compose"}
184
- assert set(organisations) == {"airbytehq", "docker"}
185
-
186
-
187
- @responses.activate
188
- def test_organization_or_repo_available(monkeypatch, rate_limit_mock_response):
189
- monkeypatch.setattr(SourceGithub, "_get_org_repositories", MagicMock(return_value=(False, False)))
190
- source = SourceGithub()
191
- with pytest.raises(Exception) as exc_info:
192
- config = {"access_token": "test_token", "repository": ""}
193
- source.streams(config=config)
194
- assert exc_info.value.args[0] == "No streams available. Please check permissions"
195
-
196
-
197
- def test_check_config_repository():
198
- source = SourceGithub()
199
- source.check = MagicMock(return_value=True)
200
- config = {"credentials": {"access_token": "access_token"}, "start_date": "1900-01-01T00:00:00Z"}
201
-
202
- repos_ok = [
203
- "airbytehq/airbyte",
204
- "airbytehq/airbyte-test",
205
- "airbytehq/airbyte_test",
206
- "erohmensing/thismonth.rocks",
207
- "airbytehq/*",
208
- "airbytehq/.",
209
- "airbyte_hq/airbyte",
210
- "airbytehq/123",
211
- "airbytehq/airbytexgit",
212
- ]
213
-
214
- repos_fail = [
215
- "airbytehq",
216
- "airbytehq/",
217
- "airbytehq/*/",
218
- "airbytehq/airbyte.git",
219
- "airbytehq/airbyte/",
220
- "airbytehq/air*yte",
221
- "airbyte*/airbyte",
222
- "airbytehq/airbyte-test/master-branch",
223
- "https://github.com/airbytehq/airbyte",
224
- ]
225
-
226
- config["repositories"] = []
227
- with pytest.raises(AirbyteTracedException):
228
- assert command_check(source, config)
229
- config["repositories"] = []
230
- with pytest.raises(AirbyteTracedException):
231
- assert command_check(source, config)
232
-
233
- for repos in repos_ok:
234
- config["repositories"] = [repos]
235
- assert command_check(source, config)
236
-
237
- for repos in repos_fail:
238
- config["repositories"] = [repos]
239
- with pytest.raises(AirbyteTracedException):
240
- assert command_check(source, config)
241
-
242
-
243
- @responses.activate
244
- def test_streams_no_streams_available_error(monkeypatch, rate_limit_mock_response):
245
- monkeypatch.setattr(SourceGithub, "_get_org_repositories", MagicMock(return_value=(False, False)))
246
- with pytest.raises(AirbyteTracedException) as e:
247
- SourceGithub().streams(config={"access_token": "test_token", "repository": "airbytehq/airbyte-test"})
248
- assert str(e.value) == "No streams available. Please check permissions"
249
-
250
-
251
- @responses.activate
252
- def test_streams_page_size(rate_limit_mock_response):
253
- responses.get("https://api.github.com/repos/airbytehq/airbyte", json={"full_name": "airbytehq/airbyte", "default_branch": "master"})
254
- responses.get("https://api.github.com/repos/airbytehq/airbyte/branches", json=[{"repository": "airbytehq/airbyte", "name": "master"}])
255
-
256
- config = {
257
- "credentials": {"access_token": "access_token"},
258
- "repository": "airbytehq/airbyte",
259
- "start_date": "1900-07-12T00:00:00Z",
260
- }
261
-
262
- source = SourceGithub()
263
- streams = source.streams(config)
264
- assert constants.DEFAULT_PAGE_SIZE != constants.DEFAULT_PAGE_SIZE_FOR_LARGE_STREAM
265
-
266
- for stream in streams:
267
- if stream.large_stream:
268
- assert stream.page_size == constants.DEFAULT_PAGE_SIZE_FOR_LARGE_STREAM
269
- else:
270
- assert stream.page_size == constants.DEFAULT_PAGE_SIZE
271
-
272
-
273
- @responses.activate
274
- @pytest.mark.parametrize(
275
- "config, expected",
276
- (
277
- (
278
- {
279
- "start_date": "2021-08-27T00:00:46Z",
280
- "access_token": "test_token",
281
- "repository": "airbyte/test",
282
- },
283
- 39,
284
- ),
285
- ({"access_token": "test_token", "repository": "airbyte/test"}, 39),
286
- ),
287
- )
288
- def test_streams_config_start_date(config, expected, rate_limit_mock_response):
289
- responses.add(responses.GET, "https://api.github.com/repos/airbyte/test?per_page=100", json={"full_name": "airbyte/test"})
290
- responses.add(
291
- responses.GET,
292
- "https://api.github.com/repos/airbyte/test?per_page=100",
293
- json={"full_name": "airbyte/test", "default_branch": "default_branch"},
294
- )
295
- responses.add(
296
- responses.GET,
297
- "https://api.github.com/repos/airbyte/test/branches?per_page=100",
298
- json=[{"repository": "airbyte/test", "name": "name"}],
299
- )
300
- source = SourceGithub()
301
- streams = source.streams(config=config)
302
- # projects stream that uses start date
303
- project_stream = streams[4]
304
- assert len(streams) == expected
305
- if config.get("start_date"):
306
- assert project_stream._start_date == "2021-08-27T00:00:46Z"
307
- else:
308
- assert not project_stream._start_date
309
-
310
-
311
- @pytest.mark.parametrize(
312
- "error_message, expected_user_friendly_message",
313
- [
314
- (
315
- "404 Client Error: Not Found for url: https://api.github.com/repos/repo_name",
316
- 'Repo name: "repo_name" is unknown, "repository" config option should use existing full repo name <organization>/<repository>',
317
- ),
318
- (
319
- "404 Client Error: Not Found for url: https://api.github.com/orgs/org_name",
320
- 'Organization name: "org_name" is unknown, "repository" config option should be updated. Please validate your repository config.',
321
- ),
322
- (
323
- "401 Client Error: Unauthorized for url",
324
- "Github credentials have expired or changed, please review your credentials and re-authenticate or renew your access token.",
325
- ),
326
- ],
327
- )
328
- def test_user_friendly_message(error_message, expected_user_friendly_message):
329
- source = SourceGithub()
330
- user_friendly_error_message = source.user_friendly_error_message(error_message)
331
- assert user_friendly_error_message == expected_user_friendly_message