Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,19 @@ file for more details about which credentials are required.

Checkout the [`tox.ini`](./tox.ini) for all available commands to develop with
bert-e.

## Contributing a new check

Every new check that blocks a merge **must** ship with a corresponding
`bypass_<check_name>` privileged option. This is a hard requirement — without
a bypass, a false positive permanently blocks a legitimate PR with no
administrator escape hatch.

Checklist for a new check:

1. Add `bypass_<check_name>(job)` to `bert_e/workflow/gitwaterflow/utils.py`
2. Register the option in `commands.py` `setup()` with `privileged=True`
3. Import and call `bypass_<check_name>(job)` at the top of the check function
4. Mention the bypass in the error message template
5. Document the check and bypass in `bert_e/docs/USER_DOC.md`
6. Add a unit test that verifies the bypass skips the check
17 changes: 17 additions & 0 deletions bert_e/docs/USER_DOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ __Bert-E__.
| bypass_jira_check | Bypass the Jira issue check | yes | no
| bypass_peer_approval | Bypass the pull request peer's approval | yes | no
| bypass_leader_approval | Bypass the pull request leader's approval | yes | no
| bypass_source_branch_lineage | Bypass the cross-branch contamination check | yes | no
| create_pull_requests | Let __Bert-E__ create pull requests corresponding to integration branches | no | no
| create_integration_branches | Request __Bert-E__ to create integration branches and move forward with the gitwaterflow | no | no
| no_octopus | Prevent Wall-E from doing any octopus merge and use multiple consecutive merge instead | yes | no
Expand Down Expand Up @@ -278,6 +279,21 @@ includes: _feature/..._, _bugfix/..._, _improvement/..._.

___

**The source branch does not carry commits from a higher release line.**
__Bert-E__ verifies that the source branch has not been accidentally rebased
on a Bert-E integration commit (e.g. a `w/` branch) or another higher
development branch. Doing so would cause a silent fast-forward that merges
hundreds of unrelated commits into a maintenance branch.

*__Bert-E__ sends message code 137 in case of non-conformance.*

> This check can be bypassed by an admin with the
> __bypass_source_branch_lineage__ option.
> Use only when the detection is a confirmed false positive (e.g. a legitimate
> backport that shares history with a higher line).

---

**The prefix of the source branch is compatible with the destination branch.**
__Bert-E__ prevents the merge of a feature in a maintenance branch (only
bugfixes and improvements branches are accepted).
Expand Down Expand Up @@ -490,6 +506,7 @@ to progress to the next step. message code
| 122 | Unknown command | One of the participants asked __Bert-E__ to activate an option, or execute a command he doesn't know. Edit the corresponding message if it contains a typo. Delete it otherwise
| 123 | Not authorized | One of the participants asked __Bert-E__ to activate a privileged option, or execute a privileged command, but doesn't have enough credentials to do so. Delete the corresponding command ask a __Bert-E__ administrator to run/set the desired command/option.
| 134 | Not author | One of the participants asked __Bert-E__ to activate an authored option, but the participant is not the author of the pull request.
| 137 | Foreign commits in source branch | The source branch shares history with a higher release line. Rebase the branch directly on the target branch, or ask an administrator to set `bypass_source_branch_lineage` if this is a confirmed false positive.

Queues
------
Expand Down
6 changes: 6 additions & 0 deletions bert_e/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ class QueueBuildFailedMessage(TemplateException):
template = "queue_build_failed.md"


class ForeignCommitsInSourceBranch(TemplateException):
code = 137
template = "foreign_commits_in_source_branch.md"
status = "failure"


# internal exceptions
class UnableToSendEmail(InternalException):
code = 201
Expand Down
1 change: 1 addition & 0 deletions bert_e/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class PrAuthorsOptions(fields.Dict):
'bypass_incompatible_branch',
'bypass_peer_approval',
'bypass_leader_approval',
'bypass_source_branch_lineage',
]

def serialize(self, value, attr=None, obj=None, **kwargs):
Expand Down
46 changes: 46 additions & 0 deletions bert_e/templates/foreign_commits_in_source_branch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{% extends "message.md" %}

{% block title -%}
Foreign commits detected in source branch
{% endblock %}

{% block message %}
The source branch `{{ src_branch }}` shares history with the following
release line(s), which are not ancestors of `{{ dst_branch }}`:

{% for branch in foreign_branches %}
- `{{ branch }}`
{% endfor %}

This typically happens when the feature branch was accidentally based on
commits from a higher release line rather than directly on `{{ dst_branch }}`.
Common causes include:

- Rebasing on a Bert-E integration branch (e.g. a `w/` branch) instead of
directly on `{{ dst_branch }}`
- Branching from a higher development branch instead of `{{ dst_branch }}`
- Merging a higher development branch into the feature branch

**How to fix**

Create a new branch directly from `{{ dst_branch }}` and cherry-pick your
changes onto it:

```
git checkout -b <new-branch-name> origin/{{ dst_branch }}
git cherry-pick <your-commits>
```

Then open a new pull request from that branch.

**If this is a false positive**

If your branch is a legitimate backport and was previously merged into one
of the branches above before being extended with new commits, an
administrator can bypass this check with:

```
@bert-e bypass_source_branch_lineage
```

{% endblock %}
18 changes: 18 additions & 0 deletions bert_e/tests/unit/conftest.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@

"""Unit tests fixtures."""
import os
import sys
from os.path import abspath
from types import ModuleType
from unittest.mock import MagicMock

import pytest

from bert_e.settings import setup_settings


def _install_jira_stub():
"""Stub jira==2.0.0 which imports `imghdr` removed in Python 3.13."""
if 'jira' not in sys.modules:
_stub = ModuleType('jira')
_stub.JIRA = MagicMock()
_stub.exceptions = ModuleType('jira.exceptions')
_stub.exceptions.JIRAError = Exception
sys.modules['jira'] = _stub
sys.modules['jira.exceptions'] = _stub.exceptions
Comment thread
matthiasL-scality marked this conversation as resolved.


_install_jira_stub()


@pytest.fixture
def settings():
"""Simple settings fixture."""
Expand Down
Loading
Loading