diff --git a/.augment-guidelines b/.augment-guidelines new file mode 100644 index 000000000..154156b0f --- /dev/null +++ b/.augment-guidelines @@ -0,0 +1,328 @@ +# Augment Guidelines + +## Development Process + +### Project Stack + +The project uses the following tools and technologies: + +- **uv** - Python package management and virtual environments +- **ruff** - Fast Python linter and formatter +- **py.test** - Testing framework + - **pytest-watcher** - Continuous test runner +- **mypy** - Static type checking +- **doctest** - Testing code examples in documentation + +### Development Workflow + +1. **Start with Formatting** + ``` + uv run ruff format . + ``` + +2. **Run Tests** + ``` + uv run py.test + ``` + + For continuous testing during development, use pytest-watcher: + ``` + # Watch all tests + uv run ptw . + + # Watch and run tests immediately, including doctests + uv run ptw . --now --doctest-modules + + # Watch specific files or directories + uv run ptw . --now --doctest-modules src/libtmux/_internal/ + ``` + +3. **Commit Initial Changes** + Make an atomic commit for your changes using conventional commits. + +4. **Run Linting and Type Checking** + ``` + uv run ruff check . --fix --show-fixes + uv run mypy + ``` + +5. **Verify Tests Again** + ``` + uv run py.test + ``` + +6. **Final Commit** + Make a final commit with any linting/typing fixes. + +### Python Code Standards + +#### Docstring Guidelines + +For `src/**/*.py` files, follow these docstring guidelines: + +1. **Use reStructuredText format** for all docstrings. + ```python + """Short description of the function or class. + + Detailed description using reStructuredText format. + + Parameters + ---------- + param1 : type + Description of param1 + param2 : type + Description of param2 + + Returns + ------- + type + Description of return value + """ + ``` + +2. **Keep the main description on the first line** after the opening `"""`. + +3. **Use NumPy docstyle** for parameter and return value documentation. + +#### Doctest Guidelines + +For doctests in `src/**/*.py` files: + +1. **Use narrative descriptions** for test sections rather than inline comments: + ```python + """Example function. + + Examples + -------- + Create an instance: + + >>> obj = ExampleClass() + + Verify a property: + + >>> obj.property + 'expected value' + """ + ``` + +2. **Move complex examples** to dedicated test files at `tests/examples//test_.py` if they require elaborate setup or multiple steps. + +3. **Utilize pytest fixtures** via `doctest_namespace` for more complex test scenarios: + ```python + """Example with fixture. + + Examples + -------- + >>> # doctest_namespace contains all pytest fixtures from conftest.py + >>> example_fixture = getfixture('example_fixture') + >>> example_fixture.method() + 'expected result' + """ + ``` + +4. **Keep doctests simple and focused** on demonstrating usage rather than comprehensive testing. + +5. **Add blank lines between test sections** for improved readability. + +6. **Test your doctests continuously** using pytest-watcher during development: + ``` + # Watch specific modules for doctest changes + uv run ptw . --now --doctest-modules src/path/to/module.py + ``` + +#### Pytest Testing Guidelines + +1. **Use existing fixtures over mocks**: + - Use fixtures from conftest.py instead of `monkeypatch` and `MagicMock` when available + - For instance, if using libtmux, use provided fixtures: `server`, `session`, `window`, and `pane` + - Document in test docstrings why standard fixtures weren't used for exceptional cases + +2. **Preferred pytest patterns**: + - Use `tmp_path` (pathlib.Path) fixture over Python's `tempfile` + - Use `monkeypatch` fixture over `unittest.mock` + +#### Import Guidelines + +1. **Prefer namespace imports**: + - Import modules and access attributes through the namespace instead of importing specific symbols + - Example: Use `import enum` and access `enum.Enum` instead of `from enum import Enum` + - This applies to standard library modules like `pathlib`, `os`, and similar cases + +2. **Standard aliases**: + - For `typing` module, use `import typing as t` + - Access typing elements via the namespace: `t.NamedTuple`, `t.TypedDict`, etc. + - Note primitive types like unions can be done via `|` pipes and primitive types like list and dict can be done via `list` and `dict` directly. + +3. **Benefits of namespace imports**: + - Improves code readability by making the source of symbols clear + - Reduces potential naming conflicts + - Makes import statements more maintainable + +## Git Commit Standards + +### Commit Message Format +``` +Component/File(commit-type[Subcomponent/method]): Concise description + +why: Explanation of necessity or impact. +what: +- Specific technical changes made +- Focused on a single topic + +refs: #issue-number, breaking changes, or relevant links +``` + +### Component Patterns +#### General Code Changes +``` +Component/File(feat[method]): Add feature +Component/File(fix[method]): Fix bug +Component/File(refactor[method]): Code restructure +``` + +#### Packages and Dependencies +| Language | Standard Packages | Dev Packages | Extras / Sub-packages | +|------------|------------------------------------|-------------------------------|-----------------------------------------------| +| General | `lang(deps):` | `lang(deps[dev]):` | | +| Python | `py(deps):` | `py(deps[dev]):` | `py(deps[extra]):` | +| JavaScript | `js(deps):` | `js(deps[dev]):` | `js(deps[subpackage]):`, `js(deps[dev{subpackage}]):` | + +##### Examples +- `py(deps[dev]): Update pytest to v8.1` +- `js(deps[ui-components]): Upgrade Button component package` +- `js(deps[dev{linting}]): Add ESLint plugin` + +#### Documentation Changes +Prefix with `docs:` +``` +docs(Component/File[Subcomponent/method]): Update API usage guide +``` + +#### Test Changes +Prefix with `tests:` +``` +tests(Component/File[Subcomponent/method]): Add edge case tests +``` + +### Commit Types Summary +- **feat**: New features or enhancements +- **fix**: Bug fixes +- **refactor**: Code restructuring without functional change +- **docs**: Documentation updates +- **chore**: Maintenance (dependencies, tooling, config) +- **test**: Test-related updates +- **style**: Code style and formatting + +### General Guidelines +- Subject line: Maximum 50 characters +- Body lines: Maximum 72 characters +- Use imperative mood (e.g., "Add", "Fix", not "Added", "Fixed") +- Limit to one topic per commit +- Separate subject from body with a blank line +- Mark breaking changes clearly: `BREAKING:` +- Use `See also:` to provide external references + +### Good Commit Example +``` +Pane(feat[capture_pane]): Add screenshot capture support + +why: Provide visual debugging capability +what: +- Implement capturePane method with image export +- Integrate with existing Pane component logic +- Document usage in Pane README + +refs: #485 +See also: https://example.com/docs/pane-capture +``` + +### Bad Commit Example +``` +fixed stuff and improved some functions +``` + +## Avoiding Debug Loops + +When debugging becomes circular and unproductive, follow these steps: + +### Detection +- You have made multiple unsuccessful attempts to fix the same issue +- You are adding increasingly complex code to address errors +- Each fix creates new errors in a cascading pattern +- You are uncertain about the root cause after 2-3 iterations + +### Action Plan + +1. **Pause and acknowledge the loop** + - Explicitly state that you are in a potential debug loop + - Review what approaches have been tried and failed + +2. **Minimize to MVP** + - Remove all debugging cruft and experimental code + - Revert to the simplest version that demonstrates the issue + - Focus on isolating the core problem without added complexity + +3. **Comprehensive Documentation** + - Provide a clear summary of the issue + - Include minimal but complete code examples that reproduce the problem + - Document exact error messages and unexpected behaviors + - Explain your current understanding of potential causes + +4. **Format for Portability** + - Present the problem in quadruple backticks for easy copying: + +```` +# Problem Summary +[Concise explanation of the issue] + +## Minimal Reproduction Code +```python +# Minimal code example that reproduces the issue +``` + +## Error/Unexpected Output +``` +[Exact error messages or unexpected output] +``` + +## Failed Approaches +[Brief summary of approaches already tried] + +## Suspected Cause +[Your current hypothesis about what might be causing the issue] +```` + +## LLM-Optimized Markdown Content Guidelines + +When creating or editing markdown files within notes directories, adhere to the following guidelines: + +1. **Conciseness and Clarity**: + - **Be Brief**: Present information succinctly, avoiding unnecessary elaboration. + - **Use Clear Language**: Employ straightforward language to convey ideas effectively. + +2. **Structured Formatting**: + - **Headings**: Utilize markdown headings (`#`, `##`, `###`, etc.) to organize content hierarchically. + - **Lists**: Use bullet points (`-`) or numbered lists (`1.`, `2.`, etc.) to enumerate items clearly. + - **Code Blocks**: Enclose code snippets within triple backticks (```) to distinguish them from regular text. + +3. **Semantic Elements**: + - **Emphasis**: Use asterisks (`*`) or underscores (`_`) for italicizing text to denote emphasis. + - **Strong Emphasis**: Use double asterisks (`**`) or double underscores (`__`) for bold text to highlight critical points. + - **Inline Code**: Use single backticks (`) for inline code references. + +4. **Linking and References**: + - **Hyperlinks**: Format links using `[Link Text](mdc:URL)` to provide direct access to external resources. + - **References**: When citing sources, use footnotes or inline citations to maintain readability. + +5. **Avoid Redundancy**: + - **Eliminate Repetition**: Ensure that information is not unnecessarily repeated within the document. + - **Use Summaries**: Provide brief summaries where detailed explanations are not essential. + +6. **Standard Compliance**: + - **llms.txt Conformance**: Structure the document in alignment with the `llms.txt` standard, which includes: + - An H1 heading with the project or site name. + - A blockquote summarizing the project's purpose. + - Additional markdown sections providing detailed information. + - H2-delimited sections containing lists of URLs for further details. + +For more information on the `llms.txt` standard, refer to the official documentation: https://llmstxt.org/ diff --git a/.codex/instructions.md b/.codex/instructions.md new file mode 120000 index 000000000..4ff3f86e7 --- /dev/null +++ b/.codex/instructions.md @@ -0,0 +1 @@ +../.windsurfrules \ No newline at end of file diff --git a/.cursor/rules/avoid-debug-loops.mdc b/.cursor/rules/avoid-debug-loops.mdc new file mode 100644 index 000000000..8a241ec99 --- /dev/null +++ b/.cursor/rules/avoid-debug-loops.mdc @@ -0,0 +1,57 @@ +--- +description: When stuck in debugging loops, break the cycle by minimizing to an MVP, removing debugging cruft, and documenting the issue completely for a fresh approach +globs: *.py +alwaysApply: true +--- +# Avoid Debug Loops + +When debugging becomes circular and unproductive, follow these steps: + +## Detection +- You have made multiple unsuccessful attempts to fix the same issue +- You are adding increasingly complex code to address errors +- Each fix creates new errors in a cascading pattern +- You are uncertain about the root cause after 2-3 iterations + +## Action Plan + +1. **Pause and acknowledge the loop** + - Explicitly state that you are in a potential debug loop + - Review what approaches have been tried and failed + +2. **Minimize to MVP** + - Remove all debugging cruft and experimental code + - Revert to the simplest version that demonstrates the issue + - Focus on isolating the core problem without added complexity + +3. **Comprehensive Documentation** + - Provide a clear summary of the issue + - Include minimal but complete code examples that reproduce the problem + - Document exact error messages and unexpected behaviors + - Explain your current understanding of potential causes + +4. **Format for Portability** + - Present the problem in quadruple backticks for easy copying: + +```` +# Problem Summary +[Concise explanation of the issue] + +## Minimal Reproduction Code +```python +# Minimal code example that reproduces the issue +``` + +## Error/Unexpected Output +``` +[Exact error messages or unexpected output] +``` + +## Failed Approaches +[Brief summary of approaches already tried] + +## Suspected Cause +[Your current hypothesis about what might be causing the issue] +```` + +This format enables the user to easily copy the entire problem statement into a fresh conversation for a clean-slate approach. diff --git a/.cursor/rules/dev-loop.mdc b/.cursor/rules/dev-loop.mdc new file mode 100644 index 000000000..d60a52109 --- /dev/null +++ b/.cursor/rules/dev-loop.mdc @@ -0,0 +1,187 @@ +--- +description: QA every edit +globs: *.py +alwaysApply: true +--- + +# Development Process + +## Project Stack + +The project uses the following tools and technologies: + +- **uv** - Python package management and virtual environments +- **ruff** - Fast Python linter and formatter +- **py.test** - Testing framework + - **pytest-watcher** - Continuous test runner +- **mypy** - Static type checking +- **doctest** - Testing code examples in documentation + +## 1. Start with Formatting + +Format your code first: + +``` +uv run ruff format . +``` + +## 2. Run Tests + +Verify that your changes pass the tests: + +``` +uv run py.test +``` + +For continuous testing during development, use pytest-watcher: + +``` +# Watch all tests +uv run ptw . + +# Watch and run tests immediately, including doctests +uv run ptw . --now --doctest-modules + +# Watch specific files or directories +uv run ptw . --now --doctest-modules src/libtmux/_internal/ +``` + +## 3. Commit Initial Changes + +Make an atomic commit for your changes using conventional commits. +Use `@git-commits.mdc` for assistance with commit message standards. + +## 4. Run Linting and Type Checking + +Check and fix linting issues: + +``` +uv run ruff check . --fix --show-fixes +``` + +Check typings: + +``` +uv run mypy +``` + +## 5. Verify Tests Again + +Ensure tests still pass after linting and type fixes: + +``` +uv run py.test +``` + +## 6. Final Commit + +Make a final commit with any linting/typing fixes. +Use `@git-commits.mdc` for assistance with commit message standards. + +## Development Loop Guidelines + +If there are any failures at any step due to your edits, fix them before proceeding to the next step. + +## Python Code Standards + +### Docstring Guidelines + +For `src/**/*.py` files, follow these docstring guidelines: + +1. **Use reStructuredText format** for all docstrings. + ```python + """Short description of the function or class. + + Detailed description using reStructuredText format. + + Parameters + ---------- + param1 : type + Description of param1 + param2 : type + Description of param2 + + Returns + ------- + type + Description of return value + """ + ``` + +2. **Keep the main description on the first line** after the opening `"""`. + +3. **Use NumPy docstyle** for parameter and return value documentation. + +### Doctest Guidelines + +For doctests in `src/**/*.py` files: + +1. **Use narrative descriptions** for test sections rather than inline comments: + ```python + """Example function. + + Examples + -------- + Create an instance: + + >>> obj = ExampleClass() + + Verify a property: + + >>> obj.property + 'expected value' + """ + ``` + +2. **Move complex examples** to dedicated test files at `tests/examples//test_.py` if they require elaborate setup or multiple steps. + +3. **Utilize pytest fixtures** via `doctest_namespace` for more complex test scenarios: + ```python + """Example with fixture. + + Examples + -------- + >>> # doctest_namespace contains all pytest fixtures from conftest.py + >>> example_fixture = getfixture('example_fixture') + >>> example_fixture.method() + 'expected result' + """ + ``` + +4. **Keep doctests simple and focused** on demonstrating usage rather than comprehensive testing. + +5. **Add blank lines between test sections** for improved readability. + +6. **Test your doctests continuously** using pytest-watcher during development: + ``` + # Watch specific modules for doctest changes + uv run ptw . --now --doctest-modules src/path/to/module.py + ``` + +### Pytest Testing Guidelines + +1. **Use existing fixtures over mocks**: + - Use fixtures from conftest.py instead of `monkeypatch` and `MagicMock` when available + - For instance, if using libtmux, use provided fixtures: `server`, `session`, `window`, and `pane` + - Document in test docstrings why standard fixtures weren't used for exceptional cases + +2. **Preferred pytest patterns**: + - Use `tmp_path` (pathlib.Path) fixture over Python's `tempfile` + - Use `monkeypatch` fixture over `unittest.mock` + +### Import Guidelines + +1. **Prefer namespace imports**: + - Import modules and access attributes through the namespace instead of importing specific symbols + - Example: Use `import enum` and access `enum.Enum` instead of `from enum import Enum` + - This applies to standard library modules like `pathlib`, `os`, and similar cases + +2. **Standard aliases**: + - For `typing` module, use `import typing as t` + - Access typing elements via the namespace: `t.NamedTuple`, `t.TypedDict`, etc. + - Note primitive types like unions can be done via `|` pipes and primitive types like list and dict can be done via `list` and `dict` directly. + +3. **Benefits of namespace imports**: + - Improves code readability by making the source of symbols clear + - Reduces potential naming conflicts + - Makes import statements more maintainable diff --git a/.cursor/rules/git-commits.mdc b/.cursor/rules/git-commits.mdc new file mode 100644 index 000000000..f9c0980db --- /dev/null +++ b/.cursor/rules/git-commits.mdc @@ -0,0 +1,95 @@ +--- +description: git-commits: Git commit message standards and AI assistance +globs: git-commits: Git commit message standards and AI assistance | *.git/* .gitignore .github/* CHANGELOG.md CHANGES.md +alwaysApply: true +--- +# Optimized Git Commit Standards + +## Commit Message Format +``` +Component/File(commit-type[Subcomponent/method]): Concise description + +why: Explanation of necessity or impact. +what: +- Specific technical changes made +- Focused on a single topic + +refs: #issue-number, breaking changes, or relevant links +``` + +## Component Patterns +### General Code Changes +``` +Component/File(feat[method]): Add feature +Component/File(fix[method]): Fix bug +Component/File(refactor[method]): Code restructure +``` + +### Packages and Dependencies +| Language | Standard Packages | Dev Packages | Extras / Sub-packages | +|------------|------------------------------------|-------------------------------|-----------------------------------------------| +| General | `lang(deps):` | `lang(deps[dev]):` | | +| Python | `py(deps):` | `py(deps[dev]):` | `py(deps[extra]):` | +| JavaScript | `js(deps):` | `js(deps[dev]):` | `js(deps[subpackage]):`, `js(deps[dev{subpackage}]):` | + +#### Examples +- `py(deps[dev]): Update pytest to v8.1` +- `js(deps[ui-components]): Upgrade Button component package` +- `js(deps[dev{linting}]): Add ESLint plugin` + +### Documentation Changes +Prefix with `docs:` +``` +docs(Component/File[Subcomponent/method]): Update API usage guide +``` + +### Test Changes +Prefix with `tests:` +``` +tests(Component/File[Subcomponent/method]): Add edge case tests +``` + +## Commit Types Summary +- **feat**: New features or enhancements +- **fix**: Bug fixes +- **refactor**: Code restructuring without functional change +- **docs**: Documentation updates +- **chore**: Maintenance (dependencies, tooling, config) +- **test**: Test-related updates +- **style**: Code style and formatting + +## General Guidelines +- Subject line: Maximum 50 characters +- Body lines: Maximum 72 characters +- Use imperative mood (e.g., "Add", "Fix", not "Added", "Fixed") +- Limit to one topic per commit +- Separate subject from body with a blank line +- Mark breaking changes clearly: `BREAKING:` +- Use `See also:` to provide external references + +## AI Assistance Workflow in Cursor +- Stage changes with `git add` +- Use `@commit` to generate initial commit message +- Review and refine generated message +- Ensure adherence to these standards + +## Good Commit Example +``` +Pane(feat[capture_pane]): Add screenshot capture support + +why: Provide visual debugging capability +what: +- Implement capturePane method with image export +- Integrate with existing Pane component logic +- Document usage in Pane README + +refs: #485 +See also: https://example.com/docs/pane-capture +``` + +## Bad Commit Example +``` +fixed stuff and improved some functions +``` + +These guidelines ensure clear, consistent commit histories, facilitating easier code review and maintenance. \ No newline at end of file diff --git a/.cursor/rules/notes-llms-txt.mdc b/.cursor/rules/notes-llms-txt.mdc new file mode 100644 index 000000000..ac1709773 --- /dev/null +++ b/.cursor/rules/notes-llms-txt.mdc @@ -0,0 +1,42 @@ +--- +description: LLM-friendly markdown format for notes directories +globs: notes/**/*.md,**/notes/**/*.md +alwaysApply: true +--- + +# Instructions for Generating LLM-Optimized Markdown Content + +When creating or editing markdown files within the specified directories, adhere to the following guidelines to ensure the content is optimized for LLM understanding and efficient token usage: + +1. **Conciseness and Clarity**: + - **Be Brief**: Present information succinctly, avoiding unnecessary elaboration. + - **Use Clear Language**: Employ straightforward language to convey ideas effectively. + +2. **Structured Formatting**: + - **Headings**: Utilize markdown headings (`#`, `##`, `###`, etc.) to organize content hierarchically. + - **Lists**: Use bullet points (`-`) or numbered lists (`1.`, `2.`, etc.) to enumerate items clearly. + - **Code Blocks**: Enclose code snippets within triple backticks (```) to distinguish them from regular text. + +3. **Semantic Elements**: + - **Emphasis**: Use asterisks (`*`) or underscores (`_`) for italicizing text to denote emphasis. + - **Strong Emphasis**: Use double asterisks (`**`) or double underscores (`__`) for bold text to highlight critical points. + - **Inline Code**: Use single backticks (`) for inline code references. + +4. **Linking and References**: + - **Hyperlinks**: Format links using `[Link Text](mdc:URL)` to provide direct access to external resources. + - **References**: When citing sources, use footnotes or inline citations to maintain readability. + +5. **Avoid Redundancy**: + - **Eliminate Repetition**: Ensure that information is not unnecessarily repeated within the document. + - **Use Summaries**: Provide brief summaries where detailed explanations are not essential. + +6. **Standard Compliance**: + - **llms.txt Conformance**: Structure the document in alignment with the `llms.txt` standard, which includes: + - An H1 heading with the project or site name. + - A blockquote summarizing the project's purpose. + - Additional markdown sections providing detailed information. + - H2-delimited sections containing lists of URLs for further details. + +By following these guidelines, the markdown files will be tailored for optimal LLM processing, ensuring that the content is both accessible and efficiently tokenized for AI applications. + +For more information on the `llms.txt` standard, refer to the official documentation: https://llmstxt.org/ diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..1246879c4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.dump eol=lf diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..d202a332d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "weekly" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 5da69bd96..000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - schedule: - - cron: '16 5 * * 2' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: "python" - - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 929a2b854..01608bc74 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -10,11 +10,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10"] + python-version: ['3.13'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Filter changed file paths to outputs - uses: dorny/paths-filter@v2.7.0 + uses: dorny/paths-filter@v3.0.2 id: changes with: filters: | @@ -27,31 +27,30 @@ jobs: python_files: - 'libvcs/**' - pyproject.toml - - poetry.lock + - uv.lock - name: Should publish if: steps.changes.outputs.docs == 'true' || steps.changes.outputs.root_docs == 'true' || steps.changes.outputs.python_files == 'true' run: echo "PUBLISH=$(echo true)" >> $GITHUB_ENV - - name: Install poetry + - name: Install uv if: env.PUBLISH == 'true' - run: pipx install "poetry==1.2.1" + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true - name: Set up Python ${{ matrix.python-version }} if: env.PUBLISH == 'true' - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - cache: 'poetry' + run: uv python install ${{ matrix.python-version }} - name: Install dependencies [w/ docs] if: env.PUBLISH == 'true' - run: poetry install --extras "docs lint" + run: uv sync --all-extras --dev - name: Build documentation if: env.PUBLISH == 'true' run: | - pushd docs; make SPHINXBUILD='poetry run sphinx-build' html; popd + pushd docs; make SPHINXBUILD='uv run sphinx-build' html; popd - name: Push documentation to S3 if: env.PUBLISH == 'true' @@ -62,8 +61,8 @@ jobs: AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_REGION: "us-west-1" # optional: defaults to us-east-1 - SOURCE_DIR: "docs/_build/html" # optional: defaults to entire repository + AWS_REGION: 'us-west-1' # optional: defaults to us-east-1 + SOURCE_DIR: 'docs/_build/html' # optional: defaults to entire repository - name: Purge cache on Cloudflare if: env.PUBLISH == 'true' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 568576f39..ec7f4d9fa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,39 +16,41 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ '3.9', '3.10' ] + python-version: ['3.9', '3.13'] steps: - - uses: actions/checkout@v3 - - name: Install poetry - run: pipx install "poetry==1.2.1" + - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - cache: 'poetry' + run: uv python install ${{ matrix.python-version }} - name: Install dependencies - run: poetry install -E "docs test coverage lint format" + run: uv sync --all-extras --dev + + - name: Lint with ruff check + run: uv run ruff check . - - name: Lint with flake8 - run: poetry run flake8 + - name: Format with ruff + run: uv run ruff format . --check - name: Lint with mypy - run: poetry run mypy . + run: uv run mypy . - name: Print python versions run: | python -V - poetry run python -V + uv run python -V - name: Test with pytest - run: poetry run py.test --cov=./ --cov-append --cov-report=xml + run: uv run py.test --cov=./ --cov-append --cov-report=xml env: COV_CORE_SOURCE: . COV_CORE_CONFIG: .coveragerc COV_CORE_DATAFILE: .coverage.eager - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -59,26 +61,23 @@ jobs: strategy: matrix: - python-version: ["3.10"] + python-version: ['3.13'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: Install poetry - run: pipx install "poetry==1.2.1" + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - cache: 'poetry' + run: uv python install ${{ matrix.python-version }} - name: Build package - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') - run: poetry build + run: uv build - name: Publish package - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ diff --git a/.gitignore b/.gitignore index 2b9e6ffe7..29869d033 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,8 @@ pip-wheel-metadata/ # Monkeytype monkeytype.sqlite3 + +# AI +*repopack* + +**/.claude/settings.local.json diff --git a/.python-version b/.python-version index 5ca284fcd..4eba2a62e 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.10.7 3.9.13 +3.13.0 diff --git a/.tmuxp.yaml b/.tmuxp.yaml index d524776d6..20b81abb0 100644 --- a/.tmuxp.yaml +++ b/.tmuxp.yaml @@ -1,25 +1,15 @@ session_name: libvcs start_directory: ./ # load session relative to config location (project root). shell_command_before: -- '[ -f .venv/bin/activate ] && source .venv/bin/activate && reset' +- uv virtualenv --quiet > /dev/null 2>&1 && clear windows: - window_name: libvcs focus: True layout: main-horizontal options: - main-pane-height: 35 + main-pane-height: 67% panes: - focus: true - - pane - - make watch_mypy - - make start -- window_name: docs - layout: main-horizontal - options: - main-pane-height: 35 - start_directory: docs/ - panes: - - focus: true - - pane + - pane - pane - make start diff --git a/.tool-versions b/.tool-versions index b4576c08e..5bf889935 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -poetry 1.2.1 -python 3.10.7 3.9.13 +uv 0.7.12 +python 3.13.4 3.12.11 3.11.13 3.10.18 3.9.23 diff --git a/.vim/coc-settings.json b/.vim/coc-settings.json new file mode 100644 index 000000000..d542a7262 --- /dev/null +++ b/.vim/coc-settings.json @@ -0,0 +1,19 @@ +{ + "[markdown][python]": { + "coc.preferences.formatOnSave": true + }, + "python.analysis.autoSearchPaths": true, + "python.analysis.typeCheckingMode": "basic", + "python.analysis.useLibraryCodeForTypes": true, + "python.formatting.provider": "ruff", + "python.linting.ruffEnabled": true, + "python.linting.mypyEnabled": true, + "python.linting.flake8Enabled": false, + "python.linting.pyflakesEnabled": false, + "python.linting.pycodestyleEnabled": false, + "python.linting.banditEnabled": false, + "python.linting.pylamaEnabled": false, + "python.linting.pylintEnabled": false, + "pyright.organizeimports.provider": "ruff", + "pyright.testing.provider": "pytest", +} diff --git a/.windsurfrules b/.windsurfrules new file mode 100644 index 000000000..b0de6f120 --- /dev/null +++ b/.windsurfrules @@ -0,0 +1,162 @@ +# Python Project Rules + + +- uv - Python package management and virtual environments +- ruff - Fast Python linter and formatter +- py.test - Testing framework + - pytest-watcher - Continuous test runner +- mypy - Static type checking +- doctest - Testing code examples in documentation + + + +- Use a consistent coding style throughout the project +- Format code with ruff before committing +- Run linting and type checking before finalizing changes +- Verify tests pass after each significant change + + + +- Use reStructuredText format for all docstrings in src/**/*.py files +- Keep the main description on the first line after the opening `"""` +- Use NumPy docstyle for parameter and return value documentation +- Format docstrings as follows: + ```python + """Short description of the function or class. + + Detailed description using reStructuredText format. + + Parameters + ---------- + param1 : type + Description of param1 + param2 : type + Description of param2 + + Returns + ------- + type + Description of return value + """ + ``` + + + +- Use narrative descriptions for test sections rather than inline comments +- Format doctests as follows: + ```python + """ + Examples + -------- + Create an instance: + + >>> obj = ExampleClass() + + Verify a property: + + >>> obj.property + 'expected value' + """ + ``` +- Add blank lines between test sections for improved readability +- Keep doctests simple and focused on demonstrating usage +- Move complex examples to dedicated test files at tests/examples//test_.py +- Utilize pytest fixtures via doctest_namespace for complex scenarios + + + +- Run tests with `uv run py.test` before committing changes +- Use pytest-watcher for continuous testing: `uv run ptw . --now --doctest-modules` +- Fix any test failures before proceeding with additional changes + + + +- Make atomic commits with conventional commit messages +- Start with an initial commit of functional changes +- Follow with separate commits for formatting, linting, and type checking fixes + + + +- Use the following commit message format: + ``` + Component/File(commit-type[Subcomponent/method]): Concise description + + why: Explanation of necessity or impact. + what: + - Specific technical changes made + - Focused on a single topic + + refs: #issue-number, breaking changes, or relevant links + ``` + +- Common commit types: + - **feat**: New features or enhancements + - **fix**: Bug fixes + - **refactor**: Code restructuring without functional change + - **docs**: Documentation updates + - **chore**: Maintenance (dependencies, tooling, config) + - **test**: Test-related updates + - **style**: Code style and formatting + +- Prefix Python package changes with: + - `py(deps):` for standard packages + - `py(deps[dev]):` for development packages + - `py(deps[extra]):` for extras/sub-packages + +- General guidelines: + - Subject line: Maximum 50 characters + - Body lines: Maximum 72 characters + - Use imperative mood (e.g., "Add", "Fix", not "Added", "Fixed") + - Limit to one topic per commit + - Separate subject from body with a blank line + - Mark breaking changes clearly: `BREAKING:` + + + +- Use fixtures from conftest.py instead of monkeypatch and MagicMock when available +- For instance, if using libtmux, use provided fixtures: server, session, window, and pane +- Document in test docstrings why standard fixtures weren't used for exceptional cases +- Use tmp_path (pathlib.Path) fixture over Python's tempfile +- Use monkeypatch fixture over unittest.mock + + + +- Prefer namespace imports over importing specific symbols +- Import modules and access attributes through the namespace: + - Use `import enum` and access `enum.Enum` instead of `from enum import Enum` + - This applies to standard library modules like pathlib, os, and similar cases +- For typing, use `import typing as t` and access via the namespace: + - Access typing elements as `t.NamedTuple`, `t.TypedDict`, etc. + - Note primitive types like unions can be done via `|` pipes + - Primitive types like list and dict can be done via `list` and `dict` directly +- Benefits of namespace imports: + - Improves code readability by making the source of symbols clear + - Reduces potential naming conflicts + - Makes import statements more maintainable + + + +- Use our own libvcs pytest fixtures for all repository-related tests in this project: + - Create temporary repositories efficiently with factory fixtures + - Benefit from automatic cleanup when tests finish + - Utilize proper environment variables and configurations + - Test against real VCS operations without mocking + +- Basic repository testing pattern: + ```python + def test_repository_operation(create_git_remote_repo): + # Create a test repository + repo_path = create_git_remote_repo() + + # Test vcspull functionality with the repository + # ... + ``` + +- For more complex scenarios, use the pre-configured repository instances: + ```python + def test_sync_operations(git_repo): + # git_repo is already a GitSync instance + # Test vcspull sync operations + # ... + ``` + diff --git a/CHANGES b/CHANGES index a0a276146..64c7c3cd5 100644 --- a/CHANGES +++ b/CHANGES @@ -9,9 +9,540 @@ To install the unreleased libvcs version, see $ pip install --user --upgrade --pre libvcs ``` -## libvcs 0.18.x (unreleased) +## libvcs 0.36.x (unreleased) -- _Add your latest changes from PRs here_ +- _Notes on upcoming releases will be added here_ + + + +### Development + +- Cursor rules for development loop and git commit messages (#488) + +## libvcs 0.35.0 (2025-02-22) + +### Breaking changes + +#### `run()` now uses `text=True` (#485) + +This means that unicode, not bytes, will be used for running `subprocess` +commands in libvcs. If there are any compatibility issues with this, please file +a ticket. + +### Development + +#### chore: Implement PEP 563 deferred annotation resolution (#483) + +- Add `from __future__ import annotations` to defer annotation resolution and reduce unnecessary runtime computations during type checking. +- Enable Ruff checks for PEP-compliant annotations: + - [non-pep585-annotation (UP006)](https://docs.astral.sh/ruff/rules/non-pep585-annotation/) + - [non-pep604-annotation (UP007)](https://docs.astral.sh/ruff/rules/non-pep604-annotation/) + +For more details on PEP 563, see: https://peps.python.org/pep-0563/ + +## libvcs 0.34.0 (2024-11-22) + +_Maintenance only, no bug fixes, or new features_ + +### Development + +#### Project and package management: poetry to uv (#479) + +[uv] is the new package and project manager for the project, replacing Poetry. + +[uv]: https://github.com/astral-sh/uv + +#### Build system: poetry to hatchling (#479) + +[Build system] moved from [poetry] to [hatchling]. + +[Build system]: https://packaging.python.org/en/latest/tutorials/packaging-projects/#choosing-a-build-backend +[poetry]: https://github.com/python-poetry/poetry +[hatchling]: https://hatch.pypa.io/latest/ + +## libvcs 0.33.0 (2024-10-13) + +### New features + +#### Python 3.13 support (#477) + +Added Python 3.13 to package trove classifiers and CI tests. + +#### pytest plugin: Authorship fixtures (#476) + +- New, customizable session-scoped fixtures for default committer on Mercurial and Git: + - Name: {func}`libvcs.pytest_plugin.vcs_name` + - Email: {func}`libvcs.pytest_plugin.vcs_email` + - User (e.g. _`user `_): {func}`libvcs.pytest_plugin.vcs_user` + - For git only: {func}`libvcs.pytest_plugin.git_commit_envvars` + +#### pytest plugins: Default repos use authorship fixtures (#476) + +New repos will automatically apply these session-scoped fixtures. + +## libvcs 0.32.3 (2024-10-13) + +### Bug fixes + +- Pytest fixtures `hg_remote_repo_single_commit_post_init()` and `git_remote_repo_single_commit_post_init()` now support passing `env` for VCS configuration. + + Both functions accept `hgconfig` and `gitconfig` fixtures, now applied in the `hg_repo` and `git_repo` fixtures. + +## libvcs 0.32.2 (2024-10-13) + +### Bug fixes + +- Pytest fixtures: `git_repo` and `hg_repo`: Set configuration for both fixtures. + +## libvcs 0.32.1 (2024-10-12) + +### Revert accidental commit + +Update to commands for `Git` from #465 were pushed to trunk before being prepared (even for experimental use). + +## libvcs 0.32.0 (2024-10-12) + +### Breaking changes + +#### pytest fixtures: Session-scoped `hgconfig` and `gitconfig` (#475) + +These are now set by `set_hgconfig` and `set_gitconfig`, which set `HGRCPATH` and `GIT_CONFIG`, instead of overriding `HOME`. + +### Documentation + +- Updates for pytest plugin documentation. + +## libvcs 0.31.0 (2024-10-12) + +### Breaking changes + +#### pytest plugin: Improve performacne via session-based scoping (#472) + +Improved test execution speed by over 54% by eliminated repetitive repository reinitialization between test runs. +Git, Subversion, and Mercurial repositories are now cached from an initial starter repository + +#### pytest fixtures: `git_local_clone` renamed to `example_git_repo` (#468) + +Renamed `git_local_clone` to `example_git_repo` for better understandability in +documentation / doctests. + +#### cmd: Listing method renamed (#466) + +- `libvcs.cmd.git.GitCmd._list()` -> `libvcs.cmd.git.Git.ls()` +- `libvcs.cmd.svn.Svn._list()` -> `libvcs.cmd.svn.Svn.ls()` + +## libvcs 0.30.1 (2024-06-18) + +### Bug Fixes + +- url(git): Remove unused `weight=0` flags from `AWS_CODE_COMMIT_DEFAULT_RULES` + (#464) +- url(git[GitURL]): Support for detection of AWS CodeCommit URLs (#464) + +### Tests + +- url(registry): Tests for `test_registry.py` detection of AWS CodeCommit URLs + (#464) + +### Documentation + +- README: Overhaul and fixes + +## libvcs 0.30.0 (2024-06-18) + +### New features + +### urls: AWS CodeCommit support (#443) + +- Support for [AWS CodeCommit] URL patterns. Examples: + + - HTTPS: `https://git-codecommit.us-east-1.amazonaws.com/v1/repos/test` + - SSH: `ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/test` + - HTTPS (GRC): + - `codecommit::us-east-1://test` + - `codecommit://test` + +[AWS CodeCommit]: https://docs.aws.amazon.com/codecommit/ + +### Breaking changes + +#### urls: Variable changes (#463) + +- `RE_PIP_REV` moved from `libvcs.url.git` to `libvcs.url.constants`. +- Regex pattern for user (e.g., `git@`) decoupled to `RE_USER`. +- `RE_PATH` and `SCP_REGEX` (now `RE_SCP`) no longer include user regex pattern + - Existing patterns now use `RE_USER` explicitly. +- `REGEX_SCP` renamed to `RE_SCP` for consistency. + +### Documentation + +- Automatically linkify links that were previously only text. +- Fix docstrings in `query_list` for `MultipleObjectsReturned` and + `ObjectDoesNotExist`. + +### Development + +- poetry: 1.8.1 -> 1.8.2 + + See also: https://github.com/python-poetry/poetry/blob/1.8.2/CHANGELOG.md + +- Code quality: Use f-strings in more places (#460) + + via [ruff 0.4.2](https://github.com/astral-sh/ruff/blob/v0.4.2/CHANGELOG.md). + +## libvcs 0.29.0 (2024-03-24) + +_Maintenance only, no bug fixes, or new features_ + +### Development + +- Aggressive automated lint fixes via `ruff` (#458) + + via ruff v0.3.4, all automated lint fixes, including unsafe and previews were applied: + + ```sh + ruff check --select ALL . --fix --unsafe-fixes --preview --show-fixes; ruff format . + ``` + + Branches were treated with: + + ```sh + git rebase \ + --strategy-option=theirs \ + --exec 'poetry run ruff check --select ALL . --fix --unsafe-fixes --preview --show-fixes; poetry run ruff format .; git add src tests; git commit --amend --no-edit' \ + origin/master + ``` + +- poetry: 1.7.1 -> 1.8.1 + + See also: https://github.com/python-poetry/poetry/blob/1.8.1/CHANGELOG.md + +- ruff 0.2.2 -> 0.3.0 (#457) + + Related formattings. Update CI to use `ruff check .` instead of `ruff .`. + + See also: https://github.com/astral-sh/ruff/blob/v0.3.0/CHANGELOG.md + +## libvcs 0.28.2 (2024-02-17) + +### Fixes + +- `Git.rev_list`: Fix argument expansion (#455) + + Resolves issue with _fatal: '--max-count': not an integer_. + +### Testing + +- CI: Bump actions to Node 20 releases (#456) + +## libvcs 0.28.1 (2024-02-08) + +### Packaging + +- Source distribution: Include `CHANGES`, `MIGRATION`, and `docs/` in tarball + (#454) + +## libvcs 0.28.0 (2024-02-07) + +### Improvement + +- `QueryList` generic support improved (#453) + +## libvcs 0.27.0 (2024-02-06) + +### Development + +- Strengthen linting (#514) + + - Add flake8-commas (COM) + + - https://docs.astral.sh/ruff/rules/#flake8-commas-com + - https://pypi.org/project/flake8-commas/ + + - Add flake8-builtins (A) + + - https://docs.astral.sh/ruff/rules/#flake8-builtins-a + - https://pypi.org/project/flake8-builtins/ + + - Add flake8-errmsg (EM) + + - https://docs.astral.sh/ruff/rules/#flake8-errmsg-em + - https://pypi.org/project/flake8-errmsg/ + +### CI + +- Move CodeQL from advanced configuration file to GitHub's default + +## libvcs 0.26.0 (2023-11-26) + +### Breaking changes + +- Rename pytest plugin protocol typings (#450): + + - `CreateProjectCallbackProtocol` -> `CreateRepoPostInitFn` + - `CreateProjectCallbackFixtureProtocol` -> `CreateRepoPytestFixtureFn` + +### Bug fixes + +- Remove unused command: `Svn.mergelist` (#450) +- Fix `Git.config` docstring (#450) + +### Development + +- ci: Add pydocstyle rule to ruff (#449) +- Add test for direct usage of `HgSync` (#450) +- pytest-watcher, Add configuration (#450): + + - Run initially by default + - Skip post-save files from vim + +### Documentation + +- Add docstrings to functions, methods, classes, and packages (#449) + +## libvcs 0.25.1 (2023-11-23) + +### Packaging + +- Move `gp-libs` to `test` dependencies + +## libvcs 0.25.0 (2023-11-19) + +_Maintenance only, no bug fixes, or new features_ + +### Packaging + +- Poetry: 1.6.1 -> 1.7.0 + + See also: https://github.com/python-poetry/poetry/blob/1.7.0/CHANGELOG.md + +- Move formatting from `black` to [`ruff format`] (#448) + + This retains the same formatting style of `black` while eliminating a + dev dependency by using our existing rust-based `ruff` linter. + + [`ruff format`]: https://docs.astral.sh/ruff/formatter/ + +- Packaging (poetry): Fix development dependencies + + Per [Poetry's docs on managing dependencies] and `poetry check`, we had it wrong: Instead of using extras, we should create these: + + ```toml + [tool.poetry.group.group-name.dependencies] + dev-dependency = "1.0.0" + ``` + + Which we now do. + + [Poetry's docs on managing dependencies]: https://python-poetry.org/docs/master/managing-dependencies/ + +### Development + +- CI: Update action package to fix warnings + + - [dorny/paths-filter]: 2.7.0 -> 2.11.1 + + [dorny/paths-filter]: https://github.com/dorny/paths-filter + +## libvcs 0.24.0 (2023-10-22) + +### Bug fixes + +- Git Remote URLs: Fix bug that would cause git remotes with `@` to be chopped off after the + protocol (#446, fixes #431) + +### Packaging + +- Move pytest configuration to `pyproject.toml` (#441) + +### Development + +- ruff: Remove ERA / `eradicate` plugin + + This rule had too many false positives to trust. Other ruff rules have been beneficial. + +- query_list: Refactor to use access {mod}`typing` via namespace as `t` (#439) + +## libvcs 0.23.0 (2023-08-20) + +_Maintenance only, no bug fixes, or new features_ + +### Development + +- Code quality improvements (#438) + + Additional ruff settings have been enabled. The most recent contribution + includes 100+ automated fixes and 50+ hand-made fixes. + +### Post-release: v0.23.0post0 (2023-08-20) + +- Fixes code comments cleaned up by `ruff`, but missed in QA. In the future, + even when using an automated tool, we will review more thoroughly. + +## libvcs 0.22.2 (2023-08-20) + +_Maintenance only, no bug fixes, or new features_ + +### Development + +- `SubprocessCommand`: Typing fix for `text` param. Found via mypy(1). + +## libvcs 0.22.1 (2023-05-28) + +_Maintenance only, no bug fixes, or new features_ + +### Development + +- Add back `black` for formatting + + This is still necessary to accompany `ruff`, until it replaces black. + +## libvcs 0.22.0 (2023-05-27) + +_Maintenance only, no bug fixes, or new features_ + +### Internal improvements + +- Move formatting, import sorting, and linting to [ruff]. + + This rust-based checker has dramatically improved performance. Linting and + formatting can be done almost instantly. + + This change replaces black, isort, flake8 and flake8 plugins. + +- poetry: 1.4.0 -> 1.5.0 + + See also: https://github.com/python-poetry/poetry/releases/tag/1.5.0 + +## libvcs 0.21.2 (2023-04-07) + +### Development + +- Update mypy to 1.2.0 + +### Fixes + +- SkipDefaultFieldsReprMixin: Fix typing for mypy 1.2.0 + +## libvcs 0.21.1 (2023-03-15) + +### Fixes + +- Remove more `typing_extensions` from runtime (#437 didn't get them all) + +## libvcs 0.21.0 (2023-03-15) + +### New + +- QueryList learned to `.get()` to pick the first result (#435) + + - Raises error if no items found (unless `default=` keyword argument passed) + - Raises error if multiple items found + +### Bug fixes + +- Remove required dependency of typing-extensions (#437) +- Ignore a single line of mypy check in dataclasses for now (#437) + +## libvcs 0.20.0 (2022-10-31) + +### What's new + +#### Python 3.11 support (#433) + +Official support for python 3.11 + +#### URLs: Mapping now class attributes (#433) + +`URL.rule_map` is now a class attribute rather than a dataclass attribute. + +```console + File "/home/user/.python/3.11.0/lib/python3.11/dataclasses.py", line 1211, in wrap + return _process_class(cls, init, repr, eq, order, unsafe_hash, + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/user/.python/3.11.0/lib/python3.11/dataclasses.py", line 959, in _process_class + cls_fields.append(_get_field(cls, name, type, kw_only)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/user/.python/3.11.0/lib/python3.11/dataclasses.py", line 816, in _get_field + raise ValueError(f'mutable default {type(f.default)} for field ' +ValueError: mutable default for field rule_map is not allowed: use default_factory +``` + +## libvcs 0.19.1 (2022-10-23) + +### Tests + +- Sync, git: Update pytest fixtures, via #432 + +### Documentation + +- CLI, git: Split subcommands into separate pages (remote, stash, submodule), via #432 + +## libvcs 0.19.0 (2022-10-23) + +### New features + +#### Commands + +via #430 + +- Git + + - Support for progress bar + - Add subcommands for: + - stash: {attr}`Git.stash ` -> {class}`libvcs.cmd.git.GitStashCmd` + - remote: {attr}`Git.remote ` -> {class}`libvcs.cmd.git.GitRemoteCmd` + - submodule: {attr}`Git.submodule ` -> + {class}`libvcs.cmd.git.GitSubmoduleCmd` + - Added commands for: + - {meth}`libvcs.cmd.git.Git.rev_parse` + - {meth}`libvcs.cmd.git.Git.rev_list` + - {meth}`libvcs.cmd.git.Git.symbolic_ref` + - {meth}`libvcs.cmd.git.Git.show_ref` + +- SVN + + New and improved: + + - {meth}`libvcs.cmd.svn.Svn.unlock` + - {meth}`libvcs.cmd.svn.Svn.lock` + - {meth}`libvcs.cmd.svn.Svn.propset` + +- Mercurial + + New and improved: + + - {meth}`libvcs.cmd.hg.Hg.pull` + - {meth}`libvcs.cmd.hg.Hg.clone` + - {meth}`libvcs.cmd.hg.Hg.update` + +#### Syncing + +via #430 + +Git, SVN, and Mercurial have moved to `libvcs.cmd` + +## libvcs 0.18.1 (2022-10-23) + +_Maintenance only release, no bug fixes, or new features_ + +- Documentation improvements +- Development package updates +- Add citation file (CITATION.cff) + +## libvcs 0.18.0 (2022-10-09) + +### New features + +#### URLs + +- Added `weight` to matchers (#428) + + - More heavily weighted matcher will have preference over others + - Fixes an issue where `defaults` would be overwritten + + The first, highest weighted will "win", avoiding the recursion causing defau defaults for other + matchers to be applied. ## libvcs 0.17.0 (2022-09-25) @@ -147,7 +678,7 @@ Temporarily add `Faker` as a dependency (due to pytest), track longterm fix on ( ### Documentation -- Render changelog in [`linkify_issues`] (~~#396~~, #403) +- Render changelog in [`linkify_issues`] (#396, #403) - Fix Table of contents rendering with sphinx autodoc with [`sphinx_toctree_autodoc_fix`] (#403) - Deprecate `sphinx-autoapi`, per above fixing the table of contents issue (#403) @@ -239,7 +770,7 @@ Temporarily add `Faker` as a dependency (due to pytest), track longterm fix on ( _Backport from 0.13.4_ -- {func}`~libvcs.shortcuts.create_project`: Add overloads that return the typed project (e.g. +- {func}`~libvcs.shortcuts.create_project`: Add overloads that return the typed project (e.g., {class}`~libvcs.sync.git.GitSync`) _Backport from 0.13.3_ @@ -253,8 +784,7 @@ Temporarily add `Faker` as a dependency (due to pytest), track longterm fix on ( [python/cpython@ead169d] -[python/cpython@ead169d]: - https://github.com/python/cpython/commit/ead169d3114ed0f1041b5b59ca20293449608c50 +[python/cpython@ead169d]: https://github.com/python/cpython/commit/ead169d3114ed0f1041b5b59ca20293449608c50 [^python:bugs:8657]: @@ -282,7 +812,7 @@ Temporarily add `Faker` as a dependency (due to pytest), track longterm fix on ( ### Typings -- `create_project()`: Add overloads that return the typed project (e.g. +- `create_project()`: Add overloads that return the typed project (e.g., {class}`~libvcs.sync.git.GitSync`) ## libvcs 0.13.2 (2022-06-12) @@ -328,7 +858,7 @@ Temporarily add `Faker` as a dependency (due to pytest), track longterm fix on ( Before: `project.parent_dir` - After: `project.parent.dir`. + After: `project.parent.path`. - `repo_name` switched from attribute to property @@ -370,7 +900,7 @@ Temporarily add `Faker` as a dependency (due to pytest), track longterm fix on ( ### Bug fixes -- Fix argument input for commands, e.g. `git config --get color.diff` would not properly +- Fix argument input for commands, for instance `git config --get color.diff` would not properly pass-through to subprocess. git: #360, svn and hg: #365 ### Internals @@ -446,13 +976,13 @@ Temporarily add `Faker` as a dependency (due to pytest), track longterm fix on ( `libvcs.sync.{module}.{Module}Project` - `repo_dir` param is renamed to `dir`: - Before: `GitSync(url='...', repo_dir='...')` + Before: `GitSync(url='...', repo_path='...')` - After: `GitSync(url='...', dir='...')` + After: `GitSync(url='...', path='...')` #324 -- `dir` to `pathlib`, `BaseSync.path` -> `BaseSync.dir` +- `dir` to `pathlib`, `BaseSync.path` -> `BaseSync.path` - Logging functions moved to {attr}`libvcs.sync.base.BaseSync.log` (#322) - Rename `ProjectLoggingAdapter` to `CmdLoggingAdapter` - `CmdLoggingAdapter`: Rename `repo_name` param to `keyword` @@ -492,7 +1022,7 @@ Temporarily add `Faker` as a dependency (due to pytest), track longterm fix on ( ```python repo = GitSync( url="https://github.com/vcs-python/libvcs", - repo_dir=checkout, + repo_path=checkout, remotes={ 'gitlab': 'https://gitlab.com/vcs-python/libvcs', } @@ -502,7 +1032,7 @@ Temporarily add `Faker` as a dependency (due to pytest), track longterm fix on ( ```python repo = GitSync( url="https://github.com/vcs-python/libvcs", - repo_dir=checkout, + repo_path=checkout, remotes={ 'gitlab': { 'fetch_url': 'https://gitlab.com/vcs-python/libvcs', @@ -617,7 +1147,7 @@ releases. The API is subject to change significantly in pre-1.0 builds. - Move sphinx api format to Numpy-style - Move from reStructuredText to Markdown (via recommonmark). The master plan is to eliminate - docutils and sphinx as a bottleneck completely in favor of something else (e.g. gatsby with a + docutils and sphinx as a bottleneck completely in favor of something else (e.g., gatsby with a source that inspects our modules and can source intersphinx) - Move from RTD to GitHub Action, full support of poetry extras packages, deploys straight to S3 diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 000000000..5474ca5e7 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,13 @@ +cff-version: 1.2.0 +message: >- + If you use this software, please cite it as below. + NOTE: Change "x.y" by the version you use. If you are unsure about which version + you are using run: `pip show libvcs`." +authors: +- family-names: "Narlock" + given-names: "Tony" + orcid: "https://orcid.org/0000-0002-2568-415X" +title: "libvcs" +type: software +version: x.y +url: "https://libvcs.git-pull.com" diff --git a/MIGRATION b/MIGRATION new file mode 100644 index 000000000..99a841bad --- /dev/null +++ b/MIGRATION @@ -0,0 +1,94 @@ +# Migration notes + +Migration and deprecation notes for libvcs are here, see {ref}`history` as well. + +```{admonition} Welcome on board! 👋 +1. 📌 For safety, **always** pin the package +2. 📖 Check the migration notes _(You are here)_ +3. 📣 If you feel something got deprecated and it interrupted you - past, present, or future - voice your opinion on the [tracker]. + + We want to make libvcs fun, reliable, and useful for users. + + API changes can be painful. + + If we can do something to draw the sting, we'll do it. We're taking a balanced approach. That's why these notes are here! + + (Please pin the package. 🙏) + + [tracker]: https://github.com/vcs-python/libvcs/discussions +``` + +## Next release + +_Notes on the upcoming release will be added here_ + + + +#### pytest fixtures: `git_local_clone` renamed to `example_git_repo` (#468) + +- pytest: `git_local_clone` renamed to `example_git_repo` + +#### Commands: Listing method renamed (#466) + +- `libvcs.cmd.git.GitCmd._list()` -> `libvcs.cmd.git.Git.ls()` +- `libvcs.cmd.svn.Svn._list()` -> `libvcs.cmd.svn.Svn.ls()` + +## libvcs 0.30.0 (2024-06-18) + +### URLs: Variable renamings and moves (#463) + +- `RE_PIP_REV` moved from `libvcs.url.git` to `libvcs.url.constants`. +- `RE_PATH` has changed: + + - The pattern for user matching (e.g., `git@`) has been extracted to `RE_USER`. + - `RE_PATH` and `SCP_REGEX` (now `RE_SCP`) no longer include user regex pattern + - Existing patterns now use `RE_USER` explicitly. + +- `REGEX_SCP` renamed to `RE_SCP` for consistency. + +## libvcs 0.20.0 (2022-10-31) + +### URLs: Mapping now class attributes (#433) + +`URL.rule_map` is now a class attribute rather than a dataclass attribute. + +Before: + +```python +@dataclasses.dataclass(repr=False) +class GitLabURL(GitURL): + rule_map: RuleMap = RuleMap( + _rule_map={'gitlab_prefix': GitLabPrefix} + ) +``` + +In python 3.11, that raises an error: + +```console + File "/home/user/.python/3.11.0/lib/python3.11/dataclasses.py", line 1211, in wrap + return _process_class(cls, init, repr, eq, order, unsafe_hash, + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/user/.python/3.11.0/lib/python3.11/dataclasses.py", line 959, in _process_class + cls_fields.append(_get_field(cls, name, type, kw_only)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/user/.python/3.11.0/lib/python3.11/dataclasses.py", line 816, in _get_field + raise ValueError(f'mutable default {type(f.default)} for field ' +ValueError: mutable default for field rule_map is not allowed: use default_factory +``` + +After release: + +```python +>>> import dataclasses +>>> from libvcs.url.base import RuleMap +>>> from libvcs.url.git import GitURL, DEFAULT_RULES +>>> @dataclasses.dataclass(repr=False) +... class MyGitURL(GitURL): +... rule_map = RuleMap( +... _rule_map={'gitlab_prefix': DEFAULT_RULES} +... ) +``` + + diff --git a/Makefile b/Makefile index 8bf6684a3..d96552f2e 100644 --- a/Makefile +++ b/Makefile @@ -9,20 +9,14 @@ entr_warn: @echo " ! File watching functionality non-operational ! " @echo " " @echo "Install entr(1) to automatically run tasks on file change." - @echo "See http://entrproject.org/ " + @echo "See https://eradman.com/entrproject/ " @echo "----------------------------------------------------------" -isort: - poetry run isort `${PY_FILES}` - -black: - poetry run black `${PY_FILES}` - test: - poetry run py.test $(test) + uv run py.test $(test) start: - $(MAKE) test; poetry run ptw . + $(MAKE) test; uv run ptw . watch_test: if command -v entr > /dev/null; then ${ALL_FILES} | entr -c $(MAKE) test; else $(MAKE) test entr_warn; fi @@ -39,14 +33,17 @@ start_docs: design_docs: $(MAKE) -C docs design -flake8: - poetry run flake8 +ruff_format: + uv run ruff format . + +ruff: + uv run ruff check . -watch_flake8: - if command -v entr > /dev/null; then ${PY_FILES} | entr -c $(MAKE) flake8; else $(MAKE) flake8 entr_warn; fi +watch_ruff: + if command -v entr > /dev/null; then ${PY_FILES} | entr -c $(MAKE) ruff; else $(MAKE) ruff entr_warn; fi mypy: - poetry run mypy `${PY_FILES}` + uv run mypy `${PY_FILES}` watch_mypy: if command -v entr > /dev/null; then ${PY_FILES} | entr -c $(MAKE) mypy; else $(MAKE) mypy entr_warn; fi @@ -55,7 +52,7 @@ format_markdown: prettier --parser=markdown -w *.md docs/*.md docs/**/*.md CHANGES monkeytype_create: - poetry run monkeytype run `poetry run which py.test` + uv run monkeytype run `uv run which py.test` monkeytype_apply: - poetry run monkeytype list-modules | xargs -n1 -I{} sh -c 'poetry run monkeytype apply {}' + uv run monkeytype list-modules | xargs -n1 -I{} sh -c 'uv run monkeytype apply {}' diff --git a/README.md b/README.md index 4a06c9408..0c5db2102 100644 --- a/README.md +++ b/README.md @@ -6,25 +6,28 @@ detection and parsing of URLs, commanding, and syncing with `git`, `hg`, and `sv ## Overview -Features for Git, Subversion, and Mercurial: +### Key Features -- **Detect and parse** VCS URLs -- **Command** VCS via python API -- **Sync** repos locally -- **Test fixtures** for temporary local repos and working copies +- **URL Detection and Parsing**: Validate and parse Git, Mercurial, and Subversion URLs. +- **Command Abstraction**: Interact with VCS systems through a Python API. +- **Repository Synchronization**: Clone and update repositories locally via + Python API. +- **py.test fixtures**: Create temporary local repositories and working copies for testing for unit tests. -To **get started**, see the [quickstart](https://libvcs.git-pull.com/quickstart.html) for more. +_Supports Python 3.9 and above, Git (including AWS CodeCommit), Subversion, and Mercurial._ + +To **get started**, see the [quickstart guide](https://libvcs.git-pull.com/quickstart.html) for more information. ```console $ pip install --user libvcs ``` -## URL Parser +## URL Detection and Parsing -You can validate and parse Git, Mercurial, and Subversion URLs through -[`libvcs.url`](https://libvcs.git-pull.com/url/index.html): +Easily validate and parse VCS URLs using the +[`libvcs.url`](https://libvcs.git-pull.com/url/index.html) module: -Validate: +### Validate URLs ```python >>> from libvcs.url.git import GitURL @@ -33,7 +36,7 @@ Validate: True ``` -Parse and adjust a Git URL: +### Parse and adjust Git URLs: ```python >>> from libvcs.url.git import GitURL @@ -71,24 +74,29 @@ Switch repo libvcs -> vcspull: See more in the [parser document](https://libvcs.git-pull.com/parse/index.html). -## Commands +## Command Abstraction + +Abstracts CLI commands for `git(1)`, `hg(1)`, `svn(1)` via a lightweight [`subprocess`](https://docs.python.org/3/library/subprocess.html) wrapper. -Simple [`subprocess`](https://docs.python.org/3/library/subprocess.html) wrappers around `git(1)`, -`hg(1)`, `svn(1)`. Here is [`Git`](https://libvcs.git-pull.com/cmd/git.html#libvcs.cmd.git.Git) w/ -[`Git.clone`](http://libvcs.git-pull.com/cmd/git.html#libvcs.cmd.git.Git.clone): +### Run Git Commands ```python import pathlib from libvcs.cmd.git import Git -git = Git(dir=pathlib.Path.cwd() / 'my_git_repo') +git = Git(path=pathlib.Path.cwd() / 'my_git_repo') git.clone(url='https://github.com/vcs-python/libvcs.git') ``` -## Sync +Above: [`libvcs.cmd.git.Git`](https://libvcs.git-pull.com/cmd/git.html#libvcs.cmd.git.Git) using +[`Git.clone()`](http://libvcs.git-pull.com/cmd/git.html#libvcs.cmd.git.Git.clone). + +## Repository Synchronization + +Synchronize your repositories using the +[`libvcs.sync`](https://libvcs.git-pull.com/sync/) module. -Create a [`GitSync`](https://libvcs.git-pull.com/projects/git.html#libvcs.sync.git.GitProject) -object of the project to inspect / checkout / update: +### Clone and Update Repositories ```python import pathlib @@ -96,7 +104,7 @@ from libvcs.sync.git import GitSync repo = GitSync( url="https://github.com/vcs-python/libvcs", - dir=pathlib.Path().cwd() / "my_repo", + path=pathlib.Path().cwd() / "my_repo", remotes={ 'gitlab': 'https://gitlab.com/vcs-python/libvcs' } @@ -110,31 +118,35 @@ repo = GitSync( u'5c227e6ab4aab44bf097da2e088b0ff947370ab8' ``` -## Pytest plugin +Above: [`libvcs.sync.git.GitSync`](https://libvcs.git-pull.com/projects/git.html#libvcs.sync.git.GitSync) repository +object using +[`GitSync.update_repo()`](https://libvcs.git-pull.com/sync/git.html#libvcs.sync.git.GitSync.update_repo) +and +[`GitSync.get_revision()`](https://libvcs.git-pull.com/sync/git.html#libvcs.sync.git.GitSync.get_revision). -libvcs also provides a test rig for local repositories. It automatically can provide clean local -repositories and working copies for git, svn, and mercurial. They are automatically cleaned up after -each test. +## Pytest plugin: Temporary VCS repositories for testing -It works by bootstrapping a temporary `$HOME` environment in a -[`TmpPathFactory`](https://docs.pytest.org/en/7.1.x/reference/reference.html#tmp-path-factory-factory-api) -for automatic cleanup. +libvcs [pytest plugin](https://libvcs.git-pull.com/pytest-plugin.html) provides [py.test fixtures] to swiftly create local VCS repositories and working repositories to test with. Repositories are automatically cleaned on test teardown. + +[py.test fixtures]: https://docs.pytest.org/en/8.2.x/explanation/fixtures.html + +### Use temporary, local VCS in py.test ```python import pathlib -from libvcs.pytest_plugin import CreateProjectCallbackFixtureProtocol +from libvcs.pytest_plugin import CreateRepoPytestFixtureFn from libvcs.sync.git import GitSync def test_repo_git_remote_checkout( - create_git_remote_repo: CreateProjectCallbackFixtureProtocol, + create_git_remote_repo: CreateRepoPytestFixtureFn, tmp_path: pathlib.Path, projects_path: pathlib.Path, ) -> None: git_server = create_git_remote_repo() git_repo_checkout_dir = projects_path / "my_git_checkout" - git_repo = GitSync(dir=str(git_repo_checkout_dir), url=f"file://{git_server!s}") + git_repo = GitSync(path=str(git_repo_checkout_dir), url=f"file://{git_server!s}") git_repo.obtain() git_repo.update_repo() @@ -145,7 +157,9 @@ def test_repo_git_remote_checkout( assert pathlib.Path(git_repo_checkout_dir / ".git").exists() ``` -Learn more on the docs at https://libvcs.git-pull.com/pytest-plugin.html +Under the hood: fixtures bootstrap a temporary `$HOME` environment in a +[`TmpPathFactory`](https://docs.pytest.org/en/7.1.x/reference/reference.html#tmp-path-factory-factory-api) +for automatic cleanup and `pytest-xdist` compatibility.. ## Donations @@ -153,7 +167,7 @@ Your donations fund development of new features, testing and support. Your money maintenance and development of the project. If you are an individual, feel free to give whatever feels right for the value you get out of the project. -See donation options at . +See donation options at . ## More information diff --git a/conftest.py b/conftest.py index 98bc77c0f..6a3efb34a 100644 --- a/conftest.py +++ b/conftest.py @@ -1,4 +1,4 @@ -"""Conftest.py (root-level) +"""Conftest.py (root-level). We keep this in root pytest fixtures in pytest's doctest plugin to be available, as well as avoiding conftest.py from being included in the wheel, in addition to pytest_plugin @@ -7,19 +7,25 @@ See "pytest_plugins in non-top-level conftest files" in https://docs.pytest.org/en/stable/deprecations.html """ -import pathlib + +from __future__ import annotations + import typing as t import pytest +if t.TYPE_CHECKING: + import pathlib + pytest_plugins = ["pytester"] @pytest.fixture(autouse=True) def add_doctest_fixtures( request: pytest.FixtureRequest, - doctest_namespace: t.Dict[str, t.Any], + doctest_namespace: dict[str, t.Any], ) -> None: + """Configure doctest fixtures for pytest-doctest.""" from _pytest.doctest import DoctestItem if isinstance(request._pyfuncitem, DoctestItem): @@ -27,15 +33,16 @@ def add_doctest_fixtures( request.getfixturevalue("set_home") +@pytest.fixture(autouse=True) +def cwd_default(monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path) -> None: + """Configure current directory for pytest tests.""" + monkeypatch.chdir(tmp_path) + + @pytest.fixture(autouse=True) def setup( request: pytest.FixtureRequest, gitconfig: pathlib.Path, set_home: pathlib.Path, ) -> None: - pass - - -@pytest.fixture(autouse=True) -def cwd_default(monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path) -> None: - monkeypatch.chdir(tmp_path) + """Configure test fixtures for pytest.""" diff --git a/docs/Makefile b/docs/Makefile index abae2b765..bb403f717 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -6,7 +6,7 @@ WATCH_FILES= find .. -type f -not -path '*/\.*' | grep -i '.*[.]\(rst\|md\)\$\|. # You can set these variables from the command line. SPHINXOPTS = -SPHINXBUILD = poetry run sphinx-build +SPHINXBUILD = uv run sphinx-build PAPER = BUILDDIR = _build @@ -173,16 +173,16 @@ serve: @echo 'docs server running at http://localhost:${HTTP_PORT}/' @echo @echo '==============================================================' - poetry run python -m http.server ${HTTP_PORT} --directory _build/html + uv run python -m http.server ${HTTP_PORT} --directory _build/html dev: $(MAKE) -j watch serve start: - poetry run sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) --port ${HTTP_PORT} $(O) + uv run sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) --port ${HTTP_PORT} $(O) design: # This adds additional watch directories (for _static file changes) and disable incremental builds - poetry run sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) --port ${HTTP_PORT} \ + uv run sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) --port ${HTTP_PORT} \ --watch ".." --ignore "../.*" --ignore "_build" -a \ $(O) diff --git a/docs/_templates/sidebar/projects.html b/docs/_templates/sidebar/projects.html index 330d15930..7b46e0bce 100644 --- a/docs/_templates/sidebar/projects.html +++ b/docs/_templates/sidebar/projects.html @@ -1,7 +1,7 @@