Skip to content

Commit 2690638

Browse files
committed
make QA checks tolerate connector without dockerfile
1 parent b608d76 commit 2690638

File tree

5 files changed

+67
-66
lines changed

5 files changed

+67
-66
lines changed

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

+10-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import sys
77
from pathlib import Path
8-
from typing import Iterable, Optional, Set, Tuple
8+
from typing import Callable, Iterable, Optional, Set, Tuple
99

1010
from connector_ops.utils import Connector
1111
from pydash.objects import get
@@ -238,7 +238,7 @@ def check_metadata_version_matches_dockerfile_label(connector: Connector) -> boo
238238
return connector.version_in_dockerfile_label == connector.version
239239

240240

241-
QA_CHECKS = [
241+
DEFAULT_QA_CHECKS = (
242242
check_documentation_file_exists,
243243
check_migration_guide,
244244
# Disabling the following check because it's likely to not pass on a lot of connectors.
@@ -250,8 +250,13 @@ def check_metadata_version_matches_dockerfile_label(connector: Connector) -> boo
250250
# https://github.com/airbytehq/airbyte/issues/21606
251251
check_connector_https_url_only,
252252
check_connector_has_no_critical_vulnerabilities,
253-
check_metadata_version_matches_dockerfile_label,
254-
]
253+
)
254+
255+
256+
def get_qa_checks_to_run(connector: Connector) -> Tuple[Callable]:
257+
if connector.has_dockerfile:
258+
return DEFAULT_QA_CHECKS + (check_metadata_version_matches_dockerfile_label,)
259+
return DEFAULT_QA_CHECKS
255260

256261

257262
def remove_strict_encrypt_suffix(connector_technical_name: str) -> str:
@@ -285,7 +290,7 @@ def run_qa_checks():
285290
connector_technical_name = remove_strict_encrypt_suffix(connector_technical_name)
286291
connector = Connector(connector_technical_name)
287292
print(f"Running QA checks for {connector_technical_name}:{connector.version}")
288-
qa_check_results = {qa_check.__name__: qa_check(connector) for qa_check in QA_CHECKS}
293+
qa_check_results = {qa_check.__name__: qa_check(connector) for qa_check in get_qa_checks_to_run(connector)}
289294
if not all(qa_check_results.values()):
290295
print(f"QA checks failed for {connector_technical_name}:{connector.version}:")
291296
for check_name, check_result in qa_check_results.items():

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

+10-8
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ def icon_path(self) -> Path:
236236
def code_directory(self) -> Path:
237237
return Path(f"./airbyte-integrations/connectors/{self.technical_name}")
238238

239+
@property
240+
def has_dockerfile(self) -> bool:
241+
return (self.code_directory / "Dockerfile").is_file()
242+
239243
@property
240244
def metadata_file_path(self) -> Path:
241245
return self.code_directory / METADATA_FILE_NAME
@@ -253,22 +257,20 @@ def language(self) -> ConnectorLanguage:
253257
return ConnectorLanguage.LOW_CODE
254258
if Path(self.code_directory / "setup.py").is_file():
255259
return ConnectorLanguage.PYTHON
256-
try:
257-
with open(self.code_directory / "Dockerfile") as dockerfile:
258-
if "FROM airbyte/integration-base-java" in dockerfile.read():
259-
return ConnectorLanguage.JAVA
260-
except FileNotFoundError:
261-
pass
260+
if Path(self.code_directory / "build.gradle").is_file():
261+
return ConnectorLanguage.JAVA
262262
return None
263263

264264
@property
265-
def version(self) -> str:
265+
def version(self) -> Optional[str]:
266266
if self.metadata is None:
267267
return self.version_in_dockerfile_label
268268
return self.metadata["dockerImageTag"]
269269

270270
@property
271-
def version_in_dockerfile_label(self) -> str:
271+
def version_in_dockerfile_label(self) -> Optional[str]:
272+
if not self.has_dockerfile:
273+
return None
272274
with open(self.code_directory / "Dockerfile") as f:
273275
for line in f:
274276
if "io.airbyte.version" in line:

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.2.3"
7+
version = "0.2.4"
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_qa_checks.py

