Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 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
3 changes: 2 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
recursive-include openhexa/cli/skeleton *
recursive-include openhexa/cli/skeleton *
recursive-include openhexa/cli/graphql *
60 changes: 60 additions & 0 deletions openhexa/cli/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import logging
import os
import tempfile
import time
import typing
from importlib.metadata import version
from pathlib import Path
Expand All @@ -18,6 +19,8 @@
from docker.models.containers import Container
from jinja2 import Template

from graphql import build_client_schema, build_schema, get_introspection_query
from graphql.utilities import find_breaking_changes
from openhexa.cli.settings import settings
from openhexa.sdk.pipelines import get_local_workspace_config
from openhexa.sdk.pipelines.runtime import get_pipeline
Expand Down Expand Up @@ -104,7 +107,63 @@ def get_library_versions() -> tuple[str, str]:
return installed_version, installed_version


def detect_graphql_breaking_changes(token):
"""Detect breaking changes between the schema referenced in the SDK and the server using graphql-core."""
stored_schema_obj = build_schema((Path(__file__).parent / "graphql" / "schema.generated.graphql").open().read())
server_schema_obj = build_client_schema(
_query_graphql(get_introspection_query(input_value_deprecation=True), token=token)
)

breaking_changes = find_breaking_changes(stored_schema_obj, server_schema_obj)
if breaking_changes:
current_version, latest_version = get_library_versions()
click.echo(
click.style(
f"⚠️ Breaking changes detected between the SDK (version {current_version}) and the server:",
fg="red",
)
)
for change in breaking_changes:
click.echo(click.style(f"- {change.description}", fg="yellow"))
click.echo(click.style("This could lead to unexpected results.", fg="red"))
click.echo(
click.style(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you give an example of command to update the openhexa.sdk package to the user as well please ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea, thanks

f"Please update the SDK to the latest version ({latest_version}) or use a version of the SDK compatible with the server.",
fg="red",
)
)


_COOLDOWN_PERIOD = 3600 # Cooldown period in seconds
_CACHE_FILE = Path.home() / f".openhexa_{version('openhexa.sdk')}" # Cache file in the user's home directory


def get_last_checked():
"""Retrieve the last checked timestamp from the cache file."""
if _CACHE_FILE.exists():
try:
return float(_CACHE_FILE.read_text().strip())
except ValueError:
pass
return None


def update_last_checked():
"""Update the cache file with the current timestamp."""
_CACHE_FILE.write_text(str(time.time()))


def graphql(query: str, variables=None, token=None):
"""Check that there is no breaking change and perform a GraphQL request."""
last_checked = get_last_checked()
current_time = time.time()
if not last_checked or (current_time - last_checked) >= _COOLDOWN_PERIOD:
detect_graphql_breaking_changes(token)
update_last_checked()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not totally convinced myself on the caching on the disk. WDYT ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mmm me neither. I'd prefer to store this in the config of the user (where we store the workspaces and the token)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok I agree, will do the change

return _query_graphql(query, variables, token)


def _query_graphql(query: str, variables=None, token=None):
"""Perform a GraphQL request."""
url = settings.api_url + "/graphql/"
if token is None:
Expand All @@ -121,6 +180,7 @@ def graphql(query: str, variables=None, token=None):
click.echo(f"Variables: {variables}")

session = create_requests_session()

response = session.post(
url,
headers={
Expand Down
Loading
Loading