Commit Graph

19 Commits

Author SHA1 Message Date
Simon Glass
47ffd9b6a3 pickman: Improve function names and line-length compliance
Make some simple tweaks to reduces the size of lines:

- Rename format_history_summary() -> format_history()
- Rename update_history_with_review() -> update_history()
- Rename update_mr_description() -> update_mr_desc()
- Rename SIGNAL_ALREADY_APPLIED -> SIGNAL_APPLIED
- Import gitlab_api as 'gitlab' in ftest.py
- Shorten test hash strings by 1 character
- Remove unused _cmd variable assignment
- Shorten exception message 'branch not found' -> 'not found'

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-24 14:05:35 -07:00
Simon Glass
9d2495c0bf pickman: Fix 80-column line length compliance
Break long lines to comply with 80-character limit and remove trailing
whitespace across agent.py, control.py, database.py, gitlab_api.py, and
__main__.py

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-24 13:56:12 -07:00
Simon Glass
7ecd1216aa pickman: Fix push errors for new and aborted branches
Fix two issues with push-branch:

1. Handle missing remote branch: When pushing a new branch for the
   first time, the fetch to update tracking refs fails because the
   branch doesn't exist on the remote yet. Handle this by catching
   the fetch failure and using regular --force instead of
   --force-with-lease for new branches.

2. Detect aborted cherry-picks: When the agent aborts a cherry-pick
   (e.g., because commits are already applied), it may delete the
   branch. Verify the branch exists after the agent runs to avoid
   attempting to push a non-existent branch.

Cover-letter:
pickman and CI improvements
This series contains pickman enhancements and a CI fix:

- Process MRs oldest first to handle rebases chronologically
- Add --run-ci option for push-branch to trigger pipelines after rebase
- Fix force-push tracking ref issues by fetching before push
- Handle edge cases: new branches and agent-aborted cherry-picks
- Push master to GitHub for ReadTheDocs documentation rebuilds
END

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-21 08:19:22 -07:00
Simon Glass
cdd3ed1365 pickman: Fetch before force-push to update tracking refs
When using --force-with-lease with an HTTPS URL (instead of a remote
name), git cannot find the tracking refs automatically. This causes
"stale info" errors when the local tracking ref is out of date.

Fix by fetching the branch first to update the tracking ref before
pushing.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-21 08:15:41 -07:00
Simon Glass
5b83f25996 pickman: Add --run-ci option for push-branch command
Add a --run-ci flag to push-branch that triggers the CI pipeline instead
of skipping it. This is needed when pushing rebased branches where the
MR pipeline should run to verify the changes.

Update the review agent prompt to use --run-ci when pushing after
rebase operations.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-21 08:15:21 -07:00
Simon Glass
64e1d96c06 pickman: Process MRs oldest first
Sort merge requests by created_at ascending so older MRs are processed
before newer ones. This ensures that MRs needing rebase are handled in
chronological order.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-21 08:14:16 -07:00
Simon Glass
9ffbb25d0f pickman: Use GitLab API token for push authentication
Add support for pushing branches using the GitLab API token, so commits
appear as coming from the token owner (e.g., a bot account) rather than
the user's configured git credentials.

Add get_push_url() function that creates a token-authenticated URL in
the format https://oauth2:TOKEN@host/project.git. Update push_branch()
to use this URL when available.

Add a new 'push-branch' command that the agent can use for pushing:
  ./tools/pickman/pickman push-branch <branch> -r <remote> [-f]

Update the review agent prompt to use this command instead of direct
git push, ensuring all pickman commits come from the same account.

Series-to: concept
Cover-letter:
pickman: Improvements for robustness and automation
These changes improve pickman's robustness when interrupted, add the
ability to skip problematic MRs during review, support multiple
concurrent MRs, and ensure all commits come from the pickman bot
account.

This series adds several improvements to pickman:

- Fix rebase-detection for open MRs
- Add skip/unskip support via review comments (pickman: skip/unskip)
- Skip already-processed commits to handle interruptions gracefully
- Handle 409 errors when MR already exists
- Document the commit-selection algorithm and skip feature
- Add --max-mrs option for parallel MR creation
- Run a CI pipeline after review-comment changes
- Use GitLab API token for push authentication (bot-account support)
END

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-20 12:22:59 -07:00
Simon Glass
044e663274 pickman: Handle existing MR when creating new one
If pickman crashes or is interrupted after pushing a branch but before
recording the MR, the next run would try to create an MR for the same
branch and receive a 409 Conflict error. Handle this gracefully by
finding the existing MR and returning its URL.

Add MrCreateError exception class to allow testing without importing
the gitlab module.

Co-developed-by: Claude <noreply@anthropic.com>
2025-12-20 12:22:59 -07:00
Simon Glass
cb2c28b7ca pickman: Add skip/unskip support for MRs via review comments
Allow reviewers to skip an MR by commenting "pickman skip" (or
"pickman: skip", "@pickman skip"). When skipped, the MR title is
updated to include "[skipped]" and pickman continues creating new
MRs for subsequent cherry-picks.

