Skip to content

Development Guide

This guide covers everything you need to know to develop in the grizzly repository.

Repository Structure

This is a monorepo for all Grizzly-related projects, managed as a uv workspace.

  • Language: Python
  • Package Manager: uv
  • Build System: hatchling
  • Linting & Formatting: ruff
  • Testing: pytest

Packages

  1. grizzly-loadtester-common - Shared code between packages (exceptions, constants, utilities)
  2. grizzly-loadtester - Core framework with locust messages, test data producer/consumer, gherkin parser, and load users
  3. grizzly-loadtester-cli - Command line interface for running tests, Azure Keyvault integration, TOTP generator, project scaffolding
  4. grizzly-loadtester-ls - Language server implementation using LSP protocol
  5. vscode extension - Visual Studio Code extension integrating the language server
  6. grizzly-docs - MkDocs-based documentation hosted on GitHub Pages

Setting Up Development Environment

Prerequisites

  • Python 3.10 or higher
  • uv package manager
  • Node.js 24 (for VS Code extension development)
  • Git

Installing Dependencies

Install all dependencies for all packages (preserving the lock file):

uv sync --locked -p 3.13 --active --all-packages --all-groups

Important: Always use --locked to ensure reproducible builds by preserving the dependency lock file.

Development Container

This repository includes a dev container configuration for VS Code, which provides a pre-configured development environment with all necessary tools.

Running Tests

The repository uses hatch environments for running tests across different Python versions.

Unit Tests

Run unit tests for a specific package:

# Framework
hatch run test:framework-unit

# CLI
hatch run test:cli-unit

# Language Server
hatch run test:ls-unit

# Common
hatch run test:common-unit

# Docs
hatch run test:docs-unit

End-to-End Tests

Run e2e tests for packages that support them:

# Framework (local mode)
hatch run test:framework-e2e-local

# Framework (distributed mode)
hatch run test:framework-e2e-dist

# Framework (example tests)
hatch run test:framework-e2e-example

# CLI
hatch run test:cli-e2e

# Language Server
hatch run test:ls-e2e

All Tests

Run all tests (unit + e2e) for a package:

hatch run test:framework-all
hatch run test:cli-all
hatch run test:ls-all

Test Matrix

Tests run across multiple Python versions (3.10, 3.11, 3.12, 3.13). Use the matrix syntax:

hatch run +py=3.13 test:framework-unit

Code Quality

Formatting

Format all code using ruff:

hatch run lint:format

Type Checking

Run mypy type checking:

hatch run lint:types

Linting

Run ruff linting checks:

hatch run lint:check

Development Patterns

Code Style

  • All code should be Pythonic and follow PEP-8
  • Use type hints where appropriate
  • Write descriptive docstrings for public functions and classes

Package Dependencies

  1. Keep shared code in grizzly-loadtester-common
  2. Don't duplicate code across packages
  3. Move common utilities to the common package

  4. Use workspace dependencies in pyproject.toml

    [project]
    dependencies = [
        "grizzly-loadtester-common",
    ]
    

  5. Always preserve uv.lock

  6. Use uv sync --locked when installing
  7. Commit the lock file to ensure reproducible builds

Testing Strategy

  1. Unit Tests: Mock external dependencies, fast execution
  2. E2E Tests: Run against real services, validate full functionality
  3. Coverage: All code must be covered with unit tests
  4. Group Tests: Organize tests by functionality

Adding a New Package

When adding a new package to the workspace:

  1. Create the package directory with pyproject.toml
  2. Update root pyproject.toml:
  3. tool.pytest.ini_options
  4. tool.coverage.path
  5. tool.mypy
  6. Add test scripts to tool.hatch.envs.test.scripts
  7. Run uv sync --locked to update the lock file

Release Process

Releases are automated via the .github/workflows/release.yaml workflow.

Release Triggers

The release workflow can be triggered in two ways:

  1. Automatic (PR Merge): When a PR is merged to main with one of these labels:
  2. major - Breaking changes (X.0.0)
  3. minor - New features (0.X.0)
  4. patch - Bug fixes (0.0.X)

  5. Manual (Workflow Dispatch): Manually trigger the workflow from GitHub Actions UI

  6. Specify the PR number
  7. Optionally enable dry-run mode (no actual release)

Release Workflow Steps

  1. Prerequisites Job
  2. Validates the PR and checks for the version bump label
  3. Detects which packages changed using .github/changes-filter.yaml
  4. Maps changes to packages and their dependencies

  5. UV Release Job (Python packages)

  6. Builds packages using uv build --package <package> --sdist --wheel
  7. Creates a git tag (e.g., framework@v1.2.3)
  8. Publishes to PyPI using trusted publishing (OIDC)
  9. Pushes the tag only if all steps succeed

  10. NPM Release Job (VS Code extension)

  11. Builds the extension using @vscode/vsce package
  12. Creates a git tag (e.g., vscode-extension@v1.2.3)
  13. Publishes to VS Code Marketplace
  14. Pushes the tag only if all steps succeed

  15. Documentation Job

  16. Builds and deploys documentation to GitHub Pages
  17. Only runs if previous jobs succeed