+26-4
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def test_run_qa_checks_success(capsys, mocker, user_input, expect_qa_checks_to_r
8080
mocker.patch.object(qa_checks, "Connector")
8181
mock_qa_check = mocker.Mock(return_value=True, __name__="mock_qa_check")
8282
if expect_qa_checks_to_run:
83-
mocker.patch.object(qa_checks, "QA_CHECKS", [mock_qa_check])
83+
mocker.patch.object(qa_checks, "get_qa_checks_to_run", return_value=[mock_qa_check])
8484
with pytest.raises(SystemExit) as wrapped_error:
8585
qa_checks.run_qa_checks()
8686
assert wrapped_error.value.code == 0
@@ -101,7 +101,7 @@ def test_run_qa_checks_error(capsys, mocker):
101101
mocker.patch.object(qa_checks.sys, "argv", ["", "source-faker"])
102102
mocker.patch.object(qa_checks, "Connector")
103103
mock_qa_check = mocker.Mock(return_value=False, __name__="mock_qa_check")
104-
mocker.patch.object(qa_checks, "QA_CHECKS", [mock_qa_check])
104+
mocker.patch.object(qa_checks, "DEFAULT_QA_CHECKS", (mock_qa_check,))
105105
with pytest.raises(SystemExit) as wrapped_error:
106106
qa_checks.run_qa_checks()
107107
assert wrapped_error.value.code == 1
@@ -201,7 +201,7 @@ def test_check_missing_migration_guide(mocker, tmp_path, capsys):
201201
}
202202
mocker.patch.object(qa_checks.Connector, "metadata", mock_metadata_dict)
203203

204-
assert qa_checks.check_migration_guide(connector) == False
204+
assert qa_checks.check_migration_guide(connector) is False
205205
stdout, _ = capsys.readouterr()
206206
assert "Migration guide file is missing for foobar. Please create a foobar-migrations.md file in the docs folder" in stdout
207207

