sym-cli
Advanced tools
+1
-1
| Metadata-Version: 2.1 | ||
| Name: sym-cli | ||
| Version: 0.5.0 | ||
| Version: 0.5.1 | ||
| Summary: Sym's Official CLI for Users | ||
@@ -5,0 +5,0 @@ Home-page: https://symops.com/ |
+1
-1
| [tool.poetry] | ||
| name = "sym-cli" | ||
| version = "0.5.0" | ||
| version = "0.5.1" | ||
| description = "Sym's Official CLI for Users" | ||
@@ -5,0 +5,0 @@ authors = ["SymOps, Inc. <pypi@symops.io>"] |
+12
-10
@@ -34,13 +34,15 @@ import json | ||
| def boto_client(saml_client, service): | ||
| # For the AwsConfig SAML Client, we want to continue to use | ||
| # the boto session that has the aws profile name configured in it | ||
| # there could be more better ways to do this if necessary in the future | ||
| if hasattr(saml_client, "boto_session"): | ||
| return saml_client.boto_session.client(service) | ||
| creds = saml_client.get_creds() | ||
| if access_key_id := creds.get("AWS_ACCESS_KEY_ID"): | ||
| return boto3.client( | ||
| service, | ||
| config=BotoConfig(region_name=get_region(saml_client, creds)), | ||
| aws_access_key_id=access_key_id, | ||
| aws_secret_access_key=creds["AWS_SECRET_ACCESS_KEY"], | ||
| aws_session_token=creds.get("AWS_SESSION_TOKEN"), | ||
| ) | ||
| # If there is no access key id, then assume that the boto3 default session is set up | ||
| return boto3.client(service) | ||
| return boto3.client( | ||
| service, | ||
| region_name=get_region(saml_client, creds), | ||
| aws_access_key_id=creds["AWS_ACCESS_KEY_ID"], | ||
| aws_secret_access_key=creds["AWS_SECRET_ACCESS_KEY"], | ||
| aws_session_token=creds.get("AWS_SESSION_TOKEN"), | ||
| ) | ||
@@ -47,0 +49,0 @@ |
@@ -7,3 +7,3 @@ import os | ||
| from boto3 import setup_default_session | ||
| from boto3.session import Session | ||
| from sym.shared.cli.helpers.contexts import push_env | ||
@@ -32,8 +32,8 @@ from sym.shared.cli.helpers.keywords_to_options import Argument | ||
| options: "GlobalOptions" | ||
| boto_session: Session | ||
| def __init__(self, resource: str, *, options: "GlobalOptions") -> None: | ||
| super().__init__(resource, options=options) | ||
| # Make the default session use our AWS profile so we don't need to manage sessions in | ||
| # whatever other call chains there are to get AWS creds | ||
| setup_default_session(profile_name=resource) | ||
| self.raise_if_invalid() | ||
| self.boto_session = Session(profile_name=self.resource) | ||
@@ -71,3 +71,8 @@ @classmethod | ||
| def get_creds(self): | ||
| return {} | ||
| creds = self.boto_session.get_credentials().get_frozen_credentials() | ||
| return { | ||
| "AWS_ACCESS_KEY_ID": creds.access_key, | ||
| "AWS_SECRET_ACCESS_KEY": creds.secret_key, | ||
| "AWS_SESSION_TOKEN": creds.token, | ||
| } | ||
@@ -74,0 +79,0 @@ @intercept_errors() |
@@ -1,1 +0,1 @@ | ||
| __version__ = '0.5.0' | ||
| __version__ = '0.5.1' |
| import json | ||
| import os | ||
| from contextlib import ExitStack | ||
| from pathlib import Path | ||
| from typing import Iterator | ||
| from unittest.mock import MagicMock, patch | ||
| import pytest | ||
| import responses | ||
| from freezegun import freeze_time | ||
| from semver import VersionInfo | ||
| from sym.shared.cli.helpers.updater import SymUpdater | ||
| CURRENT_ISH_VERSION = VersionInfo.parse("0.2.7") | ||
| @pytest.fixture | ||
| def time_travel() -> Iterator: | ||
| with patch("yaml.safe_dump"): # YAML can't serialize FakeDatetimes | ||
| with freeze_time() as time: | ||
| yield time | ||
| @pytest.fixture | ||
| def pypi_response(): | ||
| def responder(name) -> dict: | ||
| return json.load((Path(__file__).parent / "responses" / f"{name}.json").open()) | ||
| return responder | ||
| @pytest.fixture | ||
| def http_mock(pypi_response) -> Iterator: | ||
| with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps: | ||
| if os.getenv("CI"): | ||
| rsps.add_passthru("http") # make real requests on CI | ||
| else: | ||
| rsps.add( | ||
| responses.GET, | ||
| "https://pypi.org/pypi/sym-cli/json", | ||
| json=pypi_response("sym-cli"), | ||
| ) | ||
| rsps.add( | ||
| responses.GET, | ||
| f"https://pypi.org/pypi/sym-cli/{CURRENT_ISH_VERSION}/json", | ||
| json=pypi_response("sym-cli-0.2.7"), | ||
| ) | ||
| yield rsps | ||
| @pytest.fixture | ||
| def updater(sandbox, http_mock) -> Iterator[SymUpdater]: | ||
| with ExitStack() as stack: | ||
| stack.enter_context(sandbox.push_home()) | ||
| stack.enter_context(sandbox.push_xdg_config_home()) | ||
| stack.enter_context(sandbox.push_exec_path()) | ||
| updater = MagicMock(wraps=SymUpdater)() | ||
| updater._env_is_local = lambda: False | ||
| yield updater | ||
| @pytest.fixture | ||
| def other_updater(sandbox, updater) -> SymUpdater: | ||
| updater.dir = sandbox.create_dir("my-sym-cli") | ||
| return updater | ||
| @pytest.fixture | ||
| def sitepackage_updater(sandbox, updater) -> SymUpdater: | ||
| root = Path() / "foo" | ||
| sandbox.create_binary(root / "bin" / "pip") | ||
| updater.dir = sandbox.create_dir(root / "lib" / "python3.8" / "site-packages") | ||
| return updater | ||
| @pytest.fixture | ||
| def pipx_updater(sandbox, updater) -> SymUpdater: | ||
| sandbox.create_binary("bin/pipx") | ||
| updater.is_local = MagicMock(return_value=False) | ||
| updater.dir = ( | ||
| sandbox.path | ||
| / "home" | ||
| / ".local" | ||
| / "pipx" | ||
| / "venvs" | ||
| / "sym-cli" | ||
| / "lib" | ||
| / "python3.8" | ||
| / "site-packages" | ||
| ) | ||
| return updater | ||
| @pytest.fixture | ||
| def brew_updater(sandbox, updater) -> SymUpdater: | ||
| sandbox.create_binary("bin/brew") | ||
| sandbox.create_binary("bin/git") | ||
| updater.is_local = MagicMock(return_value=False) | ||
| updater.dir = ( | ||
| Path("/") | ||
| / "usr" | ||
| / "local" | ||
| / "Cellar" | ||
| / "sym-cli" | ||
| / "0.0.0" | ||
| / "libexec" | ||
| / "lib" | ||
| / "python3.8" | ||
| / "site-packages" | ||
| ) | ||
| return updater |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| import datetime | ||
| import os | ||
| import re | ||
| from pathlib import Path | ||
| from unittest.mock import MagicMock | ||
| import pytest | ||
| from semver import VersionInfo | ||
| from sym.shared.cli.helpers.updater import FAIL_LOG_PATH | ||
| from sym.cli.helpers.config import Config, SymConfigFile | ||
| V1 = VersionInfo.parse("0.0.1") | ||
| def test_pipx_path(pipx_updater): | ||
| assert pipx_updater.is_pipx() == True | ||
| def test_sitepackage_path(sitepackage_updater): | ||
| assert sitepackage_updater.is_sitepackage() == True | ||
| def test_brew_path(brew_updater): | ||
| assert brew_updater.is_brew() == True | ||
| def test_local_if_v0(updater): | ||
| updater.dir = Path("/foo/bar") | ||
| assert updater.is_local() == True | ||
| updater.get_current_version = MagicMock(return_value=V1) | ||
| assert updater.is_local() == False | ||
| def test_default_path(updater): | ||
| assert (updater.dir / "sym" / "cli").exists() == True | ||
| def test_noop_if_local(updater): | ||
| assert updater.is_local() == True | ||
| assert updater.should_check() == False | ||
| def test_no_manual_if_local(updater): | ||
| updater.update = MagicMock() | ||
| updater.manual_update() | ||
| updater.update.assert_not_called() | ||
| def test_checks_first_time(pipx_updater): | ||
| assert pipx_updater.should_check() == True | ||
| def test_checks_first_time_no_autoupdate(pipx_updater): | ||
| Config.instance()["autoupdate"] = "false" | ||
| assert pipx_updater.should_check() == False | ||
| def test_no_check_second_time(pipx_updater): | ||
| assert pipx_updater.should_check() == True | ||
| assert pipx_updater.should_check() == False | ||
| def test_check_after_a_day(pipx_updater, time_travel): | ||
| assert pipx_updater.should_check() == True | ||
| time_travel.tick(delta=datetime.timedelta(days=1)) | ||
| assert pipx_updater.should_check() == True | ||
| def test_get_version(updater): | ||
| assert updater.get_latest_version() is not None | ||
| assert updater.get_latest_version().major == 0 | ||
| assert updater.get_latest_version().minor >= 2 | ||
| def test_needs_update(pipx_updater): | ||
| pipx_updater.get_current_version = MagicMock(return_value=V1) | ||
| assert pipx_updater.needs_update() is True | ||
| def test_needs_no_update(pipx_updater): | ||
| pipx_updater.get_current_version = MagicMock(return_value=V1) | ||
| pipx_updater.get_latest_version = MagicMock(return_value=V1) | ||
| assert pipx_updater.needs_update() is False | ||
| def test_failed_fetch(pipx_updater): | ||
| pipx_updater.get_latest_version = MagicMock(return_value=None) | ||
| assert pipx_updater.needs_update() is False | ||
| def test_update_sitepackage(sitepackage_updater, capture_command): | ||
| with capture_command(): | ||
| assert sitepackage_updater._update() == True | ||
| capture_command.assert_command(re.compile(r"pip install -U sym-cli")) | ||
| def test_update_sitepackage_failed(sitepackage_updater, capture_command): | ||
| capture_command.register_output("pip", "", exit_code=1) | ||
| with capture_command(): | ||
| assert sitepackage_updater._update() == False | ||
| def test_update_pipx(pipx_updater, capture_command): | ||
| with capture_command(): | ||
| assert pipx_updater._update() == True | ||
| capture_command.assert_command(["pipx", "upgrade", "sym-cli"]) | ||
| def test_update_pipx_failed(pipx_updater, capture_command): | ||
| capture_command.register_output("pipx", "", exit_code=1) | ||
| with capture_command(): | ||
| assert pipx_updater._update() == False | ||
| def test_update_brew(brew_updater, capture_command): | ||
| capture_command.register_output(r"brew --repo", "/foo/bar") | ||
| with capture_command(): | ||
| brew_updater.latest_version = V1 | ||
| assert brew_updater._update() == True | ||
| capture_command.assert_command( | ||
| ["brew", "--repo", "symopsio/tap"], | ||
| ["git", "pull", "origin", "master"], | ||
| ["brew", "install", "sym@0.0.1"], | ||
| ["brew", "link", "sym@0.0.1"], | ||
| ) | ||
| def test_update_brew_failed(brew_updater, capture_command): | ||
| capture_command.register_output("brew", "", exit_code=1) | ||
| with capture_command(): | ||
| assert brew_updater._update() == False | ||
| def test_update_brew_failed_debug(brew_updater, capture_command, capsys): | ||
| capture_command.register_output("brew", "an error!", exit_code=1) | ||
| with capture_command(): | ||
| brew_updater.debug = True | ||
| assert brew_updater._update() == False | ||
| assert "an error!" in capsys.readouterr().err | ||
| def test_update_brew_timeout(brew_updater, capture_command, capsys): | ||
| capture_command.register_output(r"brew --repo", "/foo/bar") | ||
| capture_command.register_output(r"brew install", "something slow...", timeout=True) | ||
| with capture_command(): | ||
| brew_updater.latest_version = V1 | ||
| brew_updater.debug = True | ||
| assert brew_updater._update() == False | ||
| capture_command.assert_command( | ||
| ["brew", "--repo", "symopsio/tap"], | ||
| ["git", "pull", "origin", "master"], | ||
| ["brew", "install", "sym@0.0.1"], | ||
| ["brew", "link", "sym"], | ||
| ) | ||
| config_file = SymConfigFile(file_name=FAIL_LOG_PATH, uid_scope=False) | ||
| assert str(config_file.path) in capsys.readouterr().err | ||
| assert "something slow..." in config_file.read() | ||
| @pytest.mark.skipif(not os.getenv("CI"), reason="skipping real requests locally") | ||
| def test_update_other(other_updater): | ||
| version = other_updater.get_latest_version() | ||
| assert other_updater._update() == True | ||
| assert (other_updater.dir / "sym").exists() == True | ||
| assert str(version) in (other_updater.dir / "sym" / "cli" / "version.py").read_text() |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
287874
-65.37%113
-4.24%7000
-66.17%