Skip to content

Commit 67f9a4b

Browse files
authored
Merge branch 'main' into fix/222-update-environment-details
2 parents 92a80f1 + 24db6d6 commit 67f9a4b

38 files changed

Lines changed: 2641 additions & 54 deletions

.devcontainer/Dockerfile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM mcr.microsoft.com/devcontainers/python:1-3.12-bookworm
2+
3+
ARG POETRY_VERSION=2.0.1
4+
5+
ENV TZ=Etc/UTC \
6+
POETRY_HOME=/opt/poetry \
7+
VIRTUAL_ENV=/home/vscode/.venv \
8+
POETRY_VIRTUALENVS_CREATE=false
9+
ENV PATH="${VIRTUAL_ENV}/bin:${POETRY_HOME}/bin:${PATH}"
10+
11+
RUN python -m venv "${POETRY_HOME}" \
12+
&& "${POETRY_HOME}/bin/python" -m pip install --no-cache-dir \
13+
"poetry==${POETRY_VERSION}" \
14+
&& python -m venv "${VIRTUAL_ENV}" \
15+
&& chown -R vscode:vscode "${VIRTUAL_ENV}"

.devcontainer/devcontainer.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "cwms-cli",
3+
"build": {
4+
"dockerfile": "Dockerfile",
5+
"args": {
6+
"POETRY_VERSION": "2.0.1"
7+
}
8+
},
9+
"remoteUser": "vscode",
10+
"containerEnv": {
11+
"TZ": "Etc/UTC",
12+
"POETRY_HOME": "/opt/poetry",
13+
"VIRTUAL_ENV": "/home/vscode/.venv",
14+
"POETRY_VIRTUALENVS_CREATE": "false"
15+
},
16+
"postCreateCommand": "git config --global --add safe.directory \"$(pwd)\" && poetry install --with dev --no-interaction",
17+
"customizations": {
18+
"vscode": {
19+
"extensions": [
20+
"ms-python.python"
21+
],
22+
"settings": {
23+
"python.defaultInterpreterPath": "/home/vscode/.venv/bin/python"
24+
}
25+
}
26+
}
27+
}

.github/ISSUE_TEMPLATE/bug-report.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ body:
88
label: CLI Script
99
description: Select the script this pertains to
1010
options:
11-
- blob
12-
- cwms-cli
13-
- csv2cwms
14-
- getusgs-measurements
11+
- blob
12+
- cwms-cli
13+
- csv2cwms
14+
- dss
15+
- getusgs-measurements
1516
- getusgs-ratings
1617
- getusgs-timeseries
1718
- shefcritimport

.github/ISSUE_TEMPLATE/feature-request.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ body:
88
label: CLI Script
99
description: Select the script this pertains to
1010
options:
11-
- blob
12-
- cwms-cli
13-
- csv2cwms
14-
- getusgs-measurements
11+
- blob
12+
- cwms-cli
13+
- csv2cwms
14+
- dss
15+
- getusgs-measurements
1516
- getusgs-ratings
1617
- getusgs-timeseries
1718
- shefcritimport

.github/workflows/cli-tests.yml

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,27 @@ on:
66

77
jobs:
88
test:
9-
name: Test CLI on ${{ matrix.python-version }}
10-
runs-on: ubuntu-latest
9+
name: Test CLI on ${{ matrix.name }} with Python ${{ matrix.python-version }}
10+
runs-on: ${{ matrix.os }}
1111

1212
strategy:
13+
fail-fast: false
1314
matrix:
14-
# Test 3.9 for T7, 3.12 for general/cloud use
15-
python-version: ["3.9", "3.12"]
15+
include:
16+
# Test the supported Python range on Linux and exercise the primary
17+
# Python version on each supported desktop operating system.
18+
- name: Linux
19+
os: ubuntu-latest
20+
python-version: "3.9"
21+
- name: Linux
22+
os: ubuntu-latest
23+
python-version: "3.12"
24+
- name: Windows
25+
os: windows-latest
26+
python-version: "3.12"
27+
- name: macOS
28+
os: macos-latest
29+
python-version: "3.12"
1630

1731
steps:
1832
- name: Checkout repository
@@ -38,3 +52,17 @@ jobs:
3852

3953
- name: Run full test suite
4054
run: poetry run pytest -q
55+
56+
test-devcontainer:
57+
name: Test dev container on 3.12
58+
runs-on: ubuntu-latest
59+
60+
steps:
61+
- name: Checkout repository
62+
uses: actions/checkout@v7
63+
64+
- name: Build dev container and run tests
65+
uses: devcontainers/ci@v0.3
66+
with:
67+
push: never
68+
runCmd: poetry run pytest -q

.github/workflows/release-please.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ jobs:
7070
uses: pypa/gh-action-pypi-publish@release/v1
7171