@@ -241,6 +241,28 @@ def test_check_invalid_migration_guides(mocker, tmp_path, capsys, test_file, exp
241241

242242
mocker.patch.object(qa_checks.Connector, "metadata", mock_metadata_dict)
243243

244-
assert qa_checks.check_migration_guide(connector) == False
244+
assert qa_checks.check_migration_guide(connector) is False
245245
stdout, _ = capsys.readouterr()
246246
assert expected_stdout in stdout
247+
248+
249+
def test_get_qa_checks_to_run(mocker):
250+
mocker.patch.object(utils.Connector, "has_dockerfile", False)
251+
connector = utils.Connector("source-faker")
252+
253+
assert (
254+
qa_checks.get_qa_checks_to_run(connector) == qa_checks.DEFAULT_QA_CHECKS
255+
), "A connector without a Dockerfile should run the default set of QA checks"
256+
mocker.patch.object(utils.Connector, "has_dockerfile", True)
257+
connector = utils.Connector("source-faker")
258+
assert qa_checks.get_qa_checks_to_run(connector) == qa_checks.DEFAULT_QA_CHECKS + (
259+
qa_checks.check_metadata_version_matches_dockerfile_label,
260+
), "A connector with a Dockerfile should run the default set of QA checks plus check_metadata_version_matches_dockerfile_label"
261+
262+
263+
def test_check_metadata_version_matches_dockerfile_label_without_dockerfile(mocker):
264+
mocker.patch.object(utils.Connector, "has_dockerfile", False)
265+
connector_without_dockerfile = utils.Connector("source-faker")
266+
assert (
267+
qa_checks.check_metadata_version_matches_dockerfile_label(connector_without_dockerfile) is False
268+
), "A connector without a Dockerfile should fail check_metadata_version_matches_dockerfile_label"

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

+20-48
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ def test_init(self, connector, exists, mocker, tmp_path):
5151
assert connector.support_level is None
5252
assert connector.acceptance_test_config is None
5353
assert connector.icon_path == Path(f"./airbyte-integrations/connectors/{connector.technical_name}/icon.svg")
54-
with pytest.raises(FileNotFoundError):
55-
connector.version
54+
assert connector.version is None
5655
with pytest.raises(utils.ConnectorVersionNotFound):
5756
Path(tmp_path / "Dockerfile").touch()
5857
mocker.patch.object(utils.Connector, "code_directory", tmp_path)
@@ -73,6 +72,25 @@ def test_metadata_query_match(self, mocker):
7372
assert not connector.metadata_query_match("data.ab_internal.ql > 101")
7473
assert not connector.metadata_query_match("data.ab_internal == whatever")
7574

75+
@pytest.fixture
76+
def connector_without_dockerfile(self, mocker, tmp_path):
77+
mocker.patch.object(utils.Connector, "code_directory", tmp_path)
78+
connector = utils.Connector("source-faker")
79+
return connector
80+
81+
def test_has_dockerfile_without_dockerfile(self, connector_without_dockerfile):
82+
assert not connector_without_dockerfile.has_dockerfile
83+
84+
@pytest.fixture
85+
def connector_with_dockerfile(self, mocker, tmp_path):
86+
mocker.patch.object(utils.Connector, "code_directory", tmp_path)
87+
connector = utils.Connector("source-faker")
88+
tmp_path.joinpath("Dockerfile").touch()
89+
return connector
90+
91+
def test_has_dockerfile_with_dockerfile(self, connector_with_dockerfile):
92+
assert connector_with_dockerfile.has_dockerfile
93+
7694

7795
@pytest.fixture()
7896
def gradle_file_with_dependencies(tmpdir) -> Path:
@@ -105,49 +123,3 @@ def test_parse_dependencies(gradle_file_with_dependencies):
105123
assert all([regular_dependency in expected_regular_dependencies for regular_dependency in regular_dependencies])
106124
assert len(test_dependencies) == len(expected_test_dependencies)
107125
assert all([test_dependency in expected_test_dependencies for test_dependency in test_dependencies])
108-
109-
110-
@pytest.mark.parametrize("with_test_dependencies", [True, False])
111-
def test_get_all_gradle_dependencies(with_test_dependencies):
112-
build_file = Path("airbyte-integrations/connectors/source-postgres-strict-encrypt/build.gradle")
113-
if with_test_dependencies:
114-
all_dependencies = utils.get_all_gradle_dependencies(build_file)
115-
expected_dependencies = [
116-
Path("airbyte-cdk/java/airbyte-cdk"),
117-
Path("airbyte-db/db-lib"),
118-
Path("airbyte-json-validation"),
119-
Path("airbyte-config-oss/config-models-oss"),
120-
Path("airbyte-commons"),
121-
Path("airbyte-test-utils"),
122-
Path("airbyte-api"),
123-
Path("airbyte-connector-test-harnesses/acceptance-test-harness"),
124-
Path("airbyte-commons-protocol"),
125-
Path("airbyte-integrations/bases/base-java"),
126-
Path("airbyte-commons-cli"),
127-
Path("airbyte-integrations/bases/base"),
128-
Path("airbyte-integrations/connectors/source-postgres"),
129-
Path("airbyte-integrations/bases/debezium"),
130-
Path("airbyte-integrations/connectors/source-jdbc"),
131-
Path("airbyte-integrations/connectors/source-relational-db"),
132-
Path("airbyte-integrations/bases/standard-source-test"),
133-
]
134-
assert len(all_dependencies) == len(expected_dependencies)
135-
assert all([dependency in expected_dependencies for dependency in all_dependencies])
136-
else:
137-
all_dependencies = utils.get_all_gradle_dependencies(build_file, with_test_dependencies=False)
138-
expected_dependencies = [
139-
Path("airbyte-cdk/java/airbyte-cdk"),
140-
Path("airbyte-db/db-lib"),
141-
Path("airbyte-json-validation"),
142-
Path("airbyte-config-oss/config-models-oss"),
143-
Path("airbyte-commons"),
144-
Path("airbyte-integrations/bases/base-java"),
145-
Path("airbyte-commons-cli"),
146-
Path("airbyte-integrations/bases/base"),
147-
Path("airbyte-integrations/connectors/source-postgres"),
148-
Path("airbyte-integrations/bases/debezium"),
149-
Path("airbyte-integrations/connectors/source-jdbc"),
150-
Path("airbyte-integrations/connectors/source-relational-db"),
151-
]
152-
assert len(all_dependencies) == len(expected_dependencies)
153-
assert all([dependency in expected_dependencies for dependency in all_dependencies])

0 commit comments

Comments
 (0)