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
3 changes: 2 additions & 1 deletion agents/package_update_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pydantic import BaseModel, Field
from pathlib import Path

from common.constants import JiraLabels
from common.constants import JiraLabels, GITLAB_MR_CHECKLIST
from common.config import load_rhel_config
from common.models import LogOutputSchema

Expand Down Expand Up @@ -143,6 +143,7 @@ async def create_merge_request_checklist(state, next_step, dry_run, gateway_tool
await tasks.run_tool(
"create_merge_request_checklist",
merge_request_url=state.merge_request_url,
note_body=GITLAB_MR_CHECKLIST,
available_tools=gateway_tools,
)
logger.info(f"Created checklist for MR {state.merge_request_url}")
Expand Down
29 changes: 13 additions & 16 deletions common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,11 @@ def all_labels(cls) -> set[str]:

- [ ] **ROG CI Pipeline**: All automated tests pass
- for any failures, it might be useful to check the previous MRs to see if the test failures are not expected, based on the comments
- [ ] **CentOS Stream Build**: Successful scratch build
- [ ] **RHEL Build**: Successful scratch build
- [ ] **build_rpm**: Successful draft build. Once the gating is complete, it will automatically trigger a RHEL build.
- [ ] **Gitbz Check**: Commit messages correctly associated with approved Jira ticket (commit messages use "Resolves: RHEL-XXXXX" format)
- [ ] **Labels**: `target::latest` is set, exception or zstream are set only for exceptions or 0day, please consult Veronika Kabatova for that
- you can utilise draft builds if you don’t want to trigger builds after merging manually, by labelling the MR with `feature::draft-builds::enabled` and clicking `Run pipeline` to rerun the pipeline
- [ ] **Labels**: These are applied automatically (`target::latest` for Y-stream, `target::zstream` for Z-stream/0-day), check if the correct one is applied. The `target::exception` is set for exceptions and should be consulted with Veronika Kabatova.
- Draft builds are now enabled by default, you should see the label `feature::draft-builds::enabled` on your MR.
- 0day is a regular zstream build, it just needs to be added to the 0day batch at the Erratum level.
- [ ] **Branch References**: depending on the existing branch references and the process (RHEL-X Z-stream/0day workflow checklist, CentOS Stream X (RHEL-X Y-stream) workflow checklist, RHEL maintenance phase, RHEL Hotfix Build) you want/need to follow you may need to create new branches.
- [ ] **Upstream Alignment**: Changes align with upstream practices

Expand All @@ -130,15 +130,13 @@ def all_labels(cls) -> set[str]:

## ✅ Post-Merge Tasks

- [ ] **Trigger Builds**: manually trigger regular builds (or/and hotfix build if needed)
- if using draft builds (feature::draft-builds::enabled label), this step is not needed
- [ ] **Gating Results**: reviewed and waive/fix failures

### Verify automated steps

- [ ] **Gating Process**: Build picked up for gating
- [ ] **Errata Tool**: errata created (requires Preliminary Testing: Pass)
- [ ] **Release Date**: check the errata `Release Date` which in case of CVE should be ASAP, if not ask in [#forum-rhel-program](https://redhat.enterprise.slack.com/archives/C04S8PHPXH7)
- [ ] **Release Date**: check the errata `Release Date` which in case of important or critical CVE should be ASAP (medium or low severity CVEs should be set to Batch that respects the Due date set in Jira), if not ask in [#forum-rhel-program](https://redhat.enterprise.slack.com/archives/C04S8PHPXH7)

## 🤖 Jötnar specific tasks

Expand All @@ -149,22 +147,23 @@ def all_labels(cls) -> set[str]:

## 📋 Process specific workflow checklists

### [RHEL-X Z-stream/0day workflow checklist: Z stream branch has not been forked from the rhel x main branch](https://one.redhat.com/rhel-development-guide/#_z_stream_branch_has_not_been_forked_from_the_rhel_x_main_branch)
### [RHEL-X Z-stream/0day workflow checklist: Z stream branch has NOT been forked from the rhel x main branch](https://one.redhat.com/rhel-development-guide/#_z_stream_branch_has_not_been_forked_from_the_rhel_x_main_branch)

- [ ] **write**: commit goes to cXs
- [ ] **pre-merge**: *verify that the rhel-X-main branch is not also referencing the Z-stream branch.* If the Z-stream branch has not been forked yet, you need to create (fork it from `rhel-X-main`) and push it to the RHEL-X repository: `git push origin rhel-X-main:rhel-X.Y.0` (RHEL 10 and newer do not use the last number e.g. rhel-10.0).
- [ ] **build**: **create a CentOS Stream build with the RHEL `rhel-<Y-stream-pre-GA-version>-z-candidate` tag**. Use command `centpkg build --rhel-target=zstream` for it. The RHEL build will be created automatically
- [ ] **pre-merge**: *verify that the rhel-X-main branch is not also referencing the Z-stream branch.*
- [ ] **build**: Verify that the **build_rpm** pipeline is successful and the label **target::zstream** is set. Once the gating is complete, it will automatically trigger a RHEL build as well.

### [RHEL-X Z-stream/0day workflow checklist: Z-stream branch HAS been forked from the rhel-X-main branch](https://one.redhat.com/rhel-development-guide/#_z_stream_branch_has_been_forked_from_the_rhel_x_main_branch)
- [ ] **write**: one MR against RHEL repository Z-stream branch and one against cXs (to be merged after the rhel one is shipped)
- [ ] **rhel builds**: **build the package from the Z-stream** branch using the `rhpkg build` command in the RHEL repository of the package.
- [ ] **write**: one MR against RHEL repository Z-stream branch and one against cXs (to be merged after the Z-stream one is shipped)
- [ ] **rhel builds**: Verify that the **build_rpm** pipeline is successful.
- [ ] **verify**: check an advisory has been created
- [ ] **centos build**: **once the erratum is shipped**, submit the CentOS Stream build from the `cXs` branch using the `centpkg` command with the option `--rhel-target=none`
- [ ] **centos build**: **once the Z-stream erratum is shipped**, submit the CentOS Stream build from the `cXs` branch using the `centpkg` command with the option `--rhel-target=none`
- Once this [issue](https://issues.redhat.com/browse/OSCI-8940) is resolved, it should be also done automatically via the draft build feature.

### [CentOS Stream X (RHEL-X Y-stream) workflow checklist](https://one.redhat.com/rhel-development-guide/#_centos_stream_x_rhel_x_y_stream_workflow_checklist)
- [ ] **write**: the commit goes to `cXs`
- [ ] **pre-merge**: *verify that the rhel-X-main branch is not also referencing the Z-stream branch*. If the Z-stream branch has not been forked yet, you need to create (fork it from rhel-X-main) and push it to the RHEL-X repository. In the example you can achieve it by using a command like `git push origin rhel-8-main:rhel-8.8.0` (RHEL 10 and newer do not use the last number e.g. rhel-10.0).
- [ ] **build**: create a build from the `cXs` production branch using `centpkg build` command. (When the CentOS Stream X build is successful, automation will trigger an automated RHEL-X Y-stream brew build).
- [ ] **build**: Verify that the **build_rpm** pipeline is successful and the label **target::latest** is set. Once the gating is complete, it will automatically trigger a RHEL build as well.
- [ ] **verify**: check an advisory has been created

### [RHEL (8 as of now) maintenance phase](https://one.redhat.com/rhel-development-guide/#_rhel_x_10_z_specific)
Expand All @@ -175,6 +174,4 @@ def all_labels(cls) -> set[str]:
### [RHEL Hotfix Build](https://source.redhat.com/groups/public/release-engineering/release_engineering_rcm_wiki/rhel_hotfix_build_process_description)
Jötnar shouldn’t create hotfixes. If it happens follow linked document.

You can find even more detailed checklists in [this document](https://docs.google.com/document/d/1GA_JFyO1unlL74LElaFpB6W7iDWudBocPSzMro6xIOA/edit?tab=t.0), it depends on the process you chose to follow.
Update the MR and pre/post tasks status in [this document](https://docs.google.com/spreadsheets/d/1E4tx1LFdOTEq5lJOiF-JudMLYrc-zKIqgkJx4m7zBnc/edit?gid=1662692521#gid=1662692521).
"""
22 changes: 22 additions & 0 deletions mcp_server/gitlab_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,31 @@ async def create_merge_request_checklist(
) -> str:
"""
Creates our pre/post merge checklist for our dist-git merge requests.
Checks for existing checklist to avoid duplicates.
"""
try:
mr = await _get_merge_request_from_url(merge_request_url)

def check_existing_checklist():
notes = mr._raw_pr.notes.list(get_all=True)

checklist_body = note_body.strip()
if not checklist_body:
return False
checklist_identifier = checklist_body.splitlines()[0]

for note in notes:
note_body_text = note.body.strip()
if (checklist_identifier in note_body_text or
note_body_text == checklist_body):
return True

return False

exists = await asyncio.to_thread(check_existing_checklist)
if exists:
return f"Checklist already exists in merge request {merge_request_url}, not adding duplicate"

# internal note docs: https://docs.gitlab.com/api/notes/#create-new-issue-note
await asyncio.to_thread(mr._raw_pr.notes.create, {"body": note_body}, internal=True)
return f"Successfully created checklist for merge request {merge_request_url}"
Expand Down
37 changes: 34 additions & 3 deletions mcp_server/tests/unit/test_gitlab_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,9 +321,9 @@ async def test_create_merge_request_checklist():
flexmock(
id=123,
_raw_pr=flexmock(
notes=flexmock().should_receive("create").and_return(
flexmock(id=1),
).mock(),
notes=flexmock()
.should_receive("list").with_args(get_all=True).and_return([]).mock()
.should_receive("create").and_return(flexmock(id=1)).mock(),
),
),
).mock()
Expand All @@ -337,6 +337,37 @@ async def test_create_merge_request_checklist():
assert result == f"Successfully created checklist for merge request {merge_request_url}"


@pytest.mark.asyncio
async def test_create_merge_request_checklist_duplicate():
"""Test that duplicate checklists are not created"""
merge_request_url = "https://gitlab.com/redhat/rhel/rpms/bash/-/merge_requests/123"

# Mock an existing note with the checklist identifier
existing_note = flexmock(body="# Jötnar MR Review Checklist\n\nSome checklist content")

flexmock(GitlabService).should_receive("get_project_from_url").with_args(
url=merge_request_url.rsplit("/-/merge_requests/", 1)[0],
).and_return(
flexmock().should_receive("get_pr").and_return(
flexmock(
id=123,
_raw_pr=flexmock(
notes=flexmock()
.should_receive("list").with_args(get_all=True).and_return([existing_note]).mock(),
),
),
).mock()
)

result = await create_merge_request_checklist(
merge_request_url=merge_request_url,
note_body=GITLAB_MR_CHECKLIST,
)

assert "already exists" in result
assert "not adding duplicate" in result


@pytest.mark.asyncio
async def test_retry_pipeline_job():
project_url = "https://gitlab.com/redhat/rhel/rpms/bash"
Expand Down