-
Notifications
You must be signed in to change notification settings - Fork 30
feat(cli): Add image build
command to airbyte-cdk
CLI
#489
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
Closed
devin-ai-integration
wants to merge
53
commits into
aj/feat/add-standard-tests-cli
from
devin/1744841809-add-build-command
Closed
Changes from 18 commits
Commits
Show all changes
53 commits
Select commit
Hold shift + click to select a range
c65d832
feat: Add build command to CDK CLI
devin-ai-integration[bot] bd7a765
fix: Update formatting for build command files
devin-ai-integration[bot] 2a32e27
feat: Add Click-based CLI interface
devin-ai-integration[bot] 653bda1
chore: Update poetry.lock
devin-ai-integration[bot] 9510f2d
fix: Add type annotations to CLI functions
devin-ai-integration[bot] 84d649b
feat: Always build for both AMD64 and ARM64 architectures
devin-ai-integration[bot] f3e1743
fix: Format code with ruff
devin-ai-integration[bot] 2bc8848
fix: Address PR comments - remove infer_connector_language, use build…
devin-ai-integration[bot] ca1bbbe
fix: Update Dockerignore to use * pattern and fix formatting
devin-ai-integration[bot] 373f263
fix: Format all files with ruff
devin-ai-integration[bot] 430dd8d
docs: Move build.md content to __init__.py docstring
devin-ai-integration[bot] fe946ac
docs: Update __init__.py docstring with build command documentation
devin-ai-integration[bot] af3e56e
Delete airbyte_cdk/cli/entrypoint/run.py
aaronsteers 7b6dc5d
fix: Clean up duplicate code in _run.py and update imports
devin-ai-integration[bot] 2b1db11
refactor: Move build functionality to utils/docker and metadata model…
devin-ai-integration[bot] 4d45bab
fix: Remove unsupported --ignorefile flag and implement proper cleanu…
devin-ai-integration[bot] 7e68925
fix: Add fallback to single platform build when multi-platform not av…
devin-ai-integration[bot] df4b315
fix: Update dockerignore to include source_* directories
devin-ai-integration[bot] 83eaca9
enhancement: Improve build process to match airbyte-ci's approach wit…
devin-ai-integration[bot] 789f109
fix: Apply ruff formatting to fix CI checks
devin-ai-integration[bot] ba09434
fix: Add run_command function to build.py and update imports
devin-ai-integration[bot] b25671b
fix: Add run_command function to build.py
devin-ai-integration[bot] d7ee4f1
Merge branch 'aj/feat/add-standard-tests-cli' into devin/1744841809-a…
aaronsteers e1c7c13
delete unnecessay
aaronsteers ba0ab6b
move docstring
aaronsteers 61fdced
fully move model to models.connector_metadata
aaronsteers f293e7e
clean up
aaronsteers 7daa7f0
fix docstring
aaronsteers 4ba7e5c
clean up cli module
aaronsteers 49c9045
revert format update
aaronsteers d9c1ced
lean into pydantic model
aaronsteers 3103d0c
clean up
aaronsteers 52546be
clean up
aaronsteers 63cbc9b
fix: Address PR feedback - fix typo in __all__, update docstring, and…
devin-ai-integration[bot] c8f91cf
fix: Correct CLI entry point in pyproject.toml
devin-ai-integration[bot] 71652ef
Apply suggestions from code review
aaronsteers 78b173c
add-back the help text
aaronsteers 598d454
refactor, tidy up
aaronsteers bcf5d9f
Merge branch 'aj/feat/add-standard-tests-cli' into devin/1744841809-a…
aaronsteers 871cb71
refactor docker implementation
aaronsteers 42af39d
toggle default arch, fix return value for verify step
aaronsteers 964a215
better err handling
aaronsteers d7f9c7b
clean up
aaronsteers 3e9183b
tidy docstring
aaronsteers 6ea0623
ruff fix
aaronsteers ea5fd85
poe lock
aaronsteers 0229421
fix mypy
aaronsteers 297a98c
fix base image
aaronsteers f7b19e1
use uv instead of pip for installs
aaronsteers 7a87b62
use rich click
aaronsteers f7e4ddf
refactor, use build args
aaronsteers f323849
improve language detection
aaronsteers 51301d4
remove java image option
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 |
---|---|---|
@@ -1 +1,28 @@ | ||
# Copyright (c) 2024 Airbyte, Inc., all rights reserved. | ||
"""Airbyte CDK CLI. | ||
|
||
The Airbyte CDK provides command-line tools for working with connectors and related resources. | ||
|
||
|
||
```bash | ||
pip install airbyte-cdk | ||
|
||
pipx run airbyte-cdk [command] | ||
``` | ||
|
||
|
||
|
||
- `airbyte-cdk-build`: Build connector Docker images (legacy entry point) | ||
- `source-declarative-manifest`: Run a declarative YAML manifest connector | ||
- `airbyte-cdk`: Main CLI entry point with subcommands | ||
|
||
|
||
The `airbyte-cdk` command includes subcommands organized by category: | ||
|
||
```bash | ||
airbyte-cdk image build [OPTIONS] CONNECTOR_DIR | ||
``` | ||
|
||
|
||
For details on specific commands, see the documentation for each command module. | ||
""" |
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,41 @@ | ||
"""Airbyte CDK Build Command. | ||
|
||
The `airbyte-cdk-build` command provides a simplified way to build connector Docker images without requiring the full Airbyte CI pipeline. | ||
|
||
|
||
```bash | ||
pip install airbyte-cdk | ||
|
||
pipx run airbyte-cdk-build [arguments] | ||
``` | ||
|
||
|
||
```bash | ||
airbyte-cdk-build /path/to/connector | ||
|
||
airbyte-cdk image build /path/to/connector | ||
|
||
airbyte-cdk image build /path/to/connector --tag custom_tag | ||
|
||
airbyte-cdk image build /path/to/connector --no-verify | ||
|
||
airbyte-cdk image build /path/to/connector --verbose | ||
``` | ||
|
||
|
||
- `connector_dir`: Path to the connector directory (required) | ||
- `--tag`: Tag to apply to the built image (default: "dev") | ||
- `--no-verify`: Skip verification of the built image | ||
- `--verbose`, `-v`: Enable verbose logging | ||
|
||
|
||
The command reads the connector's metadata from the `metadata.yaml` file, builds a Docker image using the connector's Dockerfile, and verifies the image by running the `spec` command. The image is tagged according to the repository name specified in the metadata and the provided tag. | ||
|
||
This command is designed to be a simpler alternative to the `airbyte-ci build` command, using Docker directly on the host machine instead of Dagger. | ||
""" | ||
|
||
from airbyte_cdk.cli.build._run import run | ||
|
||
__all__ = [ | ||
"run", | ||
] |
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,42 @@ | ||
# Copyright (c) 2024 Airbyte, Inc., all rights reserved. | ||
"""Implements the `airbyte-cdk build` command for building connector Docker images. | ||
|
||
This command provides a simplified way to build connector Docker images without | ||
requiring the full Airbyte CI pipeline, which uses Dagger. | ||
""" | ||
|
||
from __future__ import annotations | ||
|
||
import argparse | ||
import sys | ||
from pathlib import Path | ||
|
||
from airbyte_cdk.utils.docker.build import run_command as docker_run_command | ||
|
||
|
||
def run() -> None: | ||
"""Entry point for the airbyte-cdk build command.""" | ||
parser = argparse.ArgumentParser(description="Build connector Docker images") | ||
parser.add_argument("connector_dir", type=str, help="Path to the connector directory") | ||
parser.add_argument( | ||
"--tag", type=str, default="dev", help="Tag to apply to the built image (default: dev)" | ||
) | ||
parser.add_argument( | ||
"--no-verify", action="store_true", help="Skip verification of the built image" | ||
) | ||
parser.add_argument("--verbose", "-v", action="store_true", help="Enable verbose logging") | ||
|
||
args = parser.parse_args(sys.argv[1:]) | ||
|
||
sys.exit( | ||
docker_run_command( | ||
connector_dir=Path(args.connector_dir), | ||
tag=args.tag, | ||
no_verify=args.no_verify, | ||
verbose=args.verbose, | ||
) | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
run() |
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,54 @@ | ||
"""Models for the build command.""" | ||
|
||
from __future__ import annotations | ||
|
||
from enum import Enum | ||
from typing import Any, Dict, Optional | ||
|
||
from pydantic import BaseModel, Field | ||
|
||
|
||
class ConnectorLanguage(str, Enum): | ||
"""Connector implementation language.""" | ||
|
||
PYTHON = "python" | ||
JAVA = "java" | ||
LOW_CODE = "low-code" | ||
MANIFEST_ONLY = "manifest-only" | ||
UNKNOWN = "unknown" | ||
|
||
|
||
class ConnectorBuildOptions(BaseModel): | ||
"""Connector build options from metadata.yaml.""" | ||
|
||
model_config = {"extra": "allow"} | ||
|
||
baseImage: Optional[str] = Field( | ||
None, description="Base image to use for building the connector" | ||
) | ||
path: Optional[str] = Field( | ||
None, description="Path to the connector code within the repository" | ||
) | ||
|
||
|
||
class ConnectorMetadata(BaseModel): | ||
"""Connector metadata from metadata.yaml.""" | ||
|
||
model_config = {"extra": "allow"} | ||
|
||
dockerRepository: str = Field(..., description="Docker repository for the connector image") | ||
dockerImageTag: str = Field(..., description="Docker image tag for the connector") | ||
language: Optional[ConnectorLanguage] = Field( | ||
None, description="Language of the connector implementation" | ||
) | ||
connectorBuildOptions: Optional[ConnectorBuildOptions] = Field( | ||
None, description="Options for building the connector" | ||
) | ||
|
||
|
||
class MetadataFile(BaseModel): | ||
"""Represents the structure of a metadata.yaml file.""" | ||
|
||
model_config = {"extra": "allow"} | ||
|
||
data: ConnectorMetadata = Field(..., description="Connector metadata") |
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 @@ | ||
"""CLI commands for Airbyte CDK.""" |
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,14 @@ | ||
"""Main CLI command group for Airbyte CDK.""" | ||
|
||
import click | ||
|
||
from airbyte_cdk.cli.commands.image import image | ||
|
||
|
||
@click.group() | ||
def cli() -> None: | ||
"""Airbyte CDK command-line interface.""" | ||
pass | ||
|
||
|
||
cli.add_command(image) |
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,98 @@ | ||
"""Image-related commands for the Airbyte CDK CLI.""" | ||
|
||
import sys | ||
from pathlib import Path | ||
|
||
import click | ||
|
||
from airbyte_cdk.utils.docker.build import ( | ||
build_from_base_image, | ||
build_from_dockerfile, | ||
read_metadata, | ||
set_up_logging, | ||
verify_docker_installation, | ||
verify_image, | ||
) | ||
|
||
|
||
@click.group() | ||
def image() -> None: | ||
"""Commands for working with connector Docker images.""" | ||
pass | ||
|
||
|
||
@image.command() | ||
@click.argument( | ||
"connector_dir", type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path) | ||
) | ||
@click.option("--tag", default="dev", help="Tag to apply to the built image (default: dev)") | ||
@click.option("--no-verify", is_flag=True, help="Skip verification of the built image") | ||
@click.option("--verbose", "-v", is_flag=True, help="Enable verbose logging") | ||
def build(connector_dir: Path, tag: str, no_verify: bool, verbose: bool) -> None: | ||
"""Build a connector Docker image. | ||
|
||
This command builds a Docker image for a connector, using either | ||
the connector's Dockerfile or a base image specified in the metadata. | ||
The image is built for both AMD64 and ARM64 architectures. | ||
""" | ||
set_up_logging(verbose) | ||
|
||
if not verify_docker_installation(): | ||
click.echo( | ||
"Docker is not installed or not running. Please install Docker and try again.", err=True | ||
) | ||
sys.exit(1) | ||
|
||
try: | ||
metadata = read_metadata(connector_dir) | ||
click.echo(f"Connector: {metadata.dockerRepository}") | ||
click.echo(f"Version: {metadata.dockerImageTag}") | ||
|
||
if metadata.language: | ||
click.echo(f"Connector language from metadata: {metadata.language}") | ||
else: | ||
click.echo("Connector language not specified in metadata") | ||
|
||
try: | ||
import subprocess | ||
result = subprocess.run( | ||
["docker", "buildx", "inspect"], | ||
capture_output=True, | ||
text=True, | ||
check=False | ||
) | ||
|
||
if "linux/amd64" in result.stdout and "linux/arm64" in result.stdout: | ||
platforms = "linux/amd64,linux/arm64" | ||
click.echo(f"Building for platforms: {platforms}") | ||
else: | ||
platforms = "linux/amd64" | ||
click.echo(f"Multi-platform build not available. Building for platform: {platforms}") | ||
click.echo("To enable multi-platform builds, configure Docker buildx with: docker buildx create --use") | ||
except Exception: | ||
platforms = "linux/amd64" | ||
click.echo(f"Multi-platform build check failed. Building for platform: {platforms}") | ||
|
||
if metadata.connectorBuildOptions and metadata.connectorBuildOptions.baseImage: | ||
image_name = build_from_base_image(connector_dir, metadata, tag, platforms) | ||
else: | ||
image_name = build_from_dockerfile(connector_dir, metadata, tag, platforms) | ||
|
||
if not no_verify: | ||
if verify_image(image_name): | ||
click.echo(f"Build completed successfully: {image_name}") | ||
sys.exit(0) | ||
else: | ||
click.echo(f"Built image failed verification: {image_name}", err=True) | ||
sys.exit(1) | ||
else: | ||
click.echo(f"Build completed successfully (without verification): {image_name}") | ||
sys.exit(0) | ||
|
||
except Exception as e: | ||
click.echo(f"Error: {str(e)}", err=True) | ||
if verbose: | ||
import traceback | ||
|
||
click.echo(traceback.format_exc(), err=True) | ||
sys.exit(1) |
Empty file.
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,5 @@ | ||
"""CLI entrypoint module for Airbyte CDK.""" | ||
|
||
from airbyte_cdk.cli.entrypoint.cli import run | ||
|
||
__all__ = ["run"] |
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,8 @@ | ||
"""Entrypoint for the Airbyte CDK CLI.""" | ||
|
||
from airbyte_cdk.cli.commands.cli import cli | ||
|
||
|
||
def run() -> None: | ||
"""Run the Airbyte CDK CLI.""" | ||
cli(prog_name="airbyte-cdk") |
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,54 @@ | ||
"""Models for connector metadata.""" | ||
|
||
from __future__ import annotations | ||
|
||
from enum import Enum | ||
from typing import Optional | ||
|
||
from pydantic import BaseModel, Field | ||
|
||
|
||
class ConnectorLanguage(str, Enum): | ||
"""Connector implementation language.""" | ||
|
||
PYTHON = "python" | ||
JAVA = "java" | ||
LOW_CODE = "low-code" | ||
MANIFEST_ONLY = "manifest-only" | ||
UNKNOWN = "unknown" | ||
|
||
|
||
class ConnectorBuildOptions(BaseModel): | ||
"""Connector build options from metadata.yaml.""" | ||
|
||
model_config = {"extra": "allow"} | ||
|
||
baseImage: Optional[str] = Field( | ||
None, description="Base image to use for building the connector" | ||
) | ||
path: Optional[str] = Field( | ||
None, description="Path to the connector code within the repository" | ||
) | ||
|
||
|
||
class ConnectorMetadata(BaseModel): | ||
"""Connector metadata from metadata.yaml.""" | ||
|
||
model_config = {"extra": "allow"} | ||
|
||
dockerRepository: str = Field(..., description="Docker repository for the connector image") | ||
dockerImageTag: str = Field(..., description="Docker image tag for the connector") | ||
language: Optional[ConnectorLanguage] = Field( | ||
None, description="Language of the connector implementation" | ||
) | ||
connectorBuildOptions: Optional[ConnectorBuildOptions] = Field( | ||
None, description="Options for building the connector" | ||
) | ||
|
||
|
||
class MetadataFile(BaseModel): | ||
"""Represents the structure of a metadata.yaml file.""" | ||
|
||
model_config = {"extra": "allow"} | ||
|
||
data: ConnectorMetadata = Field(..., description="Connector metadata") |
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
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 @@ | ||
"""Docker utilities for Airbyte CDK.""" |
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.