Skip to content

Commit 66f84ae

Browse files
committed
chore: first pass adding warnings. Includes .envrc uv fix
1 parent 47eefaa commit 66f84ae

File tree

4 files changed

+108
-5
lines changed

4 files changed

+108
-5
lines changed

.envrc

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,22 @@ if [ -d ".venv" ]; then
1818
fi
1919
fi
2020

21-
python -m uv venv .venv --python $PYTHON_VERSION
22-
python -m uv pip install -U pip uv
23-
python -m uv pip install -e .
21+
if [ ! -d ".venv" ]
22+
then
23+
# System python doesn't like us installing packages into it
24+
# Test if uv is already installed (via brew or other package manager etc.)
25+
# and use that if available. Otherwise fall back to previous behvaiour
26+
if command -v uv
27+
then
28+
uv venv .venv --python $PYTHON_VERSION
29+
uv pip install -U pip uv
30+
uv pip install -e .
31+
else
32+
python -m uv venv .venv --python $PYTHON_VERSION
33+
python -m uv pip install -U pip uv
34+
python -m uv pip install -e .
35+
fi
36+
fi
2437

2538
source ./.venv/bin/activate
2639

cloudsmith_cli/cli/commands/repos.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def print_repositories(opts, data, page_info=None, show_list_info=True):
6060
@decorators.common_cli_output_options
6161
@decorators.common_api_auth_options
6262
@decorators.initialise_api
63+
@decorators.verify_authenticated
6364
@click.pass_context
6465
def repositories(ctx, opts): # pylink: disable=unused-argument
6566
"""
@@ -101,6 +102,9 @@ def get(ctx, opts, owner_repo, page, page_size):
101102

102103
click.echo("Getting list of repositories ... ", nl=False, err=use_stderr)
103104

105+
repo = None
106+
owner = None
107+
104108
if isinstance(owner_repo, list):
105109
if len(owner_repo) == 1:
106110
owner = owner_repo[0]

cloudsmith_cli/cli/config.py

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class ConfigReader(ConfigFileReader):
7777
config_name = "standard"
7878
config_searchpath = list(_CFG_SEARCH_PATHS)
7979
config_section_schemas = [ConfigSchema.Default, ConfigSchema.Profile]
80+
config_warning_issued = False
8081

8182
@classmethod
8283
def select_config_schema_for(cls, section_name):
@@ -147,6 +148,19 @@ def has_default_file(cls):
147148

148149
return False
149150

151+
@classmethod
152+
def config_already_warned(cls):
153+
"""
154+
Check if a configuration file warning has been issued.
155+
This is required as configs are gathered at the root of the
156+
command chain as well as for command verbs
157+
"""
158+
if cls.config_warning_issued:
159+
return True
160+
161+
cls.config_warning_issued = True
162+
return False
163+
150164
@classmethod
151165
def load_config(cls, opts, path=None, profile=None):
152166
"""Load a configuration file into an options object."""
@@ -161,8 +175,32 @@ def load_config(cls, opts, path=None, profile=None):
161175
cls._load_values_into_opts(opts, values)
162176

163177
if profile and profile != "default":
164-
values = config.get("profile:%s" % profile, {})
165-
cls._load_values_into_opts(opts, values)
178+
try:
179+
values = config["profile:%s" % profile]
180+
cls._load_values_into_opts(opts, values)
181+
except KeyError:
182+
click.secho(
183+
f"Warning: profile {profile} not found in config files {cls.config_files}",
184+
fg="yellow",
185+
)
186+
187+
existing_config_paths = {
188+
path: os.path.exists(path) for path in cls.config_files
189+
}
190+
if not any(existing_config_paths.values()) and not cls.config_already_warned():
191+
click.secho(
192+
"Warning: No config files found in search paths. Tried the following:",
193+
fg="yellow",
194+
)
195+
for tested_path, exists in existing_config_paths.items():
196+
if exists:
197+
click.secho(f"{tested_path} - file exists", fg="green")
198+
else:
199+
click.secho(f"{tested_path} - file does not exist", fg="yellow")
200+
click.secho(
201+
"You may need to run `cloudsmith login` to authenticate and create a config file.",
202+
fg="yellow",
203+
)
166204

167205
return values
168206

@@ -206,6 +244,29 @@ class CredentialsReader(ConfigReader):
206244
config_searchpath = list(_CFG_SEARCH_PATHS)
207245
config_section_schemas = [CredentialsSchema.Default, CredentialsSchema.Profile]
208246

247+
@classmethod
248+
def load_config(cls, opts, path=None, profile=None):
249+
"""
250+
Load a credentials configuration file into an options object.
251+
We overload the load_config command in CredentialsReader as
252+
credentials files have their own specific default functionality.
253+
"""
254+
if path and os.path.exists(path):
255+
if os.path.isdir(path):
256+
cls.config_searchpath.insert(0, path)
257+
else:
258+
cls.config_files.insert(0, path)
259+
260+
config = cls.read_config()
261+
values = config.get("default", {})
262+
cls._load_values_into_opts(opts, values)
263+
264+
if profile and profile != "default":
265+
values = config.get("profile:%s" % profile, {})
266+
cls._load_values_into_opts(opts, values)
267+
268+
return values
269+
209270

210271
class Options:
211272
"""Options object that holds config for the application."""

cloudsmith_cli/cli/decorators.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import click
66

77
from ..core.api.init import initialise_api as _initialise_api
8+
from ..core.api.user import get_user_brief
89
from . import config, utils, validators
910

1011

@@ -309,3 +310,27 @@ def call_print_rate_limit_info_with_opts(rate_info):
309310
return ctx.invoke(f, *args, **kwargs)
310311

311312
return wrapper
313+
314+
315+
def verify_authenticated(f):
316+
"""Verify that the user is authenticated and warn if not."""
317+
318+
@click.pass_context
319+
@functools.wraps(f)
320+
def wrapper(ctx, *args, **kwargs):
321+
cloudsmith_host = kwargs["opts"].opts["api_config"].host
322+
is_auth, _, _, _ = get_user_brief()
323+
if not is_auth:
324+
click.secho(
325+
"Warning: You are not authenticated with the API. "
326+
"Please verify your config files, API key and "
327+
"run `cloudsmith login` if necessary to authenticate.",
328+
fg="yellow",
329+
)
330+
click.secho(
331+
f"You're currently attemping to connect to Cloudsmith instance {cloudsmith_host}",
332+
fg="yellow",
333+
)
334+
return ctx.invoke(f, *args, **kwargs)
335+
336+
return wrapper

0 commit comments

Comments
 (0)