1
0
mirror of https://github.com/openSUSE/osc.git synced 2026-01-07 15:37:37 +01:00

Add command git-obs pr review cancel-request

This commit is contained in:
Andrii Nikitin
2025-11-12 12:55:56 +01:00
committed by Daniel Mach
parent 73b895a5ae
commit fd9f9c8db7
3 changed files with 240 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
Feature: `git-obs pr` command
Background:
Given I set working directory to "{context.osc.temp}"
And I execute git-obs with args "repo fork pool/test-GitPkgA"
And I execute git-obs with args "repo clone Admin/test-GitPkgA --no-ssh-strict-host-key-checking"
And I set working directory to "{context.osc.temp}/test-GitPkgA"
And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.1@' *.spec"
And I execute "git commit -m 'v1.1' -a"
And I execute "sed -i 's@^\(Version: *\) .*@\1 v1.2@' *.spec"
And I execute "git commit -m 'v1.2' -a"
And I execute "git push"
And I execute git-obs with args "pr create --title 'Change version' --description='some text'"
And I execute git-obs with args "api -X POST /repos/pool/test-GitPkgA/pulls/1/requested_reviewers --data='{{"reviewers": ["bob", "alice"]}}'"
@destructive
Scenario: Check setup is correct
When I execute git-obs with args "api /repos/pool/test-GitPkgA/pulls/1/reviews"
Then the exit code is 0
And stdout contains "bob"
And stdout contains "alice"
@destructive
Scenario: Cancel reviews for single user
When I execute git-obs with args "pr review cancel-request pool/test-GitPkgA#1 bob --dry-run"
Then the exit code is 0
When I execute git-obs with args "api /repos/pool/test-GitPkgA/pulls/1/reviews"
Then the exit code is 0
And stdout contains "bob"
And stdout contains "alice"
# When I execute git-obs with args "api -X DELETE /repos/pool/test-GitPkgA/pulls/1/requested_reviewers --data='{{"reviewers": ["bob"]}}'"
When I execute git-obs with args "pr review cancel-request pool/test-GitPkgA#1 bob"
Then the exit code is 0
When I execute git-obs with args "api /repos/pool/test-GitPkgA/pulls/1/reviews"
Then the exit code is 0
And stdout doesn't contain "bob"
And stdout contains "alice"
When I execute git-obs with args "pr review cancel-request pool/test-GitPkgA#1 bob"
Then the exit code is 1
@destructive
Scenario: Cancel review requests for all
When I execute git-obs with args "pr review cancel-request pool/test-GitPkgA#1 --all --dry-run"
Then the exit code is 0
When I execute git-obs with args "api /repos/pool/test-GitPkgA/pulls/1/reviews"
Then the exit code is 0
And stdout contains "bob"
And stdout contains "alice"
# When I execute git-obs with args "api -X DELETE /repos/pool/test-GitPkgA/pulls/1/requested_reviewers --data='{{"reviewers": ["bob","alice"]}}'"
When I execute git-obs with args "pr review cancel-request pool/test-GitPkgA#1 --all"
Then the exit code is 0
When I execute git-obs with args "api /repos/pool/test-GitPkgA/pulls/1/reviews"
Then the exit code is 0
And stdout doesn't contain "bob"
And stdout doesn't contain "alice"
@destructive
Scenario: Cancel review requests for all with exclude lowercase
When I execute git-obs with args "pr review cancel-request pool/test-GitPkgA#1 --all --exclude bob"
Then the exit code is 0
When I execute git-obs with args "api /repos/pool/test-GitPkgA/pulls/1/reviews"
Then the exit code is 0
And stdout contains "bob"
And stdout doesn't contain "alice"
@destructive
Scenario: Cancel review request for all with exclude mixed case
When I execute git-obs with args "pr review cancel-request pool/test-GitPkgA#1 --all --exclude BoB --exclude unknown"
Then the exit code is 0
When I execute git-obs with args "api /repos/pool/test-GitPkgA/pulls/1/reviews"
Then the exit code is 0
And stdout contains "bob"
And stdout doesn't contain "alice"

View File

