Skip to content

Commit 427e8fd

Browse files
authored
feat(airbyte-ci): include components.py in manifest-only build (#44879)
1 parent 095d30e commit 427e8fd

File tree

11 files changed

+76
-7
lines changed

11 files changed

+76
-7
lines changed

airbyte-ci/connectors/connector_ops/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ poetry run pytest
3737
```
3838

3939
## Changelog
40+
- 0.9.0: Add components path attribute for manifest-only connectors.
4041
- 0.8.1: Gradle dependency discovery logic supports the Bulk CDK.
4142
- 0.8.0: Add a `sbom_url` property to `Connector`
4243
- 0.7.0: Added required reviewers for manifest-only connector changes/additions.

airbyte-ci/connectors/connector_ops/connector_ops/utils.py

+6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def download_catalog(catalog_url):
6060

6161
OSS_CATALOG = download_catalog(OSS_CATALOG_URL)
6262
MANIFEST_FILE_NAME = "manifest.yaml"
63+
COMPONENTS_FILE_NAME = "components.py"
6364
DOCKERFILE_FILE_NAME = "Dockerfile"
6465
PYPROJECT_FILE_NAME = "pyproject.toml"
6566
ICON_FILE_NAME = "icon.svg"
@@ -347,6 +348,11 @@ def manifest_path(self) -> Path:
347348

348349
return self._manifest_low_code_path
349350

351+
@property
352+
def manifest_only_components_path(self) -> Path:
353+
"""Return the path to the components.py file of a manifest-only connector."""
354+
return self.code_directory / COMPONENTS_FILE_NAME
355+
350356
@property
351357
def has_dockerfile(self) -> bool:
352358
return self.dockerfile_file_path.is_file()

airbyte-ci/connectors/connector_ops/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "connector_ops"
7-
version = "0.8.1"
7+
version = "0.9.0"
88
description = "Packaged maintained by the connector operations team to perform CI for connectors"
99
authors = ["Airbyte <[email protected]>"]
1010

airbyte-ci/connectors/connector_ops/tests/test_required_reviewer_checks.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def mock_diffed_branched(mocker):
2323

2424
@pytest.fixture
2525
def pokeapi_metadata_path():
26-
return "airbyte-integrations/connectors/source-pokeapi/metadata.yaml"
26+
return "airbyte-integrations/connectors/source-zoho-crm/metadata.yaml"
2727

2828

2929
@pytest.fixture
@@ -37,7 +37,7 @@ def not_tracked_change_expected_team(tmp_path, pokeapi_metadata_path):
3737
backup_path = tmp_path / "non_strategic_acceptance_test_config.backup"
3838
shutil.copyfile(pokeapi_metadata_path, backup_path)
3939
with open(pokeapi_metadata_path, "a") as metadata_file:
40-
metadata_file.write("not_tracked")
40+
metadata_file.write("\nnot_tracked: true\n")
4141
yield expected_teams
4242
shutil.copyfile(backup_path, pokeapi_metadata_path)
4343

airbyte-ci/connectors/pipelines/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,7 @@ airbyte-ci connectors --language=low-code migrate-to-manifest-only
843843

844844
| Version | PR | Description |
845845
| ------- | ---------------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------|
846+
| 4.35.0 | [#44879](https://github.com/airbytehq/airbyte/pull/44879) | Mount `components.py` when building manifest-only connector image |
846847
| 4.34.2 | [#44786](https://github.com/airbytehq/airbyte/pull/44786) | Pre-emptively skip archived connectors when searching for modified files |
847848
| 4.34.1 | [#44557](https://github.com/airbytehq/airbyte/pull/44557) | Conditionally propagate parameters in manifest-only migration |
848849
| 4.34.0 | [#44551](https://github.com/airbytehq/airbyte/pull/44551) | `connectors publish` do not push the `latest` tag when the current version is a release candidate. |

airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/build_image/steps/manifest_only_connectors.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from pipelines.airbyte_ci.connectors.build_image.steps import build_customization
1010
from pipelines.airbyte_ci.connectors.build_image.steps.common import BuildConnectorImagesBase
1111
from pipelines.airbyte_ci.connectors.context import ConnectorContext
12-
from pipelines.consts import MANIFEST_FILE_PATH
12+
from pipelines.consts import COMPONENTS_FILE_PATH, MANIFEST_FILE_PATH
1313
from pipelines.models.steps import StepResult
1414
from pydash.objects import get # type: ignore
1515

@@ -43,11 +43,20 @@ async def _build_from_base_image(self, platform: Platform) -> Container:
4343
"""
4444
self.logger.info(f"Building connector from base image in metadata for {platform}")
4545

46+
# Mount manifest file
4647
base_container = self._get_base_container(platform).with_file(
4748
f"source_declarative_manifest/{MANIFEST_FILE_PATH}",
4849
(await self.context.get_connector_dir(include=[MANIFEST_FILE_PATH])).file(MANIFEST_FILE_PATH),
4950
)
5051

52+
# Mount components file if it exists
53+
components_file = self.context.connector.manifest_only_components_path
54+
if components_file.exists():
55+
base_container = base_container.with_file(
56+
f"source_declarative_manifest/{COMPONENTS_FILE_PATH}",
57+
(await self.context.get_connector_dir(include=[COMPONENTS_FILE_PATH])).file(COMPONENTS_FILE_PATH),
58+
)
59+
5160
connector_container = build_customization.apply_airbyte_entrypoint(base_container, self.context.connector)
5261
return connector_container
5362

airbyte-ci/connectors/pipelines/pipelines/consts.py

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
PYPROJECT_TOML_FILE_PATH = "pyproject.toml"
1212
MANIFEST_FILE_PATH = "manifest.yaml"
13+
COMPONENTS_FILE_PATH = "components.py"
1314
LICENSE_SHORT_FILE_PATH = "LICENSE_SHORT"
1415
CONNECTOR_TESTING_REQUIREMENTS = [
1516
"pip==21.3.1",

airbyte-ci/connectors/pipelines/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "pipelines"
7-
version = "4.34.2"
7+
version = "4.35.0"
88
description = "Packaged maintained by the connector operations team to perform CI for connectors' pipelines"
99
authors = ["Airbyte <[email protected]>"]
1010

airbyte-ci/connectors/pipelines/tests/test_build_image/test_manifest_only_connectors.py

+48
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,22 @@ def test_context_with_connector_with_base_image(self, test_context):
3535
}
3636
return test_context
3737

38+
@pytest.fixture
39+
def mock_connector_directory(self, mocker):
40+
mock_components_file = mocker.Mock()
41+
mock_connector_dir = mocker.Mock()
42+
mock_connector_dir.file.return_value = mock_components_file
43+
return mock_connector_dir, mock_components_file
44+
45+
def _assert_file_not_handled(self, container_mock, file_path):
46+
"""Assert that a specified file_path was not handled by the container_mock"""
47+
assert not any(file_path in call.args[0] for call in container_mock.with_file.call_args_list)
48+
3849
async def test__run_using_base_image_with_mocks(self, mocker, test_context_with_connector_with_base_image, all_platforms):
3950
container_built_from_base = mock_container()
4051
container_built_from_base.with_label.return_value = container_built_from_base
4152

53+
mocker.patch.object(Path, "exists", return_value=True) # Mock Path.exists() to always return True
4254
mocker.patch.object(
4355
manifest_only_connectors.BuildConnectorImages,
4456
"_build_from_base_image",
@@ -59,3 +71,39 @@ async def test__run_using_base_image_with_mocks(self, mocker, test_context_with_
5971
assert step_result.status is StepStatus.SUCCESS
6072
for platform in all_platforms:
6173
assert step_result.output[platform] == container_built_from_base
74+
75+
@pytest.mark.parametrize("components_file_exists", [True, False])
76+
async def test__run_using_base_image_with_components_file(
77+
self, mocker, all_platforms, test_context_with_connector_with_base_image, mock_connector_directory, components_file_exists
78+
):
79+
mock_connector_dir, mock_components_file = mock_connector_directory
80+
container_built_from_base = mock_container()
81+
82+
container_built_from_base.with_label.return_value = container_built_from_base
83+
container_built_from_base.with_file.return_value = container_built_from_base
84+
85+
test_context_with_connector_with_base_image.get_connector_dir = mocker.AsyncMock(return_value=mock_connector_dir)
86+
test_context_with_connector_with_base_image.connector.manifest_only_components_path.exists = mocker.Mock(
87+
return_value=components_file_exists
88+
)
89+
90+
mocker.patch.object(
91+
manifest_only_connectors.BuildConnectorImages,
92+
"_get_base_container",
93+
return_value=container_built_from_base,
94+
)
95+
96+
mocker.patch.object(
97+
build_customization,
98+
"apply_airbyte_entrypoint",
99+
return_value=container_built_from_base,
100+
)
101+
102+
step = manifest_only_connectors.BuildConnectorImages(test_context_with_connector_with_base_image)
103+
104+
await step._build_connector(all_platforms[0], container_built_from_base)
105+
if components_file_exists:
106+
container_built_from_base.with_file.assert_any_call("source_declarative_manifest/components.py", mock_components_file)
107+
mock_connector_dir.file.assert_any_call("components.py")
108+
else:
109+
self._assert_file_not_handled(container_built_from_base, "source_declarative_manifest/components.py")

airbyte-ci/connectors/pipelines/tests/test_helpers/test_utils.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ async def test_check_path_in_workdir(dagger_client):
183183
.with_workdir(str(connector.code_directory))
184184
)
185185
assert await utils.check_path_in_workdir(container, "metadata.yaml")
186-
assert await utils.check_path_in_workdir(container, "pyproject.toml")
187-
assert await utils.check_path_in_workdir(container, "poetry.lock")
186+
assert await utils.check_path_in_workdir(container, "manifest.yaml")
188187
assert await utils.check_path_in_workdir(container, "not_existing_file") is False
189188

190189

airbyte-ci/connectors/pipelines/tests/utils.py

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ def with_label(self, *args, **kwargs):
1919
async def with_exec(self, *args, **kwargs):
2020
return self
2121

22+
def with_file(self, *args, **kwargs):
23+
return self
24+
2225

2326
def pick_a_random_connector(
2427
language: ConnectorLanguage = None,
@@ -55,4 +58,5 @@ def mock_container():
5558
container_mock = AsyncMock(MockContainerClass)
5659
container_mock.with_label.return_value = container_mock
5760
container_mock.with_exec.return_value = container_mock
61+
container_mock.with_file.return_value = container_mock
5862
return container_mock

0 commit comments

Comments
 (0)