|
| 1 | +# Development Guide |
| 2 | + |
| 3 | +Guide for developing the Seqera Platform CLI. |
| 4 | + |
| 5 | +## Quick Start |
| 6 | + |
| 7 | +### Installation |
| 8 | + |
| 9 | +```bash |
| 10 | +# Install in development mode with all dependencies |
| 11 | +pip install -e ".[dev]" |
| 12 | +``` |
| 13 | + |
| 14 | +### Running Tests |
| 15 | + |
| 16 | +```bash |
| 17 | +# Run all tests |
| 18 | +pytest |
| 19 | + |
| 20 | +# Run specific test file |
| 21 | +pytest tests/credentials/test_credentials_cmd.py |
| 22 | + |
| 23 | +# Run with verbose output |
| 24 | +pytest -v |
| 25 | + |
| 26 | +# Run with coverage |
| 27 | +pytest --cov=seqera --cov-report=html |
| 28 | +``` |
| 29 | + |
| 30 | +### Running the CLI |
| 31 | + |
| 32 | +```bash |
| 33 | +# Run the CLI directly |
| 34 | +python -m seqera.main --help |
| 35 | + |
| 36 | +# Or if installed |
| 37 | +seqera --help |
| 38 | + |
| 39 | +# Example: List credentials |
| 40 | +seqera credentials list |
| 41 | + |
| 42 | +# Example with custom server |
| 43 | +seqera --url http://localhost:8080 --access-token your_token credentials list |
| 44 | +``` |
| 45 | + |
| 46 | +## Project Structure |
| 47 | + |
| 48 | +```text |
| 49 | +tower-cli/ |
| 50 | +├── src/seqera/ # Python source code |
| 51 | +│ ├── main.py # CLI entry point |
| 52 | +│ ├── api/ # API client |
| 53 | +│ │ └── client.py # SeqeraClient class |
| 54 | +│ ├── commands/ # CLI commands |
| 55 | +│ │ ├── actions/ # Actions commands |
| 56 | +│ │ ├── computeenvs/ # Compute environment commands |
| 57 | +│ │ ├── credentials/ # Credentials commands |
| 58 | +│ │ ├── datalinks/ # Data links commands |
| 59 | +│ │ ├── datasets/ # Datasets commands |
| 60 | +│ │ ├── labels/ # Labels commands |
| 61 | +│ │ ├── members/ # Members commands |
| 62 | +│ │ ├── organizations/ # Organizations commands |
| 63 | +│ │ ├── participants/ # Participants commands |
| 64 | +│ │ ├── pipelines/ # Pipeline commands |
| 65 | +│ │ ├── runs/ # Runs commands |
| 66 | +│ │ ├── secrets/ # Secrets commands |
| 67 | +│ │ ├── studios/ # Data studios commands |
| 68 | +│ │ ├── teams/ # Teams commands |
| 69 | +│ │ ├── workspaces/ # Workspaces commands |
| 70 | +│ │ ├── info.py # Info command |
| 71 | +│ │ └── launch.py # Launch command |
| 72 | +│ ├── exceptions/ # Custom exceptions |
| 73 | +│ ├── responses/ # Response models |
| 74 | +│ └── utils/ # Utilities (output formatting, etc.) |
| 75 | +└── tests/ # Tests |
| 76 | + ├── conftest.py # Pytest fixtures |
| 77 | + └── ... # Command-specific tests |
| 78 | +``` |
| 79 | + |
| 80 | +## Code Quality |
| 81 | + |
| 82 | +### Linting |
| 83 | + |
| 84 | +```bash |
| 85 | +# Check code style |
| 86 | +ruff check src/ tests/ |
| 87 | + |
| 88 | +# Fix auto-fixable issues |
| 89 | +ruff check --fix src/ tests/ |
| 90 | +``` |
| 91 | + |
| 92 | +### Formatting |
| 93 | + |
| 94 | +```bash |
| 95 | +# Format code |
| 96 | +ruff format src/ tests/ |
| 97 | +``` |
| 98 | + |
| 99 | +### Type Checking |
| 100 | + |
| 101 | +```bash |
| 102 | +# Run mypy |
| 103 | +mypy src/seqera |
| 104 | +``` |
| 105 | + |
| 106 | +### Pre-commit Hooks |
| 107 | + |
| 108 | +Install pre-commit hooks to run checks automatically: |
| 109 | + |
| 110 | +```bash |
| 111 | +pre-commit install |
| 112 | +``` |
| 113 | + |
| 114 | +## Testing |
| 115 | + |
| 116 | +### Test Structure |
| 117 | + |
| 118 | +Tests are organized by command: |
| 119 | + |
| 120 | +```text |
| 121 | +tests/ |
| 122 | +├── conftest.py # Common fixtures |
| 123 | +├── test_info_cmd.py # Info command tests |
| 124 | +├── test_launch_cmd.py # Launch command tests |
| 125 | +├── actions/ # Actions tests |
| 126 | +├── credentials/ # Credentials tests |
| 127 | +└── ... |
| 128 | +``` |
| 129 | + |
| 130 | +### Writing Tests |
| 131 | + |
| 132 | +Tests use pytest and pytest-httpserver for mocking API responses: |
| 133 | + |
| 134 | +```python |
| 135 | +import pytest |
| 136 | +from pytest_httpserver import HTTPServer |
| 137 | +from tests.conftest import exec_command |
| 138 | + |
| 139 | + |
| 140 | +def test_list_credentials( |
| 141 | + httpserver: HTTPServer, |
| 142 | + cli_runner, |
| 143 | + base_args, |
| 144 | +) -> None: |
| 145 | + """Test credentials list command.""" |
| 146 | + # Mock API response |
| 147 | + httpserver.expect_request( |
| 148 | + "/credentials", |
| 149 | + method="GET", |
| 150 | + ).respond_with_json({ |
| 151 | + "credentials": [ |
| 152 | + {"id": "1", "name": "test-cred"} |
| 153 | + ] |
| 154 | + }) |
| 155 | + |
| 156 | + # Run command |
| 157 | + out = exec_command( |
| 158 | + cli_runner, |
| 159 | + base_args, |
| 160 | + ["credentials", "list"], |
| 161 | + output_format="json" |
| 162 | + ) |
| 163 | + |
| 164 | + # Assert |
| 165 | + assert out.exit_code == 0 |
| 166 | + assert "test-cred" in out.stdout |
| 167 | +``` |
| 168 | + |
| 169 | +### Test Fixtures |
| 170 | + |
| 171 | +Common fixtures in `conftest.py`: |
| 172 | + |
| 173 | +- `cli_runner` - Typer CLI test runner |
| 174 | +- `base_args` - Base CLI arguments (--url, --access-token, --insecure) |
| 175 | +- `api_url` - Mock server URL |
| 176 | +- `auth_token` - Test authentication token |
| 177 | +- `user_workspace_name` - Test user workspace name |
| 178 | + |
| 179 | +### Running Specific Tests |
| 180 | + |
| 181 | +```bash |
| 182 | +# Run tests for a specific command |
| 183 | +pytest tests/credentials/ -v |
| 184 | + |
| 185 | +# Run tests matching a pattern |
| 186 | +pytest -k "test_list" -v |
| 187 | + |
| 188 | +# Run with output capture disabled (for debugging) |
| 189 | +pytest -s tests/test_info_cmd.py |
| 190 | +``` |
| 191 | + |
| 192 | +## Adding New Commands |
| 193 | + |
| 194 | +### 1. Create Command Module |
| 195 | + |
| 196 | +```python |
| 197 | +# src/seqera/commands/mycommand/__init__.py |
| 198 | +import typer |
| 199 | + |
| 200 | +app = typer.Typer(name="mycommand", help="My command description") |
| 201 | + |
| 202 | + |
| 203 | +@app.command("list") |
| 204 | +def list_items( |
| 205 | + workspace: str | None = typer.Option(None, "-w", "--workspace"), |
| 206 | +) -> None: |
| 207 | + """List items.""" |
| 208 | + # Implementation |
| 209 | + pass |
| 210 | +``` |
| 211 | + |
| 212 | +### 2. Register Command |
| 213 | + |
| 214 | +```python |
| 215 | +# src/seqera/main.py |
| 216 | +from seqera.commands import mycommand |
| 217 | + |
| 218 | +app.add_typer(mycommand.app, name="mycommand") |
| 219 | +``` |
| 220 | + |
| 221 | +### 3. Add Tests |
| 222 | + |
| 223 | +```python |
| 224 | +# tests/mycommand/test_mycommand_cmd.py |
| 225 | +def test_list(httpserver, cli_runner, base_args): |
| 226 | + httpserver.expect_request("/my-endpoint").respond_with_json({...}) |
| 227 | + out = exec_command(cli_runner, base_args, ["mycommand", "list"]) |
| 228 | + assert out.exit_code == 0 |
| 229 | +``` |
| 230 | + |
| 231 | +## Dependencies |
| 232 | + |
| 233 | +### Runtime Dependencies |
| 234 | + |
| 235 | +- `typer` - CLI framework |
| 236 | +- `httpx` - HTTP client |
| 237 | +- `rich` - Terminal formatting |
| 238 | +- `pydantic` - Data validation |
| 239 | +- `pyyaml` - YAML support |
| 240 | + |
| 241 | +### Development Dependencies |
| 242 | + |
| 243 | +- `pytest` - Testing framework |
| 244 | +- `pytest-httpserver` - HTTP mocking |
| 245 | +- `ruff` - Linter and formatter |
| 246 | +- `mypy` - Type checker |
| 247 | +- `pre-commit` - Git hooks |
| 248 | + |
| 249 | +## Release Process |
| 250 | + |
| 251 | +1. Update version in `pyproject.toml` |
| 252 | +2. Run tests: `pytest` |
| 253 | +3. Run quality checks: `ruff check && mypy src/seqera` |
| 254 | +4. Create release commit and tag |
| 255 | +5. Push to trigger CI/CD |
| 256 | + |
| 257 | +## Troubleshooting |
| 258 | + |
| 259 | +### Import Errors |
| 260 | + |
| 261 | +If you get import errors, ensure the package is installed in development mode: |
| 262 | + |
| 263 | +```bash |
| 264 | +pip install -e . |
| 265 | +``` |
| 266 | + |
| 267 | +### Test Discovery Issues |
| 268 | + |
| 269 | +Ensure test files and functions follow naming conventions: |
| 270 | +- Files: `test_*.py` |
| 271 | +- Functions: `test_*` |
| 272 | +- Classes: `Test*` |
| 273 | + |
| 274 | +### HTTP Mock Issues |
| 275 | + |
| 276 | +If tests fail with unexpected requests, check the mock server logs for the actual requests being made vs. what was expected. |
0 commit comments