airbyte-internal-ops 0.9.1__py3-none-any.whl → 0.10.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: airbyte-internal-ops
3
- Version: 0.9.1
3
+ Version: 0.10.0
4
4
  Summary: MCP and API interfaces that let the agents do the admin work
5
5
  Author-email: Aaron Steers <aj@airbyte.io>
6
6
  Keywords: admin,airbyte,api,mcp
@@ -220,6 +220,7 @@ airbyte_ops_mcp/airbyte_repo/__init__.py,sha256=3yEpCOop1h33UuCtU7-1UB3kun2Qsxtg
220
220
  airbyte_ops_mcp/airbyte_repo/bump_version.py,sha256=rtXYv105BhElj7twQmy20VjNsj6vCb0Ulrzmc4Z-1cE,15384
221
221
  airbyte_ops_mcp/airbyte_repo/changelog_fix.py,sha256=sT94FkH5YuPc_NZCoMr9IUydcD4CO-i5ifGm8FOuI9g,13890
222
222
  airbyte_ops_mcp/airbyte_repo/list_connectors.py,sha256=UI4RKMfFWOXHBtvh7TIw1v0BnV4rQQGuUgh8e9yvpos,19907
223
+ airbyte_ops_mcp/airbyte_repo/progressive_rollout.py,sha256=axBXWDCxfho5hOHIjbnQKWQNrDJR4kKuOdVQwJoqTTs,9459
223
224
  airbyte_ops_mcp/airbyte_repo/utils.py,sha256=TXlOAfhiu_hVRNjCxB4PRPVDhTWCU5lYmgqz4QG_-EA,3201
224
225
  airbyte_ops_mcp/cli/__init__.py,sha256=XpL7FyVfgabfBF2JR7u7NwJ2krlYqjd_OwLcWf-Xc7s,114
225
226
  airbyte_ops_mcp/cli/_base.py,sha256=I8tWnyQf0ks4r3J8N8h-5GZxyn37T-55KsbuHnxYlcg,415
@@ -227,13 +228,13 @@ airbyte_ops_mcp/cli/_shared.py,sha256=jg-xMyGzTCGPqKd8VTfE_3kGPIyO_3Kx5sQbG4rPc0
227
228
  airbyte_ops_mcp/cli/app.py,sha256=xxlyJzlFvZuy-qKAhTPPmzj-t0o7MSqQ7aPHonfT1vU,790
228
229
  airbyte_ops_mcp/cli/cloud.py,sha256=jac0FcG3UvNNeNNhqZR04uY9BCyVvins1kjO0LRZ86Y,45861
229
230
  airbyte_ops_mcp/cli/gh.py,sha256=koJPu0MDB6AW7mJq2z4dZV65ofvsZTkqoeitGF8KJR8,5364
230
- airbyte_ops_mcp/cli/local.py,sha256=kJe3rO6AWdXyjvrlcyP5MC_wIGu9cm1DaCNuO2gxkhU,40806
231
+ airbyte_ops_mcp/cli/local.py,sha256=amxtJ7aY1nrOs36zuWkV7jZVMyHNLT7HDUvyyOXF8mM,44459
231
232
  airbyte_ops_mcp/cli/registry.py,sha256=CVm15_6YWpLD99DZ8f8y68npXJw01Ckde7Ty3o89YNE,16631
232
233
  airbyte_ops_mcp/cloud_admin/__init__.py,sha256=cqE96Q10Kp6elhH9DAi6TVsIwSUy3sooDLLrxTaktGk,816
233
- airbyte_ops_mcp/cloud_admin/api_client.py,sha256=pzdnZpIxOaXJsF_vQuw9_goiDbqwgEQxFwZwsoupY40,57459
234
+ airbyte_ops_mcp/cloud_admin/api_client.py,sha256=2DNYx-GXOTCuP9-rEkZFTM8MIR3MDnXSaqs_z1DsTwQ,70361
234
235
  airbyte_ops_mcp/cloud_admin/auth.py,sha256=qE2Aqe0qbZB755KscL65s54Jz78-F-X5a8fXKsrYEOQ,3749
