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

Validate instance version before SQL validation #87

Merged
merged 2 commits into from Oct 31, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 58 additions & 0 deletions spectacles/client.py
Expand Up @@ -81,6 +81,64 @@ def authenticate(

logger.info(f"Connected using Looker API {api_version}")

def get_looker_release_version(self) -> str:
"""Gets the version number of connected Looker instance.

Returns:
str: Looker instance release version number (e.g. 6.22.12)

"""
logger.debug("Checking Looker instance release version")

url = utils.compose_url(self.api_url, path=["versions"])

response = self.session.get(url=url)
try:
response.raise_for_status()
except requests.exceptions.HTTPError as error:
details = utils.details_from_http_error(response)
raise ApiConnectionError(
"Failed to get Looker instance release version\n"
f"Looker API error encountered: {error}\n"
+ "Message received from Looker's API: "
f'"{details}"'
)

return response.json()["looker_release_version"]

def validate_looker_release_version(self, required_version: str) -> bool:
"""Checks that the current Looker version meets a specified minimum.

Args:
required_version: Minimum instance version number (e.g. 6.22.12)

Returns:
bool: True if the current Looker version >= the required version

"""
current_version = self.get_looker_release_version()
logger.info(f"Looker instance version is {current_version}")

def expand_version(version: str):
return [int(number) for number in version.split(".")]

current = expand_version(current_version)
required = expand_version(required_version)

# If version is provided in format 6.20 or 7, extend with .0(s)
# e.g. 6.20 would become 6.20.0, 7 would become 7.0.0
if len(current) < 3:
current.extend([0] * (3 - len(current)))

for current_num, required_num in zip(current, required):
if current_num < required_num:
return False
elif current_num > required_num:
return True

# Loop exits successfully if current version == required version
return True

def update_session(self, project: str, branch: str) -> None:
"""Switches to a development mode session and checks out the desired branch.

Expand Down
9 changes: 9 additions & 0 deletions spectacles/validators.py
Expand Up @@ -43,9 +43,18 @@ class SqlValidator(Validator):
"""

timeout = aiohttp.ClientTimeout(total=300)
MIN_LOOKER_VERSION = "6.22.12"
Copy link
Contributor

Choose a reason for hiding this comment

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

Just wanting to confirm this is in fact the min version required, because #81 mentions 6.20.12?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Looks like the version in #81 is a typo (I've fixed it). However, we were told by Looker
that the API fix required here should be backported to 6.20, but I’m not
sure if that’s happened yet.

Anything after 6.22.12 should have the fix we’re checking for here, but if
the back port has occurred it should work on 6.20+

If you are able to get it working on pre-6.22.12, please let us know!


def __init__(self, client: LookerClient, project: str):
super().__init__(client)
meets_required_version = self.client.validate_looker_release_version(
required_version=self.MIN_LOOKER_VERSION
)
if not meets_required_version:
raise SpectaclesException(
"SQL validation requires version "
f"{self.MIN_LOOKER_VERSION} of Looker or higher."
)
self.project = Project(project, models=[])
self.query_tasks: dict = {}

Expand Down
9 changes: 9 additions & 0 deletions tests/test_sql_validator.py
Expand Up @@ -21,7 +21,16 @@ def load(filename):
@pytest.fixture
def client(monkeypatch):
mock_authenticate = Mock(spec=LookerClient.authenticate)
mock_validate_looker_release_version = Mock(
spec=LookerClient.validate_looker_release_version
)
mock_validate_looker_release_version.return_value = True
monkeypatch.setattr(LookerClient, "authenticate", mock_authenticate)
monkeypatch.setattr(
LookerClient,
"validate_looker_release_version",
mock_validate_looker_release_version,
)
return LookerClient(TEST_BASE_URL, TEST_CLIENT_ID, TEST_CLIENT_SECRET)


Expand Down