Skip to content
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

πŸ™ octavia-cli: generate open api client #9277

Merged
merged 20 commits into from
Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
default_language_version:
cgardens marked this conversation as resolved.
Show resolved Hide resolved
python: python3.7
python: python3

repos:
- repo: https://github.com/johann-petrak/licenseheaders.git
rev: v0.8.8
hooks:
- id: licenseheaders
args: ["--tmpl=LICENSE_SHORT", "--ext=py", "-f"]

- repo: https://github.com/ambv/black
rev: 21.11b1
hooks:
- id: black

- repo: https://github.com/timothycrosley/isort
rev: 5.10.1
hooks:
- id: isort
args: ["--dont-follow-links", "--jobs=-1"]
additional_dependencies: ["colorama"]

- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.5.0
hooks:
Expand All @@ -29,7 +26,8 @@ repos:
(?x)^.*(
.github/|
source_specs.yaml|
destination_specs.yaml
destination_specs.yaml|
.gitlab-ci.yml
).?$

- repo: https://github.com/csachs/pyproject-flake8
Expand All @@ -38,12 +36,14 @@ repos:
- id: pyproject-flake8
additional_dependencies: ["mccabe"]
alias: flake8

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.910-1
hooks:
- id: mypy

exclude: |
(?x)^.*(
octavia-cli/unit_tests/|
).?$
- repo: local
hooks:
- id: spec-linter
Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ subprojects {
source = fileTree(dir: projectDir)
.include("**/*.py")
.exclude(".venv/**/*.py")
.exclude("**/airbyte_api_client/**/*.py")
.exclude("**/__init__.py")
strictCheck = true
}
Expand Down
1 change: 1 addition & 0 deletions octavia-cli/.dockerignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
build
!build/airbyte_api_client
.venv
octavia_cli.egg-info
9 changes: 5 additions & 4 deletions octavia-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ The project is under development: readers can refer to our [tech spec deck](http
We encourage users to use the CLI with docker to avoid the hassle of setting up a Python installation.
The project is under development: we have not yet published any docker image to our Docker registry.

1. Build the image locally:
1. Build the project locally (from the root of the repo):
```bash
docker build -t octavia-cli:dev --rm .
SUB_BUILD=OCTAVIA_CLI ./gradlew build #from the root of the repo
```
2. Run the CLI from docker:
```bash
Expand All @@ -34,14 +34,15 @@ Octavia is currently under development.
You can find a detailed and updated execution plan [here](https://docs.google.com/spreadsheets/d/1weB9nf0Zx3IR_QvpkxtjBAzyfGb7B0PWpsVt6iMB5Us/edit#gid=0).
We welcome community contributions!

Summary of achievements:
**Summary of achievements**:

| Date | Milestone |
|------------|-------------------------------------|
| 2022-01-06 | Generate an API Python client from our Open API spec |
| 2021-12-22 | Bootstrapping the project's code base |

# Developing locally
1. Install Python 3.10.0. We suggest doing it through `pyenv`
1. Install Python 3.8.12. We suggest doing it through `pyenv`
alafanechere marked this conversation as resolved.
Show resolved Hide resolved
2. Create a virtualenv: `python -m venv .venv`
3. Activate the virtualenv: `source .venv/bin/activate`
4. Install dev dependencies: `pip install -e .\[dev\]`
Expand Down
16 changes: 16 additions & 0 deletions octavia-cli/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import org.openapitools.generator.gradle.plugin.tasks.GenerateTask

plugins {
id "org.openapi.generator" version "5.3.1"
id 'airbyte-python'
id 'airbyte-docker'
}
Expand All @@ -7,3 +10,16 @@ airbytePython {
moduleDirectory 'octavia_cli'
}


task generateApiClient(type: GenerateTask) {
inputSpec = "$rootDir.absolutePath/airbyte-api/src/main/openapi/config.yaml"
outputDir = "$buildDir/airbyte_api_client"

generatorName = "python"
packageName = "airbyte_api_client"
}

blackFormat.dependsOn generateApiClient
isortFormat.dependsOn generateApiClient
flakeCheck.dependsOn generateApiClient
installReqs.dependsOn generateApiClient
43 changes: 29 additions & 14 deletions octavia-cli/octavia_cli/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,56 @@
# Copyright (c) 2021 Airbyte, Inc., all rights reserved.
#

import airbyte_api_client
import click
from airbyte_api_client.api import workspace_api


@click.group()
@click.option("--airbyte-url", envvar="AIRBYTE_URL", default="http://localhost:8000", help="The URL of your Airbyte instance.")
def octavia(airbyte_url):
# TODO: check if the airbyte_url is reachable
click.secho(f"πŸ™ - Octavia is targetting your Airbyte instance running at {airbyte_url}")
@click.pass_context
def octavia(ctx: click.Context, airbyte_url: str) -> None:
ctx.ensure_object(dict)
client_configuration = airbyte_api_client.Configuration(host=f"{airbyte_url}/api")
api_client = airbyte_api_client.ApiClient(client_configuration)
# TODO alafanechere workspace check might deserve its own function
api_instance = workspace_api.WorkspaceApi(api_client)
# open-api-generator consider non-required field as not nullable
# This will break validation of WorkspaceRead object for firstCompletedSync and feedbackDone fields
# This is why we bypass _check_return_type
api_response = api_instance.list_workspaces(_check_return_type=False)
# TODO alafanechere prompt user to chose a workspace if multiple workspaces exist
workspace_id = api_response.workspaces[0]["workspaceId"]
click.echo(f"πŸ™ - Octavia is targetting your Airbyte instance running at {airbyte_url} on workspace {workspace_id}")
ctx.obj["API_CLIENT"] = api_client
ctx.obj["WORKSPACE_ID"] = workspace_id


@octavia.command(help="Scaffolds a local project directories.")
def init():
def init() -> None:
raise click.ClickException("The init command is not yet implemented.")


@octavia.command(name="list", help="List existing resources on the Airbyte instance.")
def _list():
raise click.ClickException("The init command is not yet implemented.")
def _list() -> None:
raise click.ClickException("The list command is not yet implemented.")


@octavia.command(name="import", help="Import an existing resources from the Airbyte instance.")
def _import():
raise click.ClickException("The init command is not yet implemented.")
def _import() -> None:
raise click.ClickException("The import command is not yet implemented.")


@octavia.command(help="Generate a YAML configuration file to manage a resource.")
def create():
raise click.ClickException("The init command is not yet implemented.")
def create() -> None:
raise click.ClickException("The create command is not yet implemented.")


@octavia.command(help="Create or update resources according to YAML configurations.")
def apply():
raise click.ClickException("The init command is not yet implemented.")
def apply() -> None:
raise click.ClickException("The apply command is not yet implemented.")


@octavia.command(help="Delete resources")
def delete():
raise click.ClickException("The init command is not yet implemented.")
def delete() -> None:
raise click.ClickException("The delete command is not yet implemented.")
5 changes: 3 additions & 2 deletions octavia-cli/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Copyright (c) 2021 Airbyte, Inc., all rights reserved.
#

import os
import pathlib

from setuptools import find_packages, setup
Expand Down Expand Up @@ -39,8 +40,8 @@
"Source": "https://github.com/airbytehq/airbyte",
"Tracker": "https://github.com/airbytehq/airbyte/issues",
},
packages=find_packages(exclude=("tests", "docs")),
install_requires=["click~=8.0.3"],
packages=find_packages(exclude=("unit_tests", "docs")),
install_requires=["click~=8.0.3", f"airbyte_api_client @ file://{os.getcwd()}/build/airbyte_api_client"],
python_requires=">=3.8.12",
extras_require={
"dev": ["MyPy~=0.812", "pytest~=6.2.5", "pytest-cov", "pytest-mock", "requests-mock", "pre-commit"],
Expand Down
28 changes: 25 additions & 3 deletions octavia-cli/unit_tests/test_entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,38 @@
# Copyright (c) 2021 Airbyte, Inc., all rights reserved.
#

from unittest import mock

import click
import pytest
from click.testing import CliRunner
from octavia_cli import entrypoint


def test_octavia():
@click.command()
@click.pass_context
def dumb(ctx):
Copy link
Contributor

Choose a reason for hiding this comment

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

πŸ˜‚

pass


def test_octavia(mocker):
mocker.patch.object(entrypoint, "workspace_api")
mocker.patch.object(entrypoint, "airbyte_api_client")

context_object = {}
mock_api_instance = entrypoint.workspace_api.WorkspaceApi.return_value
mock_api_instance.list_workspaces.return_value = mock.MagicMock(workspaces=[{"workspaceId": "expected_workspace_id"}])

entrypoint.octavia.add_command(dumb)
runner = CliRunner()
result = runner.invoke(entrypoint.octavia)
result = runner.invoke(entrypoint.octavia, ["--airbyte-url", "test-airbyte-url", "dumb"], obj=context_object)
entrypoint.airbyte_api_client.Configuration.assert_called_with(host="test-airbyte-url/api")
entrypoint.airbyte_api_client.ApiClient.assert_called_with(entrypoint.airbyte_api_client.Configuration.return_value)
entrypoint.workspace_api.WorkspaceApi.assert_called_with(entrypoint.airbyte_api_client.ApiClient.return_value)
mock_api_instance.list_workspaces.assert_called_once()
assert context_object["API_CLIENT"] == entrypoint.airbyte_api_client.ApiClient.return_value
assert context_object["WORKSPACE_ID"] == "expected_workspace_id"
assert result.exit_code == 0
assert result.output.startswith("Usage: octavia [OPTIONS] COMMAND [ARGS]...")


@pytest.mark.parametrize(
Expand Down
1 change: 1 addition & 0 deletions tools/python/.flake8
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ exclude =
.eggs # python libraries"
.tox
build
airbyte_api_client # generated api client in octavia-cli
extend-ignore =
E203, # whitespace before ':' (conflicts with Black)
E231, # Bad trailing comma (conflicts with Black)
Expand Down