Skip to content

feat(connectors-qa): support manifest-only connectors #43377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 8, 2024
4 changes: 4 additions & 0 deletions airbyte-ci/connectors/connectors_qa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ poe lint

## Changelog

### 1.6.0

Added `manifest-only` connectors support — they will run basic assets and metadata checks.

### 1.5.1

Bumped dependencies.
Expand Down
2 changes: 1 addition & 1 deletion airbyte-ci/connectors/connectors_qa/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "connectors-qa"
version = "1.5.1"
version = "1.6.0"
description = "A package to run QA checks on Airbyte connectors, generate reports and documentation."
authors = ["Airbyte <[email protected]>"]
readme = "README.md"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.

from __future__ import annotations

import os
from datetime import datetime, timedelta
Expand Down Expand Up @@ -40,8 +40,11 @@ class CheckConnectorLanguageTag(MetadataCheck):

PYTHON_LANGUAGE_TAG = "language:python"
JAVA_LANGUAGE_TAG = "language:java"
MANIFEST_ONLY_LANGUAGE_TAG = "language:manifest-only"

def get_expected_language_tag(self, connector: Connector) -> str:
if (connector.code_directory / "manifest.yaml").exists():
return self.MANIFEST_ONLY_LANGUAGE_TAG
if (connector.code_directory / consts.SETUP_PY_FILE_NAME).exists() or (
connector.code_directory / consts.PYPROJECT_FILE_NAME
).exists():
Expand Down Expand Up @@ -145,7 +148,6 @@ class ValidateBreakingChangesDeadlines(MetadataCheck):
minimum_days_until_deadline = 7

def _run(self, connector: Connector) -> CheckResult:

# fetch the current branch version of the connector first.
# we'll try and see if there are any breaking changes associated
# with it next.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.

from __future__ import annotations

import semver
import toml
Expand Down Expand Up @@ -63,6 +63,24 @@ def _run(self, connector: Connector) -> CheckResult:
return self.create_check_result(connector=connector, passed=True, message="PyPi publishing is enabled")


class CheckManifestOnlyConnectorBaseImage(PackagingCheck):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@natikgadzhi I think we need to add an instance of this class to the ENABLED_CHECKS list at the bottom of this file for it to run?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BREH you're right.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One other check we could add here is that there are none of the python boilerplate files in this connector directory (e.g. source.py, run.py, etc).

But if we want to add that, that can come in a separate PR. Doesn't need to block this

name = "Manifest-only connectors must use `source-declarative-manifest` as their base image"
description = "Manifest-only connectors must use `airbyte/source-declarative-manifest` as their base image."
applies_to_connector_languages = [ConnectorLanguage.MANIFEST_ONLY]

def _run(self, connector: Connector) -> CheckResult:
base_image = get(connector.metadata, "connectorBuildOptions.baseImage")
base_image_name = base_image.split(":")[0] if base_image else None

if base_image_name != "docker.io/airbyte/source-declarative-manifest":
return self.create_check_result(
connector=connector,
passed=False,
message=f"A manifest-only connector must use `source-declarative-manifest` base image. Replace the base image in {consts.METADATA_FILE_NAME} file",
)
return self.create_check_result(connector=connector, passed=True, message="Connector uses source-declarative-manifest base image")


class CheckConnectorLicense(PackagingCheck):
name = "Connectors must be licensed under MIT or Elv2"
description = f"Connectors must be licensed under the MIT or Elv2 license. This is to ensure that all connectors are licensed under a permissive license. More details in our [License FAQ]({consts.LICENSE_FAQ_URL})."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class CheckConnectorUsesPythonBaseImage(SecurityCheck):
applies_to_connector_languages = [
ConnectorLanguage.PYTHON,
ConnectorLanguage.LOW_CODE,
ConnectorLanguage.MANIFEST_ONLY,
]

def _run(self, connector: Connector) -> CheckResult:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
LOW_CODE_MANIFEST_FILE_NAME = "manifest.yaml"
METADATA_DOCUMENTATION_URL = "https://docs.airbyte.com/connector-development/connector-metadata-file"
METADATA_FILE_NAME = "metadata.yaml"
MANIFEST_FILE_NAME = "manifest.yaml"
POETRY_LOCK_FILE_NAME = "poetry.lock"
PYPROJECT_FILE_NAME = "pyproject.toml"
SEMVER_FOR_CONNECTORS_DOC_URL = "https://docs.airbyte.com/contributing-to-airbyte/#semantic-versioning-for-connectors"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
ConnectorLanguage.JAVA,
ConnectorLanguage.LOW_CODE,
ConnectorLanguage.PYTHON,
ConnectorLanguage.MANIFEST_ONLY,
]

ALL_TYPES = ["source", "destination"]
Expand Down Expand Up @@ -62,7 +63,6 @@ def __repr__(self) -> str:


class Check(ABC):

requires_metadata: bool = True
runs_on_released_connectors: bool = True

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
from __future__ import annotations

import os

Expand All @@ -9,7 +10,6 @@


class TestValidateMetadata:

def test_fail_when_deserialization_fails(self, mocker, tmp_path):
# Arrange
mocker.patch.object(metadata, "validate_and_load", return_value=(None, "error"))
Expand Down Expand Up @@ -38,6 +38,19 @@ def test_pass_when_metadata_file_is_valid(self, mocker, tmp_path):
assert result.status == CheckStatus.PASSED
assert result.message == "Metadata file valid."

def test_checks_apply_to_manifest_only_connectors(self, mocker, tmp_path):
# Arrange
connector = mocker.MagicMock(metadata={"tags": ["language:manifest-only"]}, code_directory=tmp_path)
code_directory = tmp_path
(code_directory / consts.MANIFEST_FILE_NAME).touch()