235
236
  airbyte_ops_mcp/cloud_admin/connection_config.py,sha256=9opGQer-cGMJANmm-LFLMwvMCNu3nzxa2n2XHkZj9Fw,4899
236
- airbyte_ops_mcp/cloud_admin/models.py,sha256=yldPAL9Lce83U3JN-f6qPc2X5LPnLCYqgnXrM1DRq98,4799
237
+ airbyte_ops_mcp/cloud_admin/models.py,sha256=Wn6O48Yp2QB3jsknmw-mG-LJ6GdBIyAg06MGLC1kOjM,8299
237
238
  airbyte_ops_mcp/connection_config_retriever/__init__.py,sha256=Xoi-YvARrNPhECdpwEDDkdwEpnvj8zuUlwULpf4iRrU,800
238
239
  airbyte_ops_mcp/connection_config_retriever/audit_logging.py,sha256=QdOG9984NXeMaKeJnFUZ4oCOmqi37PBRG2NRBBjrZQQ,2753
239
240
  airbyte_ops_mcp/connection_config_retriever/retrieval.py,sha256=s6yeCyrboWkUd6KdaheEo87x-rLtQNTL8XeR8O9z2HI,12160
@@ -268,21 +269,22 @@ airbyte_ops_mcp/mcp/_guidance.py,sha256=n0dLggQXNi2PKZ0eFDqQx5YIjhQpMnI3xcjouub9
268
269
  airbyte_ops_mcp/mcp/cloud_connector_versions.py,sha256=dRKrgsRGadQieTSvBrc5HYI6TTDzVAT6-4tiOHNcDHU,36244
269
270
  airbyte_ops_mcp/mcp/connector_analysis.py,sha256=OC4KrOSkMkKPkOisWnSv96BDDE5TQYHq-Jxa2vtjJpo,298
270
271
  airbyte_ops_mcp/mcp/connector_qa.py,sha256=aImpqdnqBPDrz10BS0owsV4kuIU2XdalzgbaGZsbOL0,258
272
+ airbyte_ops_mcp/mcp/connector_rollout.py,sha256=KYQhRCcpJCquhX_aGNjhT9WKT5lqDpNKNA1Wki-7zPU,29020
271
273
  airbyte_ops_mcp/mcp/gcp_logs.py,sha256=QCDQHmsxQHJ26BB0sxkBgKXr7Ja9wVFkdpY6423H-xo,2677
272
274
  airbyte_ops_mcp/mcp/github_actions.py,sha256=G0NmjNVWpVtLXdQnhX7qJwPFkfEX5gBXf55xt0FpJJ0,11752
273
275
  airbyte_ops_mcp/mcp/github_repo_ops.py,sha256=YHeuN7Xc_L3xkJ-F3l1t1TIPW2j2CjecBDbb0DUvZO8,5306
274
276
  airbyte_ops_mcp/mcp/metadata.py,sha256=fwGW97WknR5lfKcQnFtK6dU87aA6TmLj1NkKyqDAV9g,270
275
277
  airbyte_ops_mcp/mcp/prerelease.py,sha256=jSrAwk95vZLfwYFn5Menb-ziAMTUZnzAMHIJAitd9x8,9553
276
- airbyte_ops_mcp/mcp/prod_db_queries.py,sha256=EdZyrccrM5tHKEtjks4598hzbZ62FuDCCHTjjFT4Wt0,47545
278
+ airbyte_ops_mcp/mcp/prod_db_queries.py,sha256=iesP8H2hCmkdjsmLgYOrwqNQeQwbcScQc4tr4cfs8es,56334
277
279
  airbyte_ops_mcp/mcp/prompts.py,sha256=v4bguskw7hSsISkseACzKQm5QwrIXmiwbs27oclXTE8,1591
278
280
  airbyte_ops_mcp/mcp/registry.py,sha256=PW-VYUj42qx2pQ_apUkVaoUFq7VgB9zEU7-aGrkSCCw,290
279
281
  airbyte_ops_mcp/mcp/regression_tests.py,sha256=zwdQ-ymUhWtVcIjwiNIZAC151GKhuxi55HDi4S91RnI,17046
