Skip to content
204 changes: 191 additions & 13 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,31 +117,209 @@ fetch master and create these branches for you:

### 4. Commit your changes

Commit your change. The commit command must include a specific message format:
Commit your changes using the Conventional Commits format. All commits must follow the format described in the [Conventional Commits](#conventional-commits) section below and include proper git trailers for issue tracking.

**Basic commit format:**
```bash
git commit -m "<component>: <change_message> #<issue number>"
git commit -m "<type>(<scope>): <description>" --trailer "Closes: #<issue_number>"
```

Valid component names are listed in the [__label
list__](https://github.com/rucio/rucio/labels) and are usually specified on the
issue of the change.
**Example:**
```bash
git commit -m "feat(Transfers): Group bulk transfers by authentication method" --trailer "Closes: #8199"
```

Add additional explanations to the body of the commit, such as motivation for
certain decisions and background information. [Here are some general rules.](https://cbea.ms/git-commit/).

If you add a [__github-recognised
keyword__](https://help.github.com/articles/closing-issues-using-keywords/) then
the associated issue can be closed automatically once the pull request is
merged, e.g.:
Using multiple commits is allowed as long as they achieve an independent,
well-defined, change and are well-described. Otherwise multiple commits should
be squashed.

#### **Conventional Commits**

Rucio enforces the [Conventional Commits](https://www.conventionalcommits.org/) specification to ensure consistent and meaningful commit messages across the project. This is enforced through [commitlint](https://commitlint.js.org/) during CI checks and can be enabled locally via pre-commit hooks.

**Commit Message Format:**
```
<type>(<scope>): <description>

[optional body]

[optional footer(s)]
```

**Rules:**

1. **Type**: Must be one of the following allowed types:

| Type | Category | Description |
|------|----------|-------------|
| `feat` | Functional | Introduces a new feature or capability |
| `fix` | Functional | Corrects a bug or unexpected behavior |
| `docs` | Non-functional | Updates documentation or code comments |
| `style` | Non-functional | Formatting, whitespace, or cosmetic changes |
| `refactor` | Non-functional | Restructures code without changing its behavior |
| `test` | Non-functional | Adds, updates, or fixes tests |
| `ci` | Non-functional | Modifies CI/CD pipelines or scripts |
| `revert` | Non-functional | Undoes a previous commit |

<details>
<summary><strong>Quick guide: How to choose the right type</strong></summary>

Ask yourself these questions in order:

1. Are you adding a **new feature or capability** that didn't exist before? → `feat`
2. Are you fixing **broken or incorrect behavior**? → `fix`
3. Are you **only updating documentation** (README, docstrings, comments)? → `docs`
4. Are you making **cosmetic changes** like formatting, whitespace, or linting fixes? → `style`
5. Are you **reorganizing or cleaning up code** without changing what it does? → `refactor`
6. Are you **adding, updating, or fixing tests**? → `test`
7. Are you modifying **CI/CD pipelines, workflows, or build scripts**? → `ci`
8. Are you **reverting a previous commit**? → `revert`

> **Tip:** If none of these fit, consider splitting your commit into smaller, focused changes.

</details>

2. **Scope**: Must be one of the predefined Rucio components (PascalCase). The available scopes are:
- `Auth`: Authentication & Authorisation
- `Clients`: Client libraries and tools
- `Consistency`: Consistency checks
- `Core`: Core & Internals
- `Database`: Database-related changes
- `DatasetDeletion`: Dataset deletion functionality
- `Deletion`: File deletion functionality
- `DIRAC`: DIRAC integration
- `Containerization`: Docker, Kubernetes, and container-related functionality
- `Documentation`: Documentation updates
- `Lifetime`: Life time model processing
- `Messaging`: Messaging system
- `Metadata`: Metadata workflows
- `Monitoring`: Monitoring, observability, and traces
- `MultiVO`: Multi-VO functionality
- `OpenData`: Open data functionality
- `Policies`: Policy management
- `Probes`: Probes & Alarms
- `Protocols`: Upload, Download, Deletion protocols
- `Rebalancing`: Data rebalancing
- `Recovery`: Data recovery
- `Replicas`: Replica workflows
- `API`: REST & API
- `Rules`: Replication rules and rule daemons
- `Subscriptions`: Subscription daemon
- `Testing`: Regression tests, Unit tests, and CI
- `Transfers`: Transfer daemons
- `WebUI`: Web user interface

**Note**: Any changes to this list should also be applied to the [GitHub labels](https://github.com/rucio/rucio/issues/labels) and the [commitlint config](https://github.com/rucio/rucio/blob/master/commitlint.config.js)

3. **Description**:
- Should not end with a period
- Should be concise but descriptive
- Use imperative mood ("add feature" not "added feature")

4. **Line Length**: Header must not exceed 100 characters to prevent truncation in GitHub UI

**Examples:**
```bash
<component>: <change_message> Fix #<issue number>
feat(Transfers): Group bulk transfers by authentication method
fix(Core): Fix exception when attaching nonexistent DID to container
docs(Documentation): Update API endpoint descriptions
style(Transfers): Touch up comments
refactor(Transfers): Simplify group key construction
```

Using multiple commits is allowed as long as they achieve an independent,
well-defined, change and are well-described. Otherwise multiple commits should
be squashed.
**Choosing the Right Type:**

Sometimes it's unclear which type to use. Consider the **intent** and **impact** of your change:

| Ambiguity | Choose | When |
|-----------|--------|------|
| `style` vs `refactor` | `style` | Formatting, whitespace, comment tweaks |
| `style` vs `refactor` | `refactor` | Modernizing syntax, restructuring code |
| `fix` vs `refactor` | `fix` | Correcting incorrect behavior |
| `fix` vs `refactor` | `refactor` | Improving code without fixing a bug |
| `docs` vs `style` | `docs` | Updating documentation files or docstrings |
| `docs` vs `style` | `style` | Minor comment formatting within code |
| `test` vs `fix` | `fix` | Fixing flaky test due to race condition |
| `test` vs `fix` | `test` | Adding new test cases or correcting test logic |

**Examples:**

| Scenario | Preferred | Rationale |
|----------|-----------|-----------|
| Replacing `Union[X, None]` with `Optional[X]` across 60+ files | `refactor(Core): Remove deprecated constructs from the typing module` | Modernizes codebase to newer Python conventions |
| Adding type hints to function signatures | `style(Core): Add type hints to transfer functions` | Improves code documentation without changing behavior |
| Fixing a test that fails intermittently due to timing | `fix(Testing): Resolve judge evaluator test flakiness` | Corrects broken behavior in test suite |
| Adding new test cases for edge cases | `test(Testing): Add tests for attaching nonexistent DIDs` | Extends test coverage |
| Updating README with new installation steps | `docs(Documentation): Update installation instructions` | Documentation-only change |
| Fixing typos in code comments | `style(Core): Fix typos in transfer module comments` | Minor stylistic improvement |

#### **Breaking Changes**

Commits that introduce breaking API or behavioral changes must use `!` after the type/scope in the header and include a corresponding `BREAKING CHANGE` footer.

**Format:**
```
<type>(<scope>)!: <description>

[optional body]

BREAKING CHANGE: <description of the breaking change and its impact>
```

**Requirement:** A breaking change commit must include **both** the `!` marker in the header (e.g., `feat(Core)!: ...`) **and** a `BREAKING CHANGE` footer with a description explaining the impact.

**Example:**
```bash
refactor(Core)!: Make session a mandatory keyword-only argument

BREAKING CHANGE: The session argument is now mandatory and keyword-only
for all core functions. Callers must explicitly pass session=<session>
instead of relying on positional arguments or default values.

Closes: #5947
```

#### **Git Trailers**

All commits must reference a GitHub issue using git trailers. This ensures proper traceability and automatic issue closure.

**Supported Trailers:**
- `Closes: #<issue_number>` - Automatically closes the issue when PR is merged
- `Issue: #<issue_number>` - References an issue without closing it

**Adding Git Trailers:**

**Method 1: Using git commit command**
```bash
git commit -m "feat(Transfers): Group bulk transfers by authentication method" --trailer "Closes: #8199"
```

**Method 2: Adding to commit body**
```bash
git commit -m "feat(Transfers): Group bulk transfers by authentication method

The authentication method is a property of the FTS job. If Rucio does
not partition the transfers based on it, then some may be done with an
incorrect authentication method.

Closes: #8199"
```

**Complete Example:**
```bash
feat(Transfers): Group bulk transfers by authentication method

The authentication method is a property of the FTS job. If Rucio does
not partition the transfers based on it, then some may be done with an
incorrect authentication method.

Closes: #8199
```

*See the [original commit](https://github.com/rucio/rucio/commit/6ba2559) for reference.*

### 5. Push changes and create a Pull Request

Expand Down