airbyte-internal-ops 0.2.2__py3-none-any.whl → 0.2.3__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_internal_ops-0.2.2.dist-info → airbyte_internal_ops-0.2.3.dist-info}/METADATA +1 -1
- {airbyte_internal_ops-0.2.2.dist-info → airbyte_internal_ops-0.2.3.dist-info}/RECORD +7 -7
- airbyte_ops_mcp/cli/registry.py +117 -1
- airbyte_ops_mcp/github_actions.py +45 -0
- airbyte_ops_mcp/mcp/prerelease.py +42 -1
- {airbyte_internal_ops-0.2.2.dist-info → airbyte_internal_ops-0.2.3.dist-info}/WHEEL +0 -0
- {airbyte_internal_ops-0.2.2.dist-info → airbyte_internal_ops-0.2.3.dist-info}/entry_points.txt +0 -0
|
@@ -2,7 +2,7 @@ airbyte_ops_mcp/__init__.py,sha256=tuzdlMkfnWBnsri5KGHM2M_xuNnzFk2u_aR79mmN7Yg,7
|
|
|
2
2
|
airbyte_ops_mcp/_annotations.py,sha256=MO-SBDnbykxxHDESG7d8rviZZ4WlZgJKv0a8eBqcEzQ,1757
|
|
3
3
|
airbyte_ops_mcp/constants.py,sha256=GeZ2_WWluMSrGkyqGvqUVFCy-5PD-lyzZbQ7eO-vyUo,5192
|
|
4
4
|
airbyte_ops_mcp/gcp_auth.py,sha256=5k-k145ZoYhHLjyDES8nrA8f8BBihRI0ykrdD1IcfOs,3599
|
|
5
|
-
airbyte_ops_mcp/github_actions.py,sha256=
|
|
5
|
+
airbyte_ops_mcp/github_actions.py,sha256=wKnuIVmF4u1gMYNdSoryD_PUmvMz5SaHgOvbU0dsolA,9957
|
|
6
6
|
airbyte_ops_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
airbyte_ops_mcp/_legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
airbyte_ops_mcp/_legacy/airbyte_ci/README.md,sha256=qEYx4geDR8AEDjrcA303h7Nol-CMDLojxUyiGzQprM8,236
|
|
@@ -354,7 +354,7 @@ airbyte_ops_mcp/cli/_shared.py,sha256=jg-xMyGzTCGPqKd8VTfE_3kGPIyO_3Kx5sQbG4rPc0
|
|
|
354
354
|
airbyte_ops_mcp/cli/app.py,sha256=SEdBpqFUG2O8zGV5ifwptxrLGFph_dLr66-MX9d69gQ,789
|
|
355
355
|
airbyte_ops_mcp/cli/cloud.py,sha256=JJusGl67ca41rvoS8BPl5Kmb7Kyu7iMH-tvbaJsKsPs,41359
|
|
356
356
|
airbyte_ops_mcp/cli/gh.py,sha256=91b1AxFXvHQCFyXhrrym-756ZjnMCqvxFdmwCtma1zI,2046
|
|
357
|
-
airbyte_ops_mcp/cli/registry.py,sha256
|
|
357
|
+
airbyte_ops_mcp/cli/registry.py,sha256=tcf_CDiUVJpSdBRNqlEL3zFKMqK53AhFpJjAETM4gLs,9781
|
|
358
358
|
airbyte_ops_mcp/cli/repo.py,sha256=G1hoQpH0XYhUH3FFOsia9xabGB0LP9o3XcwBuqvFVo0,16331
|
|
359
359
|
airbyte_ops_mcp/cloud_admin/__init__.py,sha256=cqE96Q10Kp6elhH9DAi6TVsIwSUy3sooDLLrxTaktGk,816
|
|
360
360
|
airbyte_ops_mcp/cloud_admin/api_client.py,sha256=tx1kwGIKMPesibflQkFOlbNp0t0CfJD4Ab097ngsjHA,19126
|
|
@@ -375,7 +375,7 @@ airbyte_ops_mcp/mcp/connector_qa.py,sha256=aImpqdnqBPDrz10BS0owsV4kuIU2XdalzgbaG
|
|
|
375
375
|
airbyte_ops_mcp/mcp/github.py,sha256=h3M3VJrq09y_F9ueQVCq3bUbVBNFuTNKprHtGU_ttio,8045
|
|
376
376
|
airbyte_ops_mcp/mcp/github_repo_ops.py,sha256=PiERpt8abo20Gz4CfXhrDNlVM4o4FOt5sweZJND2a0s,5314
|
|
377
377
|
airbyte_ops_mcp/mcp/metadata.py,sha256=fwGW97WknR5lfKcQnFtK6dU87aA6TmLj1NkKyqDAV9g,270
|
|
378
|
-
airbyte_ops_mcp/mcp/prerelease.py,sha256=
|
|
378
|
+
airbyte_ops_mcp/mcp/prerelease.py,sha256=nc6VU03ADVHWM3OjGKxbS5XqY4VoyRyrZNU_fyAtaOI,10465
|
|
379
379
|
airbyte_ops_mcp/mcp/prod_db_queries.py,sha256=FfGoq3aEj6ZUT4ysBIs1w7LzzwBeRXTaRvPGEx62RzI,25474
|
|
380
380
|
airbyte_ops_mcp/mcp/prompts.py,sha256=mJld9mdPECXYZffWXGSvNs4Xevx3rxqUGNlzGKVC2_s,1599
|
|
381
381
|
airbyte_ops_mcp/mcp/registry.py,sha256=PW-VYUj42qx2pQ_apUkVaoUFq7VgB9zEU7-aGrkSCCw,290
|
|
@@ -410,7 +410,7 @@ airbyte_ops_mcp/regression_tests/regression/comparators.py,sha256=MJkLZEKHivgrG0
|
|
|
410
410
|
airbyte_ops_mcp/regression_tests/validation/__init__.py,sha256=MBEwGOoNuqT4_oCahtoK62OKWIjUCfWa7vZTxNj_0Ek,1532
|
|
411
411
|
airbyte_ops_mcp/regression_tests/validation/catalog_validators.py,sha256=jqqVAMOk0mtdPgwu4d0hA0ZEjtsNh5gapvGydRv3_qk,12553
|
|
412
412
|
airbyte_ops_mcp/regression_tests/validation/record_validators.py,sha256=RjauAhKWNwxMBTu0eNS2hMFNQVs5CLbQU51kp6FOVDk,7432
|
|
413
|
-
airbyte_internal_ops-0.2.
|
|
414
|
-
airbyte_internal_ops-0.2.
|
|
415
|
-
airbyte_internal_ops-0.2.
|
|
416
|
-
airbyte_internal_ops-0.2.
|
|
413
|
+
airbyte_internal_ops-0.2.3.dist-info/METADATA,sha256=c-kIcUr44n9G4r4yImy7oEQuSrLRueORjI4SeW-2ZNI,5679
|
|
414
|
+
airbyte_internal_ops-0.2.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
415
|
+
airbyte_internal_ops-0.2.3.dist-info/entry_points.txt,sha256=WxP0l7bRFss4Cr5uQqVj9mTEKwnRKouNuphXQF0lotA,171
|
|
416
|
+
airbyte_internal_ops-0.2.3.dist-info/RECORD,,
|
airbyte_ops_mcp/cli/registry.py
CHANGED
|
@@ -5,6 +5,7 @@ This module provides CLI wrappers for registry operations. The core logic
|
|
|
5
5
|
lives in the `airbyte_ops_mcp.registry` capability module.
|
|
6
6
|
|
|
7
7
|
Commands:
|
|
8
|
+
airbyte-ops registry connector compute-prerelease-tag - Compute prerelease version tag
|
|
8
9
|
airbyte-ops registry connector publish-prerelease - Publish connector prerelease
|
|
9
10
|
airbyte-ops registry connector publish - Publish connector (apply/rollback version override)
|
|
10
11
|
airbyte-ops registry image inspect - Inspect Docker image on DockerHub
|
|
@@ -12,9 +13,12 @@ Commands:
|
|
|
12
13
|
|
|
13
14
|
from __future__ import annotations
|
|
14
15
|
|
|
16
|
+
import contextlib
|
|
17
|
+
import sys
|
|
15
18
|
from pathlib import Path
|
|
16
19
|
from typing import Annotated
|
|
17
20
|
|
|
21
|
+
import yaml
|
|
18
22
|
from cyclopts import App, Parameter
|
|
19
23
|
|
|
20
24
|
from airbyte_ops_mcp.cli._base import app
|
|
@@ -24,8 +28,15 @@ from airbyte_ops_mcp.cli._shared import (
|
|
|
24
28
|
print_json,
|
|
25
29
|
print_success,
|
|
26
30
|
)
|
|
31
|
+
from airbyte_ops_mcp.github_actions import (
|
|
32
|
+
get_file_contents_at_ref,
|
|
33
|
+
resolve_github_token,
|
|
34
|
+
)
|
|
27
35
|
from airbyte_ops_mcp.mcp.github import get_docker_image_info
|
|
28
|
-
from airbyte_ops_mcp.mcp.prerelease import
|
|
36
|
+
from airbyte_ops_mcp.mcp.prerelease import (
|
|
37
|
+
compute_prerelease_docker_image_tag,
|
|
38
|
+
publish_connector_to_airbyte_registry,
|
|
39
|
+
)
|
|
29
40
|
from airbyte_ops_mcp.registry import (
|
|
30
41
|
ConnectorPublishResult,
|
|
31
42
|
PublishAction,
|
|
@@ -47,6 +58,111 @@ image_app = App(name="image", help="Docker image operations.")
|
|
|
47
58
|
registry_app.command(image_app)
|
|
48
59
|
|
|
49
60
|
|
|
61
|
+
AIRBYTE_REPO_OWNER = "airbytehq"
|
|
62
|
+
AIRBYTE_REPO_NAME = "airbyte"
|
|
63
|
+
CONNECTOR_PATH_PREFIX = "airbyte-integrations/connectors"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _get_connector_version_from_github(
|
|
67
|
+
connector_name: str,
|
|
68
|
+
ref: str,
|
|
69
|
+
token: str | None = None,
|
|
70
|
+
) -> str | None:
|
|
71
|
+
"""Fetch connector version from metadata.yaml via GitHub API.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
connector_name: Connector name (e.g., "source-github")
|
|
75
|
+
ref: Git ref (commit SHA, branch name, or tag)
|
|
76
|
+
token: GitHub API token (optional for public repos)
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Version string from metadata.yaml, or None if not found.
|
|
80
|
+
"""
|
|
81
|
+
path = f"{CONNECTOR_PATH_PREFIX}/{connector_name}/metadata.yaml"
|
|
82
|
+
contents = get_file_contents_at_ref(
|
|
83
|
+
owner=AIRBYTE_REPO_OWNER,
|
|
84
|
+
repo=AIRBYTE_REPO_NAME,
|
|
85
|
+
path=path,
|
|
86
|
+
ref=ref,
|
|
87
|
+
token=token,
|
|
88
|
+
)
|
|
89
|
+
if contents is None:
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
metadata = yaml.safe_load(contents)
|
|
93
|
+
return metadata.get("data", {}).get("dockerImageTag")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@connector_app.command(name="compute-prerelease-tag")
|
|
97
|
+
def compute_prerelease_tag(
|
|
98
|
+
connector_name: Annotated[
|
|
99
|
+
str,
|
|
100
|
+
Parameter(help="Connector name (e.g., 'source-github')."),
|
|
101
|
+
],
|
|
102
|
+
sha: Annotated[
|
|
103
|
+
str,
|
|
104
|
+
Parameter(help="Git commit SHA (full or at least 7 characters)."),
|
|
105
|
+
],
|
|
106
|
+
base_version: Annotated[
|
|
107
|
+
str | None,
|
|
108
|
+
Parameter(
|
|
109
|
+
help="Base version override. If not provided, fetched from metadata.yaml at the given SHA."
|
|
110
|
+
),
|
|
111
|
+
] = None,
|
|
112
|
+
) -> None:
|
|
113
|
+
"""Compute the pre-release docker image tag.
|
|
114
|
+
|
|
115
|
+
Outputs the version tag to stdout for easy capture in shell scripts.
|
|
116
|
+
This is the single source of truth for pre-release version format.
|
|
117
|
+
|
|
118
|
+
The command fetches the connector's metadata.yaml from GitHub at the given SHA
|
|
119
|
+
to determine the base version. It also compares against the master branch and
|
|
120
|
+
prints a warning to stderr if no version bump is detected.
|
|
121
|
+
|
|
122
|
+
If --base-version is provided, it is used directly instead of fetching from GitHub.
|
|
123
|
+
|
|
124
|
+
Example:
|
|
125
|
+
airbyte-ops registry connector compute-prerelease-tag --connector-name source-github --sha abcdef1234567
|
|
126
|
+
# Output: 1.2.3-preview.abcdef1
|
|
127
|
+
|
|
128
|
+
airbyte-ops registry connector compute-prerelease-tag --connector-name source-github --sha abcdef1234567 --base-version 1.2.3
|
|
129
|
+
# Output: 1.2.3-preview.abcdef1 (uses provided version, skips GitHub API)
|
|
130
|
+
"""
|
|
131
|
+
# Try to get a GitHub token (optional, but helps avoid rate limiting)
|
|
132
|
+
# Token resolution may fail if no token is configured, which is fine for public repos
|
|
133
|
+
token: str | None = None
|
|
134
|
+
with contextlib.suppress(ValueError):
|
|
135
|
+
token = resolve_github_token()
|
|
136
|
+
|
|
137
|
+
# Determine base version
|
|
138
|
+
version: str
|
|
139
|
+
if base_version:
|
|
140
|
+
version = base_version
|
|
141
|
+
else:
|
|
142
|
+
# Fetch version from metadata.yaml at the given SHA
|
|
143
|
+
fetched_version = _get_connector_version_from_github(connector_name, sha, token)
|
|
144
|
+
if fetched_version is None:
|
|
145
|
+
print(
|
|
146
|
+
f"Error: Could not fetch metadata.yaml for {connector_name} at ref {sha}",
|
|
147
|
+
file=sys.stderr,
|
|
148
|
+
)
|
|
149
|
+
sys.exit(1)
|
|
150
|
+
version = fetched_version
|
|
151
|
+
|
|
152
|
+
# Compare with master branch version and warn if no bump detected
|
|
153
|
+
master_version = _get_connector_version_from_github(connector_name, "master", token)
|
|
154
|
+
if master_version and master_version == version:
|
|
155
|
+
print(
|
|
156
|
+
f"Warning: No version bump detected for {connector_name}. "
|
|
157
|
+
f"Version {version} matches master branch.",
|
|
158
|
+
file=sys.stderr,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Compute and output the prerelease tag
|
|
162
|
+
tag = compute_prerelease_docker_image_tag(version, sha)
|
|
163
|
+
print(tag)
|
|
164
|
+
|
|
165
|
+
|
|
50
166
|
@connector_app.command(name="publish-prerelease")
|
|
51
167
|
def publish_prerelease(
|
|
52
168
|
connector_name: Annotated[
|
|
@@ -106,6 +106,51 @@ class WorkflowJobInfo:
|
|
|
106
106
|
"""ISO 8601 timestamp when the job completed"""
|
|
107
107
|
|
|
108
108
|
|
|
109
|
+
def get_file_contents_at_ref(
|
|
110
|
+
owner: str,
|
|
111
|
+
repo: str,
|
|
112
|
+
path: str,
|
|
113
|
+
ref: str,
|
|
114
|
+
token: str | None = None,
|
|
115
|
+
) -> str | None:
|
|
116
|
+
"""Fetch file contents from GitHub at a specific ref.
|
|
117
|
+
|
|
118
|
+
Uses the GitHub Contents API to retrieve file contents at a specific
|
|
119
|
+
commit SHA, branch, or tag. This allows reading files without having
|
|
120
|
+
the repository checked out locally.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
owner: Repository owner (e.g., "airbytehq")
|
|
124
|
+
repo: Repository name (e.g., "airbyte")
|
|
125
|
+
path: Path to the file within the repository
|
|
126
|
+
ref: Git ref (commit SHA, branch name, or tag)
|
|
127
|
+
token: GitHub API token (optional for public repos, but recommended
|
|
128
|
+
to avoid rate limiting)
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
File contents as a string, or None if the file doesn't exist.
|
|
132
|
+
|
|
133
|
+
Raises:
|
|
134
|
+
requests.HTTPError: If API request fails (except 404).
|
|
135
|
+
"""
|
|
136
|
+
url = f"{GITHUB_API_BASE}/repos/{owner}/{repo}/contents/{path}"
|
|
137
|
+
headers = {
|
|
138
|
+
"Accept": "application/vnd.github.raw+json",
|
|
139
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
140
|
+
}
|
|
141
|
+
if token:
|
|
142
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
143
|
+
|
|
144
|
+
params = {"ref": ref}
|
|
145
|
+
|
|
146
|
+
response = requests.get(url, headers=headers, params=params, timeout=30)
|
|
147
|
+
if response.status_code == 404:
|
|
148
|
+
return None
|
|
149
|
+
response.raise_for_status()
|
|
150
|
+
|
|
151
|
+
return response.text
|
|
152
|
+
|
|
153
|
+
|
|
109
154
|
def get_workflow_jobs(
|
|
110
155
|
owner: str,
|
|
111
156
|
repo: str,
|
|
@@ -31,6 +31,45 @@ PRERELEASE_TOKEN_ENV_VARS = [
|
|
|
31
31
|
"GITHUB_TOKEN",
|
|
32
32
|
]
|
|
33
33
|
|
|
34
|
+
# =============================================================================
|
|
35
|
+
# Pre-release Version Tag Constants
|
|
36
|
+
# =============================================================================
|
|
37
|
+
|
|
38
|
+
PRERELEASE_TAG_PREFIX = "preview"
|
|
39
|
+
"""The prefix used for pre-release version tags (e.g., '1.2.3-preview.abcde12')."""
|
|
40
|
+
|
|
41
|
+
PRERELEASE_SHA_LENGTH = 7
|
|
42
|
+
"""The number of characters from the git SHA to include in pre-release tags."""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def compute_prerelease_docker_image_tag(base_version: str, sha: str) -> str:
|
|
46
|
+
"""Compute the pre-release docker image tag.
|
|
47
|
+
|
|
48
|
+
This is the SINGLE SOURCE OF TRUTH for pre-release version format.
|
|
49
|
+
All other code should receive this value as a parameter, not recompute it.
|
|
50
|
+
|
|
51
|
+
The format is: {base_version}-preview.{short_sha}
|
|
52
|
+
|
|
53
|
+
Where:
|
|
54
|
+
- base_version: The base version from metadata.yaml (e.g., "1.2.3")
|
|
55
|
+
- short_sha: The first 7 characters of the git commit SHA
|
|
56
|
+
|
|
57
|
+
Examples:
|
|
58
|
+
>>> compute_prerelease_docker_image_tag("1.2.3", "abcdef1234567890")
|
|
59
|
+
'1.2.3-preview.abcdef1'
|
|
60
|
+
>>> compute_prerelease_docker_image_tag("0.1.0", "1234567")
|
|
61
|
+
'0.1.0-preview.1234567'
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
base_version: The base version from metadata.yaml (e.g., "1.2.3")
|
|
65
|
+
sha: The full git commit SHA (or at least 7 characters)
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Pre-release version tag (e.g., "1.2.3-preview.abcde12")
|
|
69
|
+
"""
|
|
70
|
+
short_sha = sha[:PRERELEASE_SHA_LENGTH]
|
|
71
|
+
return f"{base_version}-{PRERELEASE_TAG_PREFIX}.{short_sha}"
|
|
72
|
+
|
|
34
73
|
|
|
35
74
|
class PRHeadInfo(BaseModel):
|
|
36
75
|
"""Information about a PR's head commit."""
|
|
@@ -268,7 +307,9 @@ def publish_connector_to_airbyte_registry(
|
|
|
268
307
|
docker_image = data.get("dockerRepository")
|
|
269
308
|
base_version = data.get("dockerImageTag")
|
|
270
309
|
if base_version:
|
|
271
|
-
docker_image_tag =
|
|
310
|
+
docker_image_tag = compute_prerelease_docker_image_tag(
|
|
311
|
+
base_version, head_info.sha
|
|
312
|
+
)
|
|
272
313
|
|
|
273
314
|
return PrereleaseWorkflowResult(
|
|
274
315
|
success=True,
|
|
File without changes
|
{airbyte_internal_ops-0.2.2.dist-info → airbyte_internal_ops-0.2.3.dist-info}/entry_points.txt
RENAMED
|
File without changes
|