rust-diff-analyzer 1.2.0

Semantic analyzer for Rust PR diffs that distinguishes production code from test code
Documentation
<!--
SPDX-FileCopyrightText: 2025 RAprogramm <andrey.rozanov.vl@gmail.com>
SPDX-License-Identifier: MIT
-->

# Участие в разработке Rust Diff Analyzer

Спасибо за интерес к участию в проекте!

## Стиль кода и стандарты

Этот проект следует стандартам кодирования [RustManifest](https://github.com/RAprogramm/RustManifest). Пожалуйста, ознакомьтесь с ними перед началом работы.

Ключевые моменты:
- Используйте `cargo +nightly fmt` для форматирования
- Никаких `unwrap()` или `expect()` в продакшен коде
- Документация только через Rustdoc (без инлайн комментариев)
- Описательные имена переменных и функций

## Настройка окружения

### Требования

- Rust nightly toolchain
- cargo-make (опционально, для автоматизации задач)
- cargo-nextest (для запуска тестов)

### Установка

```bash
git clone https://github.com/RAprogramm/rust-prod-diff-checker
cd rust-prod-diff-checker

# Установка nightly toolchain
rustup toolchain install nightly
rustup component add rustfmt --toolchain nightly
rustup component add clippy

# Установка test runner (опционально, но рекомендуется)
cargo install cargo-nextest
```

### Pre-commit проверки

Перед коммитом убедитесь, что все проверки проходят:

```bash
# Проверка форматирования
cargo +nightly fmt --all -- --check

# Линтинг
cargo clippy --all-targets --all-features -- -D warnings

# Тесты
cargo test --all-features

# Или с nextest
cargo nextest run --all-features
```

## Git Workflow

### Именование веток

Используйте номер issue как имя ветки:
```
123
```

### Сообщения коммитов

Формат: `#<номер_issue> <тип>: <описание>`

```
#123 feat: add new output format
#123 fix: correct line counting in parser
#45 docs: update API examples
#78 test: add property tests for extractor
#90 refactor: simplify config loading
```

Типы:
- `feat` - новая функциональность
- `fix` - исправление бага
- `docs` - документация
- `test` - тесты
- `refactor` - рефакторинг кода
- `chore` - служебные задачи

### Pull Requests

1. Создайте ветку от `main`
2. Внесите изменения
3. Убедитесь, что все CI проверки проходят
4. Создайте PR с описательным заголовком
5. Включите `Closes #<issue>` в описание

### Держите изменения продакшен кода маленькими

**Качество код-ревью падает с размером.** Важен именно *продакшен код*, а не общее количество строк.

| Продакшен код | Качество ревью | Риск |
|---------------|----------------|------|
| < 100 строк | Тщательное | Низкий |
| 100-300 строк | Умеренное | Средний |
| 300+ строк | Поверхностное | Высокий |

**Тесты и бенчмарки не считаются так же:**

- PR с 50 строками в `src/` и 1000 строками тестов — **легко ревьюить**
- PR с 300 строками в `src/` и 0 тестов — **сложно ревьюить и рискованно**

Используйте [rust-prod-diff-checker](https://github.com/RAprogramm/rust-prod-diff-checker) GitHub Action для автоматического анализа размера PR и разделения продакшен изменений от тестов/бенчмарков.

**Правило:** Если ревьюер не может понять ваши изменения продакшен кода за 15 минут — PR слишком большой.

## Тестирование

### Организация тестов

```
tests/
├── integration.rs    # Интеграционные тесты
├── property.rs       # Property-based тесты
└── fixtures/         # Тестовые данные
```

### Написание тестов

- Покрывайте все публичные API функции
- Тестируйте пути ошибок, не только happy path
- Используйте property-based тестирование для парсеров
- Никаких `unwrap()` в тестах — используйте `?` с правильными типами ошибок

```rust
#[test]
fn test_parse_diff() -> Result<(), Box<dyn std::error::Error>> {
    let diff = include_str!("fixtures/sample.diff");
    let result = parse_diff(diff)?;

    assert_eq!(result.len(), 3);
    Ok(())
}
```

### Запуск тестов

```bash
# Все тесты
cargo test --all-features

# С покрытием
cargo llvm-cov nextest --all-features

# Конкретный тест
cargo test test_parse_diff

# Только property тесты
cargo test --test property
```

## CI/CD Pipeline

### Автоматические проверки

Каждый PR запускает:

| Задача | Описание |
|--------|----------|
| Format | `cargo +nightly fmt --check` |
| Clippy | `cargo clippy -D warnings` |
| Test | `cargo test --all-features` |
| Doc | `cargo doc --no-deps` |
| Coverage | Загрузка в Codecov |
| Benchmark | Компиляция бенчмарков |
| Audit | Сканирование уязвимостей |
| REUSE | Проверка лицензий |

### Требования к покрытию

- Цель проекта: auto (поддерживать текущий уровень)
- Цель патча: 80% (новый код должен быть хорошо протестирован)

## Архитектура

### Структура модулей

```
src/
├── lib.rs              # Экспорт публичного API
├── error.rs            # Типы ошибок (AppError)
├── config.rs           # Работа с конфигурацией
├── analysis/
│   ├── mod.rs          # Модуль анализа
│   ├── ast_visitor.rs  # AST visitor для семантического извлечения
│   ├── extractor.rs    # Извлечение AST
│   └── mapper.rs       # Маппинг изменений (возвращает MapResult)
├── classifier/
│   └── ...             # Логика классификации кода
├── git/
│   └── diff_parser.rs  # Парсинг git diff
├── types/
│   ├── change.rs       # Change, Summary, AnalysisResult
│   ├── classification.rs # Enum CodeType
│   ├── scope.rs        # AnalysisScope, ExclusionReason
│   └── semantic_unit.rs # SemanticUnit с qualified_name()
└── output/
    ├── formatter.rs    # Форматирование вывода
    ├── comment.rs      # Формат PR комментария с таблицами
    ├── github.rs       # Формат GitHub Actions
    └── json.rs         # JSON формат
```

### Ключевые типы

- `SemanticUnit` - Элемент кода с `qualified_name()` для контекста impl
- `Change` - Изменение semantic unit с классификацией и счётчиком строк
- `MapResult` - Результат `map_changes()` содержит изменения и `AnalysisScope`
- `AnalysisScope` - Отслеживает проанализированные и пропущенные файлы
- `ExclusionReason` - Причина пропуска файла (NonRust, IgnorePattern)
- `CodeType` - Классификация: Production, Test, Benchmark, Example
- `Config` - Конфигурация времени выполнения

## Добавление функциональности

### Новый формат вывода

1. Создайте `src/output/newformat.rs`
2. Реализуйте трейт `OutputFormatter`
3. Добавьте в enum `OutputFormat` в `config.rs`
4. Зарегистрируйте в `src/output/formatter.rs`
5. Добавьте тесты и документацию

### Новый тип Code Unit

1. Добавьте вариант в `UnitKind` в `src/analysis/extractor.rs`
2. Реализуйте извлечение в `extract_units()`
3. Добавьте вес в `config.rs`
4. Обновите тесты

## Процесс релиза

Релизы автоматизированы через CI при пуше тега:

1. Обновите версию в `Cargo.toml`
2. Коммит: `chore(release): prepare v1.x.x`
3. Создайте и запушьте тег:
   ```bash
   git tag v1.x.x
   git push origin v1.x.x
   ```
4. CI собирает бинарники для всех платформ
5. GitHub Release создается автоматически
6. Changelog обновляется

### Версионирование

Следуйте [Semantic Versioning](https://semver.org/):
- MAJOR: Ломающие изменения API
- MINOR: Новая функциональность, обратно совместимая
- PATCH: Исправления багов

## Документация

### Документация кода

Все публичные элементы должны иметь Rustdoc:

```rust
/// Parses a unified diff string into structured file diffs.
///
/// # Errors
///
/// Returns `AppError::DiffParse` if the diff format is invalid.
///
/// # Examples
///
/// ```
/// use rust_diff_analyzer::git::parse_diff;
///
/// let diff = "diff --git a/foo.rs b/foo.rs\n...";
/// let files = parse_diff(diff)?;
/// # Ok::<(), rust_diff_analyzer::AppError>(())
/// ```
pub fn parse_diff(input: &str) -> Result<Vec<FileDiff>, AppError> {
    // ...
}
```

### Обновление README

Обновляйте README.md при:
- Добавлении новых CLI опций
- Изменении формата конфигурации
- Добавлении новых форматов вывода
- Изменении inputs/outputs GitHub Action

## Получение помощи

- Открывайте issue для багов или запросов функциональности
- Проверяйте существующие issues перед созданием новых
- Предоставляйте минимальное воспроизведение для багов

## Лицензия

Участвуя в проекте, вы соглашаетесь, что ваши contributions будут лицензированы под MIT License.