Skip to content

Commit c4127de

Browse files
authored
feat(cli): add CLI with CI convenience functions (#394)
* feat(cli): add CLI with CI convenience functions for NiFi automation - Add nipyapi CLI with 'ci' subcommand for NiFi CI/CD operations - Profile auto-resolution: switch() without args auto-detects env vars or profile file - CI functions: deploy_flow, start_flow, stop_flow, get_status, cleanup, configure_params - New functions: configure_inherited_params, purge_flowfiles, upload_asset - get_status defaults to root process group when no PG specified - Log control via NIFI_LOG_LEVEL and NIFI_LOG_ON_ERROR env vars - Suppress SSL warnings to keep CI output clean - Convert snake_case to kebab-case for GitHub Actions output format - resolve_git_ref to resolve tags/branches to SHAs * feat: add layout module, CLI enhancements, and improve test infrastructure Layout Module: - New nipyapi/layout.py with intelligent canvas positioning - Process group grid alignment (align_pg_grid, suggest_pg_position) - Flow layout functions (below, above, right_of, left_of, fork, new_flow) - Component movement with self-loop bend handling - Flow transposition and de-overlap capabilities - Spine/branch detection for flow restructuring (find_flow_spine, get_side_branches) - Automated flow layout (suggest_flow_layout) Canvas Enhancements: - get_flow_components() for graph traversal of connected components - Automatic bend calculation for self-loop connections - Bends parameter support in create_connection() CLI Improvements: - Expose layout functions via CLI (align_pg_grid, suggest_pg_position, etc.) - SafeModule wrapper for structured error handling - Custom serializer for formatted output Client Generation: - Add octet-stream handler to rest.mustache template - Regenerate NiFi and Registry clients with binary upload support Profile System: - Fix get_default_profile_name() to honor NIPYAPI_PROFILES_FILE env var - Improve profile resolution order for testing isolation CI Module: - Fix purge_flowfiles.py to use detail='all' for process group status Test Infrastructure: - Add NIPYAPI_PROFILES_FILE to Makefile for test isolation - Update conftest.py to use env var for profiles path - Add comprehensive tests for layout, CLI, CI, canvas, and parameters - 332 tests passing, lint clean (10.00/10) * fix: remove switch() from CI functions to prevent profile override - CI functions no longer call profiles.switch() internally - Profile configuration is now solely the responsibility of the caller - CLI main() handles switch() with --profile arg or auto-resolution - Fixes bug where --profile flag was ignored by CI commands Also includes: - Add --profile CLI option for explicit profile selection - Add NIPYAPI_PROFILE env var support in switch() auto-resolution - Update profiles.rst documentation - Add tests for new profile resolution behavior * fix: regenerate clients with basicAuth and fix Python 3.9 test - Regenerate NiFi and Registry clients from augmented OpenAPI specs - Restore basicAuth in Registry configuration.py and access_api.py - Fix mock patch path in test_ci.py for Python 3.9 compatibility (use @patch('requests.get') instead of module path) * fix(ci): select token env var based on provider The ensure_registry function was resolving the token before determining the provider, always preferring GH_REGISTRY_TOKEN regardless of whether gitlab was specified. This caused GitLab deployments to fail when both tokens were set. Now resolves provider first, then selects the appropriate token: - gitlab: GL_REGISTRY_TOKEN first, fallback to GH_REGISTRY_TOKEN - github: GH_REGISTRY_TOKEN first, fallback to GL_REGISTRY_TOKEN * style(tests): use urlparse for hostname assertion Replace string 'in' check with urlparse().hostname for cleaner URL validation. * test: improve coverage for cli, profiles, and ci modules CLI coverage: 62% -> 81% - Add tests for list serialization, heredoc format, _to_dict methods - Add tests for _parse_profile_arg function - Add tests for SafeModule error handling and log level inclusion Profiles coverage: 68% -> 74% - Add tests for unicode error handling in properties files - Add tests for get_default_profile_name edge cases CI coverage: 50% -> 58% - ensure_registry: 17% -> 95% (validation + token priority tests) - deploy_flow: 17% -> 61% (validation tests) - configure_params: 27% -> 49% (JSON validation tests) Overall coverage: 66% -> 69% * docs: add comprehensive CLI and CI documentation CLI documentation (cli.rst): - Installation options (pip, uv, uvx) - Configuration (env vars, profiles, priority) - Discovering commands with --help - All available modules with API reference links - Output formatting (JSON, GitHub Actions, GitLab) - Note that low-level nifi/registry APIs not exposed CI documentation (ci.rst): - All 14 CI operations with full parameter tables - configure_inherited_params for inheritance-aware updates - resolve_git_ref utility function - Environment variable reference - Complete workflow examples (shell, GitHub, GitLab, Python) Other changes: - Fix test_safe_module_error_handling for CI environments - Fix security.rst title (was incorrectly 'NiPyAPI 2') - Add layout module to core_modules docs - Update dependencies list * test: improve coverage for CI, parameters, layout modules and fix test isolation Add integration tests against real NiFi for better coverage: test_ci.py: - configure_inherited_params: 10 tests (validation + integration) - upload_asset: 8 tests (file path, PG resolution, param linking) test_parameters.py: - get_parameter_context_hierarchy: 3 tests - get_parameter_ownership_map: 2 tests - update_parameter_in_context: 4 tests test_layout.py: - move_port: 3 tests (input, output, no-refresh) - move_component with port: 1 test - snap_position, get_pg_grid_position, left_of, check_overlap: 5 tests test_versioning.py: - Fix test isolation: wait for async revert to complete in test_revert_flow_ver_wait_false before test ends, preventing revision conflicts in subsequent tests using same fixture * feat(ci): add version control CI functions and helpers New CI functions: - commit_flow: save flow to version control (initial or subsequent) - get_flow_versions: list version history for a flow - detach_flow: remove version control (for forking workflows) - get_flow_diff: get local modifications to a versioned flow Renames for consistency: - change_version -> change_flow_version - get_versions -> list_flows New versioning helper: - get_local_modifications: helper for fetching local changes Improvements: - list_flows: use nipyapi.utils.getenv_bool for env var parsing - list_flows: use nipyapi.canvas.get_flow helper instead of direct API - save_git_flow_ver: accept string process group ID Tests: - Added comprehensive tests for all new CI functions - Fixed flaky versioning tests with proper state handling - Improved test isolation in shared fixtures * feat(ci): add export_flow_definition and import_flow_definition commands - Add export_flow_definition CI function for exporting process groups to files - Add import_flow_definition CI function for importing flow definitions from files - Support JSON and YAML formats for export - Add include_referenced_services option to include external controller services - Use smart positioning (suggest_pg_position) when import location not provided - Add 10 tests covering validation, roundtrip export/import, and file operations * feat(extensions): add NAR management with defensive lifecycle handling - Add nipyapi.extensions module for NAR upload, delete, download - Add Python processor initialization status and wait functions - Add processor bundle version management for multi-version NARs - Implement defensive delete_nar with initialization guard and cleanup wait - Implement two-phase upload_nar wait (install + processor discovery) - Fix canvas.create_processor to include bundle for multi-version support - Add programmatic NAR generation for testing (create_test_nar) - Add comprehensive tests for extension operations - Add extensions operations guide (docs/extensions.rst) covering NAR lifecycle, Python processor initialization, version management, and troubleshooting * fix(cli): quote dotenv values containing special characters Values with spaces, pipes, brackets, and other shell special characters are now properly quoted in dotenv output format. This prevents export failures when values contain characters like | [ ] that break shell parsing. Embedded double quotes are escaped with backslash. * feat(parameters): enhance get_parameter_context_hierarchy with bindings and optional parameters - Add include_bindings parameter to include bound_process_groups for each context - Add include_parameters parameter to optionally exclude parameter details - Add description field to parameter output for better context - Add tests for new functionality including transitive binding behavior - Useful for cleanup workflows and parameter inspection during deployment * feat(cli): add --version and verbosity flags - Add --version/-V flags to display version and exit - Add -v/-vv/-vvv flags to control log verbosity - Refactor _parse_profile_arg to _parse_cli_flags for combined parsing - Add _apply_verbosity to set NIFI_LOG_LEVEL from verbosity count - Add comprehensive unit tests for flag parsing - Add integration tests for version output * feat(canvas): allow create_process_group to accept pg_id string - Accept either a string ID or ProcessGroupEntity for parent_pg parameter - Maintains backward compatibility with existing code using entities - Raises TypeError with clear message for invalid types - Supports 'root' as parent_pg for creating PGs on root canvas - Add tests for string ID, UUID string, and invalid type cases * feat: add list_registry_flows CI function and improve registry client handling Registry client improvements: - versioning.get_registry_client: add greedy parameter (default True for compat) - ci.deploy_flow: accept registry client name or ID, add greedy param - ci.list_registry_flows: new function to list flows in registry bucket Canvas improvements: - create_process_group: accept string ID or ProcessGroupEntity for parent_pg - delete_remote_process_group: add force param to stop transmission before delete - set_remote_process_group_transmission: wait for state change before returning Test fixes: - conftest: use force=True when cleaning up RPGs - Add tests for greedy parameter and list_registry_flows validation * fix: JSON-serialize lists in GitHub/GitLab CI output formats Previously, lists nested within dict results were converted via str() which produces Python repr format with single quotes. This is not valid JSON and breaks downstream parsing. Now lists and dicts at leaf positions are JSON-serialized with json.dumps() producing valid JSON with double quotes. Fixes output for: list_flows, list_registry_flows, get_flow_versions, get_flow_diff, and any future CI functions returning list values. Added tests for nested list serialization in both GitHub and dotenv formats. * feat(ci): add is_uuid() utility and auto-detect registry client ID vs name - Add is_uuid() function to nipyapi/utils.py for UUID format detection - Update deploy_flow and list_registry_flows to auto-detect if registry_client is UUID (ID) or name - Add comprehensive tests for is_uuid() in test_utils.py - Update docstrings to document auto-detection behavior * feat(layout): add connection management and improved bend handling - Add get_connection() to fetch connection by ID or entity - Add update_connection() with name/bends parameters (bends=[] clears) - Add clear_flow_bends() to clear bends before flow reorganization - Update get_flow_components() to return FlowSubgraph(components, connections) - Add include_retry parameter to move_component/move_processor - Refactor transpose_flow to handle all bends in single pass - Add comprehensive tests for new functionality * feat: add config verification functions and test optimizations - Add nipyapi.canvas.verify_controller() for controller service verification - Add nipyapi.canvas.verify_processor() for processor verification - Add nipyapi.ci.verify_config() for batch verification of process groups - Add refresh parameter to delete_controller and update_controller - Improve delete_controller to accept ID or object - Add PYTEST_ARGS support to Makefile test target - Add fix_multi_version_nars module-scoped fixture for test optimization - Remove useless @pytest.mark.usefixtures() decorator - Extension tests now ~27% faster with shared NAR fixtures * feat: add orphaned context cleanup and bulletin filtering - Add list_orphaned_contexts() to parameters module for detecting parameter contexts not bound to any process groups - Enhance get_bulletin_board() with pg_id, source_name, message, and limit filters for scoped bulletin retrieval - Add delete_orphaned_contexts option to ci.cleanup() for safe removal of unused parameter contexts after PG deletion - Add comprehensive tests for all new functionality Note: NiFi does not provide an API to clear bulletins in 2.6.0. Clear bulletins API was introduced in 2.7.0 - upgrade planned separately. * feat(bulletins): add bulletin management module with NiFi 2.7.0+ clearing New nipyapi.bulletins module: - get_bulletins(): controller-level bulletins - get_bulletin_board(): filtered bulletins returning BulletinDTO directly - clear_*_bulletins(): component-specific clearing (10 functions) - clear_all_bulletins(): high-level helper for CI Additional changes: - nipyapi.profiles: add list_profiles, show, current commands - nipyapi.utils: add format_timestamp utility - nipyapi.ci.get_status: fix to capture controller service bulletins - nipyapi.canvas: bulletin functions now alias to bulletins module - Makefile: intelligent uv/pip detection - docs: updated contributing guide, module documentation * feat(canvas): add component state management functions - Add get_processor_state and clear_processor_state for processor state inspection - Add get_controller_state and clear_controller_state for controller service state - All functions accept entity objects or ID strings - Fix CLI --help flag handling in SafeModule wrapper - Remove unused LogCapture.all_records attribute - Add fix_state_flow test fixture with MapCacheServer and ListFile - Add comprehensive tests for state operations * feat(ci): add parameter export/import and VCS parameter handling - Add export_parameters CI command for exporting parameter values - Add --parameters_file option to configure_inherited_params for file-based import - Add parameter_context_handling option to deploy_git_registry_flow for VCS - Add deploy_flow CI command parameter_context_handling support - Fix test fixture isolation to prevent shared fixtures being deleted - Fix parameter context cleanup version check logic - Add ACTIVE_PROFILES_PATH for consistent profile file handling - Add parameter inheritance tests for VCS deployments * test: add comprehensive CLI JSON input/output serialization tests Add 43 new tests for CLI handling of complex JSON objects: - 19 JSON input parsing tests (quotes, newlines, backslashes, nested structures, Unicode, null/empty values, mixed types) - 4 roundtrip tests (serialize -> parse verification) - 8 CLI subprocess tests (verify JSON passes through CLI correctly) - 12 CI function tests for configure_params complex inputs These tests verify AI agents can use the nipyapi CLI directly for common operations without needing to write Python code for complex parameter structures. * fix(tests): force JSON output format in CLI subprocess tests In GitHub Actions CI, GITHUB_ACTIONS=true causes the CLI to auto-detect 'github' output format (key=value), but the tests expect JSON output for parsing. Force NIFI_OUTPUT_FORMAT=json in the subprocess environment to ensure consistent JSON output. Fixes JSONDecodeError in configure_params CLI tests. * docs: comprehensive docstring and documentation revision - Create AGENTS.md for AI agent guidance (consuming/contributing sections) - Update contributing.rst with docstring standards and discovery patterns - Fix all 51 Sphinx docstring warnings (nested lists, Example formatting) - Standardize Example:: format across 91 instances with required blank lines - Fix RST title underlines in ci.rst, security.rst - Add cross-reference notation guidance for Sphinx - Add module intent comments to __init__.py * feat(canvas): add get_processor_docs() and enhance schedule_processor() New features: - get_processor_docs(processor): retrieve full processor documentation including property_descriptors, tags, use cases. Accepts ProcessorEntity, DocumentedTypeDTO, or processor type name string. - schedule_processor() enhancements: - Now accepts processor ID string or ProcessorEntity object - Supports all processor states: RUNNING, STOPPED, DISABLED, RUN_ONCE - Uses direct processor API for reliable state transitions - Backwards compatible: bool values still work (True=RUNNING, False=STOPPED) Client fixes: - Add nifi_processor_state_enum.py augmentation to fix upstream NiFi OpenAPI bug where ProcessorDTO.state enum was missing transitional states Testing improvements: - Add pytest filterwarnings config to suppress InsecureRequestWarning in tests - Add comprehensive tests for new functionality Docs: - Minor AGENTS.md improvement: venv activation reminder * Add FlowFile inspection helpers and enhance fs_write for binary mode - nipyapi.canvas: Add list_flowfiles, get_flowfile_details, get_flowfile_content, peek_flowfiles - get_flowfile_content supports decode options (auto/text/bytes) and output_file saving - nipyapi.utils.fs_write: Add binary=False parameter for raw byte writing (backwards compatible) - Tests: Add test_fs_write_binary, expand test_get_flowfile_content coverage * Address Copilot review feedback - Extract NiFi Registry functions to nipyapi.nifi_registry module with backwards-compatible shims in versioning.py - Replace global cache with @lru_cache in conftest.py - Clarify switch() usage in profiles.py error message - Document UUID format-only validation in utils.py - Fix URL validation in test_ci.py (use urlparse for hostname check) * Fix cluster_node_id handling, remove fail_on_error, improve CLI docstrings Bug fixes: - canvas.py: Add _resolve_flowfile_cluster_node() helper for clustered NiFi - canvas.py: get_flowfile_details/get_flowfile_content auto-resolve cluster_node_id - canvas.py: peek_flowfiles preserves cluster_node_id from FlowFileSummaryDTO - canvas.py: create_processor accepts string ID or ProcessGroupEntity - verify_config.py: Remove fail_on_error param (always return result dict) CLI improvements: - cli.py: Use functools.wraps for proper signature preservation in fire - canvas.py, layout.py, utils.py: Inline docstring format for CLI compatibility Documentation: - contributing.rst: Add CLI-specific docstring guidance Tests: - test_canvas.py: Add tests for cluster_node_id handling - test_ci.py: Update tests for verify_config changes * docs: Add CLI boolean parameter gotcha to contributing guide * fix: Use bulk disable instead of delete for controllers in force delete_process_group Previously, force deletion would delete each controller service individually, which was slow and caused version control to show local modifications. Now uses schedule_all_controllers() to bulk disable, which is faster and non-destructive. * fix: Disable controllers in fix_state_flow cleanup before PG deletion MapCacheServer binds to port 4557 and won't release it until disabled. Without explicit cleanup, subsequent tests fail with 'Address already in use' when trying to enable their own MapCacheServer. Added finalizer to disable both server and client controllers before fix_pg's finalizer runs to delete the process group. * fix: schedule_all_controllers now waits for controllers to reach target state Previously the function returned immediately after the API call, leaving controllers in transitional states (ENABLING/DISABLING). This caused race conditions in slower environments (e.g. Python 3.9) where callers would check controller state before transitions completed. Now uses wait_to_complete to poll until all controllers in the PG reach the target state, consistent with schedule_controller behavior. * docs: Prepare 1.2.0 release - CLI documentation and history
1 parent b69632a commit c4127de

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+22945
-653
lines changed

AGENTS.md

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# AGENTS.md
2+
3+
Agent guidance for NiPyAPI - Apache NiFi Python Client SDK.
4+
5+
**Which workflow applies?**
6+
- Using nipyapi in another project → [Consuming nipyapi](#consuming-nipyapi)
7+
- Working in the nipyapi repository → [Contributing to nipyapi](#contributing-to-nipyapi)
8+
9+
---
10+
11+
## Consuming nipyapi
12+
13+
For agents using nipyapi to perform NiFi operations.
14+
15+
### Install
16+
17+
```bash
18+
uv pip install "nipyapi[cli]" # Recommended: includes CLI
19+
pip install nipyapi # Alternative: library only
20+
```
21+
22+
### Connect
23+
24+
```bash
25+
# Option 1: Profile (recommended)
26+
export NIPYAPI_PROFILE=my-profile
27+
# Create profile in ~/.nipyapi/profiles.yml - see examples/profiles.yml
28+
29+
# Option 2: Environment variables
30+
export NIFI_API_ENDPOINT=https://nifi.example.com/nifi-api
31+
export NIFI_USERNAME=admin
32+
export NIFI_PASSWORD=secret
33+
```
34+
35+
### Documentation
36+
37+
| If you need to... | See |
38+
|-------------------|-----|
39+
| Install nipyapi | `README.rst` → "Quick Start" |
40+
| Configure profiles | `examples/profiles.yml`, `docs/profiles.rst` |
41+
| Authenticate (Basic, mTLS, LDAP, OIDC) | `docs/security.rst` |
42+
| Migrate from 0.x | `docs/migration.rst` |
43+
| Full API reference | https://nipyapi.readthedocs.io |
44+
| CLI usage and options | `nipyapi --help`, `nipyapi <module> --help` |
45+
| Function signatures and behavior | Read module docstrings directly (comprehensive) |
46+
47+
### Modules
48+
49+
Prefer in this order: `nipyapi.ci` → helper modules → low-level API.
50+
51+
For function discovery: `nipyapi <module> --help` (CLI) or `help(nipyapi.canvas)` (Python).
52+
53+
| If you need to... | Use |
54+
|-------------------|-----|
55+
| Deploy flows in CI/CD | `nipyapi.ci` |
56+
| Manage processors, process groups, connections | `nipyapi.canvas` |
57+
| Import/export versioned flows | `nipyapi.versioning` |
58+
| Authenticate, manage users/policies | `nipyapi.security` |
59+
| Work with parameter contexts | `nipyapi.parameters` |
60+
| Switch connection profiles | `nipyapi.profiles` |
61+
| Position components on canvas | `nipyapi.layout` |
62+
| Get system/cluster info | `nipyapi.system` |
63+
| Retrieve/filter/clear bulletins | `nipyapi.bulletins` |
64+
| Manage NiFi extensions (NARs) | `nipyapi.extensions` |
65+
| File operations, filtering, common utilities | `nipyapi.utils` |
66+
| Access/modify endpoint configuration | `nipyapi.config` |
67+
| Direct NiFi API access (when helpers insufficient) | `nipyapi.nifi.*` |
68+
| Direct Registry API access (when helpers insufficient) | `nipyapi.registry.*` |
69+
70+
### CLI Examples
71+
72+
```bash
73+
nipyapi ci ensure_registry --name my-registry --uri https://github.com/org/repo
74+
nipyapi ci deploy_flow --registry_client my-registry --bucket flows --flow my-flow
75+
nipyapi ci start_flow --pg_id <process-group-id>
76+
nipyapi canvas list_all_process_groups
77+
```
78+
79+
---
80+
81+
## Contributing to nipyapi
82+
83+
For agents modifying the nipyapi codebase.
84+
85+
### Project Context
86+
87+
This project is nearly 10 years old with a substantial user base. Approach changes with care:
88+
89+
- **Existing patterns may handle edge cases** you're not aware of - ask before "simplifying"
90+
- **Some code predates modern Python** (originated in Python 2 era) - refactoring requires testing
91+
- **Changes can have broad impact** - prefer surgical modifications over sweeping rewrites
92+
- **When in doubt, discuss first** - the PLAN→ACT→REVIEW workflow exists for good reason
93+
94+
### Setup
95+
96+
```bash
97+
git clone https://github.com/Chaffelson/nipyapi.git && cd nipyapi
98+
make dev-install # Uses uv if available, pip otherwise
99+
make help # See all available targets
100+
```
101+
102+
**Important**:
103+
- Always activate venv first: `source .venv/bin/activate` before running Python/make commands
104+
- Prefer make commands: Check `make help` for available targets before using generic tooling (pip, pytest, sphinx, etc.)
105+
106+
### Intent Routing
107+
108+
| If you need to... | See |
109+
|-------------------|-----|
110+
| Set up dev environment | `docs/contributing.rst` → "Get Started!" |
111+
| Understand code organization | `docs/contributing.rst` → "Generated vs Maintained Code" |
112+
| Run tests | `docs/contributing.rst` → "Make Targets Quick Reference" |
113+
| Add a new module | `docs/contributing.rst` → "Adding New Core Modules" |
114+
| Submit a PR | `docs/contributing.rst` → "Pull Request Guidelines" |
115+
| Understand profiles system | `docs/profiles.rst` |
116+
| Migrate from 0.x | `docs/migration.rst` |
117+
118+
### Before Writing Code
119+
120+
**Discovery pattern** - check before implementing new helpers:
121+
122+
1. Read `nipyapi/__init__.py` for module intent mapping (comments describe each module's purpose)
123+
2. Check `__all__` at top of relevant module (`utils.py`, `canvas.py`, etc.)
124+
3. Grep function names that might serve your purpose
125+
4. Read docstrings to understand intent and edge cases handled
126+
5. For tests: check `tests/conftest.py` for fixtures, read an example test file first
127+
128+
See `docs/contributing.rst` → "Reuse Existing Code" for detailed guidance.
129+
130+
### Critical Rules
131+
132+
**Will cause failures if ignored:**
133+
134+
1. **Profile required for tests**: `make test NIPYAPI_PROFILE=<profile>` - never bare pytest
135+
2. **Docker readiness**: Always `make wait-ready NIPYAPI_PROFILE=<profile>` before testing
136+
3. **Certificates before containers**: Run `make down` before `make certs`
137+
4. **Zsh bracket quoting**: Use `make dev-install` not bare `pip install -e .[dev]`
138+
139+
### Code Organization
140+
141+
**Maintained** (where to contribute):
142+
- `nipyapi/*.py` - Core modules
143+
- `tests/` - Test suite
144+
- `examples/` - Usage examples
145+
- `docs/` - Documentation
146+
147+
**Generated** (do not directly modify):
148+
- `nipyapi/nifi/` - NiFi API client (generated from OpenAPI specs)
149+
- `nipyapi/registry/` - Registry API client (generated from OpenAPI specs)
150+
- `nipyapi/_version.py` - Git version (generated by setuptools-scm)
151+
152+
**To modify generated clients**: Edit templates in `resources/client_gen/`, then run `make gen-clients`.
153+
See `docs/contributing.rst` → "Regenerating Clients" and "Augmentation System" for the full workflow.
154+
155+
### Testing Workflow
156+
157+
```bash
158+
make certs # Generate certificates (once)
159+
make up NIPYAPI_PROFILE=single-user # Start Docker services
160+
make wait-ready NIPYAPI_PROFILE=single-user
161+
make test NIPYAPI_PROFILE=single-user # Run tests
162+
make down # Stop services
163+
```
164+
165+
Profiles: `single-user`, `secure-ldap`, `secure-mtls`, `secure-oidc`
166+
167+
**Profile file behavior**: Make targets default to `examples/profiles.yml` (local Docker setup).
168+
To use your own profiles (e.g., `~/.nipyapi/profiles.yml`), set `NIPYAPI_PROFILES_FILE`.
169+
170+
### Code Style
171+
172+
- **Line length**: 100 chars
173+
- **Formatting**: black + isort
174+
- **Linting**: flake8 + pylint
175+
- **Docstrings**: Google style
176+
- **Python**: 3.9-3.12
177+
178+
**Before committing**: Run `make pre-commit` (auto-fixes formatting, then lints).
179+
This avoids commit failures where black rewrites files. Use `make lint` for check-only.
180+
181+
### Workflow
182+
183+
1. **PLAN** - Investigate codebase, discuss approach, propose changes. No file edits until user authorizes.
184+
2. **ACT** - Execute agreed plan with surgical, minimal changes. Follow discovery pattern. Use established patterns.
185+
3. **REVIEW**:
186+
- Validate implementation solves the stated problem
187+
- Run `make pre-commit` to fix formatting and check lint
188+
- Run tests if code was changed (`make test NIPYAPI_PROFILE=...`)
189+
- Update documentation if functionality was added
190+
- Present changes for user review and feedback
191+
- Reflect: any lessons learned or patterns discovered to carry forward?
192+
193+
---
194+
195+
## References
196+
197+
| Resource | Location |
198+
|----------|----------|
199+
| Full documentation | https://nipyapi.readthedocs.io |
200+
| Contributing guide | `docs/contributing.rst` |
201+
| Profiles guide | `docs/profiles.rst` |
202+
| Security guide | `docs/security.rst` |
203+
| Migration 0.x→1.x | `docs/migration.rst` |
204+
| Example scripts | `examples/` |
205+
| Issues | https://github.com/Chaffelson/nipyapi/issues |

Makefile

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,30 @@
55
NIFI_VERSION ?= 2.7.2
66

77
# Load .env file if it exists (for secrets like GH_REGISTRY_TOKEN)
8+
# WARNING: All variables from .env are exported and can override profile settings.
9+
# If tests fail with unexpected URLs, check if .env contains NIFI_API_ENDPOINT
10+
# or other NIFI_*/REGISTRY_* variables that conflict with examples/profiles.yml.
11+
# For development/testing, either remove .env or ensure it doesn't contain
12+
# conflicting endpoint URLs.
813
-include .env
914
export
1015

1116
# Python command for cross-platform compatibility
1217
# Defaults to 'python' for conda/venv users, override with PYTHON=python3 for system installs
1318
PYTHON ?= python
1419

20+
# Package installer: prefer uv if available, fall back to pip
21+
# Users with uv get faster installs; users without uv work unchanged
22+
UV := $(shell command -v uv 2>/dev/null)
23+
ifdef UV
24+
PIP := uv pip
25+
else
26+
PIP := pip
27+
endif
28+
29+
# Profiles file for development/testing (explicitly use examples file, not user's ~/.nipyapi/profiles.yml)
30+
NIPYAPI_PROFILES_FILE ?= examples/profiles.yml
31+
1532
# Paths and docker compose helpers (avoid cd by using -f)
1633
COMPOSE_DIR := $(abspath resources/docker)
1734
COMPOSE_FILE := $(COMPOSE_DIR)/compose.yml
@@ -107,8 +124,8 @@ clean-build: ## remove build artifacts
107124
rm -fr build/
108125
rm -fr dist/
109126
rm -fr .eggs/
110-
find . -name '*.egg-info' -exec rm -fr {} +
111-
find . -name '*.egg' -exec rm -f {} +
127+
find . -path ./.venv -prune -o -name '*.egg-info' -exec rm -fr {} +
128+
find . -path ./.venv -prune -o -name '*.egg' -exec rm -rf {} +
112129

113130
clean-pyc: ## remove Python file artifacts
114131
find . -name '*.pyc' -exec rm -f {} +
@@ -141,21 +158,21 @@ clean-docker: clean-act ## comprehensive Docker cleanup: act + containers + volu
141158
@echo "Comprehensive Docker cleanup complete"
142159

143160
install: clean ## install the package to the active Python's site-packages
144-
pip install .
161+
$(PIP) install .
145162

146163
dev-install: ## install dev extras for local development
147-
pip install -e ".[dev]"
164+
$(PIP) install -e ".[dev]"
148165

149166
docs-install: ## install docs extras
150-
pip install -e ".[docs]"
167+
$(PIP) install -e ".[docs]"
151168

152169
coverage: ensure-certs ## run pytest with coverage and generate report (set coverage-min=NN to enforce; requires infrastructure)
153170
@echo "Running coverage analysis (single-user profile)..."
154171
@echo "Ensuring single-user infrastructure is ready..."
155172
$(MAKE) up NIPYAPI_PROFILE=single-user
156173
$(MAKE) wait-ready NIPYAPI_PROFILE=single-user
157174
@echo "Running pytest with coverage..."
158-
NIPYAPI_PROFILE=single-user PYTHONPATH=$(PWD):$$PYTHONPATH pytest --cov=nipyapi --cov-report=term-missing --cov-report=html
175+
NIPYAPI_PROFILE=single-user NIPYAPI_PROFILES_FILE=$(NIPYAPI_PROFILES_FILE) PYTHONPATH=$(PWD):$$PYTHONPATH pytest --cov=nipyapi --cov-report=term-missing --cov-report=html
159176
@if [ -n "$(coverage-min)" ]; then coverage report --fail-under=$(coverage-min); fi
160177
@echo "Coverage analysis complete. See htmlcov/index.html for detailed report."
161178

@@ -181,7 +198,7 @@ flake8: ## run flake8 linter on core nipyapi files
181198
pylint: ## run pylint on core nipyapi files
182199
pylint nipyapi/ --rcfile=pylintrc --ignore=nifi,registry,_version.py
183200

184-
pre-commit: ## run pre-commit hooks on all files
201+
pre-commit: ## run pre-commit hooks on all files (black, isort, flake8, pylint)
185202
pre-commit run --all-files
186203

187204
#################################################################################
@@ -244,7 +261,7 @@ down: ## bring down all docker services
244261
wait-ready: ## wait for readiness using profile configuration; requires NIPYAPI_PROFILE=single-user|secure-ldap|secure-mtls|secure-oidc|github-cicd
245262
@if [ -z "$(NIPYAPI_PROFILE)" ]; then echo "ERROR: NIPYAPI_PROFILE is required"; exit 1; fi
246263
@echo "Waiting for $(NIPYAPI_PROFILE) infrastructure to be ready..."
247-
@NIPYAPI_PROFILE=$(NIPYAPI_PROFILE) $(PYTHON) resources/scripts/wait_ready.py
264+
@NIPYAPI_PROFILE=$(NIPYAPI_PROFILE) NIPYAPI_PROFILES_FILE=$(NIPYAPI_PROFILES_FILE) $(PYTHON) resources/scripts/wait_ready.py
248265

249266
# API & Client generation
250267
fetch-openapi-base: ## refresh base OpenAPI specs for current NIFI_VERSION (always overwrite base)
@@ -272,9 +289,9 @@ gen-clients: ## generate NiFi and Registry clients from specs (use wv_spec_varia
272289

273290
# Individual testing
274291

275-
test: ## run pytest with provided NIPYAPI_PROFILE; config resolved by tests/conftest.py
292+
test: ## run pytest with provided NIPYAPI_PROFILE; use PYTEST_ARGS for extra options (e.g., make test NIPYAPI_PROFILE=single-user PYTEST_ARGS="-k verify -v")
276293
@if [ -z "$(NIPYAPI_PROFILE)" ]; then echo "NIPYAPI_PROFILE is required (single-user|secure-ldap|secure-mtls|secure-oidc|github-cicd)"; exit 1; fi; \
277-
NIPYAPI_PROFILE=$(NIPYAPI_PROFILE) PYTHONPATH=$(PWD):$$PYTHONPATH pytest -q
294+
NIPYAPI_PROFILE=$(NIPYAPI_PROFILE) NIPYAPI_PROFILES_FILE=$(NIPYAPI_PROFILES_FILE) PYTHONPATH=$(PWD):$$PYTHONPATH pytest -q $(PYTEST_ARGS)
278295

279296
test-su: ## shortcut: NIPYAPI_PROFILE=single-user pytest
280297
NIPYAPI_PROFILE=single-user $(MAKE) test
@@ -288,10 +305,11 @@ test-mtls: ## shortcut: NIPYAPI_PROFILE=secure-mtls pytest
288305
test-oidc: check-certs ## shortcut: NIPYAPI_PROFILE=secure-oidc pytest (requires: make sandbox NIPYAPI_PROFILE=secure-oidc)
289306
NIPYAPI_PROFILE=secure-oidc $(MAKE) test
290307

291-
test-specific: ## run specific pytest with provided NIPYAPI_PROFILE and TEST_ARGS
292-
@if [ -z "$(NIPYAPI_PROFILE)" ]; then echo "NIPYAPI_PROFILE is required (single-user|secure-ldap|secure-mtls|secure-oidc|github-cicd)"; exit 1; fi; \
293-
if [ -z "$(TEST_ARGS)" ]; then echo "TEST_ARGS is required (e.g., tests/test_utils.py::test_dump -v)"; exit 1; fi; \
294-
NIPYAPI_PROFILE=$(NIPYAPI_PROFILE) PYTHONPATH=$(PWD):$$PYTHONPATH pytest -q $(TEST_ARGS)
308+
test-specific: ## DEPRECATED: use 'make test PYTEST_ARGS="..."' instead
309+
@echo "DEPRECATED: Use 'make test NIPYAPI_PROFILE=... PYTEST_ARGS=\"...\"' instead"
310+
@if [ -z "$(NIPYAPI_PROFILE)" ]; then echo "NIPYAPI_PROFILE is required"; exit 1; fi; \
311+
if [ -z "$(TEST_ARGS)" ]; then echo "TEST_ARGS is required"; exit 1; fi; \
312+
NIPYAPI_PROFILE=$(NIPYAPI_PROFILE) NIPYAPI_PROFILES_FILE=$(NIPYAPI_PROFILES_FILE) PYTHONPATH=$(PWD):$$PYTHONPATH pytest -q $(TEST_ARGS)
295313

296314

297315
# Build & Documentation
@@ -345,7 +363,7 @@ sandbox: ensure-certs ## create isolated environment with sample objects: make s
345363
@echo "=== 2/4: Waiting for readiness ==="
346364
$(MAKE) wait-ready NIPYAPI_PROFILE=$(NIPYAPI_PROFILE)
347365
@echo "=== 3/4: Setting up authentication and sample objects ==="
348-
@NIPYAPI_PROFILE=$(NIPYAPI_PROFILE) $(PYTHON) examples/sandbox.py $(NIPYAPI_PROFILE)
366+
@NIPYAPI_PROFILE=$(NIPYAPI_PROFILE) NIPYAPI_PROFILES_FILE=$(NIPYAPI_PROFILES_FILE) $(PYTHON) examples/sandbox.py $(NIPYAPI_PROFILE)
349367

350368
rebuild-all: ## comprehensive rebuild: clean -> certs -> extract APIs -> gen clients -> test all -> build -> validate -> docs
351369
@echo "Starting comprehensive rebuild from clean slate..."

0 commit comments

Comments
 (0)