-
Notifications
You must be signed in to change notification settings - Fork 32
feat: add airbyte-cdk CLI with support for: connector test, secrets fetch and --version
#493
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
Changes from all commits
Commits
Show all changes
102 commits
Select commit
Hold shift + click to select a range
3de3edf
add skeleton implementation, imported from airbyte-pytest
aaronsteers 3b88490
tidy imports
aaronsteers 1250472
fix some imports
aaronsteers 9dec6e3
Merge branch 'main' into aj/feat/mini-cat-test-suites
aaronsteers 11d89f6
working test of tests
aaronsteers 42d8a4e
remove old file
aaronsteers c8e7722
misc fixes
aaronsteers 6248994
allow subclasses of abstractsource
aaronsteers a0f8ed5
Merge remote-tracking branch 'origin/main' into aj/feat/mini-cat-test…
aaronsteers fcfe697
fix test handling for expected errors
aaronsteers 03f3360
Auto-fix lint and format issues
460c40a
remove unused code
aaronsteers 8918bfe
fix tests
aaronsteers 83344f3
use pep440 style dynamic versioning
aaronsteers 76a92a9
update ci job (temporarily run on all pushes)
aaronsteers e6911e5
Merge remote-tracking branch 'origin/main' into aj/feat/mini-cat-test…
aaronsteers 039eef0
Merge remote-tracking branch 'origin/main' into aj/feat/mini-cat-test…
aaronsteers 5658441
Update .github/workflows/pypi_publish.yml
aaronsteers 310ea68
fix fixture resource paths
aaronsteers 1e74eef
lint fixes
aaronsteers c9ad3bd
fix imports
aaronsteers f8b581e
fix lint issues
aaronsteers 4a05f46
fix lint and typing
aaronsteers e58dfad
[cherry-pick-me][chore]: resolve pytest warnings undeclared marks, an…
aaronsteers 418dcb9
fix relative path logic
aaronsteers 8d75d0d
ruff fix
aaronsteers c3a32ae
[cherry-pick-me][fix]: dataclasses constructor break with __test__ me…
aaronsteers 0897b83
fix paths
aaronsteers b282e5d
[cherry-pick-me]: use kw args
aaronsteers 9a8b5eb
Merge branch 'main' into aj/feat/mini-cat-test-suites
aaronsteers d5aaf3c
[cherry-pick-me]: kw args
aaronsteers 7a00ff4
[cherry-pick-me]: use kw args for Test* dataclasses
aaronsteers 5dff39e
Merge remote-tracking branch 'origin/main' into aj/feat/mini-cat-test…
aaronsteers 3160691
fix relative resource paths
aaronsteers 015ced9
fix imports
aaronsteers e2a9fb9
fix more tests
aaronsteers bfc1943
format fix
aaronsteers f82b76a
[cherry-pick-me][chore]: resolve pytest warnings undeclared marks, an…
aaronsteers f091b53
[cherry-pick-me][fix]: dataclasses constructor break with __test__ me…
aaronsteers 12afc3d
[cherry-pick-me]: use kw args
aaronsteers cca55f7
[cherry-pick-me]: kw args
aaronsteers 4f7a84e
[cherry-pick-me]: use kw args for Test* dataclasses
aaronsteers e24594b
Merge branch 'devin/1744436819-cherry-pick-test-fixes' into aj/feat/m…
aaronsteers 9389cc5
reduce code needed for inheritance
aaronsteers e4cae20
fix type hint
aaronsteers 18ff2e8
Use ClassVar[bool] for __test__ instead of kw_only=True
devin-ai-integration[bot] 40fddcc
Use ClassVar[bool] for __test__ attributes instead of kw_only=True
devin-ai-integration[bot] e2c69df
Update more classes to use ClassVar[bool] for __test__ attributes
devin-ai-integration[bot] e79e901
Apply ruff formatting
devin-ai-integration[bot] c26345e
Fix remaining files with ruff formatting
devin-ai-integration[bot] eb0f643
addl cleanup
aaronsteers 7a750d6
Merge branch 'devin/1744436819-cherry-pick-test-fixes' into aj/feat/m…
aaronsteers b8407e5
Merge branch 'main' into devin/1744436819-cherry-pick-test-fixes
aaronsteers 88acba3
Merge branch 'main' into aj/feat/mini-cat-test-suites
aaronsteers 4b6c53e
poe lock
aaronsteers f0bea0c
remove unrelated changes
aaronsteers 8c91964
Merge branch 'devin/1744436819-cherry-pick-test-fixes' into aj/feat/m…
aaronsteers 4f84c14
revert unnecessary changes
aaronsteers d0aba9f
Merge branch 'devin/1744436819-cherry-pick-test-fixes' into aj/feat/m…
aaronsteers 1468a48
clean up naming, remove unused
aaronsteers 2812e7d
tidy up pr
aaronsteers c4e6655
clean up IConnector interface
aaronsteers f6d6ccd
ruff fix
aaronsteers d20d91f
poe lock
aaronsteers b363b52
Merge branch 'main' into aj/feat/mini-cat-test-suites
aaronsteers b045532
clean up test module structure and pytest hooks
aaronsteers dc95a71
remove extra pytest files
aaronsteers a36d6a9
add usage docs
aaronsteers da442a9
clean up
aaronsteers 623df9c
new cli
aaronsteers dd1f040
add airbyte-cdk cli scaffold
aaronsteers 0209c1e
add comment
aaronsteers 38c7166
add helper functions: find_connector_root(), find_connector_root_from…
aaronsteers c371030
misc fixes (working now)
aaronsteers 8892914
delete unused devtools.py file
aaronsteers de07f9d
clean up cli module structure
aaronsteers a330cb7
update cli entrypoint
aaronsteers 14b1385
add image command stub
aaronsteers 1b45851
add --version support
aaronsteers 67e4aca
Merge remote-tracking branch 'origin/main' into aj/feat/add-standard-…
aaronsteers 79b11dc
ruff format
aaronsteers aec8602
chore: `poetry add rich` (transitive dependency)
aaronsteers ea848b0
remove click declaration (replaced by rich-click)
aaronsteers 4fc4932
typing fixes
aaronsteers 0cc217e
fix deptry issues
aaronsteers c4f9eee
pull in refactoring from downstream pr
aaronsteers 5f025ba
add manifest help text
aaronsteers 6fdf2c6
feat: add secrets fetch command to CDK CLI (#494)
devin-ai-integration[bot] db52db6
apply suggestion (owner-only read/write)
aaronsteers 4d524b6
ensure we print the absolute path so secrets don't get lost
aaronsteers 72514ac
allow imports outside of cwd
aaronsteers 8cdf876
remove stale files from other PR
aaronsteers 032d5e7
remove stale declarative module
aaronsteers 7de9ab7
fix imports and such
aaronsteers a28e63b
tidy up cli help text declarations
aaronsteers 1b47886
Merge branch 'main' into aj/feat/add-standard-tests-cli
aaronsteers e45e19b
Merge branch 'main' into aj/feat/add-standard-tests-cli
aaronsteers bf7ce53
Auto-commit Resolving dependencies... changes
e40f3a1
Merge branch 'main' into aj/feat/add-standard-tests-cli
aaronsteers 4f383fc
chore: add optional 'dev' dependency
aaronsteers b012495
Auto-commit Resolving dependencies... changes
9ea97fa
Merge branch 'main' into aj/feat/add-standard-tests-cli
aaronsteers File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,3 +15,4 @@ dist | |
| .idea | ||
| .vscode | ||
| **/__pycache__ | ||
| .tmp | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| # Copyright (c) 2025 Airbyte, Inc., all rights reserved. | ||
| """CLI commands for `airbyte-cdk`. | ||
|
|
||
| This CLI interface allows you to interact with your connector, including | ||
| testing and running commands. | ||
|
|
||
| **Basic Usage:** | ||
|
|
||
| ```bash | ||
| airbyte-cdk --help | ||
| airbyte-cdk --version | ||
| airbyte-cdk connector --help | ||
| airbyte-cdk manifest --help | ||
| ``` | ||
|
|
||
| **Running Statelessly:** | ||
|
|
||
| You can run the latest version of this CLI, from any machine, using `pipx` or `uvx`: | ||
|
|
||
| ```bash | ||
| # Run the latest version of the CLI: | ||
| pipx run airbyte-cdk connector --help | ||
| uvx airbyte-cdk connector --help | ||
|
|
||
| # Run from a specific CDK version: | ||
| pipx run airbyte-cdk==6.5.1 connector --help | ||
| uvx airbyte-cdk==6.5.1 connector --help | ||
| ``` | ||
|
|
||
| **Running within your virtualenv:** | ||
|
|
||
| You can also run from your connector's virtualenv: | ||
|
|
||
| ```bash | ||
| poetry run airbyte-cdk connector --help | ||
| ``` | ||
|
|
||
| """ | ||
|
|
||
| from typing import cast | ||
|
|
||
| import rich_click as click | ||
|
|
||
| from airbyte_cdk.cli.airbyte_cdk._connector import connector_cli_group | ||
| from airbyte_cdk.cli.airbyte_cdk._image import image_cli_group | ||
| from airbyte_cdk.cli.airbyte_cdk._manifest import manifest_cli_group | ||
| from airbyte_cdk.cli.airbyte_cdk._secrets import secrets_cli_group | ||
| from airbyte_cdk.cli.airbyte_cdk._version import print_version | ||
|
|
||
|
|
||
| @click.group( | ||
| help=__doc__.replace("\n", "\n\n"), # Render docstring as help text (markdown) | ||
| invoke_without_command=True, | ||
| ) | ||
| @click.option( | ||
| "--version", | ||
| is_flag=True, | ||
| help="Show the version of the Airbyte CDK.", | ||
| ) | ||
| @click.pass_context | ||
| def cli( | ||
| ctx: click.Context, | ||
| version: bool, | ||
| ) -> None: | ||
| """Airbyte CDK CLI. | ||
|
|
||
| Help text is provided from the file-level docstring. | ||
| """ | ||
| if version: | ||
| print_version(short=False) | ||
| ctx.exit() | ||
|
|
||
| if ctx.invoked_subcommand is None: | ||
| # If no subcommand is provided, show the help message. | ||
| click.echo(ctx.get_help()) | ||
| ctx.exit() | ||
|
|
||
|
|
||
| cli.add_command(connector_cli_group) | ||
| cli.add_command(manifest_cli_group) | ||
| cli.add_command(image_cli_group) | ||
| cli.add_command(secrets_cli_group) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| cli() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| # Copyright (c) 2025 Airbyte, Inc., all rights reserved. | ||
| """CLI command for `airbyte-cdk`.""" | ||
|
|
||
| USAGE = """CLI command for `airbyte-cdk`. | ||
|
|
||
| This CLI interface allows you to interact with your connector, including | ||
| testing and running commands. | ||
|
|
||
| **Basic Usage:** | ||
|
|
||
| ```bash | ||
| airbyte-cdk --help | ||
| airbyte-cdk connector --help | ||
| airbyte-cdk manifest --help | ||
| ``` | ||
|
|
||
| **Running Statelessly:** | ||
|
|
||
| You can run the latest version of this CLI, from any machine, using `pipx` or `uvx`: | ||
|
|
||
| ```bash | ||
| # Run the latest version of the CLI: | ||
| pipx run airbyte-cdk connector --help | ||
| uvx airbyte-cdk connector --help | ||
|
|
||
| # Run from a specific CDK version: | ||
| pipx run airbyte-cdk==6.5.1 connector --help | ||
| uvx airbyte-cdk==6.5.1 connector --help | ||
| ``` | ||
|
|
||
| **Running within your virtualenv:** | ||
|
|
||
| You can also run from your connector's virtualenv: | ||
|
|
||
| ```bash | ||
| poetry run airbyte-cdk connector --help | ||
| ``` | ||
|
|
||
| """ | ||
|
|
||
| import os | ||
| from pathlib import Path | ||
| from types import ModuleType | ||
|
|
||
| import rich_click as click | ||
|
|
||
| # from airbyte_cdk.test.standard_tests import pytest_hooks | ||
| from airbyte_cdk.cli.airbyte_cdk._util import resolve_connector_name_and_directory | ||
| from airbyte_cdk.test.standard_tests.test_resources import find_connector_root_from_name | ||
| from airbyte_cdk.test.standard_tests.util import create_connector_test_suite | ||
|
|
||
| click.rich_click.TEXT_MARKUP = "markdown" | ||
|
|
||
| pytest: ModuleType | None | ||
| try: | ||
| import pytest | ||
| except ImportError: | ||
| pytest = None | ||
| # Handle the case where pytest is not installed. | ||
| # This prevents import errors when running the script without pytest installed. | ||
| # We will raise an error later if pytest is required for a given command. | ||
|
|
||
|
|
||
| TEST_FILE_TEMPLATE = ''' | ||
| # Copyright (c) 2025 Airbyte, Inc., all rights reserved. | ||
| """FAST Airbyte Standard Tests for the source_pokeapi_w_components source.""" | ||
|
|
||
| #from airbyte_cdk.test.standard_tests import {base_class_name} | ||
| from airbyte_cdk.test.standard_tests.util import create_connector_test_suite | ||
| from pathlib import Path | ||
|
|
||
| pytest_plugins = [ | ||
| "airbyte_cdk.test.standard_tests.pytest_hooks", | ||
| ] | ||
|
|
||
| TestSuite = create_connector_test_suite( | ||
| connector_directory=Path(), | ||
| ) | ||
|
|
||
| # class TestSuite({base_class_name}): | ||
| # """Test suite for the source_pokeapi_w_components source. | ||
|
|
||
| # This class inherits from SourceTestSuiteBase and implements all of the tests in the suite. | ||
|
|
||
| # As long as the class name starts with "Test", pytest will automatically discover and run the | ||
| # tests in this class. | ||
| # """ | ||
| ''' | ||
|
|
||
|
|
||
| @click.group( | ||
| name="connector", | ||
| help=__doc__.replace("\n", "\n\n"), # Render docstring as help text (markdown) | ||
| ) | ||
| def connector_cli_group() -> None: | ||
| """Connector related commands.""" | ||
| pass | ||
|
|
||
|
|
||
| @connector_cli_group.command() | ||
| @click.option( | ||
| "--connector-name", | ||
| type=str, | ||
| help="Name of the connector to test. Ignored if --connector-directory is provided.", | ||
| ) | ||
| @click.option( | ||
| "--connector-directory", | ||
| type=click.Path(exists=True, file_okay=False, path_type=Path), | ||
| help="Path to the connector directory.", | ||
| ) | ||
| @click.option( | ||
| "--collect-only", | ||
| is_flag=True, | ||
| default=False, | ||
| help="Only collect tests, do not run them.", | ||
| ) | ||
| def test( | ||
| connector_name: str | None = None, | ||
| connector_directory: Path | None = None, | ||
| *, | ||
| collect_only: bool = False, | ||
| ) -> None: | ||
| """Run connector tests. | ||
|
|
||
| This command runs the standard connector tests for a specific connector. | ||
|
|
||
| If no connector name or directory is provided, we will look within the current working | ||
| directory. If the current working directory is not a connector directory (e.g. starting | ||
| with 'source-') and no connector name or path is provided, the process will fail. | ||
| """ | ||
| if pytest is None: | ||
| raise ImportError( | ||
| "pytest is not installed. Please install pytest to run the connector tests." | ||
| ) | ||
| click.echo("Connector test command executed.") | ||
| connector_name, connector_directory = resolve_connector_name_and_directory( | ||
| connector_name=connector_name, | ||
| connector_directory=connector_directory, | ||
| ) | ||
|
|
||
| connector_test_suite = create_connector_test_suite( | ||
| connector_name=connector_name if not connector_directory else None, | ||
| connector_directory=connector_directory, | ||
| ) | ||
|
|
||
| pytest_args: list[str] = [] | ||
| if connector_directory: | ||
| pytest_args.append(f"--rootdir={connector_directory}") | ||
| os.chdir(str(connector_directory)) | ||
| else: | ||
| print("No connector directory provided. Running tests in the current directory.") | ||
|
|
||
| file_text = TEST_FILE_TEMPLATE.format( | ||
| base_class_name=connector_test_suite.__bases__[0].__name__, | ||
| connector_directory=str(connector_directory), | ||
| ) | ||
| test_file_path = Path() / ".tmp" / "integration_tests/test_airbyte_standards.py" | ||
| test_file_path = test_file_path.resolve().absolute() | ||
| test_file_path.parent.mkdir(parents=True, exist_ok=True) | ||
| test_file_path.write_text(file_text) | ||
|
|
||
| if collect_only: | ||
| pytest_args.append("--collect-only") | ||
|
|
||
| pytest_args.append(str(test_file_path)) | ||
| click.echo(f"Running tests from connector directory: {connector_directory}...") | ||
| click.echo(f"Test file: {test_file_path}") | ||
| click.echo(f"Collect only: {collect_only}") | ||
| click.echo(f"Pytest args: {pytest_args}") | ||
| click.echo("Invoking Pytest...") | ||
| pytest.main( | ||
| pytest_args, | ||
| plugins=[], | ||
| ) | ||
|
|
||
|
|
||
| __all__ = [ | ||
| "connector_cli_group", | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # Copyright (c) 2025 Airbyte, Inc., all rights reserved. | ||
| """Docker image commands. | ||
|
|
||
| Coming soon. | ||
|
|
||
| This module is planned to provide a command line interface (CLI) for building | ||
| Docker images for Airbyte CDK connectors. | ||
| """ | ||
|
|
||
| import click | ||
|
|
||
|
|
||
| @click.group( | ||
| name="image", | ||
| help=__doc__.replace("\n", "\n\n"), # Render docstring as help text (markdown) | ||
| ) | ||
| def image_cli_group() -> None: | ||
| """Docker image commands.""" | ||
| pass | ||
|
|
||
|
|
||
| __all__ = [ | ||
| "image_cli_group", | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # Copyright (c) 2025 Airbyte, Inc., all rights reserved. | ||
| """Manifest related commands. | ||
|
|
||
| Coming soon. | ||
|
|
||
| This module is planned to provide a command line interface (CLI) for validating | ||
| Airbyte CDK manifests. | ||
| """ | ||
|
|
||
| import rich_click as click | ||
|
|
||
|
|
||
| @click.group( | ||
| name="manifest", | ||
| help=__doc__.replace("\n", "\n\n"), # Render docstring as help text (markdown) | ||
| ) | ||
| def manifest_cli_group() -> None: | ||
| """Manifest related commands.""" | ||
| pass | ||
|
|
||
|
|
||
| __all__ = [ | ||
| "manifest_cli_group", | ||
| ] |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.