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

[Feature] sc-32292 PipeRider CLI support share to temporary quick look #889

Merged
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
24 changes: 12 additions & 12 deletions piperider_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from rich.console import Console

from piperider_cli import __version__, event, sentry_dns, sentry_env
from piperider_cli.cli_utils import DbtUtil
from piperider_cli.cli_utils import DbtUtil, verify_upload_related_options
from piperider_cli.cli_utils.cloud import CloudConnectorHelper
from piperider_cli.configuration import FileSystem, is_piperider_workspace_exist
from piperider_cli.error import DbtProjectNotFoundError
Expand Down Expand Up @@ -63,6 +63,11 @@ def dbt_select_option_builder():
help='Disable auto detection of dbt projects.'),
]

feature_flags = [
click.option('--enable-quick-look-share', envvar='PIPERIDER_ENABLE_QUICK_LOOK_SHARE',
is_flag=True, default=False, hidden=True, help='Enable share to Quick Look.')
]


def add_options(options):
def _add_options(func):
Expand All @@ -78,7 +83,7 @@ def __init__(self):
super().__init__(exists=True, dir_okay=False, resolve_path=True)

def convert(
self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
) -> t.Any:
rv = value

Expand Down Expand Up @@ -230,6 +235,7 @@ def diagnose(**kwargs):
help='If set, use the given directory as the source for JSON files to compare with this project.')
])
@add_options(dbt_related_options)
@add_options(feature_flags)
@add_options(debug_option)
def run(**kwargs):
"""
Expand Down Expand Up @@ -287,6 +293,7 @@ def generate_report(**kwargs):
help='Specify the project name to upload.')
@click.option('--share', default=False, is_flag=True, help='Enable public share of the report to PipeRider Cloud.')
@click.option('--open', is_flag=True, help='Opens the generated report in the system\'s default browser')
@add_options(feature_flags)
@add_options(debug_option)
def compare_reports(**kwargs):
'Compare two existing reports selected in interactive mode or by option.'
Expand All @@ -298,22 +305,14 @@ def compare_reports(**kwargs):
tables_from = kwargs.get('tables_from')
summary_file = kwargs.get('summary_file')
open_report = kwargs.get('open')
force_upload = kwargs.get('upload')
enable_share = kwargs.get('share')
project_name = kwargs.get('project')

if enable_share or CloudConnectorHelper.is_auto_upload():
force_upload = True

if force_upload and not CloudConnectorHelper.is_login():
force_upload = False
console = Console()
console.print('[bold yellow]Warning: [/bold yellow]Reports will not be uploaded due to not logged in.')
enable_upload, enable_share = verify_upload_related_options(**kwargs)

from piperider_cli.compare_report import CompareReport
CompareReport.exec(a=a, b=b, last=last, datasource=datasource,
report_dir=kwargs.get('report_dir'), output=kwargs.get('output'), summary_file=summary_file,
tables_from=tables_from, force_upload=force_upload, enable_share=enable_share,
tables_from=tables_from, force_upload=enable_upload, enable_share=enable_share,
open_report=open_report, project_name=project_name, debug=kwargs.get('debug', False),
show_progress=True)

Expand Down Expand Up @@ -450,6 +449,7 @@ def cloud_compare_reports(**kwargs):
show_default=True),
])
@add_options(dbt_related_options)
@add_options(feature_flags)
@add_options(debug_option)
def compare_with_recipe(ref, **kwargs):
"""
Expand Down
34 changes: 34 additions & 0 deletions piperider_cli/cli_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import io
from typing import Union

from rich.console import Console

from piperider_cli.cli_utils.cloud import CloudConnectorHelper


class DbtUtil:

Expand Down Expand Up @@ -31,3 +35,33 @@ def load_credential_from_dbt_profile(dbt_profile, profile_name, target_name):
import piperider_cli.dbtutil as u
return u.load_credential_from_dbt_profile(dbt_profile=dbt_profile, profile_name=profile_name,
target_name=target_name)


def verify_upload_related_options(**kwargs):
console = Console()
upload = kwargs.get('upload', False)
upload_with_share = kwargs.get('share', False)
enable_quick_look_share = kwargs.get('enable_quick_look_share', False)
enable_auto_upload = CloudConnectorHelper.is_auto_upload()
is_cloud_login = CloudConnectorHelper.is_login()