280
- airbyte_ops_mcp/mcp/server.py,sha256=ID7wZIds8e-qcGAhsaK0vTJDQQ4YNSdYKTQGQWL3Evw,7280
282
+ airbyte_ops_mcp/mcp/server.py,sha256=7VO-awh4gh51EiYCkUvEyQd4r1gl6XRJ4-I-JybkEiA,7405
281
283
  airbyte_ops_mcp/prod_db_access/__init__.py,sha256=5pxouMPY1beyWlB0UwPnbaLTKTHqU6X82rbbgKY2vYU,1069
282
284
  airbyte_ops_mcp/prod_db_access/db_engine.py,sha256=VUqEWZtharJUR-Cri_pMwtGh1C4Neu4s195mbEXlm-w,9190
283
285
  airbyte_ops_mcp/prod_db_access/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
284
- airbyte_ops_mcp/prod_db_access/queries.py,sha256=PyZ0HU-E6jDhSgQ94XRz4wzh61vCr0ACxfMoGjeTKUU,22312
285
- airbyte_ops_mcp/prod_db_access/sql.py,sha256=E7HQratZC5LbCXdvpQzZRd09SmCVnY_4Ru-HluWaQ_c,38308
286
+ airbyte_ops_mcp/prod_db_access/queries.py,sha256=OMnIejwVoQSaTV1It1btzui6Zmrvihh3d6KNZgyyE7I,27741
287
+ airbyte_ops_mcp/prod_db_access/sql.py,sha256=J89eGlrG_0NPtpAuVVKTBS9tG3LKGj0DK-zTGUEzvFA,49526
286
288
  airbyte_ops_mcp/registry/__init__.py,sha256=iEaPlt9GrnlaLbc__98TguNeZG8wuQu7S-_2QkhHcbA,858
287
289
  airbyte_ops_mcp/registry/_gcs_util.py,sha256=3dL7iqpyoSPfl2nGBPp73TqrqGWI4Ks6egKpQXDnw24,2838
288
290
  airbyte_ops_mcp/registry/connector_stubs.py,sha256=pBzaQIOgCfBvHuy3_N45amU9Do2ALDpU8q5HnZySPTQ,5807
@@ -308,7 +310,7 @@ airbyte_ops_mcp/regression_tests/regression/comparators.py,sha256=MJkLZEKHivgrG0
308
310
  airbyte_ops_mcp/regression_tests/validation/__init__.py,sha256=MBEwGOoNuqT4_oCahtoK62OKWIjUCfWa7vZTxNj_0Ek,1532
309
311
  airbyte_ops_mcp/regression_tests/validation/catalog_validators.py,sha256=jqqVAMOk0mtdPgwu4d0hA0ZEjtsNh5gapvGydRv3_qk,12553
310
312
  airbyte_ops_mcp/regression_tests/validation/record_validators.py,sha256=RjauAhKWNwxMBTu0eNS2hMFNQVs5CLbQU51kp6FOVDk,7432
