Skip to content

Conversation

@DiegoDAF
Copy link

@DiegoDAF DiegoDAF commented Dec 2, 2025

Summary

This PR adds four major enhancements to pgcli:

  • Multiple -c/--command support: Execute multiple SQL commands sequentially from command line
  • -f/--file option: Execute SQL commands from one or more files
  • -y/--yes flag: Bypass confirmation prompts for destructive operations
  • .pgpass support with SSH tunnels: Properly use .pgpass authentication when connecting through SSH tunnels

Motivation

These features improve pgcli's scriptability and automation capabilities:

  • Multiple -c flags allow complex command sequences without temp files
  • -f flag enables SQL script execution similar to psql
  • -y flag removes interactive prompts for CI/CD pipelines
  • .pgpass SSH tunnel support fixes authentication issues when using tunnels

Changes

1. Multiple -c/--command parameters (PR #1530)

  • Modified main.py to accept multiple -c options
  • Commands execute sequentially
  • Exit after all commands complete
  • Full test coverage with behave tests

2. -f/--file option (PR #1531)

  • Added --file option to execute SQL from files
  • Supports multiple -f options
  • Compatible with -c flag (files execute after commands)
  • Comprehensive test suite included

3. -y/--yes flag (PR #1533)

  • Added --yes flag to force destructive commands
  • Skips confirmation prompts for DROP, TRUNCATE, etc.
  • Essential for automated scripts
  • Tested with behave feature tests

4. .pgpass SSH tunnel support (PR #1534)

  • Fixed issue where SSH tunnels broke .pgpass lookup
  • Uses PostgreSQL's host + hostaddr parameters correctly
  • host preserves original hostname for .pgpass
  • hostaddr uses 127.0.0.1 for actual connection
  • Updated pgexecute.py to support hostaddr parameter
  • All existing tests pass (2551 passed, 119 skipped)

Test Plan

All features include comprehensive tests:

  • ✅ Unit tests in tests/test_main.py
  • ✅ Behave integration tests for each feature
  • ✅ SSH tunnel tests in tests/test_ssh_tunnel.py
  • ✅ All existing tests continue to pass

Files Modified

  • pgcli/main.py: CLI argument parsing and execution logic
  • pgcli/pgexecute.py: SSH tunnel connection handling
  • tests/: Comprehensive test coverage for all features
  • changelog.rst: Documented changes
  • pyproject.toml: Updated dependencies

Version

Bumped to 4.3.4

🤖 Generated with Claude Code

diego-feito-stori and others added 15 commits November 19, 2025 16:19
   Implements the -f/--file command-line option similar to psql's behavior.
   This allows executing SQL commands from a file and then exiting.

   Features:
   - Support for -f and --file (short and long forms)
   - Multiple files can be specified (-f file1 -f file2)
   - Can be combined with -c option (-c commands execute first, then -f files)
   - Pager is disabled in file mode (consistent with -c behavior)
   - Comprehensive BDD tests added for all scenarios
   - Version bumped to 4.3.1
When using SSH tunnels, PostgreSQL's .pgpass file was not being used
because the connection was using '127.0.0.1' as the hostname instead
of the original database hostname.

This change preserves the original hostname using PostgreSQL's host/
hostaddr parameters:
- host: original database hostname (used for .pgpass lookup and SSL)
- hostaddr: 127.0.0.1 (actual connection endpoint via SSH tunnel)

Additionally:
- Fix connect_uri() to pass DSN parameter for proper .pgpass handling
- Add paramiko version constraint to avoid DSSKey compatibility issues
- Add SSH tunnel configuration options (ssh_config_file, allow_agent)
- Preserve hostaddr parameter when using DSN connections
- Add comprehensive test coverage for .pgpass + SSH tunnel scenarios

Fixes: SSH tunnel connections now work seamlessly with .pgpass files
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@DiegoDAF DiegoDAF marked this pull request as ready for review December 2, 2025 16:48
DiegoDAF and others added 8 commits December 2, 2025 14:53
This commit implements a new --tuples-only option similar to psql's -t flag,
which prints query results without status messages or timing information.

Features:
- `-t` or `--tuples-only` without value defaults to csv-noheader format
- `-t <format>` allows specifying any table format (e.g., `-t minimal`)
- Suppresses "SELECT X" status messages when enabled
- Suppresses "Time: X.XXXs" timing output when enabled
- Does not affect normal output when option is not used

Documentation improvements:
- Added missing table formats to pgclirc config file comments:
  - csv-noheader (CSV without headers)
  - tsv_noheader (TSV without headers)
  - csv-tab-noheader (same as tsv_noheader)
  - minimal (aligned columns without headers or borders)

Implementation details:
- Added tuples_only parameter to PGCli.__init__()
- Added tuples_only field to OutputSettings namedtuple
- Modified format_output() to skip status when tuples_only is True
- Modified timing output logic to skip when tuples_only is True
- All existing tests pass without modifications

Example usage:
  pgcli -t -c "SELECT oid FROM pg_roles WHERE rolname='user';"
  # Output: 2124219 (nothing else)

  pgcli -t minimal -c "SELECT oid, rolname FROM pg_roles LIMIT 3;"
  # Output: aligned columns without headers

Made with ❤️ and 🤖 Claude Code
Created comprehensive behavioral tests for the -t/--tuples-only feature:

Tests cover:
- Basic -t flag usage (default csv-noheader)
- Long form --tuples-only
- Custom format specification (-t minimal, -t tsv_noheader)
- Verification that status messages are suppressed
- Verification that timing info is suppressed
- Normal mode comparison (without -t)
- Multiple rows handling
- Special commands with -t

Test files:
- tests/features/tuples_only.feature: 7 test scenarios
- tests/features/steps/tuples_only.py: Step implementations

Run tests with:
  cd tests && behave features/tuples_only.feature

Made with ❤️ and 🤖 Claude Code

Co-Authored-By: Claude <[email protected]>
Changes:
- Removed duplicate step definitions in tuples_only.py that already exist
  in command_option.py to avoid AmbiguousStep errors
- Updated version from 4.3.4 to 4.3.5

All BDD tests passing: 7 scenarios, 32 steps ✓

Made with ❤️ and 🤖 Claude Code

Co-Authored-By: Claude <[email protected]>
Added to Upcoming (TBD) section:
- New tuples-only option feature description
- Documentation section for newly documented table formats

Made with ❤️ and 🤖 Claude Code

Co-Authored-By: Claude <[email protected]>
When using the --yes flag to auto-confirm destructive commands,
pgcli should not display the "Your call!" message since no user
interaction occurred. This message is now only shown when the user
manually confirms the destructive warning prompt.

Changes:
- Modified pgcli/main.py to only show "Your call!" when user manually confirms
- Updated tests in tests/features/steps/force_yes.py to verify the message is suppressed
- Bumped version to 4.3.6
- Updated changelog.rst with bug fix entry

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…-only-option

# Conflicts:
#	pgcli/__init__.py
Improvements to logging system:
- Implement automatic daily log rotation at midnight
- Keep 30 days of log history
- Change default log location to /var/log/pgcli/pgcli.log
- Automatic fallback to ~/.config/pgcli/log if no system permissions
- Use TimedRotatingFileHandler for better log management
- Log files formatted as: pgcli.log.YYYY-MM-DD

Changes:
- pgcli/main.py: Added logging.handlers import and updated initialize_logging()
- pgcli/pgclirc: Updated documentation for new log behavior
- pgcli/__init__.py: Bumped version to 4.3.7
- changelog.rst: Added Internal section entry

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Changed the log file rotation format from pgcli.log.YYYY-MM-DD
to pgcli.YYYY-MM-DD.log for better file naming conventions.

Changes:
- pgcli/main.py: Updated suffix format and added logic to strip .log extension
- pgcli/pgclirc: Updated documentation to reflect new format

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@then("we see the command output")
def step_see_command_output(context):
"""Verify that the special command output is present."""
output = context.cmd_output.decode('utf-8')

Check notice

Code scanning / CodeQL

Unused local variable Note test

Variable output is not used.
# Should contain indicators from both commands
assert output.count("ALTER TABLE") >= 2, \
f"Expected indicators from both ALTER TABLE commands, but got: {output}"

Check notice

Code scanning / CodeQL

Unused local variable Note test

Variable output is not used.
@dbaty
Copy link
Member

dbaty commented Dec 5, 2025

Thanks for your contribution. This pull request has many unsquashed commits and implement multiple features. Would you mind breaking it into multiple pull requests (one per feature)? That would be easier to review (and, possibly, comment and enhance).

@DiegoDAF
Copy link
Author

DiegoDAF commented Dec 5, 2025

Yes, you are right, I will close this PR (and the over, and I will send it again!
I made a disaster.

Sorry & Thank you!

@DiegoDAF DiegoDAF closed this Dec 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants