airbyte-source-github 2.2.1__tar.gz → 2.2.3__tar.gz
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-2.2.1 → airbyte_source_github-2.2.3}/PKG-INFO +1 -1
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/pyproject.toml +1 -1
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/manifest.yaml +34 -2
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/source.py +13 -8
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/streams.py +24 -3
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/.airbyte-pypi-readme.md +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/__init__.py +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/backoff_strategies.py +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/config_migrations.py +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/constants.py +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/errors_handlers.py +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/github_schema.py +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/graphql.py +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/run.py +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/assignees.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/branches.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/collaborators.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/comments.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/commit_comment_reactions.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/commit_comments.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/commits.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/contributor_activity.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/deployments.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/events.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/issue_comment_reactions.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/issue_events.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/issue_labels.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/issue_milestones.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/issue_reactions.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/issue_timeline_events.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/issues.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/organizations.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/project_cards.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/project_columns.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/projects.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/projects_v2.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/pull_request_comment_reactions.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/pull_request_commits.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/pull_request_stats.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/pull_requests.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/releases.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/review_comments.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/reviews.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/shared/events/comment.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/shared/events/commented.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/shared/events/committed.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/shared/events/cross_referenced.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/shared/events/reviewed.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/shared/reaction.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/shared/reactions.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/shared/user.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/shared/user_graphql.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/stargazers.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/tags.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/team_members.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/team_memberships.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/teams.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/users.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/workflow_jobs.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/workflow_runs.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/workflows.json +0 -0
- {airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/utils.py +0 -0
|
@@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",]
|
|
|
3
3
|
build-backend = "poetry.core.masonry.api"
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
|
-
version = "2.2.
|
|
6
|
+
version = "2.2.3"
|
|
7
7
|
name = "airbyte-source-github"
|
|
8
8
|
description = "Source implementation for GitHub."
|
|
9
9
|
authors = [ "Airbyte <contact@airbyte.io>",]
|
|
@@ -405,8 +405,11 @@ definitions:
|
|
|
405
405
|
- string
|
|
406
406
|
|
|
407
407
|
# Shared partition routers. Repo-scoped streams reference
|
|
408
|
-
# `repository_partition_router
|
|
409
|
-
# `
|
|
408
|
+
# `repository_partition_router`. For orgs there are deliberately two routers with
|
|
409
|
+
# different audiences: the `repositories` stream references
|
|
410
|
+
# `organization_partition_router` (config-derived candidates), the org-scoped Python
|
|
411
|
+
# streams reference `organization_resolution_partition_router` (payload-confirmed).
|
|
412
|
+
# Picking the wrong one for an org-scoped stream is what broke 2.2.0 — see below.
|
|
410
413
|
#
|
|
411
414
|
# `repository_partition_router` yields the deduplicated union of
|
|
412
415
|
# wildcard-expanded repos and validated explicit repos.
|
|
@@ -415,6 +418,16 @@ definitions:
|
|
|
415
418
|
# orgs (derived inline from config) and the orgs owning explicit repos.
|
|
416
419
|
# User-owned repos have no `organization` object, so the substream child
|
|
417
420
|
# skips them (they contribute a repository but not an organization).
|
|
421
|
+
# It drives the `repositories` stream, which has to *attempt* `orgs/{org}/repos`
|
|
422
|
+
# for a wildcard entry to learn whether the login is an organization at all.
|
|
423
|
+
#
|
|
424
|
+
# `organization_resolution_partition_router` is the narrower list the org-scoped
|
|
425
|
+
# Python streams slice on, and must not be the router above: a login taken from
|
|
426
|
+
# config text is only a *candidate* org, and `orgs/{login}` 404s on every
|
|
427
|
+
# org-scoped stream when it is a user. Both branches here take the org from a
|
|
428
|
+
# response payload instead — `owner/login` of the repos `orgs/{org}/repos`
|
|
429
|
+
# returned, `organization/login` of `repos/{owner}/{repo}` (absent for user-owned
|
|
430
|
+
# repos) — which is how the legacy Python resolver built the list.
|
|
418
431
|
repository_partition_router:
|
|
419
432
|
type: UnionPartitionRouter
|
|
420
433
|
partition_field: repository
|
|
@@ -450,6 +463,25 @@ definitions:
|
|
|
450
463
|
parent_key: "organization/login"
|
|
451
464
|
partition_field: "organization"
|
|
452
465
|
|
|
466
|
+
organization_resolution_partition_router:
|
|
467
|
+
type: UnionPartitionRouter
|
|
468
|
+
partition_field: organization
|
|
469
|
+
partition_routers:
|
|
470
|
+
- type: SubstreamPartitionRouter
|
|
471
|
+
parent_stream_configs:
|
|
472
|
+
- type: ParentStreamConfig
|
|
473
|
+
stream:
|
|
474
|
+
$ref: "#/definitions/repositories_resolver_stream"
|
|
475
|
+
parent_key: "owner/login"
|
|
476
|
+
partition_field: "organization"
|
|
477
|
+
- type: SubstreamPartitionRouter
|
|
478
|
+
parent_stream_configs:
|
|
479
|
+
- type: ParentStreamConfig
|
|
480
|
+
stream:
|
|
481
|
+
$ref: "#/definitions/repository_stats_stream"
|
|
482
|
+
parent_key: "organization/login"
|
|
483
|
+
partition_field: "organization"
|
|
484
|
+
|
|
453
485
|
repositories_stream:
|
|
454
486
|
type: DeclarativeStream
|
|
455
487
|
name: repositories
|
|
@@ -143,8 +143,8 @@ class SourceGithub(YamlDeclarativeSource, AbstractSource):
|
|
|
143
143
|
|
|
144
144
|
def _resolve_repositories_and_organizations(self, config: Mapping[str, Any]) -> Tuple[List[str], List[str]]:
|
|
145
145
|
"""Resolve wildcard patterns and explicit repos by enumerating the manifest's
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
partition routers — the same components manifest streams slice on at read
|
|
147
|
+
time, so repo-scoped Python streams see the same repository list.
|
|
148
148
|
|
|
149
149
|
Wildcard patterns (`org/*`, `org/prefix*`) expand via `repositories_resolver`;
|
|
150
150
|
explicit `org/repo` entries validate via `repository_stats`; entries that 404
|
|
@@ -153,6 +153,11 @@ class SourceGithub(YamlDeclarativeSource, AbstractSource):
|
|
|
153
153
|
The resolver streams' `use_cache: true` means this enumeration warms the HTTP
|
|
154
154
|
cache the manifest streams reuse when reading.
|
|
155
155
|
|
|
156
|
+
Organizations come from `organization_resolution_partition_router` — payload-
|
|
157
|
+
confirmed logins only — which is deliberately narrower than the
|
|
158
|
+
`organization_partition_router` the `repositories` stream slices on; see that
|
|
159
|
+
definition's comment in the manifest.
|
|
160
|
+
|
|
156
161
|
Returns (organizations, repositories), both sorted and deduplicated.
|
|
157
162
|
"""
|
|
158
163
|
try:
|
|
@@ -175,15 +180,15 @@ class SourceGithub(YamlDeclarativeSource, AbstractSource):
|
|
|
175
180
|
return sorted({stream_slice.partition[partition_key] for stream_slice in router.stream_slices()})
|
|
176
181
|
|
|
177
182
|
repositories = enumerate_router("repository_partition_router", "repository")
|
|
178
|
-
#
|
|
179
|
-
#
|
|
180
|
-
#
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
+
# `organization_resolution_partition_router`, not `organization_partition_router`: a
|
|
184
|
+
# login that config only *claims* is an org must never reach the org-scoped streams.
|
|
185
|
+
# Config-derived orgs put a user login on `Organizations`, `Teams` and `Users`, where
|
|
186
|
+
# `orgs/{user}` 404s on every request. The `in repository_owners` filter is a backstop:
|
|
187
|
+
# an org owning no resolved repository has nothing to sync.
|
|
183
188
|
repository_owners = {repository.split("/", 1)[0] for repository in repositories}
|
|
184
189
|
organizations = [
|
|
185
190
|
organization
|
|
186
|
-
for organization in enumerate_router("
|
|
191
|
+
for organization in enumerate_router("organization_resolution_partition_router", "organization")
|
|
187
192
|
if organization in repository_owners
|
|
188
193
|
]
|
|
189
194
|
return organizations, repositories
|
|
@@ -213,11 +213,34 @@ class GithubStreamABC(HttpStream, ABC):
|
|
|
213
213
|
raise e
|
|
214
214
|
|
|
215
215
|
self.logger.warning(error_msg)
|
|
216
|
+
self._close_slice_after_swallowed_error(stream_slice)
|
|
216
217
|
# Exhausting every token no longer raises a connector-specific exception here: the
|
|
217
218
|
# shared authenticator raises AirbyteTracedException(transient_error) itself, which the
|
|
218
219
|
# `except AirbyteTracedException` branch above re-raises untouched (it carries no
|
|
219
220
|
# response to classify).
|
|
220
221
|
|
|
222
|
+
def _close_slice_after_swallowed_error(self, stream_slice: Optional[Mapping[str, Any]]) -> None:
|
|
223
|
+
"""Mark the slice complete when `read_records` skipped it instead of raising.
|
|
224
|
+
|
|
225
|
+
`HttpStream._read_pages` closes a resumable-full-refresh slice only after the last
|
|
226
|
+
page, so an error swallowed mid-slice leaves the partition's cursor state empty and
|
|
227
|
+
`CursorBasedCheckpointReader._find_next_slice` hands the same partition back forever
|
|
228
|
+
— no record, no STATE, and the platform kills the attempt on the source heartbeat.
|
|
229
|
+
Closing the slice makes a swallowed error terminal, as the warning above implies.
|
|
230
|
+
"""
|
|
231
|
+
cursor = self.get_cursor()
|
|
232
|
+
if not isinstance(cursor, SubstreamResumableFullRefreshCursor):
|
|
233
|
+
return
|
|
234
|
+
# Only close a partition the slice actually names. Several substreams read their parent
|
|
235
|
+
# by calling its `read_records` straight from `stream_slices()` with a bare mapping that
|
|
236
|
+
# has no `partition` key (`TeamMembers`, `IssueTimelineEvents`, `utils.read_full_refresh`,
|
|
237
|
+
# ...), and those parents are shared instances that emit their own STATE later — closing
|
|
238
|
+
# `_extract_slice_fields`' `{}` fallback would put a meaningless entry in it.
|
|
239
|
+
partition = (stream_slice or {}).get("partition")
|
|
240
|
+
if not partition:
|
|
241
|
+
return
|
|
242
|
+
cursor.close_slice(StreamSlice(cursor_slice={}, partition=partition))
|
|
243
|
+
|
|
221
244
|
|
|
222
245
|
class GithubStream(GithubStreamABC):
|
|
223
246
|
def __init__(self, repositories: List[str], page_size_for_large_streams: int, **kwargs):
|
|
@@ -1876,9 +1899,7 @@ class ContributorActivity(GithubStream):
|
|
|
1876
1899
|
# In order to retain the existing stream behavior before we added RFR to this stream, we need to close out the
|
|
1877
1900
|
# partition after we give up the maximum number of retries on the 202 response. This does lead to the question
|
|
1878
1901
|
# of if we should prematurely exit in the first place, but for now we're going to aim for feature parity
|
|
1879
|
-
|
|
1880
|
-
if self.cursor and partition_obj:
|
|
1881
|
-
self.cursor.close_slice(StreamSlice(cursor_slice={}, partition=partition_obj))
|
|
1902
|
+
self._close_slice_after_swallowed_error(stream_slice)
|
|
1882
1903
|
else:
|
|
1883
1904
|
raise e
|
|
1884
1905
|
else:
|
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/backoff_strategies.py
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/config_migrations.py
RENAMED
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/errors_handlers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/assignees.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/branches.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/collaborators.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/comments.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/commits.json
RENAMED
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/deployments.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/events.json
RENAMED
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/issue_events.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/issue_labels.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/issues.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/organizations.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/project_cards.json
RENAMED
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/projects.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/projects_v2.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/pull_requests.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/releases.json
RENAMED
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/reviews.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/shared/user.json
RENAMED
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/stargazers.json
RENAMED
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/team_members.json
RENAMED
|
File without changes
|
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/teams.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/users.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/workflow_jobs.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/workflow_runs.json
RENAMED
|
File without changes
|
{airbyte_source_github-2.2.1 → airbyte_source_github-2.2.3}/source_github/schemas/workflows.json
RENAMED
|
File without changes
|
|
File without changes
|