7272
- name: Sign Distribution
73-
uses: sigstore/gh-action-sigstore-python@v3.4.0
73+
uses: sigstore/gh-action-sigstore-python@v3.5.0
7474
with:
7575
inputs: |
7676
./dist/*.tar.gz

AGENTS.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Repository instructions
2+
3+
Guidance for coding agents working in `HydrologicEngineeringCenter/cwms-cli`.
4+
5+
- Never push to `origin` unless the user explicitly says they are ready for
6+
that push.
7+
- Use JDK 21 or newer for new work that is not intended to run on T7 systems.
8+
On Windows, use JDK 21 at `C:\Program Files\Java\jdk-21`. On Linux or other
9+
Unix-like systems, select an installed JDK 21 or newer through `JAVA_HOME`.
10+
Use another Java version only when the target or task requires it.
11+
- Use the `.devcontainer` Linux/Python 3.12 environment for changes involving
12+
time zones, paths, native libraries, HEC-DSS, or other operating-system-
13+
dependent behavior.
14+
- Run the full dev-container test suite with
15+
`devcontainer exec --workspace-folder . poetry run pytest -q` when the dev
16+
container is available. The standard CI matrix separately covers Python 3.9
17+
and Python 3.12 package compatibility.
18+
19+
## Terminal colors
20+
21+
- Use the shared helpers in `cwmscli.utils.colors` for user-facing terminal
22+
color. Prefer `colors.ok`, `colors.warn`, `colors.err`, and `colors.dim` for
23+
their semantic cases, or `colors.c(text, color, bright=...)` when a specific
24+
color is needed.
25+
- Do not embed ANSI escape sequences or initialize Colorama in individual
26+
commands. Global logging setup owns Colorama initialization and calls
27+
`colors.set_enabled(...)` so `--no-color`, `--log-file`, and non-TTY output
28+
remain consistent.
29+
- Keep the text meaningful without color. Color should clarify status or
30+
structure, not carry information that disappears when color is disabled.
31+
- Reuse the existing conventions: green for success, yellow for warnings,
32+
red for errors, cyan or blue for identifiers and commands, and dim text for
33+
secondary detail.
34+
- When testing colored output, cover the plain-text behavior first. Enable the
35+
shared color helper explicitly only in tests that need to assert escape codes,
36+
and restore its state afterward.

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,21 @@ from cwmscli.usgs.getusgs_cda import getusgs_cda
4646
from cwmscli.usgs.getusgs_measurements_cda import getusgs_measurements_cda
4747
from cwmscli.usgs.getUSGS_ratings_cda import getusgs_rating_cda
4848
```
49+
50+
## Development environment
51+
52+
The repository includes a Linux/Python 3.12 development container exercised by
53+
a dedicated CI job. Open the repository with the VS Code Dev Containers
54+
extension, or use the Dev Container CLI:
55+
56+
```sh
57+
devcontainer up --workspace-folder .
58+
devcontainer exec --workspace-folder . poetry run pytest -q
59+
```
60+
61+
The container installs project dependencies with Poetry and uses
62+
`/home/vscode/.venv`, so it does not reuse a host operating system's `.venv`.
63+
Poetry itself is kept in a separate `/opt/poetry` environment. Use the container
64+
for changes involving time zones, paths, native libraries, or other
65+
operating-system-dependent behavior. Standard Python 3.9 and Python 3.12
66+
installations remain covered by the existing CI matrix.

cwmscli/__main__.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@
77
from click.core import ParameterSource
88

99
from cwmscli.commands import commands_cwms
10+
from cwmscli.dss import dss_group
1011
from cwmscli.load import __main__ as load
1112
from cwmscli.usgs import usgs_group
1213
from cwmscli.utils.click_help import add_version_to_help_tree
13-
from cwmscli.utils.friendly_errors import to_user_facing_error
14+
from cwmscli.utils.friendly_errors import (
15+
cda_stack_trace,
16+
format_cda_stack_trace,
17+
to_user_facing_error,
18+
)
19+
from cwmscli.utils.links import BUG_REPORT_URL
1420
from cwmscli.utils.logging import (
1521
LoggingConfig,
1622
apply_logging_policies,
@@ -89,6 +95,7 @@ def cli(
8995
cli.add_command(commands_cwms.clob_group)
9096
cli.add_command(commands_cwms.users_group)
9197
cli.add_command(load.load_group)
98+
cli.add_command(dss_group)
9299
add_version_to_help_tree(cli)
93100

94101

@@ -111,9 +118,19 @@ def main() -> None:
111118
except SystemExit:
112119
raise
113120
except click.ClickException as e:
121+
debug = debug or logging.getLogger().isEnabledFor(logging.DEBUG)
122+
if debug:
123+
server_stack_trace = cda_stack_trace(e)
124+
if server_stack_trace is not None:
125+
click.echo(format_cda_stack_trace(server_stack_trace), err=True)
126+
raise SystemExit(e.exit_code)
114127
e.show()
115128
raise SystemExit(e.exit_code)
116129
except Exception as e:
130+
# The environment switch supports failures before Click configures logging.
131+
# Once CLI setup has run, --log-level DEBUG enables the same behavior.
132+
debug = debug or logging.getLogger().isEnabledFor(logging.DEBUG)
133+
117134
if is_cert_verify_error(e) and not debug:
118135
# Keep this short, no stack trace.
119136
logging.error(
@@ -122,14 +139,21 @@ def main() -> None:
122139
click.echo(ssl_help_text(), err=True)
123140
raise SystemExit(2)
124141

125-
if not debug:
142+
if debug:
143+
server_stack_trace = cda_stack_trace(e)
144+
if server_stack_trace is not None:
145+
click.echo(format_cda_stack_trace(server_stack_trace), err=True)
146+
raise SystemExit(1)
147+
else:
126148
friendly_error = to_user_facing_error(e)
127149
if friendly_error is not None:
128150
logging.debug("Suppressed traceback for CLI exception", exc_info=e)
129151
friendly_error.show()
130152
raise SystemExit(friendly_error.exit_code)
131153

132-
# If debug is enabled (or it's not a cert verify error), keep the normal failure behavior.
154+
click.echo(f"Unexpected error. Report it at {BUG_REPORT_URL}", err=True)
155+
# Preserve raw exception behavior when CDA did not provide a server stack
156+
# trace so an issue report includes useful diagnostic details.
133157
raise
134158

135159

cwmscli/dss/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""Batch transfers between HEC-DSS files and CWMS Data API instances."""
2+
3+
from cwmscli.dss.cli import dss_group
4+
5+
__all__ = ["dss_group"]

0 commit comments

Comments
 (0)