# Contributing to markdownlint-rs
Thank you for your interest in contributing to markdownlint-rs!
## Development Setup
1. **Install Rust**: Use [rustup](https://rustup.rs/) to install Rust
2. **Clone the repository**:
```bash
git clone https://github.com/swanysimon/markdownlint-rs.git
cd markdownlint-rs
```
3. **Build the project**:
```bash
cargo build
```
4. **Run tests**:
```bash
cargo test
```
## Code Quality Standards
Before submitting a pull request, ensure your code passes all quality checks:
```bash
# Format code
cargo fmt
# Run linter
cargo clippy --all-targets --all-features -- -D warnings
# Run tests
cargo test --all-features
# Run compatibility tests (requires Docker)
cargo test --test compatibility
```
## Pull Request Process
1. **Create a feature branch** from `main`
2. **Make your changes** with clear, focused commits
3. **Add tests** for new functionality
4. **Update documentation** if needed
5. **Ensure CI passes** - all tests, clippy, and formatting checks must pass
6. **Submit PR** with a clear description of changes
## Release Process
Releases are managed using [`cargo-release`](https://github.com/crate-ci/cargo-release) and automated via GitHub Actions.
### Prerequisites
Install cargo-release:
```bash
cargo install cargo-release
```
### Creating a Release
#### Option 1: Using cargo-release (Recommended)
cargo-release automates the entire process:
```bash
# Dry run to see what will happen
cargo release patch --dry-run # 0.1.0 -> 0.1.1
cargo release minor --dry-run # 0.1.0 -> 0.2.0
cargo release major --dry-run # 0.1.0 -> 1.0.0
# Execute the release
cargo release patch --execute
```
This will:
1. ✅ Verify working directory is clean
2. ✅ Run tests
3. ✅ Bump version in `Cargo.toml`
4. ✅ Create a commit: "Release X.Y.Z"
5. ✅ Create a git tag: `vX.Y.Z`
6. ✅ Push commit and tag to GitHub
Once the tag is pushed, GitHub Actions automatically:
1. ✅ Verifies tag matches Cargo.toml version
2. ✅ Runs all CI checks (tests, clippy, fmt, build, compatibility)
3. ✅ Creates GitHub release with release notes
4. ✅ Builds binaries for all platforms (Linux x86/ARM, macOS x86/ARM, Windows)
5. ✅ Generates SHA256 checksums for all binaries
6. ✅ Uploads binaries to GitHub release
7. ✅ Publishes to crates.io (requires `CARGO_REGISTRY_TOKEN` secret)
#### Option 2: Manual Release
If you prefer manual control:
```bash
# 1. Update version in Cargo.toml
vim Cargo.toml # Change version = "0.1.0" to "0.1.1"
# 2. Commit the version change
git add Cargo.toml
git commit -m "Release 0.1.1"
# 3. Create and push the tag
git tag v0.1.1
git push origin main
git push origin v0.1.1
```
The GitHub Actions workflow will take over from here.
### Version Verification
The release workflow includes automatic version verification:
- If the git tag doesn't match the version in `Cargo.toml`, the release will fail
- This prevents accidental mismatches between tags and package versions
- Example: Tag `v0.2.0` requires `version = "0.2.0"` in Cargo.toml
### Release Checklist
Before creating a release:
- [ ] All tests pass locally: `cargo test --all-features`
- [ ] Code is formatted: `cargo fmt`
- [ ] No clippy warnings: `cargo clippy --all-targets --all-features`
- [ ] Compatibility tests pass: `cargo test --test compatibility`
- [ ] CHANGELOG.md is updated (if you maintain one)
- [ ] Version follows [SemVer](https://semver.org/) conventions:
- **MAJOR**: Incompatible API changes
- **MINOR**: New backwards-compatible functionality
- **PATCH**: Backwards-compatible bug fixes
### Troubleshooting Releases
**"Tag version doesn't match Cargo.toml"**
- Make sure you updated the version in `Cargo.toml` before creating the tag
- Use `cargo-release` to avoid this issue
**"CI checks failed"**
- The release is blocked if any quality checks fail
- Fix the issues and create a new tag
**"Release already exists"**
- The workflow is idempotent - it will reuse existing releases
- This is normal if you push multiple tags for the same commit
## Adding New Linting Rules
To add a new linting rule:
1. **Create the rule file**: `src/lint/rules/mdXXX.rs`
2. **Implement the Rule trait**:
```rust
pub struct MDXXX;
impl Rule for MDXXX {
fn name(&self) -> &str { "MD###" }
fn description(&self) -> &str { "Your description" }
fn tags(&self) -> Vec<&str> { vec!["tag1", "tag2"] }
fn check(&self, parser: &MarkdownParser, config: Option<&Value>) -> Vec<Violation> {
}
}
```
3. **Register the rule**: Add it to `create_default_registry()` in `src/lint/rule.rs`
4. **Write tests**: Add comprehensive tests in the same file
5. **Update documentation**: Document the rule's behavior
## Questions?
Feel free to open an issue for any questions or clarifications.