if is_cloud_login is True:
if enable_auto_upload is True:
console.print('[[bold green]Enable Auto Upload[/bold green]]')
upload = True
if upload_with_share is True:
upload = True
return upload, upload_with_share
else:
if upload is False and upload_with_share is True and enable_quick_look_share is True:
# Upload to Cloud Quick Look without login
console.print(
'[[bold green]Enable Quick Look Share[/bold green]] '
'Reports will be uploaded as a temporary quick look.')
return True, True
if upload is True or upload_with_share is True:
console.print(
'[[bold yellow]Warning[/bold yellow]] '
'The report won\'t be uploaded due to not logged in.')

return False, False
19 changes: 6 additions & 13 deletions piperider_cli/cli_utils/compare_with_recipe.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import time

from rich.console import Console

from piperider_cli.cli_utils import verify_upload_related_options
from piperider_cli.event import CompareEventPayload, log_event


Expand Down Expand Up @@ -32,18 +35,15 @@ def compare_with_recipe(ref, **kwargs):
"""

from piperider_cli.cli_utils import DbtUtil
from piperider_cli.cli_utils.cloud import CloudConnectorHelper
from piperider_cli.configuration import FileSystem, is_piperider_workspace_exist
from piperider_cli.error import DbtProjectNotFoundError, RecipeConfigException
from piperider_cli.error import DbtProjectNotFoundError
from piperider_cli.initializer import Initializer
from piperider_cli.recipes import RecipeConfiguration, configure_recipe_execution_flags, is_recipe_dry_run

console = Console()

recipe = kwargs.get('recipe')
summary_file = kwargs.get('summary_file')
force_upload = kwargs.get('upload')
enable_share = kwargs.get('share')
open_report = kwargs.get('open')
project_name = kwargs.get('project')
debug = kwargs.get('debug', False)
Expand All @@ -66,14 +66,7 @@ def compare_with_recipe(ref, **kwargs):
# reconfigure recipe global flags
configure_recipe_execution_flags(dry_run=kwargs.get('dry_run'), interactive=kwargs.get('interactive'))

if enable_share:
force_upload = True

if force_upload is True and CloudConnectorHelper.is_login() is False:
raise RecipeConfigException(
message='Please login to PipeRider Cloud first.',
hint='Run "piperider cloud login" to login to PipeRider Cloud.'
)
enable_upload, enable_share = verify_upload_related_options(**kwargs)

# Search dbt project config files
dbt_project_dir = kwargs.get('dbt_project_dir')
Expand Down Expand Up @@ -116,7 +109,7 @@ def compare_with_recipe(ref, **kwargs):
CompareReport.exec(a=base, b=target, last=last, datasource=None,
output=kwargs.get('output'), tables_from="all",
summary_file=summary_file,
force_upload=force_upload,
force_upload=enable_upload,
enable_share=enable_share,
open_report=open_report,
project_name=project_name,
Expand Down
17 changes: 5 additions & 12 deletions piperider_cli/cli_utils/run_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from rich.console import Console

from piperider_cli.cli_utils import verify_upload_related_options
from piperider_cli.event import log_event


Expand All @@ -30,15 +31,15 @@ def run(**kwargs):
table = kwargs.get('table')
output = kwargs.get('output')
open_report = kwargs.get('open')
enable_share = kwargs.get('share')
skip_report = kwargs.get('skip_report')
dbt_target_path = kwargs.get('dbt_target_path')
dbt_list = kwargs.get('dbt_list')
force_upload = kwargs.get('upload')
project_name = kwargs.get('project')
select = kwargs.get('select')
state = kwargs.get('state')

enable_upload, enable_share = verify_upload_related_options(**kwargs)

if project_name is not None:
os.environ.get('PIPERIDER_API_PROJECT')

Expand Down Expand Up @@ -90,14 +91,9 @@ def run(**kwargs):
skip_datasource_connection=kwargs.get('skip_datasource'),
event_payload=event_payload)
if ret in (0, EC_WARN_NO_PROFILED_MODULES):
if enable_share:
force_upload = True

auto_upload = CloudConnectorHelper.is_auto_upload()
is_cloud_view = (force_upload or auto_upload)

if not skip_report:
GenerateReport.exec(None, kwargs.get('report_dir'), output, open_report, is_cloud_view)
GenerateReport.exec(None, kwargs.get('report_dir'), output, open_report, open_in_cloud=enable_upload)

if ret == EC_WARN_NO_PROFILED_MODULES:
# No module was profiled
Expand All @@ -107,14 +103,11 @@ def run(**kwargs):
ret = 0

event_payload.step = 'upload'
if CloudConnectorHelper.is_login() and is_cloud_view:
if enable_upload:
ret = CloudConnectorHelper.upload_latest_report(report_dir=kwargs.get('report_dir'),
debug=kwargs.get('debug'),
open_report=open_report, enable_share=enable_share,
project_name=project_name)
elif not CloudConnectorHelper.is_login() and is_cloud_view:
console = Console()
console.print('[bold yellow]Warning: [/bold yellow]The report is not uploaded due to not logged in.')

if ret != 0:
reason = 'error'
Expand Down
48 changes: 33 additions & 15 deletions piperider_cli/cloud/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import os
from typing import List
from typing import List, Union

import requests
from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
Expand All @@ -27,6 +27,11 @@ def __init__(self, project: dict):
self.workspace_name = project.get('workspace_name')


class PipeRiderTemporaryProject(PipeRiderProject):
def __init__(self):
super().__init__({'id': None, 'name': None, 'workspace_name': None})


class CloudServiceHelper:

def __init__(self):
Expand Down Expand Up @@ -89,6 +94,11 @@ def url(self, uri_path: str):
return f'{self.api_service[:-1]}{uri_path}'
return f'{self.api_service}{uri_path}'

def non_auth_header(self):
return {
'User-Agent': f'PipeRider CLI/{__version__}',
}

def auth_headers(self):
return {
'User-Agent': f'PipeRider CLI/{__version__}',
Expand Down Expand Up @@ -273,8 +283,15 @@ def get_datasource_id(self, project: PipeRiderProject):

def upload_run(self, file_path, show_progress=True, project: PipeRiderProject = None):
# TODO validate project name
if not self.available:
self.raise_error()
if isinstance(project, PipeRiderTemporaryProject):
api_url = self.service.url('/api/v2/temporary/runs/upload')
headers = self.service.non_auth_header()
else:
api_url = self.service.url(
f'/api/v2/workspaces/{project.workspace_name}/projects/{project.name}/runs/upload')
if not self.available:
self.raise_error()
headers = self.service.auth_headers()

upload_progress = None
task_id = None
Expand All @@ -288,10 +305,6 @@ def _upload_callback(monitor):
fields={'file': ('run.json', file)},
)
m = MultipartEncoderMonitor(encoder, _upload_callback)

url = self.service.url(
f'/api/v2/workspaces/{project.workspace_name}/projects/{project.name}/runs/upload')
headers = self.service.auth_headers()
headers['Content-Type'] = m.content_type

if show_progress:
Expand All @@ -304,7 +317,7 @@ def _upload_callback(monitor):
task_id = upload_progress.add_task(description=file_path, total=encoder.len)
upload_progress.start()

response = requests.post(url, data=m, headers=headers)
response = requests.post(api_url, data=m, headers=headers)

if show_progress:
upload_progress.stop()
Expand All @@ -325,16 +338,21 @@ def share_run_report(self, workspace_name: str, project_name: str, run_id: int):

return response.json()

def compare_reports(self, base_id: int, target_id: int, tables_from, project: PipeRiderProject,
def compare_reports(self, base_id: Union[int, str], target_id: Union[int, str], tables_from,
project: PipeRiderProject,
metadata: dict = None):
if not self.available:
self.raise_error()
if isinstance(project, PipeRiderTemporaryProject):
api_url = self.service.url(f'/api/v2/temporary/runs/{base_id}/compare/{target_id}')
headers = self.service.non_auth_header()
else:
if not self.available:
self.raise_error()
api_url = self.service.url(
f'/api/v2/workspaces/{project.workspace_name}/projects/{project.name}/runs/{base_id}/compare/{target_id}')
headers = self.service.auth_headers()

url = self.service.url(
f'/api/v2/workspaces/{project.workspace_name}/projects/{project.name}/runs/{base_id}/compare/{target_id}')
headers = self.service.auth_headers()
data = json.dumps({'tables_from': tables_from, 'metadata': metadata})
response = requests.post(url, data=data, headers=headers)
response = requests.post(api_url, data=data, headers=headers)

if response.status_code != 200:
self.raise_error(response.reason)
Expand Down
Loading