@@ -0,0 +1,63 @@
import osc.commandline_git
class PullRequestReviewCancelRequestCommand(osc.commandline_git.GitObsCommand):
"""
Cancel a request for review of pull request
"""
name = "cancel-request"
parent = "PullRequestReviewCommand"
def init_arguments(self):
self.add_argument(
"id",
help="Pull request ID in <owner>/<repo>#<number> format",
)
self.add_argument(
"user",
nargs="*",
help="User with pending review request",
)
self.add_argument(
"-n",
"--dry-run",
action="store_true",
help="Don't do any action, only report what should be done",
)
self.add_argument(
"-a",
"--all",
action="store_true",
help="Cancel all pending review requests",
)
self.add_argument(
"-x",
"--exclude",
action="append",
help="Users to ignore when cancelling review requests.",
)
def run(self, args):
from osc import gitea_api
if len(args.user) < 1 and not args.all:
self.parser.error("Must specify a user or --all for all users")
self.print_gitea_settings()
owner, repo, number = gitea_api.PullRequest.split_id(args.id)
if args.all:
gitea_api.PullRequest.cancel_review_requests_all(
self.gitea_conn, owner, repo, number, args.exclude, args.dry_run
)
else:
gitea_api.PullRequest.cancel_review_requests(
self.gitea_conn,
owner,
repo,
number,
args.user,
args.exclude,
args.dry_run,
)

View File

@@ -802,3 +802,107 @@ class PullRequest(GiteaModel):
for label_id in label_id_list:
url = conn.makeurl("repos", owner, repo, "issues", str(number), "labels", str(label_id))
conn.request("DELETE", url)
@classmethod
def _cancel_review_requests(
cls,
conn: Connection,
owner: str,
repo: str,
number: int,
users: Optional[list],
exclude: Optional[list],
dry_run: Optional[bool],
) -> GiteaHTTPResponse:
"""
Internal method to cancel all pending review requests. Empty user list means for all users.
"""
from .exceptions import GitObsRuntimeError
pr_obj = cls.get(conn, owner, repo, number)
review_states = ["REQUEST_REVIEW"]
all_reviews = pr_obj.get_reviews(conn)
user_reviews = {i.user.lower() for i in all_reviews if i.user and i.state in review_states}
team_reviews = {i.team.lower() for i in all_reviews if i.team and i.state in review_states}
users_to_remove = []
teams_to_remove = []
if exclude:
exclude[:] = [i.lower() for i in exclude]
# empty list means we remove all users
if not users:
for user in user_reviews:
if exclude and user in exclude:
continue
users_to_remove.append(user)
else:
# remove eventual empty strings
users[:] = [i for i in users if i]
for user in users:
if exclude and user in exclude:
continue
if user[0] == "@":
team = user[1:]
if team.lower() not in team_reviews:
msg = f"Team {team} has no pending review requests in {owner}/{repo}#{number}"
raise GitObsRuntimeError(msg)
teams_to_remove.append(team)
else:
if user.lower() not in user_reviews:
msg = f"User {user} has no pending review requests in {owner}/{repo}#{number}"
raise GitObsRuntimeError(msg)
users_to_remove.append(user)
data = {
"reviewers": users_to_remove,
"teams": teams_to_remove,
}
if not users_to_remove and not teams_to_remove:
return None
url = conn.makeurl("repos", owner, repo, "pulls", str(number), "/requested_reviewers")
if dry_run:
import sys
print(f"DELETE {url} {data}", file=sys.stderr)
else:
conn.request("DELETE", url, data)
@classmethod
def cancel_review_requests_all(
cls,
conn: Connection,
owner: str,
repo: str,
number: int,
exclude: Optional[list],
dry_run: Optional[bool] = False,
) -> GiteaHTTPResponse:
"""
Cancel all pending review requests.
"""
return cls._cancel_review_requests(conn, owner, repo, number, [], exclude, dry_run)
@classmethod
def cancel_review_requests(
cls,
conn: Connection,
owner: str,
repo: str,
number: int,
users: List[str],
exclude: Optional[list],
dry_run: Optional[bool] = False,
) -> GiteaHTTPResponse:
"""
Cancel pending review requests for particular users.
"""
if not users:
return None
return cls._cancel_review_requests(conn, owner, repo, number, users, exclude, dry_run)