Skip to content

Commit

Permalink
airbyte-ci: use connectors-qa instead of connector_ops.qa_check (#35325)
Browse files Browse the repository at this point in the history
  • Loading branch information
alafanechere authored Feb 19, 2024
1 parent 87d792e commit 9525793
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 275 deletions.
3 changes: 2 additions & 1 deletion airbyte-ci/connectors/pipelines/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,8 @@ E.G.: running Poe tasks on the modified internal packages of the current branch:

| Version | PR | Description |
| ------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| 4.2.3 | [#35322](https://github.com/airbytehq/airbyte/pull/35322) | Declare `connectors_qa` as an internal package for testing. |
| 4.2.4 | [#35325](https://github.com/airbytehq/airbyte/pull/35325) | Use `connectors_qa` for QA checks and remove redundant checks. |
| 4.2.3 | [#35322](https://github.com/airbytehq/airbyte/pull/35322) | Declare `connectors_qa` as an internal package for testing. |
| 4.2.2 | [#35364](https://github.com/airbytehq/airbyte/pull/35364) | Fix connector tests following gradle changes in #35307. |
| 4.2.1 | [#35204](https://github.com/airbytehq/airbyte/pull/35204) | Run `poetry check` before `poetry install` on poetry package install. |
| 4.2.0 | [#35103](https://github.com/airbytehq/airbyte/pull/35103) | Java 21 support. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
from pipelines.airbyte_ci.connectors.build_image import steps
from pipelines.airbyte_ci.connectors.publish.context import PublishConnectorContext
from pipelines.airbyte_ci.connectors.reports import ConnectorReport
from pipelines.airbyte_ci.metadata.pipeline import MetadataUpload, MetadataValidation
from pipelines.airbyte_ci.connectors.test.steps.common import QaChecks
from pipelines.airbyte_ci.metadata.pipeline import MetadataUpload
from pipelines.airbyte_ci.steps.python_registry import PublishToPythonRegistry, PythonRegistryPublishContext
from pipelines.dagger.actions.remote_storage import upload_to_gcs
from pipelines.dagger.actions.system import docker
Expand Down Expand Up @@ -273,11 +274,11 @@ def create_connector_report(results: List[StepResult]) -> ConnectorReport:

results = []

metadata_validation_results = await MetadataValidation(context).run()
results.append(metadata_validation_results)
qa_check_results = await QaChecks(context).run()
results.append(qa_check_results)

# Exit early if the metadata file is invalid.
if metadata_validation_results.status is not StepStatus.SUCCESS:
# Exit early if the qa checks do not pass
if qa_check_results.status is not StepStatus.SUCCESS:
return create_connector_report(results)

check_connector_image_results = await CheckConnectorImageDoesNotExist(context).run()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
from pipelines.airbyte_ci.connectors.context import ConnectorContext
from pipelines.airbyte_ci.connectors.reports import ConnectorReport
from pipelines.airbyte_ci.connectors.test.steps import java_connectors, python_connectors
from pipelines.airbyte_ci.connectors.test.steps.common import QaChecks, VersionFollowsSemverCheck, VersionIncrementCheck
from pipelines.airbyte_ci.metadata.pipeline import MetadataValidation
from pipelines.airbyte_ci.connectors.test.steps.common import QaChecks, VersionIncrementCheck
from pipelines.helpers.execution.run_steps import StepToRun, run_steps

if TYPE_CHECKING:
Expand Down Expand Up @@ -57,8 +56,6 @@ async def run_connector_test_pipeline(context: ConnectorContext, semaphore: anyi
if not context.code_tests_only:
static_analysis_steps_to_run = [
[
StepToRun(id=CONNECTOR_TEST_STEP_ID.METADATA_VALIDATION, step=MetadataValidation(context)),
StepToRun(id=CONNECTOR_TEST_STEP_ID.VERSION_FOLLOW_CHECK, step=VersionFollowsSemverCheck(context)),
StepToRun(id=CONNECTOR_TEST_STEP_ID.VERSION_INC_CHECK, step=VersionIncrementCheck(context)),
StepToRun(id=CONNECTOR_TEST_STEP_ID.QA_CHECKS, step=QaChecks(context)),
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,19 @@
import os
from abc import ABC, abstractmethod
from functools import cached_property
from typing import Any, ClassVar, List, Optional
from typing import ClassVar, List, Optional

import requests # type: ignore
import semver
import yaml # type: ignore
from connector_ops.utils import Connector # type: ignore
from dagger import Container, Directory
from pipelines import hacks
from pipelines.airbyte_ci.connectors.context import ConnectorContext
from pipelines.consts import CIContext
from pipelines.airbyte_ci.steps.docker import SimpleDockerStep
from pipelines.consts import INTERNAL_TOOL_PATHS, CIContext
from pipelines.dagger.actions import secrets
from pipelines.dagger.containers import internal_tools
from pipelines.helpers.utils import METADATA_FILE_NAME
from pipelines.models.steps import STEP_PARAMS, Step, StepResult, StepStatus
from pipelines.models.steps import STEP_PARAMS, MountPath, Step, StepResult, StepStatus


class VersionCheck(Step, ABC):
Expand Down Expand Up @@ -119,71 +118,37 @@ def validate(self) -> StepResult:
return self.success_result


class VersionFollowsSemverCheck(VersionCheck):
context: ConnectorContext
title = "Connector version semver check"

@property
def failure_message(self) -> str:
return f"The dockerImageTag in {METADATA_FILE_NAME} is not following semantic versioning or was decremented. Master version is {self.master_connector_version}, current version is {self.current_connector_version}"

def validate(self) -> StepResult:
try:
if not self.current_connector_version >= self.master_connector_version:
return self.failure_result
except ValueError:
return self.failure_result
return self.success_result


class QaChecks(Step):
"""A step to run QA checks for a connector."""

context: ConnectorContext
title = "QA checks"

async def _run(self) -> StepResult:
"""Run QA checks on a connector.
The QA checks are defined in this module:
https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connector_ops/connector_ops/qa_checks.py
Args:
context (ConnectorContext): The current test context, providing a connector object, a dagger client and a repository directory.
Returns:
StepResult: Failure or success of the QA checks with stdout and stderr.
"""
connector_ops = await internal_tools.with_connector_ops(self.context)
include = [
str(self.context.connector.code_directory),
str(self.context.connector.documentation_file_path),
str(self.context.connector.migration_guide_file_path),
str(self.context.connector.icon_path),
]
if (
self.context.connector.technical_name.endswith("strict-encrypt")
or self.context.connector.technical_name == "source-file-secure"
):
original_connector = Connector(self.context.connector.technical_name.replace("-strict-encrypt", "").replace("-secure", ""))
include += [
str(original_connector.code_directory),
str(original_connector.documentation_file_path),
str(original_connector.icon_path),
str(original_connector.migration_guide_file_path),
]

filtered_repo = self.context.get_repo_dir(
include=include,
class QaChecks(SimpleDockerStep):
"""A step to run QA checks for a connectors.
More details in https://github.com/airbytehq/airbyte/blob/main/airbyte-ci/connectors/connectors_qa/README.md
"""

def __init__(self, context: ConnectorContext) -> None:
super().__init__(
title=f"Run QA checks for {context.connector.technical_name}",
context=context,
paths_to_mount=[
MountPath(context.connector.code_directory),
# These paths are optional
# But their absence might make the QA check fail
MountPath(context.connector.documentation_file_path, optional=True),
MountPath(context.connector.migration_guide_file_path, optional=True),
MountPath(context.connector.icon_path, optional=True),
],
internal_tools=[
MountPath(INTERNAL_TOOL_PATHS.CONNECTORS_QA.value),
],
secrets={
k: v
for k, v in {
"DOCKER_HUB_USERNAME": context.docker_hub_username_secret,
"DOCKER_HUB_PASSWORD": context.docker_hub_password_secret,
}.items()
if v
},
command=["connectors-qa", "run", f"--name={context.connector.technical_name}"],
)

qa_checks = (
connector_ops.with_mounted_directory("/airbyte", filtered_repo)
.with_workdir("/airbyte")
.with_exec(["run-qa-checks", f"connectors/{self.context.connector.technical_name}"])
)

return await self.get_step_result(qa_checks)


class AcceptanceTests(Step):
"""A step to run acceptance tests for a connector if it has an acceptance test config file."""
Expand Down Expand Up @@ -318,58 +283,3 @@ async def _build_connector_acceptance_test(self, connector_under_test_container:
)

return cat_container.with_unix_socket("/var/run/docker.sock", self.context.dagger_client.host().unix_socket("/var/run/docker.sock"))


class CheckBaseImageIsUsed(Step):
context: ConnectorContext
title = "Check our base image is used"

async def _run(self, *args: Any, **kwargs: Any) -> StepResult:
is_certified = self.context.connector.metadata.get("supportLevel") == "certified"
if not is_certified:
return self.skip("Connector is not certified, it does not require the use of our base image.")

is_using_base_image = self.context.connector.metadata.get("connectorBuildOptions", {}).get("baseImage") is not None
migration_hint = f"Please run 'airbyte-ci connectors --name={self.context.connector.technical_name} migrate_to_base_image <PR NUMBER>' and commit the changes."
if not is_using_base_image:
return StepResult(
step=self,
status=StepStatus.FAILURE,
stdout=f"Connector is certified but does not use our base image. {migration_hint}",
)
has_dockerfile = "Dockerfile" in await (await self.context.get_connector_dir(include=["Dockerfile"])).entries()
if has_dockerfile:
return StepResult(
step=self,
status=StepStatus.FAILURE,
stdout=f"Connector is certified but is still using a Dockerfile. {migration_hint}",
)
return StepResult(step=self, status=StepStatus.SUCCESS, stdout="Connector is certified and uses our base image.")


class CheckPythonRegistryPublishConfiguration(Step):
context: ConnectorContext
title = "Check connector is published to python registry if it's a certified python connector"

async def _run(self, *args: Any, **kwargs: Any) -> StepResult:
is_python_registry_published = self.context.connector.metadata.get("remoteRegistries", {}).get("pypi", {}).get("enabled", False)
if is_python_registry_published:
return StepResult(step=self, status=StepStatus.SUCCESS, stdout="Connector is published to PyPI.")

tags = self.context.connector.metadata.get("tags", [])
is_python_registry_compatible = ("language:python" in tags or "language:low-code" in tags) and "language:java" not in tags
is_certified = self.context.connector.metadata.get("supportLevel") == "certified"
is_source = self.context.connector.metadata.get("connectorType") == "source"
if not is_source or not is_certified or not is_python_registry_compatible:
return self.skip(
"Connector is not a certified python source connector, it does not require to be published to python registry."
)

migration_hint = "Check the airbyte-ci readme under https://github.com/airbytehq/airbyte/tree/master/airbyte-ci/connectors/pipelines#python-registry-publishing for how to configure publishing."
if not is_python_registry_published:
return StepResult(
step=self,
status=StepStatus.FAILURE,
stdout=f"Connector is a certified python source but publication to PyPI is not enabled. {migration_hint}",
)
return StepResult(step=self, status=StepStatus.SUCCESS, stdout="Connector is a certified python source and is published to PyPI.")
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from pipelines.airbyte_ci.connectors.build_image.steps.python_connectors import BuildConnectorImages
from pipelines.airbyte_ci.connectors.consts import CONNECTOR_TEST_STEP_ID
from pipelines.airbyte_ci.connectors.context import ConnectorContext
from pipelines.airbyte_ci.connectors.test.steps.common import AcceptanceTests, CheckBaseImageIsUsed, CheckPythonRegistryPublishConfiguration
from pipelines.airbyte_ci.connectors.test.steps.common import AcceptanceTests
from pipelines.consts import LOCAL_BUILD_PLATFORM
from pipelines.dagger.actions import secrets
from pipelines.dagger.actions.python.poetry import with_poetry
Expand Down Expand Up @@ -278,12 +278,5 @@ def get_test_steps(context: ConnectorContext) -> STEP_TREE:
},
depends_on=[CONNECTOR_TEST_STEP_ID.BUILD],
),
StepToRun(
id=CONNECTOR_TEST_STEP_ID.CHECK_BASE_IMAGE, step=CheckBaseImageIsUsed(context), depends_on=[CONNECTOR_TEST_STEP_ID.BUILD]
),
StepToRun(
id=CONNECTOR_TEST_STEP_ID.CHECK_PYTHON_REGISTRY_PUBLISH_CONFIGURATION,
step=CheckPythonRegistryPublishConfiguration(context),
),
],
]
1 change: 1 addition & 0 deletions airbyte-ci/connectors/pipelines/pipelines/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class ContextState(Enum):
class INTERNAL_TOOL_PATHS(str, Enum):
CI_CREDENTIALS = "airbyte-ci/connectors/ci_credentials"
CONNECTOR_OPS = "airbyte-ci/connectors/connector_ops"
CONNECTORS_QA = "airbyte-ci/connectors/connectors_qa"
METADATA_SERVICE = "airbyte-ci/connectors/metadata_service/lib"


Expand Down
2 changes: 1 addition & 1 deletion airbyte-ci/connectors/pipelines/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "pipelines"
version = "4.2.3"
version = "4.2.4"
description = "Packaged maintained by the connector operations team to perform CI for connectors' pipelines"
authors = ["Airbyte <contact@airbyte.io>"]

Expand Down
Loading

0 comments on commit 9525793

Please sign in to comment.