Compare commits
5 Commits
pickman2
...
cherry-b84
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05fd9df66b | ||
|
|
7a2f6c9624 | ||
|
|
1b6ba514cc | ||
|
|
499a8a4c9e | ||
|
|
35f4d47308 |
@@ -541,3 +541,74 @@ All 13 commits were successfully cherry-picked from `us/next` to branch `cherry-
|
||||
|
||||
---
|
||||
|
||||
## 2025-12-17: us/next
|
||||
|
||||
Branch: cherry-b841e559cd2
|
||||
|
||||
Commits:
|
||||
- b841e559cd2 Prepare v2025.01-rc4
|
||||
- 28a620d2815 board: rpi: Pass CMA through from firmware DT
|
||||
- 6a5fc32fd20 board: rpi: Enable capsule updates
|
||||
- 26512629fb3 Merge tag 'rpi-2025.01-rc5' of https://source.denx.de/u-boot/custodians/u-boot-raspberrypi
|
||||
|
||||
### Conversation log
|
||||
The repository is clean. Now let me create and checkout the new branch based on ci/master:
|
||||
|
||||
Now let me cherry-pick the first commit:
|
||||
|
||||
There's a conflict in the Makefile. Let me examine it:
|
||||
|
||||
This is a simple version conflict. The base branch has PATCHLEVEL = 12 (newer version) and the cherry-picked commit is trying to set EXTRAVERSION = -rc4 for an older release. Let me resolve this by keeping the current base PATCHLEVEL (12) and adding the EXTRAVERSION from the cherry-picked commit:
|
||||
|
||||
Let me resolve this conflict. Since we're cherry-picking to add the -rc4 release tag functionality, I'll take the EXTRAVERSION = -rc4 from the incoming commit:
|
||||
|
||||
Now let me resolve the conflict by taking the EXTRAVERSION = -rc4 from the incoming commit:
|
||||
|
||||
There's a duplicate NAME = line. Let me fix that:
|
||||
|
||||
Now let me add the file and continue the cherry-pick:
|
||||
|
||||
Now let me amend the commit to note the fix-up:
|
||||
|
||||
Now let me cherry-pick the second commit:
|
||||
|
||||
Now the third commit:
|
||||
|
||||
Now let me check if the fourth commit is a merge commit:
|
||||
|
||||
Yes, this is a merge commit. Let me use the correct options:
|
||||
|
||||
The merge commit is empty (as expected since we already have the changes from the individual commits). Let me commit it as an empty commit to preserve the merge history:
|
||||
|
||||
All cherry-picks are done. Let me verify with git log:
|
||||
|
||||
All 4 commits are present. Now let me run the build to verify:
|
||||
|
||||
Build completed successfully. Let me provide the final status:
|
||||
|
||||
## Final Status
|
||||
|
||||
### Cherry-pick Results
|
||||
All 4 commits successfully cherry-picked from `us/next` branch to new branch `cherry-b841e559cd2`:
|
||||
|
||||
| Commit | Subject | Status |
|
||||
|--------|---------|--------|
|
||||
| b841e559cd2 | Prepare v2025.01-rc4 | ✅ (conflict resolved) |
|
||||
| 28a620d2815 | board: rpi: Pass CMA through from firmware DT | ✅ |
|
||||
| 6a5fc32fd20 | board: rpi: Enable capsule updates | ✅ |
|
||||
| 26512629fb3 | Merge tag 'rpi-2025.01-rc5' | ✅ (empty merge commit preserved) |
|
||||
|
||||
### Fix-ups Made
|
||||
1. **Makefile conflict** in commit `b841e559cd2`:
|
||||
- Conflict: PATCHLEVEL was 01 in original commit, but base branch has PATCHLEVEL=12
|
||||
- Resolution: Kept PATCHLEVEL=12, applied EXTRAVERSION=-rc4
|
||||
- Note added to commit message
|
||||
|
||||
### Build Result
|
||||
✅ **OK** - Build completed successfully for sandbox board with no warnings or errors.
|
||||
|
||||
### Branch Status
|
||||
The branch `cherry-b841e559cd2` is ready for pushing with 4 new commits ahead of `ci/master`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -68,6 +68,19 @@ struct msg_get_clock_rate {
|
||||
u32 end_tag;
|
||||
};
|
||||
|
||||
struct efi_fw_image fw_images[] = {
|
||||
{
|
||||
.fw_name = u"RPI_UBOOT",
|
||||
.image_index = 1,
|
||||
},
|
||||
};
|
||||
|
||||
struct efi_capsule_update_info update_info = {
|
||||
.dfu_string = "mmc 0=u-boot.bin fat 0 1",
|
||||
.num_images = ARRAY_SIZE(fw_images),
|
||||
.images = fw_images,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
#define DTB_DIR "broadcom/"
|
||||
#else
|
||||
@@ -544,12 +557,15 @@ void update_fdt_from_fw(void *fdt, void *fw_fdt)
|
||||
if (fdt == fw_fdt)
|
||||
return;
|
||||
|
||||
/* The firmware provides a more precie model; so copy that */
|
||||
/* The firmware provides a more precise model; so copy that */
|
||||
copy_property(fdt, fw_fdt, "/", "model");
|
||||
|
||||
/* memory reserve as suggested by the firmware */
|
||||
copy_property(fdt, fw_fdt, "/", "memreserve");
|
||||
|
||||
/* copy the CMA memory setting from the firmware DT to linux */
|
||||
copy_property(fdt, fw_fdt, "/reserved-memory/linux,cma", "size");
|
||||
|
||||
/* Adjust dma-ranges for the SD card and PCI bus as they can depend on
|
||||
* the SoC revision
|
||||
*/
|
||||
|
||||
@@ -19,14 +19,19 @@ CONFIG_SYS_PBSIZE=1049
|
||||
# CONFIG_DISPLAY_BOARDINFO is not set
|
||||
CONFIG_MISC_INIT_R=y
|
||||
CONFIG_SYS_PROMPT="U-Boot> "
|
||||
CONFIG_CMD_NVEDIT_EFI=y
|
||||
CONFIG_CMD_GPIO=y
|
||||
CONFIG_CMD_MMC=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_EFIDEBUG=y
|
||||
CONFIG_CMD_FS_UUID=y
|
||||
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
|
||||
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
|
||||
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
|
||||
CONFIG_TFTP_TSIZE=y
|
||||
CONFIG_DFU_MMC=y
|
||||
CONFIG_SYS_DFU_DATA_BUF_SIZE=0x100000
|
||||
CONFIG_SYS_DFU_MAX_FILE_SIZE=0x200000
|
||||
CONFIG_BCM2835_GPIO=y
|
||||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_BCM2835=y
|
||||
@@ -49,3 +54,6 @@ CONFIG_SYS_WHITE_ON_BLACK=y
|
||||
CONFIG_VIDEO_BCM2835=y
|
||||
CONFIG_CONSOLE_SCROLL_LINES=10
|
||||
CONFIG_PHYS_TO_BUS=y
|
||||
# CONFIG_HEXDUMP is not set
|
||||
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
|
||||
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
|
||||
|
||||
@@ -19,14 +19,19 @@ CONFIG_SYS_PBSIZE=1049
|
||||
# CONFIG_DISPLAY_BOARDINFO is not set
|
||||
CONFIG_MISC_INIT_R=y
|
||||
CONFIG_SYS_PROMPT="U-Boot> "
|
||||
CONFIG_CMD_NVEDIT_EFI=y
|
||||
CONFIG_CMD_GPIO=y
|
||||
CONFIG_CMD_MMC=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_EFIDEBUG=y
|
||||
CONFIG_CMD_FS_UUID=y
|
||||
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
|
||||
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
|
||||
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
|
||||
CONFIG_TFTP_TSIZE=y
|
||||
CONFIG_DFU_MMC=y
|
||||
CONFIG_SYS_DFU_DATA_BUF_SIZE=0x100000
|
||||
CONFIG_SYS_DFU_MAX_FILE_SIZE=0x200000
|
||||
CONFIG_BCM2835_GPIO=y
|
||||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_BCM2835=y
|
||||
@@ -49,3 +54,6 @@ CONFIG_SYS_WHITE_ON_BLACK=y
|
||||
CONFIG_VIDEO_BCM2835=y
|
||||
CONFIG_CONSOLE_SCROLL_LINES=10
|
||||
CONFIG_PHYS_TO_BUS=y
|
||||
# CONFIG_HEXDUMP is not set
|
||||
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
|
||||
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
|
||||
|
||||
@@ -20,11 +20,13 @@ CONFIG_SYS_PBSIZE=1049
|
||||
# CONFIG_DISPLAY_BOARDINFO is not set
|
||||
CONFIG_MISC_INIT_R=y
|
||||
CONFIG_SYS_PROMPT="U-Boot> "
|
||||
CONFIG_CMD_NVEDIT_EFI=y
|
||||
CONFIG_CMD_DFU=y
|
||||
CONFIG_CMD_GPIO=y
|
||||
CONFIG_CMD_MMC=y
|
||||
CONFIG_CMD_PCI=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_EFIDEBUG=y
|
||||
CONFIG_CMD_FS_UUID=y
|
||||
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
|
||||
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
|
||||
@@ -65,3 +67,6 @@ CONFIG_SYS_WHITE_ON_BLACK=y
|
||||
CONFIG_VIDEO_BCM2835=y
|
||||
CONFIG_CONSOLE_SCROLL_LINES=10
|
||||
CONFIG_PHYS_TO_BUS=y
|
||||
# CONFIG_HEXDUMP is not set
|
||||
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
|
||||
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
|
||||
|
||||
@@ -18,15 +18,20 @@ CONFIG_SYS_PBSIZE=1049
|
||||
# CONFIG_DISPLAY_BOARDINFO is not set
|
||||
CONFIG_MISC_INIT_R=y
|
||||
CONFIG_SYS_PROMPT="U-Boot> "
|
||||
CONFIG_CMD_NVEDIT_EFI=y
|
||||
CONFIG_CMD_GPIO=y
|
||||
CONFIG_CMD_MMC=y
|
||||
CONFIG_CMD_PCI=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_EFIDEBUG=y
|
||||
CONFIG_CMD_FS_UUID=y
|
||||
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
|
||||
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
|
||||
CONFIG_TFTP_TSIZE=y
|
||||
CONFIG_DM_DMA=y
|
||||
CONFIG_DFU_MMC=y
|
||||
CONFIG_SYS_DFU_DATA_BUF_SIZE=0x100000
|
||||
CONFIG_SYS_DFU_MAX_FILE_SIZE=0x200000
|
||||
CONFIG_BCM2835_GPIO=y
|
||||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_SDMA=y
|
||||
@@ -56,3 +61,6 @@ CONFIG_SYS_WHITE_ON_BLACK=y
|
||||
CONFIG_VIDEO_BCM2835=y
|
||||
CONFIG_CONSOLE_SCROLL_LINES=10
|
||||
CONFIG_PHYS_TO_BUS=y
|
||||
# CONFIG_HEXDUMP is not set
|
||||
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
|
||||
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
|
||||
|
||||
@@ -73,7 +73,7 @@ For the next scheduled release, release candidates were made on::
|
||||
|
||||
* U-Boot v2025.01-rc3 was released on Mon 25 November 2024.
|
||||
|
||||
.. * U-Boot v2025.01-rc4 was released on Mon 09 December 2024.
|
||||
* U-Boot v2025.01-rc4 was released on Mon 09 December 2024.
|
||||
|
||||
.. * U-Boot v2025.01-rc5 was released on Mon 23 December 2024.
|
||||
|
||||
|
||||
@@ -136,20 +136,14 @@ def cherry_pick_commits(commits, source, branch_name, repo_path=None):
|
||||
repo_path))
|
||||
|
||||
|
||||
async def run_review_agent(mr_iid, branch_name, comments, remote, target='master',
|
||||
needs_rebase=False, has_conflicts=False,
|
||||
mr_description='', repo_path=None):
|
||||
"""Run the Claude agent to handle MR comments and/or rebase
|
||||
async def run_review_agent(mr_iid, branch_name, comments, remote, repo_path=None):
|
||||
"""Run the Claude agent to handle MR comments
|
||||
|
||||
Args:
|
||||
mr_iid (int): Merge request IID
|
||||
branch_name (str): Source branch name
|
||||
comments (list): List of comment dicts with 'author', 'body' keys
|
||||
remote (str): Git remote name
|
||||
target (str): Target branch for rebase operations
|
||||
needs_rebase (bool): Whether the MR needs rebasing
|
||||
has_conflicts (bool): Whether the MR has merge conflicts
|
||||
mr_description (str): MR description with context from previous work
|
||||
repo_path (str): Path to repository (defaults to current directory)
|
||||
|
||||
Returns:
|
||||
@@ -161,75 +155,35 @@ async def run_review_agent(mr_iid, branch_name, comments, remote, target='master
|
||||
if repo_path is None:
|
||||
repo_path = os.getcwd()
|
||||
|
||||
# Build the prompt based on what needs to be done
|
||||
tasks = []
|
||||
if needs_rebase:
|
||||
if has_conflicts:
|
||||
tasks.append("rebase and resolve merge conflicts")
|
||||
else:
|
||||
tasks.append("rebase onto latest target branch")
|
||||
if comments:
|
||||
tasks.append(f"address {len(comments)} review comment(s)")
|
||||
# Format comments for the prompt
|
||||
comment_text = '\n'.join(
|
||||
f'- [{c.author}]: {c.body}'
|
||||
for c in comments
|
||||
)
|
||||
|
||||
task_desc = " and ".join(tasks)
|
||||
|
||||
# Include MR description for context from previous work
|
||||
context_section = ""
|
||||
if mr_description:
|
||||
context_section = f"""
|
||||
Context from MR description (includes previous work done on this MR):
|
||||
|
||||
{mr_description}
|
||||
|
||||
Use this context to understand what was done previously and respond appropriately.
|
||||
"""
|
||||
|
||||
# Format comments for the prompt (if any)
|
||||
comment_section = ""
|
||||
if comments:
|
||||
comment_text = '\n'.join(
|
||||
f'- [{c.author}]: {c.body}'
|
||||
for c in comments
|
||||
)
|
||||
comment_section = f"""
|
||||
Review comments to address:
|
||||
prompt = f"""Review comments on merge request !{mr_iid} (branch: {branch_name}):
|
||||
|
||||
{comment_text}
|
||||
"""
|
||||
|
||||
# Build rebase instructions
|
||||
rebase_section = ""
|
||||
if needs_rebase:
|
||||
rebase_section = f"""
|
||||
Rebase instructions:
|
||||
- The MR is behind the target branch and needs rebasing
|
||||
- Use: git rebase --keep-empty {remote}/{target}
|
||||
- This preserves empty merge commits which are important for tracking
|
||||
- If there are conflicts, try to resolve them automatically
|
||||
- For complex conflicts that cannot be resolved, describe them and abort
|
||||
"""
|
||||
|
||||
prompt = f"""Task for merge request !{mr_iid} (branch: {branch_name}): {task_desc}
|
||||
{context_section}{comment_section}{rebase_section}
|
||||
Steps to follow:
|
||||
1. Checkout the branch: git checkout {branch_name}
|
||||
2. {'Rebase onto ' + remote + '/' + target + ' first' if needs_rebase else 'Read and understand each comment'}
|
||||
3. {'After rebase, address any review comments' if needs_rebase and comments else 'For each actionable comment:' if comments else 'Verify the rebase completed successfully'}
|
||||
{'- Make the requested changes to the code' if comments else ''}
|
||||
{'- Amend the relevant commit or create a fixup commit' if comments else ''}
|
||||
2. Read and understand each comment
|
||||
3. For each actionable comment:
|
||||
- Make the requested changes to the code
|
||||
- Amend the relevant commit or create a fixup commit
|
||||
4. Run 'crosfw sandbox -L' to verify the build
|
||||
5. Create a local branch with suffix '-v2' (or increment: -v3, -v4, etc.)
|
||||
6. Force push to the ORIGINAL remote branch to update the MR:
|
||||
git push -o ci.skip --force-with-lease {remote} HEAD:{branch_name}
|
||||
(ci.skip prevents a duplicate pipeline; the MR pipeline will run automatically)
|
||||
7. Report what was done and what reply should be posted to the MR
|
||||
git push --force-with-lease {remote} HEAD:{branch_name}
|
||||
7. Report what changes were made and what reply should be posted to the MR
|
||||
|
||||
Important:
|
||||
- Keep changes minimal and focused
|
||||
- Keep changes minimal and focused on addressing the comments
|
||||
- If a comment is unclear or cannot be addressed, note this in your report
|
||||
- Local branch: {branch_name}-v2 (or -v3, -v4 etc.)
|
||||
- Remote push: always to '{branch_name}' to update the existing MR
|
||||
- Always use -o ci.skip when pushing to avoid duplicate pipelines
|
||||
- If rebasing is requested, use: git rebase --keep-empty <base>
|
||||
This preserves empty merge commits which are important for tracking
|
||||
"""
|
||||
|
||||
options = ClaudeAgentOptions(
|
||||
@@ -237,7 +191,7 @@ Important:
|
||||
cwd=repo_path,
|
||||
)
|
||||
|
||||
tout.info(f'Starting Claude agent to {task_desc}...')
|
||||
tout.info(f'Starting Claude agent to handle {len(comments)} comment(s)...')
|
||||
tout.info('')
|
||||
|
||||
conversation_log = []
|
||||
@@ -254,9 +208,7 @@ Important:
|
||||
return False, '\n\n'.join(conversation_log)
|
||||
|
||||
|
||||
def handle_mr_comments(mr_iid, branch_name, comments, remote, target='master',
|
||||
needs_rebase=False, has_conflicts=False,
|
||||
mr_description='', repo_path=None):
|
||||
def handle_mr_comments(mr_iid, branch_name, comments, remote, repo_path=None):
|
||||
"""Synchronous wrapper for running the review agent
|
||||
|
||||
Args:
|
||||
@@ -264,10 +216,6 @@ def handle_mr_comments(mr_iid, branch_name, comments, remote, target='master',
|
||||
branch_name (str): Source branch name
|
||||
comments (list): List of comment dicts
|
||||
remote (str): Git remote name
|
||||
target (str): Target branch for rebase operations
|
||||
needs_rebase (bool): Whether the MR needs rebasing
|
||||
has_conflicts (bool): Whether the MR has merge conflicts
|
||||
mr_description (str): MR description with context from previous work
|
||||
repo_path (str): Path to repository (defaults to current directory)
|
||||
|
||||
Returns:
|
||||
@@ -275,5 +223,4 @@ def handle_mr_comments(mr_iid, branch_name, comments, remote, target='master',
|
||||
conversation_log is the agent's output text
|
||||
"""
|
||||
return asyncio.run(run_review_agent(mr_iid, branch_name, comments, remote,
|
||||
target, needs_rebase, has_conflicts,
|
||||
mr_description, repo_path))
|
||||
repo_path))
|
||||
|
||||
@@ -648,7 +648,7 @@ def do_commit_source(args, dbs):
|
||||
return 0
|
||||
|
||||
|
||||
def process_mr_reviews(remote, mrs, dbs, target='master'):
|
||||
def process_mr_reviews(remote, mrs, dbs):
|
||||
"""Process review comments on open MRs
|
||||
|
||||
Checks each MR for unresolved comments and uses Claude agent to address
|
||||
@@ -658,25 +658,17 @@ def process_mr_reviews(remote, mrs, dbs, target='master'):
|
||||
remote (str): Remote name
|
||||
mrs (list): List of MR dicts from get_open_pickman_mrs()
|
||||
dbs (Database): Database instance for tracking processed comments
|
||||
target (str): Target branch for rebase operations
|
||||
|
||||
Returns:
|
||||
int: Number of MRs with comments processed
|
||||
"""
|
||||
# Save current branch to restore later
|
||||
original_branch = run_git(['rev-parse', '--abbrev-ref', 'HEAD'])
|
||||
|
||||
# Fetch to get latest remote state (needed for rebase)
|
||||
tout.info(f'Fetching {remote}...')
|
||||
run_git(['fetch', remote])
|
||||
|
||||
processed = 0
|
||||
|
||||
for merge_req in mrs:
|
||||
mr_iid = merge_req.iid
|
||||
comments = gitlab_api.get_mr_comments(remote, mr_iid)
|
||||
if comments is None:
|
||||
comments = []
|
||||
continue
|
||||
|
||||
# Filter to unresolved comments that haven't been processed
|
||||
unresolved = []
|
||||
@@ -686,35 +678,20 @@ def process_mr_reviews(remote, mrs, dbs, target='master'):
|
||||
if dbs.comment_is_processed(mr_iid, com.id):
|
||||
continue
|
||||
unresolved.append(com)
|
||||
|
||||
# Check if rebase is needed
|
||||
needs_rebase = merge_req.needs_rebase or merge_req.has_conflicts
|
||||
|
||||
# Skip if no comments and no rebase needed
|
||||
if not unresolved and not needs_rebase:
|
||||
if not unresolved:
|
||||
continue
|
||||
|
||||
tout.info('')
|
||||
if needs_rebase:
|
||||
if merge_req.has_conflicts:
|
||||
tout.info(f"MR !{mr_iid} has merge conflicts - rebasing...")
|
||||
else:
|
||||
tout.info(f"MR !{mr_iid} needs rebase...")
|
||||
if unresolved:
|
||||
tout.info(f"MR !{mr_iid} has {len(unresolved)} new comment(s):")
|
||||
for comment in unresolved:
|
||||
tout.info(f' [{comment.author}]: {comment.body[:80]}...')
|
||||
tout.info(f"MR !{mr_iid} has {len(unresolved)} new comment(s):")
|
||||
for comment in unresolved:
|
||||
tout.info(f' [{comment.author}]: {comment.body[:80]}...')
|
||||
|
||||
# Run agent to handle comments and/or rebase
|
||||
# Run agent to handle comments
|
||||
success, conversation_log = agent.handle_mr_comments(
|
||||
mr_iid,
|
||||
merge_req.source_branch,
|
||||
unresolved,
|
||||
remote,
|
||||
target,
|
||||
needs_rebase=needs_rebase,
|
||||
has_conflicts=merge_req.has_conflicts,
|
||||
mr_description=merge_req.description,
|
||||
)
|
||||
|
||||
if success:
|
||||
@@ -743,11 +720,6 @@ def process_mr_reviews(remote, mrs, dbs, target='master'):
|
||||
tout.error(f"Failed to handle comments for MR !{mr_iid}")
|
||||
processed += 1
|
||||
|
||||
# Restore original branch
|
||||
if processed:
|
||||
tout.info(f'Returning to {original_branch}')
|
||||
run_git(['checkout', original_branch])
|
||||
|
||||
return processed
|
||||
|
||||
|
||||
@@ -939,17 +911,13 @@ def do_step(args, dbs):
|
||||
tout.info(f" !{merge_req.iid}: {merge_req.title}")
|
||||
|
||||
# Process any review comments on open MRs
|
||||
process_mr_reviews(remote, mrs, dbs, args.target)
|
||||
process_mr_reviews(remote, mrs, dbs)
|
||||
|
||||
tout.info('')
|
||||
tout.info('Not creating new MR while others are pending')
|
||||
return 0
|
||||
|
||||
# No pending MRs, run apply with push
|
||||
# First fetch to get latest remote state
|
||||
tout.info(f'Fetching {remote}...')
|
||||
run_git(['fetch', remote])
|
||||
|
||||
tout.info('No pending pickman MRs, creating new one...')
|
||||
args.push = True
|
||||
args.branch = None # Let do_apply generate branch name
|
||||
|
||||
@@ -1900,14 +1900,13 @@ class TestProcessMrReviewsCommentTracking(unittest.TestCase):
|
||||
resolved=False),
|
||||
]
|
||||
|
||||
with mock.patch.object(control, 'run_git'):
|
||||
with mock.patch.object(gitlab_api, 'get_mr_comments',
|
||||
return_value=comments):
|
||||
with mock.patch.object(agent, 'handle_mr_comments',
|
||||
return_value=(True, 'Done')) as mock_agent:
|
||||
with mock.patch.object(gitlab_api, 'update_mr_description'):
|
||||
with mock.patch.object(control, 'update_history_with_review'):
|
||||
control.process_mr_reviews('ci', mrs, dbs)
|
||||
with mock.patch.object(gitlab_api, 'get_mr_comments',
|
||||
return_value=comments):
|
||||
with mock.patch.object(agent, 'handle_mr_comments',
|
||||
return_value=(True, 'Done')) as mock_agent:
|
||||
with mock.patch.object(gitlab_api, 'update_mr_description'):
|
||||
with mock.patch.object(control, 'update_history_with_review'):
|
||||
control.process_mr_reviews('ci', mrs, dbs)
|
||||
|
||||
# Agent should only receive the new comment
|
||||
call_args = mock_agent.call_args
|
||||
@@ -1917,69 +1916,6 @@ class TestProcessMrReviewsCommentTracking(unittest.TestCase):
|
||||
|
||||
dbs.close()
|
||||
|
||||
def test_rebase_without_comments(self):
|
||||
"""Test that MRs needing rebase trigger agent even without comments."""
|
||||
with terminal.capture():
|
||||
dbs = database.Database(self.db_path)
|
||||
dbs.start()
|
||||
|
||||
# MR needs rebase but has no comments
|
||||
mrs = [gitlab_api.PickmanMr(
|
||||
iid=100,
|
||||
title='[pickman] Test MR',
|
||||
source_branch='cherry-test',
|
||||
description='Test',
|
||||
web_url='https://gitlab.com/mr/100',
|
||||
has_conflicts=False,
|
||||
needs_rebase=True,
|
||||
)]
|
||||
|
||||
with mock.patch.object(control, 'run_git'):
|
||||
with mock.patch.object(gitlab_api, 'get_mr_comments',
|
||||
return_value=[]):
|
||||
with mock.patch.object(agent, 'handle_mr_comments',
|
||||
return_value=(True, 'Rebased')) as mock_agent:
|
||||
with mock.patch.object(gitlab_api, 'update_mr_description'):
|
||||
with mock.patch.object(control, 'update_history_with_review'):
|
||||
control.process_mr_reviews('ci', mrs, dbs)
|
||||
|
||||
# Agent should be called with needs_rebase=True
|
||||
mock_agent.assert_called_once()
|
||||
call_kwargs = mock_agent.call_args[1]
|
||||
self.assertTrue(call_kwargs.get('needs_rebase'))
|
||||
self.assertFalse(call_kwargs.get('has_conflicts'))
|
||||
|
||||
dbs.close()
|
||||
|
||||
def test_skips_mr_no_rebase_no_comments(self):
|
||||
"""Test that MRs without rebase need or comments are skipped."""
|
||||
with terminal.capture():
|
||||
dbs = database.Database(self.db_path)
|
||||
dbs.start()
|
||||
|
||||
# MR has no comments and doesn't need rebase
|
||||
mrs = [gitlab_api.PickmanMr(
|
||||
iid=100,
|
||||
title='[pickman] Test MR',
|
||||
source_branch='cherry-test',
|
||||
description='Test',
|
||||
web_url='https://gitlab.com/mr/100',
|
||||
has_conflicts=False,
|
||||
needs_rebase=False,
|
||||
)]
|
||||
|
||||
with mock.patch.object(control, 'run_git'):
|
||||
with mock.patch.object(gitlab_api, 'get_mr_comments',
|
||||
return_value=[]):
|
||||
with mock.patch.object(agent, 'handle_mr_comments',
|
||||
return_value=(True, 'Done')) as mock_agent:
|
||||
control.process_mr_reviews('ci', mrs, dbs)
|
||||
|
||||
# Agent should NOT be called
|
||||
mock_agent.assert_not_called()
|
||||
|
||||
dbs.close()
|
||||
|
||||
|
||||
class TestParsePoll(unittest.TestCase):
|
||||
"""Tests for poll command argument parsing."""
|
||||
|
||||
@@ -28,11 +28,9 @@ except ImportError:
|
||||
|
||||
|
||||
# Merge request info returned by get_pickman_mrs()
|
||||
# Use defaults for new fields so existing code doesn't break
|
||||
PickmanMr = namedtuple('PickmanMr', [
|
||||
'iid', 'title', 'web_url', 'source_branch', 'description',
|
||||
'has_conflicts', 'needs_rebase'
|
||||
], defaults=[False, False])
|
||||
'iid', 'title', 'web_url', 'source_branch', 'description'
|
||||
])
|
||||
|
||||
# Comment info returned by get_mr_comments()
|
||||
MrComment = namedtuple('MrComment', [
|
||||
@@ -234,22 +232,12 @@ def get_pickman_mrs(remote, state='opened'):
|
||||
pickman_mrs = []
|
||||
for merge_req in mrs:
|
||||
if '[pickman]' in merge_req.title:
|
||||
# Check merge status - detailed_merge_status is newer API
|
||||
detailed_status = getattr(merge_req, 'detailed_merge_status', '')
|
||||
needs_rebase = detailed_status == 'need_rebase'
|
||||
# Also check diverged_commits_count as fallback
|
||||
if not needs_rebase:
|
||||
diverged = getattr(merge_req, 'diverged_commits_count', 0)
|
||||
needs_rebase = diverged and diverged > 0
|
||||
|
||||
pickman_mrs.append(PickmanMr(
|
||||
iid=merge_req.iid,
|
||||
title=merge_req.title,
|
||||
web_url=merge_req.web_url,
|
||||
source_branch=merge_req.source_branch,
|
||||
description=merge_req.description or '',
|
||||
has_conflicts=getattr(merge_req, 'has_conflicts', False),
|
||||
needs_rebase=needs_rebase,
|
||||
))
|
||||
return pickman_mrs
|
||||
except gitlab.exceptions.GitlabError as exc:
|
||||
|
||||
Reference in New Issue
Block a user