# Act
result = metadata.CheckConnectorLanguageTag()._run(connector)

# Assert
assert result.status == CheckStatus.PASSED
assert result.message == "Language tag language:manifest-only is present in the metadata file"


class TestCheckConnectorLanguageTag:
def test_fail_when_no_language_tags(self, mocker):
Expand Down Expand Up @@ -118,7 +131,6 @@ def test_pass_when_java(self, mocker, tmp_path):


class TestCheckConnectorCDKTag:

def test_fail_when_no_cdk_tags(self, mocker):
# Arrange
connector = mocker.MagicMock(metadata={"tags": []})
Expand Down Expand Up @@ -160,7 +172,7 @@ def test_fail_when_python_tag_on_low_code_connector(self, mocker, tmp_path):
connector = mocker.MagicMock(technical_name="source-test", metadata={"tags": ["cdk:python"]}, code_directory=tmp_path)
code_directory = tmp_path
(code_directory / "source_test").mkdir()
(code_directory / "source_test"/ consts.LOW_CODE_MANIFEST_FILE_NAME).touch()
(code_directory / "source_test" / consts.LOW_CODE_MANIFEST_FILE_NAME).touch()

# Act
result = metadata.CheckConnectorCDKTag()._run(connector)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
from __future__ import annotations

from connectors_qa import consts
from connectors_qa.checks import packaging
Expand Down Expand Up @@ -57,6 +58,47 @@ def test_pass_when_poetry_is_used(self, tmp_path, mocker):
assert result.message == "Poetry is used for dependency management"


class TestCheckManifestOnlyConnectorBaseImage:
def test_pass_with_source_declarative_manifest(self, mocker, tmp_path):
connector = mocker.MagicMock(
code_directory=tmp_path,
metadata={"connectorBuildOptions": {"baseImage": "docker.io/airbyte/source-declarative-manifest:4.3.0@SHA"}},
)

# Act
result = packaging.CheckManifestOnlyConnectorBaseImage()._run(connector)

# Assert
assert result.status == CheckStatus.PASSED
assert "Connector uses source-declarative-manifest base image" in result.message

def test_fail_with_different_image(self, mocker, tmp_path):
connector = mocker.MagicMock(
code_directory=tmp_path,
metadata={"connectorBuildOptions": {"baseImage": "docker.io/airbyte/connector-base-image:2.0.0@SHA"}},
)

# Act
result = packaging.CheckManifestOnlyConnectorBaseImage()._run(connector)

# Assert
assert result.status == CheckStatus.FAILED
assert "A manifest-only connector must use `source-declarative-manifest` base image" in result.message

def test_fail_with_missing_image(self, mocker, tmp_path):
connector = mocker.MagicMock(
code_directory=tmp_path,
metadata={"connectorBuildOptions": {}},
)

# Act
result = packaging.CheckManifestOnlyConnectorBaseImage()._run(connector)

# Assert
assert result.status == CheckStatus.FAILED
assert "A manifest-only connector must use `source-declarative-manifest` base image" in result.message


class TestCheckPublishToPyPiIsEnabled:
def test_fail_if_publish_to_pypi_is_not_enabled(self, mocker):
# Arrange
Expand Down
26 changes: 13 additions & 13 deletions docs/contributing-to-airbyte/resources/qa-checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ They are by no mean replacing the need for a manual review of the connector code
### Breaking changes must be accompanied by a migration guide

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -21,7 +21,7 @@ This document should contain a section for each breaking change, in order of the
### Connectors must have user facing documentation

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -30,7 +30,7 @@ The user facing connector documentation should be stored under `./docs/integrati
### Connectors must have a changelog entry for each version

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -41,7 +41,7 @@ Each new version of a connector must have a changelog entry defined in the user
### Connectors must have valid metadata.yaml file

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -50,7 +50,7 @@ Connectors must have a `metadata.yaml` file at the root of their directory. This
### Connector must have a language tag in metadata

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -68,7 +68,7 @@ Python connectors must have a CDK tag in their metadata. It must be set in the `
### Breaking change deadline should be a week in the future

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -77,7 +77,7 @@ If the connector version has a breaking change, the deadline field must be set t
### Certified source connector must have a value filled out for maxSecondsBetweenMessages in metadata

_Applies to the following connector types: source_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with certified support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -97,7 +97,7 @@ Connectors must use [Poetry](https://python-poetry.org/) for dependency manageme
### Connectors must be licensed under MIT or Elv2

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -115,7 +115,7 @@ Connectors license in metadata.yaml and pyproject.toml file must match. This is
### Connector version must follow Semantic Versioning

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand Down Expand Up @@ -144,7 +144,7 @@ Python connectors must have [PyPi](https://pypi.org/) publishing enabled in thei
### Connectors must have an icon

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -155,7 +155,7 @@ Each connector must have an icon available in at the root of the connector code
### Connectors must use HTTPS only

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -164,7 +164,7 @@ Connectors must use HTTPS only when making requests to external services.
### Python connectors must not use a Dockerfile and must declare their base image in metadata.yaml file

_Applies to the following connector types: source, destination_
_Applies to the following connector languages: python, low-code_
_Applies to the following connector languages: python, low-code, manifest-only_
_Applies to connector with any support level_
_Applies to connector with any Airbyte usage level_

Expand All @@ -176,7 +176,7 @@ This is to ensure that all connectors use a base image which is maintained and h
### Medium to High Use Connectors must enable acceptance tests

_Applies to the following connector types: source_
_Applies to the following connector languages: java, low-code, python_
_Applies to the following connector languages: java, low-code, python, manifest-only_
_Applies to connector with any support level_
_Applies to connector with medium, high Airbyte usage level_

Expand Down
Loading