To resume processing a skipped MR, comment "pickman unskip" which
removes the [skipped] tag from the title.

Skipped MRs are ignored for rebase processing and don't block
creation of new MRs.

Fix some double-quotes while here.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-20 12:22:59 -07:00
Simon Glass
88ae4fbc6c pickman: Fix rebase detection for open MRs
The GitLab list() API returns inaccurate detailed_merge_status values.
Fetch the full MR details for open MRs to get accurate rebase status.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-20 12:22:59 -07:00
Simon Glass
ddc50f4b02 pickman: Auto-detect when MRs need rebasing
Check GitLab merge request status to detect when a rebase is needed,
even if there are no review comments. This handles the case where
GitLab shows "Merge request must be rebased" or "Merge conflicts must
be resolved".

Add has_conflicts and needs_rebase fields to PickmanMr namedtuple,
populated from GitLab's detailed_merge_status and diverged_commits_count
fields.

Update process_mr_reviews() to trigger the agent for rebase when needed,
even without review comments. The agent prompt is adjusted based on
whether it needs to handle comments, rebase, or both.

Also:
- Pass MR description to agent for context from previous work
- After processing reviews, restore the original branch
- Use -o ci.skip when pushing to avoid duplicate pipelines

Series-to: concept
Series-links: 2:81 1:80
Cover-letter:
pickman: Improve handling of rebasing
This little series includes a few patches to ensure that rebases are
made against -master and detection for needing a rebase without the user
having explicitly request it.

It also passes the previous context to the agent when handling reviews,
which should improve its response.
END

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
Series-version: 2
2025-12-17 12:37:03 -07:00
Simon Glass
f903f5eb9a pickman: Skip push pipeline for MR branches
Remove SJG_LAB CI variable from push since lab tests are now
triggered automatically for MR pipelines via .gitlab-ci.yml rules.
Keep ci.skip to avoid running a pipeline on push; the MR pipeline
will run when the merge request is created.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-16 16:24:40 -07:00
Simon Glass
4e91cdc04c pickman: Add check-gitlab command
Add check-gitlab command to verify GitLab permissions for the
configured token. This helps diagnose issues like 403 Forbidden
errors when trying to create merge requests.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-16 16:23:58 -07:00
Simon Glass
0401e3763c pickman: Add config-file support for GitLab token
Add support for storing a GitLab API token in ~/.config/pickman.conf
instead of an environment variable. This allows using a dedicated bot
account for pickman without affecting the user's personal GitLab
credentials.

Config file format:
  [gitlab]
  token = glpat-xxxxxxxxxxxxxxxxxxxx

This falls back to GITLAB_TOKEN environment variable if config file is
not present.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-16 16:23:37 -07:00
Simon Glass
0785d7149c pickman: Add a way to update a gitlab merge-request
Add function to update a merge request's description via the GitLab API.
This is used to update the MR with the agent's conversation log after
processing review comments.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-16 16:22:46 -07:00
Simon Glass
acbe947db7 pickman: Use named tuples for MR data
Change get_pickman_mrs() and get_mr_comments() to return lists of named
tuples instead of dicts. This provides cleaner attribute access (e.g.
merge_req.iid instead of merge_req['iid']) and better code documentation.

Add PickmanMr and MrComment named tuples to gitlab_api.py.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-16 16:11:46 -07:00
Simon Glass
436bca1061 pickman: Update database when MRs are merged
Add automatic database updates when pickman MRs are merged. The step
command now:

1. Checks for merged pickman MRs via GitLab API
2. Parses the MR description to find the source branch and last commit
3. Updates the database's last_commit for the source branch
4. Then proceeds to check for open MRs and create new ones as before

This removes the need to manually run commit-source after each MR is
merged, enabling fully automated cherry-pick workflows with poll.

Add get_merged_pickman_mrs() and refactor get_open_pickman_mrs() to use
a common get_pickman_mrs() function with a state parameter.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 13:15:19 +00:00
Simon Glass
4c6a784666 pickman: Add review command to handle MR comments
Add do_review() command that lists open pickman MRs and checks each for
human comments. Uses a Claude agent to address actionable comments.

Also add supporting infrastructure:
- gitlab_api: get_open_pickman_mrs(), get_mr_comments(), reply_to_mr()
- agent: run_review_agent(), handle_mr_comments()
- History file support for recording cherry-pick conversations
- Return conversation_log from cherry_pick agent for MR descriptions

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-16 13:15:19 +00:00
Simon Glass
616e0abb7b pickman: Add GitLab API module
Add gitlab_api module with functions for interacting with GitLab:

- check_available(): Check if python-gitlab is installed
- get_token(): Get GitLab API token from environment
- get_remote_url(): Get URL for a git remote
- parse_url(): Parse GitLab URLs (SSH and HTTPS formats)
- push_branch(): Push a branch to a remote
- create_mr(): Create a merge request via GitLab API
- push_and_create_mr(): Combined push and MR creation

Requires python-gitlab library and GITLAB_TOKEN environment variable.

Name the module gitlab_api.py to avoid shadowing the python-gitlab
library.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
2025-12-16 13:15:19 +00:00