311
- airbyte_internal_ops-0.9.1.dist-info/METADATA,sha256=_EJMWK1bcz3g2o27Zo1c3uHqCDsgwEvzI7QD9hdm1tY,6001
312
- airbyte_internal_ops-0.9.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
313
- airbyte_internal_ops-0.9.1.dist-info/entry_points.txt,sha256=WxP0l7bRFss4Cr5uQqVj9mTEKwnRKouNuphXQF0lotA,171
314
- airbyte_internal_ops-0.9.1.dist-info/RECORD,,
313
+ airbyte_internal_ops-0.10.0.dist-info/METADATA,sha256=eP4lUCpuijAH7aJIkDW4n3mZOIoMqq8nvkF3IU5EqyM,6002
314
+ airbyte_internal_ops-0.10.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
315
+ airbyte_internal_ops-0.10.0.dist-info/entry_points.txt,sha256=WxP0l7bRFss4Cr5uQqVj9mTEKwnRKouNuphXQF0lotA,171
316
+ airbyte_internal_ops-0.10.0.dist-info/RECORD,,
@@ -0,0 +1,279 @@
1
+ # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
2
+ """Progressive rollout setup utilities for Airbyte connectors.
3
+
4
+ This module provides pure Python functionality to configure a connector's
5
+ metadata.yaml for progressive rollout of a release candidate (RC) version.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ from pathlib import Path
12
+
13
+ import semver
14
+ import yaml
15
+
16
+ from airbyte_ops_mcp.airbyte_repo.bump_version import (
17
+ InvalidVersionError,
18
+ get_connector_path,
19
+ get_current_version,
20
+ )
21
+ from airbyte_ops_mcp.airbyte_repo.list_connectors import METADATA_FILE_NAME
22
+
23
+
24
+ @dataclass
25
+ class ProgressiveRolloutSetupResult:
26
+ """Result of a progressive rollout setup operation."""
27
+
28
+ connector: str
29
+ previous_version: str
30
+ rc_version: str
31
+ pin_version: str
32
+ files_modified: list[str]
33
+ dry_run: bool
34
+
35
+
36
+ @dataclass
37
+ class ProgressiveRolloutCleanupResult:
38
+ """Result of a progressive rollout cleanup operation."""
39
+
40
+ connector: str
41
+ previous_version: str
42
+ new_version: str
43
+ files_modified: list[str]
44
+ dry_run: bool
45
+ changes_made: list[str]
46
+
47
+
48
+ def calculate_rc_version(
49
+ current_version: str,
50
+ rc_version: str | None = None,
51
+ ) -> str:
52
+ """Calculate the RC version for progressive rollout.
53
+
54
+ If rc_version is provided, validates and returns it.
55
+ Otherwise, bumps the minor version and adds -rc.1 suffix.
56
+
57
+ Args:
58
+ current_version: Current version string (e.g., "0.0.46")
59
+ rc_version: Explicit RC version (e.g., "0.1.0-rc.1")
60
+
61
+ Returns:
62
+ RC version string
63
+
64
+ Raises:
65
+ InvalidVersionError: If version format is invalid
66
+ """
67
+ if rc_version is not None:
68
+ if not rc_version.endswith("-rc.1") and "-rc." not in rc_version:
69
+ raise InvalidVersionError(
70
+ f"RC version must contain '-rc.' suffix, got: {rc_version}"
71
+ )
72
+ return rc_version
73
+
74
+ try:
75
+ version = semver.Version.parse(current_version)
76
+ except ValueError as e:
77
+ raise InvalidVersionError(
78
+ f"Cannot parse current version: {current_version}"
79
+ ) from e
80
+
81
+ bumped = version.bump_minor()
82
+ return f"{bumped}-rc.1"
83
+
84
+
85
+ def setup_progressive_rollout(
86
+ repo_path: str | Path,
87
+ connector_name: str,
88
+ rc_version: str | None = None,
89
+ pin_version: str | None = None,
90
+ dry_run: bool = False,
91
+ ) -> ProgressiveRolloutSetupResult:
92
+ """Configure a connector's metadata.yaml for progressive rollout.
93
+
94
+ This function modifies metadata.yaml to:
95
+ 1. Set dockerImageTag to the RC version
96
+ 2. Add registryOverrides.cloud.dockerImageTag to pin Cloud users to current version
97
+ 3. Add registryOverrides.oss.dockerImageTag to pin OSS users to current version
98
+ 4. Add releases.rolloutConfiguration.enableProgressiveRollout: true
99
+
100
+ Args:
101
+ repo_path: Path to the Airbyte monorepo
102
+ connector_name: Technical name of the connector (e.g., "source-github")
103
+ rc_version: Explicit RC version (default: bumps minor and adds -rc.1)
104
+ pin_version: Version to pin Cloud/OSS users to (default: current version)
105
+ dry_run: If True, don't actually modify files
106
+
107
+ Returns:
108
+ ProgressiveRolloutSetupResult with details of the operation
109
+
110
+ Raises:
111
+ ConnectorNotFoundError: If connector doesn't exist
112
+ VersionNotFoundError: If current version cannot be found
113
+ InvalidVersionError: If version format is invalid
114
+ """
115
+ repo_path = Path(repo_path)
116
+ connector_path = get_connector_path(repo_path, connector_name)
117
+ metadata_file = connector_path / METADATA_FILE_NAME
118
+
119
+ current_version = get_current_version(connector_path)
120
+ calculated_rc_version = calculate_rc_version(current_version, rc_version)
121
+ calculated_pin_version = pin_version if pin_version else current_version
122
+
123
+ with open(metadata_file) as f:
124
+ metadata = yaml.safe_load(f)
125
+
126
+ data = metadata.get("data", {})
127
+
128
+ data["dockerImageTag"] = calculated_rc_version
129
+
130
+ if "registryOverrides" not in data:
131
+ data["registryOverrides"] = {}
132
+
133
+ if "cloud" not in data["registryOverrides"]:
134
+ data["registryOverrides"]["cloud"] = {}
135
+ data["registryOverrides"]["cloud"]["dockerImageTag"] = calculated_pin_version
136
+
137
+ if "oss" not in data["registryOverrides"]:
138
+ data["registryOverrides"]["oss"] = {}
139
+ data["registryOverrides"]["oss"]["dockerImageTag"] = calculated_pin_version
140
+
141
+ if "releases" not in data:
142
+ data["releases"] = {}
143
+ if "rolloutConfiguration" not in data["releases"]:
144
+ data["releases"]["rolloutConfiguration"] = {}
145
+ data["releases"]["rolloutConfiguration"]["enableProgressiveRollout"] = True
146
+
147
+ metadata["data"] = data
148
+
149
+ files_modified: list[str] = []
150
+
151
+ if not dry_run:
152
+ with open(metadata_file, "w") as f:
153
+ yaml.dump(metadata, f, default_flow_style=False, sort_keys=False)
154
+ files_modified.append(str(metadata_file.relative_to(repo_path)))
155
+ else:
156
+ files_modified.append(str(metadata_file.relative_to(repo_path)))
157
+
158
+ return ProgressiveRolloutSetupResult(
159
+ connector=connector_name,
160
+ previous_version=current_version,
161
+ rc_version=calculated_rc_version,
162
+ pin_version=calculated_pin_version,
163
+ files_modified=files_modified,
164
+ dry_run=dry_run,
165
+ )
166
+
167
+
168
+ def extract_ga_version(rc_version: str) -> str:
169
+ """Extract the GA version from an RC version string.
170
+
171
+ Args:
172
+ rc_version: RC version string (e.g., "1.0.0-rc.1")
173
+
174
+ Returns:
175
+ GA version string (e.g., "1.0.0")
176
+
177
+ Raises:
178
+ InvalidVersionError: If version format is invalid
179
+ """
180
+ if "-rc." in rc_version:
181
+ return rc_version.split("-rc.")[0]
182
+ if "-preview." in rc_version:
183
+ return rc_version.split("-preview.")[0]
184
+ return rc_version
185
+
186
+
187
+ def cleanup_progressive_rollout(
188
+ repo_path: str | Path,
189
+ connector_name: str,
190
+ ga_version: str | None = None,
191
+ dry_run: bool = False,
192
+ ) -> ProgressiveRolloutCleanupResult:
193
+ """Clean up a connector's metadata.yaml after progressive rollout completion.
194
+
195
+ This function reverses the changes made by setup_progressive_rollout:
196
+ 1. Updates dockerImageTag to the GA version (removes -rc.X suffix)
197
+ 2. Removes registryOverrides.cloud.dockerImageTag (if it was a pin)
198
+ 3. Removes registryOverrides.oss.dockerImageTag (if it was a pin)
199
+ 4. Sets releases.rolloutConfiguration.enableProgressiveRollout to false
200
+
201
+ Args:
202
+ repo_path: Path to the Airbyte monorepo
203
+ connector_name: Technical name of the connector (e.g., "source-github")
204
+ ga_version: Explicit GA version (default: extracts from current RC version)
205
+ dry_run: If True, don't actually modify files
206
+
207
+ Returns:
208
+ ProgressiveRolloutCleanupResult with details of the operation
209
+
210
+ Raises:
211
+ ConnectorNotFoundError: If connector doesn't exist
212
+ VersionNotFoundError: If current version cannot be found
213
+ InvalidVersionError: If version format is invalid
214
+ """
215
+ repo_path = Path(repo_path)
216
+ connector_path = get_connector_path(repo_path, connector_name)
217
+ metadata_file = connector_path / METADATA_FILE_NAME
218
+
219
+ current_version = get_current_version(connector_path)
220
+
221
+ new_version = ga_version or extract_ga_version(current_version)
222
+
223
+ with open(metadata_file) as f:
224
+ metadata = yaml.safe_load(f)
225
+
226
+ data = metadata.get("data", {})
227
+ changes_made: list[str] = []
228
+
229
+ if data.get("dockerImageTag") != new_version:
230
+ data["dockerImageTag"] = new_version
231
+ changes_made.append(f"Updated dockerImageTag to {new_version}")
232
+
233
+ registry_overrides = data.get("registryOverrides", {})
234
+ cloud_overrides = registry_overrides.get("cloud", {})
235
+ oss_overrides = registry_overrides.get("oss", {})
236
+
237
+ if "dockerImageTag" in cloud_overrides:
238
+ del cloud_overrides["dockerImageTag"]
239
+ changes_made.append("Removed registryOverrides.cloud.dockerImageTag")
240
+ if not cloud_overrides:
241
+ del registry_overrides["cloud"]
242
+ changes_made.append("Removed empty registryOverrides.cloud section")
243
+
244
+ if "dockerImageTag" in oss_overrides:
245
+ del oss_overrides["dockerImageTag"]
246
+ changes_made.append("Removed registryOverrides.oss.dockerImageTag")
247
+ if not oss_overrides:
248
+ del registry_overrides["oss"]
249
+ changes_made.append("Removed empty registryOverrides.oss section")
250
+
251
+ if not registry_overrides and "registryOverrides" in data:
252
+ del data["registryOverrides"]
253
+ changes_made.append("Removed empty registryOverrides section")
254
+
255
+ releases = data.get("releases", {})
256
+ rollout_config = releases.get("rolloutConfiguration", {})
257
+ if rollout_config.get("enableProgressiveRollout"):
258
+ rollout_config["enableProgressiveRollout"] = False
259
+ changes_made.append("Set enableProgressiveRollout to false")
260
+
261
+ metadata["data"] = data
262
+
263
+ files_modified: list[str] = []
264
+
265
+ if not dry_run:
266
+ with open(metadata_file, "w") as f:
267
+ yaml.dump(metadata, f, default_flow_style=False, sort_keys=False)
268
+ files_modified.append(str(metadata_file.relative_to(repo_path)))
269
+ else:
270
+ files_modified.append(str(metadata_file.relative_to(repo_path)))
271
+
272
+ return ProgressiveRolloutCleanupResult(
273
+ connector=connector_name,
274
+ previous_version=current_version,
275
+ new_version=new_version,
276
+ files_modified=files_modified,
277
+ dry_run=dry_run,
278
+ changes_made=changes_made,
279
+ )
@@ -44,6 +44,10 @@ from airbyte_ops_mcp.airbyte_repo.list_connectors import (
44
44
  _detect_connector_language,
45
45
  get_connectors_with_local_cdk,
46
46
  )
47
+ from airbyte_ops_mcp.airbyte_repo.progressive_rollout import (
48
+ cleanup_progressive_rollout,
49
+ setup_progressive_rollout,
50
+ )
47
51
  from airbyte_ops_mcp.cli._base import app
48
52
  from airbyte_ops_mcp.cli._shared import error_console, exit_with_error, print_json
49
53
  from airbyte_ops_mcp.connector_ops.utils import Connector
@@ -1187,3 +1191,117 @@ def enterprise_stub_sync(
1187
1191
  print_json(
1188
1192
  synced_stubs if all_connectors else synced_stubs[0] if synced_stubs else {}
1189
1193
  )
1194
+
1195
+
1196
+ @connector_app.command(name="setup-progressive-rollout")
1197
+ def setup_progressive_rollout_cmd(
1198
+ name: Annotated[
1199
+ str,
1200
+ Parameter(help="Connector technical name (e.g., source-github)."),
1201
+ ],
1202
+ repo_path: Annotated[
1203
+ str,
1204
+ Parameter(help="Absolute path to the Airbyte monorepo."),
1205
+ ],
1206
+ rc_version: Annotated[
1207
+ str | None,
1208
+ Parameter(
1209
+ help="Explicit RC version (e.g., 1.0.0-rc.1). Default: bumps minor and adds -rc.1."
1210
+ ),
1211
+ ] = None,
1212
+ pin_version: Annotated[
1213
+ str | None,
1214
+ Parameter(help="Version to pin Cloud/OSS users to. Default: current version."),
1215
+ ] = None,
1216
+ dry_run: Annotated[
1217
+ bool,
1218
+ Parameter(help="Show what would be changed without modifying files."),
1219
+ ] = False,
1220
+ ) -> None:
1221
+ """Configure a connector's metadata.yaml for progressive rollout.
1222
+
1223
+ Sets up the connector for progressive rollout by:
1224
+ - Setting dockerImageTag to the RC version
1225
+ - Adding registryOverrides to pin Cloud/OSS users to current stable version
1226
+ - Enabling releases.rolloutConfiguration.enableProgressiveRollout
1227
+ """
1228
+ result = setup_progressive_rollout(
1229
+ repo_path=repo_path,
1230
+ connector_name=name,
1231
+ rc_version=rc_version,
1232
+ pin_version=pin_version,
1233
+ dry_run=dry_run,
1234
+ )
1235
+
1236
+ output = {
1237
+ "connector": result.connector,
1238
+ "previous_version": result.previous_version,
1239
+ "rc_version": result.rc_version,
1240
+ "pin_version": result.pin_version,
1241
+ "files_modified": result.files_modified,
1242
+ "dry_run": result.dry_run,
1243
+ }
1244
+ print_json(output)
1245
+
1246
+ _write_github_step_outputs(
1247
+ {
1248
+ "connector": result.connector,
1249
+ "previous_version": result.previous_version,
1250
+ "rc_version": result.rc_version,
1251
+ }
1252
+ )
1253
+
1254
+
1255
+ @connector_app.command(name="cleanup-progressive-rollout")
1256
+ def cleanup_progressive_rollout_cmd(
1257
+ name: Annotated[
1258
+ str,
1259
+ Parameter(help="Connector technical name (e.g., source-github)."),
1260
+ ],
1261
+ repo_path: Annotated[
1262
+ str,
1263
+ Parameter(help="Absolute path to the Airbyte monorepo."),
1264
+ ],
1265
+ ga_version: Annotated[
1266
+ str | None,
1267
+ Parameter(
1268
+ help="Explicit GA version. Default: extracts from current RC version."
1269
+ ),
1270
+ ] = None,
1271
+ dry_run: Annotated[
1272
+ bool,
1273
+ Parameter(help="Show what would be changed without modifying files."),
1274
+ ] = False,
1275
+ ) -> None:
1276
+ """Clean up a connector's metadata.yaml after progressive rollout completion.
1277
+
1278
+ Reverses the changes made by setup-progressive-rollout:
1279
+ - Updates dockerImageTag to the GA version (removes -rc.X suffix)
1280
+ - Removes registryOverrides.cloud.dockerImageTag
1281
+ - Removes registryOverrides.oss.dockerImageTag
1282
+ - Sets enableProgressiveRollout to false
1283
+ """
1284
+ result = cleanup_progressive_rollout(
1285
+ repo_path=repo_path,
1286
+ connector_name=name,
1287
+ ga_version=ga_version,
1288
+ dry_run=dry_run,
1289
+ )
1290
+
1291
+ output = {
1292
+ "connector": result.connector,
1293
+ "previous_version": result.previous_version,
1294
+ "new_version": result.new_version,
1295
+ "files_modified": result.files_modified,
1296
+ "changes_made": result.changes_made,
1297
+ "dry_run": result.dry_run,
1298
+ }
1299
+ print_json(output)
1300
+
1301
+ _write_github_step_outputs(
1302
+ {
1303
+ "connector": result.connector,
1304
+ "previous_version": result.previous_version,
1305
+ "new_version": result.new_version,
1306
+ }
1307
+ )