Skip to content
Browse files
[git-webkit] clean all dead pr branches

Reviewed by Aakash Jain.

* Tools/Scripts/libraries/webkitscmpy/ Bump version.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/ Ditto.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/program/
(DeletePRBranches): Iterate through all local branches and remove those
associated with a closed PR.
* Tools/Scripts/libraries/webkitscmpy/webkitscmpy/test/

Canonical link:
git-svn-id: 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
JonWBedard committed May 25, 2022
1 parent 60a5bb3 commit d6ff115c44c141b69ab5216680e5ffef5d39ebe5
Showing 5 changed files with 75 additions and 7 deletions.
@@ -29,7 +29,7 @@ def readme():

description='Library designed to interact with git and svn repositories.',
@@ -46,7 +46,7 @@ def _maybe_add_webkitcorepy_path():
"Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"

version = Version(4, 14, 5)
version = Version(4, 15, 0)

AutoInstall.register(Package('fasteners', Version(0, 15, 0)))
AutoInstall.register(Package('jinja2', Version(2, 11, 3)))
@@ -28,7 +28,7 @@
from .blame import Blame
from .branch import Branch
from .canonicalize import Canonicalize
from .clean import Clean
from .clean import Clean, DeletePRBranches
from .command import Command
from .commit import Commit
from .checkout import Checkout
@@ -79,7 +79,7 @@ def main(
Blame, Branch, Canonicalize, Checkout,
Clean, Find, Info, Land, Log, Pull,
PullRequest, Revert, Setup, InstallGitLFS,
Credentials, Commit,
Credentials, Commit, DeletePRBranches,
if subversion:
@@ -24,15 +24,16 @@
import sys

from .command import Command
from webkitcorepy import arguments, run, Terminal
from webkitscmpy import local, remote
from webkitcorepy import run, Terminal
from webkitscmpy import log, remote

class Clean(Command):
name = 'clean'
help = 'Remove all local changes from current checkout or delete local and remote branches associated with a pull-request'

PR_RE = re.compile(r'^\[?[Pp][Rr][ -](?P<number>\d+)]?$')
REMOTE_RE = re.compile(r'^remote\.(?P<name>\S+)\.fetch$')

def parser(cls, parser, loggers=None):
@@ -49,7 +50,7 @@ def parser(cls, parser, loggers=None):
def cleanup(cls, repository, argument, remote_target=None):
if not repository.is_git:
sys.stderr('Can only cleanup branches on git repositories\n')
sys.stderr.write('Can only clean up branches on git repositories\n')
return 1

rmt = repository.remote(name=remote_target)
@@ -114,3 +115,51 @@ def main(cls, args, repository, **kwargs):
for argument in args.arguments:
result += cls.cleanup(repository, argument, remote_target=args.remote)
return result

class DeletePRBranches(Command):
name = 'delete-pr-branches'
help = 'Iterate through all local development branches, find matching PRs and, if those PRs are closed, delete the local branches.'

def parser(cls, parser, loggers=None):
'--remote', dest='remote', type=str, default=None,
help='Specify remote to search for pull request from.',

def main(cls, args, repository, **kwargs):
if not repository:
sys.stderr.write('No repository provided\n')
return 1
if not repository.path:
sys.stderr.write('Cannot clean on remote repository "{}"\n'.format(repository.url))
return 1

rmt = repository.remote(name=args.remote)
if not rmt.pull_requests:
sys.stderr.write("'{}' does not have associated pull-requests\n".format(rmt.url))
return 1

result = 0
for branch in repository.branches_for(remote=False):
if not repository.dev_branches.match(branch):
continue'Checking {}...'.format(branch))
prs = list(rmt.pull_requests.find(opened=None, head=branch))
if not prs:
if any([pr.opened for pr in prs]):
result += Clean.cleanup(repository, branch, remote_target=args.remote)

for name in repository.config().keys():
match = Clean.REMOTE_RE.match(name)
if not match:
name ='name')'Deleting {}...'.format(name))
result += run([repository.executable(), 'fetch', name, '-f'], cwd=repository.root_path).returncode

return result
@@ -87,3 +87,22 @@ def test_clean_pr(self):
self.assertNotIn('eng/pr-branch', repo.commits)

def test_delete_pr_branches(self):
with OutputCapture(), mocks.remote.GitHub() as remote, mocks.local.Git(
self.path, remote='https://{}'.format(remote.remote),
) as repo, mocks.local.Svn():
repo.staged['added.txt'] = 'added'
self.assertEqual(0, program.main(
args=('pull-request', '-i', 'pr-branch'),
remote.pull_requests[-1]['state'] = 'closed'

self.assertIn('eng/pr-branch', repo.commits)
self.assertEqual(0, program.main(
args=('delete-pr-branches', '-v'),
self.assertNotIn('eng/pr-branch', repo.commits)

0 comments on commit d6ff115

Please sign in to comment.