v1.0.0: Parallel requests, comprehensive CLI, and test suite#3
v1.0.0: Parallel requests, comprehensive CLI, and test suite#3danielmeint merged 13 commits intomainfrom
Conversation
- Add --concurrency CLI option (range 1-20, default 5) - Rewrite _perform_domain_operations() to use ThreadPoolExecutor - Add progress bar for parallel mode using click.progressbar() - Preserve verbose per-domain output in sequential mode (--concurrency 1) - Handle rate limits gracefully by stopping new submissions and reporting skipped domains - Print summary (completed/failed/skipped) after parallel operations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add `denylist list <profile_id>` command to show all denylist entries - Add `allowlist list <profile_id>` command to show all allowlist entries - Support --active-only and --inactive-only filters - Show inactive entries with "(inactive)" suffix - Display total count in summary Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Export command: - Add `denylist export` and `allowlist export` commands - Export to file or stdout (with -) - Support --active-only and --inactive-only filters Clear command: - Add `denylist clear` and `allowlist clear` commands - Remove all entries from a list - Require confirmation (skip with --yes/-y) Dry-run flag: - Add global --dry-run flag to show what would be done - Works with add, remove, import, and clear commands - Skips confirmation prompts in dry-run mode Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add _resolve_profile_id() helper that resolves profile name or ID - Support case-insensitive profile name matching - Cache profiles list in ctx.obj to avoid repeated API calls - Show helpful error with available profiles when not found - Update all commands to accept either profile name or ID Example usage: nextdnsctl denylist list "My Profile" nextdnsctl denylist list abc123 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Bump version to 0.3.0 - Update README with comprehensive documentation for new features: - Parallel API requests with --concurrency option - list, export, clear commands for denylist/allowlist - --dry-run flag for previewing changes - Profile name support (in addition to IDs) - Global options documentation - Improved command reference Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create generic API functions (get_domain_list, add_to_domain_list, remove_from_domain_list) that accept list_type parameter - Keep original functions as thin wrappers for backwards compatibility - Create shared command handlers (_handle_list_command, etc.) used by both denylist and allowlist commands - Fix USER_AGENT version mismatch (0.2.0 -> 0.3.0) - Net reduction of ~130 lines of duplicate code Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security: - Support NEXTDNS_API_KEY environment variable (priority over config file) - Set secure file permissions (600) on config file - Set secure directory permissions (700) on config directory Import improvements: - Stream file/URL content for memory efficiency with large files - Support inline comments (e.g., "example.com # reason") - Better comment and whitespace handling Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comprehensive type hints to all modules (api.py, config.py, nextdnsctl.py) - Use urllib.parse.urljoin for safer API URL construction - Import typing module for List, Dict, Optional, Callable, etc. - Improves IDE support and code documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement testing infrastructure based on test-strategy.md: - Add requirements-dev.txt for declarative dev dependencies - Create pytest fixtures in tests/conftest.py - Add unit tests for config and domain parsing - Add integration tests for CLI commands (profile, denylist, auth, import) - Add API resilience tests (retry, rate limiting, network errors) - Add concurrency validation tests - Replace lint.yml with test.yml (pytest + flake8, Python 3.10-3.12 matrix) 45 tests covering unit, integration, and edge case scenarios. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add types-requests stub to requirements-dev.txt - Handle None returns from api_call() in get_profiles/get_domain_list - Change function signatures to accept Sequence[str] instead of List[str] - Add explicit type annotations for list comprehensions and progressbar Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Define __version__ in nextdnsctl/__init__.py as canonical source - Import version in nextdnsctl.py and api.py instead of duplicating - Update setup.py to read version via regex (avoids import issues) - Update classifiers for 1.0: Production/Stable, Python 3.10+ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces nextdnsctl v1.0.0 with significant enhancements for production use, including parallel API requests, comprehensive CLI commands, profile name resolution, and a complete test suite.
Changes:
- Add parallel processing support with configurable concurrency (1-20 workers, default: 5)
- Expand CLI with
list,export, andclearcommands for both denylist and allowlist - Add profile name resolution, dry-run mode, and enhanced error handling
- Implement comprehensive test suite (45 tests) covering parsing, config, CLI, API resilience, and concurrency
- Add CI/CD workflow with Python 3.10/3.11/3.12 matrix testing
- Add full type hints and mypy compliance
Reviewed changes
Copilot reviewed 15 out of 24 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_parsing.py | Tests for domain line parsing logic with comments and whitespace handling |
| tests/test_config.py | Tests for API key storage, loading, and file permissions |
| tests/test_concurrency.py | Tests verifying parallel vs sequential execution modes |
| tests/test_cli_integration.py | Integration tests for CLI commands with mocked API |
| tests/test_api_resilience.py | Tests for retry logic, rate limiting, and network error handling |
| tests/conftest.py | Pytest fixtures for test setup and mocking |
| setup.py | Updated to read version dynamically and require Python 3.10+ |
| requirements-dev.txt | Development dependencies for testing and linting |
| nextdnsctl/nextdnsctl.py | Major refactor adding parallel execution, profile resolution, and new commands |
| nextdnsctl/config.py | Enhanced with environment variable support and secure file permissions |
| nextdnsctl/api.py | Refactored with generic domain list functions and improved URL handling |
| nextdnsctl/init.py | Centralized version definition (1.0.0) |
| README.md | Comprehensive documentation update with examples and workflows |
| .github/workflows/test.yml | New CI workflow with matrix testing across Python versions |
| .github/workflows/lint.yml | Removed (consolidated into test.yml) |
Files not reviewed (7)
- .idea/.gitignore: Language not supported
- .idea/inspectionProfiles/Project_Default.xml: Language not supported
- .idea/inspectionProfiles/profiles_settings.xml: Language not supported
- .idea/misc.xml: Language not supported
- .idea/modules.xml: Language not supported
- .idea/nextdnsctl.iml: Language not supported
- .idea/vcs.xml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from .config import load_api_key | ||
|
|
||
| API_BASE = "https://api.nextdns.io" | ||
| API_BASE = "https://api.nextdns.io/" |
There was a problem hiding this comment.
The trailing slash in API_BASE combined with endpoint.lstrip('/') in the urljoin call (line 37) means endpoints can be passed with or without leading slashes. While this works, it would be clearer to either consistently include or exclude the trailing slash and document the expected endpoint format to avoid confusion.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Summary
This release brings nextdnsctl to production-ready status with major new features:
--concurrencyoption (default: 5, max: 20) for bulk operationslist,export,clearfor both denylist and allowlistnextdnsctl denylist list "My Profile")--dry-runbefore applyingBreaking Changes
Commits included
Test plan
🤖 Generated with Claude Code
Note
Production-ready v1.0 with a revamped CLI, robust API client, and CI/test coverage.
--concurrency(with progress) and--dry-run; profile resolution by name or IDdenylist/allowlistsubcommands:list,export,clear(plus existing add/remove); streaming imports and improved parsing--retry-*and--timeoutNEXTDNS_API_KEYenv support and secure file perms; centralized version in__init__(1.0.0)requirements-dev.txt, GitHub Actions with Python 3.10–3.12 matrix; consolidated lintingsetup.pyreads version, requires Python ≥3.10; README expanded;.gitignorecleaned; removed IDE filesWritten by Cursor Bugbot for commit 1b4fb3e. This will update automatically on new commits. Configure here.