Version Management

Versions are managed automatically using:

  • Python packages: hatch-vcs with git tags matching pattern in pyproject.toml

    [tool.hatch.version]
    source = "vcs"
    raw-options.scm.git.describe_command = "git describe --tags --match 'framework@v*[0-9]*'"
    

  • NPM packages: package.local.json defines the tag pattern

    {
      "tag": {
        "pattern": "ls/<IDE>@v*[0-9]*"
      }
    }
    

Release Requirements

For a package to be releasable:

  1. Python packages must have:
  2. tool.hatch.version.raw-options.scm.git.describe_command in pyproject.toml

  3. NPM packages must have:

  4. tag.pattern in package.local.json

  5. Workflow files (.github/workflows/) cannot be modified in the same PR

  6. The map-changes.py script will fail if workflow changes are detected during release
  7. This prevents permission issues with GITHUB_TOKEN when pushing tags

Tag Management

The setup-release action creates tags during the job and manages them in a cleanup phase:

  • Success: Tag is pushed to the repository
  • Failure: Tag is deleted locally (not pushed)
  • Dry-run: Tag is deleted (no push)

Secrets Required

Configure these secrets in your GitHub repository:

  1. VSCE_TOKEN: Personal Access Token for VS Code Marketplace
  2. Required for publishing the VS Code extension
  3. Get from Azure DevOps

  4. GITHUB_TOKEN: Automatically provided by GitHub Actions

  5. Used for API access and documentation deployment

Manual Release Example

# Trigger via GitHub Actions UI
# 1. Go to Actions → Release
# 2. Click "Run workflow"
# 3. Select branch: main
# 4. Enter PR number: 123
# 5. Enable dry-run: true (optional)
# 6. Click "Run workflow"

Dry-Run Mode

Test the release process without actually publishing:

# In workflow_dispatch, set dry-run: true

This will: - Create and validate tags - Build packages - Skip actual publishing to PyPI/VS Code Marketplace - Delete tags at the end

VS Code Extension Development

Building the Extension

cd editor-support/clients/vscode
npm install
npm run compile

Watch Mode

For active development with auto-rebuild:

npm run tsc-watch

Or use the VS Code task:

# Press Cmd/Ctrl+Shift+B → Select "tsc watch"

Testing the Extension

  1. Open the extension project in VS Code
  2. Press F5 to launch Extension Development Host
  3. The extension will be loaded in a new VS Code window

Important Notes

  • VS Code extension requires rebuild after language server changes
  • Always run tests after modifying language server code
  • Extension source is in TypeScript, compiled to JavaScript in dist/

Documentation

The documentation is built using MkDocs with a custom plugin for API reference generation.

Building Documentation

uv run mkdocs build

Serving Documentation Locally

uv run mkdocs serve

Then visit http://localhost:8000

Documentation Structure

  • docs/site/ - Static markdown pages
  • docs/build/ - Generated output (deployed to GitHub Pages)
  • Custom MkDocs plugin generates API reference from code

Common Gotchas

  1. Always use uv sync --locked
  2. Preserves dependency locks
  3. Ensures reproducible builds

  4. E2E tests require additional setup

  5. See package-specific READMEs
  6. May need external services (IBM MQ, Azure services, etc.)

  7. VS Code extension rebuild

  8. Required after language server changes
  9. Run npm run compile or use watch mode

  10. Python version compatibility

  11. Test across all supported versions (3.10-3.13)
  12. Use hatch matrix environments

  13. Workflow file changes

  14. Cannot be released in the same PR as package changes
  15. Will cause the release workflow to fail
  16. Create separate PRs for workflow and package changes

Troubleshooting

Dependency Issues

If you encounter dependency conflicts:

# Remove the lock file and resync
rm uv.lock
uv sync -p 3.13 --active --all-packages --all-groups

Test Failures

  1. Check if dependencies are installed: uv sync --locked
  2. Verify Python version: python --version
  3. Check for environment-specific issues in package READMEs
  4. Run with verbose output: pytest -vv

Release Failures

  1. Check PR has correct version label (major/minor/patch)
  2. Verify secrets are configured (VSCE_TOKEN)
  3. Ensure workflow files aren't modified in the PR
  4. Check GitHub Actions logs for detailed error messages
  5. Verify package has release configuration (tag pattern in pyproject.toml or package.local.json)

Contributing

  1. Create a feature branch from main
  2. Make your changes following the development patterns
  3. Write tests for new functionality
  4. Run linting and type checking
  5. Create a PR with appropriate labels (major/minor/patch for releases)
  6. Ensure all CI checks pass

Additional Resources