Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F154238193
D40023.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D40023.diff
View Options
diff --git a/tools/tools/git/git-ghpr b/tools/tools/git/git-ghpr
new file mode 100755
--- /dev/null
+++ b/tools/tools/git/git-ghpr
@@ -0,0 +1,211 @@
+#!/usr/bin/env python3
+#
+# git-ghpr - Merge commits from github pull requests to main
+#
+# Copyright (c) 2023 M. Warner Losh <imp@FreeBSD.org>
+#
+# SPX-License-Identifier: MIT
+#
+# Some code taken verbatim (or lightly tweaked) from git-publish by
+# Stefan Hajnoczi <stefanha@gmail.com> licensed under MIT.
+
+import glob
+import datetime
+import locale
+import optparse
+import os
+import re
+import subprocess
+import sys
+
+VERSION = '0.0.1'
+#git-publish+
+
+# Encoding for command-line arguments
+CMDLINE_ENCODING = locale.getpreferredencoding()
+
+# Encoding for communicating with the Git executable
+GIT_ENCODING = 'utf-8'
+
+# Encoding for files that GIT_EDITOR can edit
+TEXTFILE_ENCODING = CMDLINE_ENCODING
+
+# As a git alias it is helpful to be a single file script with no external
+# dependencies, so these git command-line wrappers are used instead of
+# python-git.
+
+class GitError(Exception):
+ pass
+
+class GitHookError(Exception):
+ pass
+
+def popen_lines(cmd, **kwargs):
+ '''Communicate with a Popen object and return a list of lines for stdout and stderr'''
+ stdout, stderr = cmd.communicate(**kwargs)
+ stdout = re.split('\r\n|\n',stdout.decode(GIT_ENCODING))[:-1]
+ stderr = re.split('\r\n|\n',stderr.decode(GIT_ENCODING))[:-1]
+ return stdout, stderr
+
+def _git_check(*args):
+ '''Run a git command and return a list of lines, may raise GitError'''
+ cmdstr = 'git ' + ' '.join(('"%s"' % arg if ' ' in arg else arg) for arg in args)
+ if VERBOSE:
+ print(cmdstr)
+ cmd = subprocess.Popen(['git'] + list(args),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = popen_lines(cmd)
+ if cmd.returncode != 0:
+ raise GitError('ERROR: %s\n%s' % (cmdstr, '\n'.join(stderr)))
+ return stdout
+
+def _git(*args):
+ '''Run a git command and return a list of lines, ignore errors'''
+ try:
+ return _git_check(*args)
+ except GitError:
+ # ignore git command errors
+ return []
+
+def _git_with_stderr(*args):
+ '''Run a git command and return a list of lines for stdout and stderr'''
+ if VERBOSE:
+ print('git ' + ' '.join(args))
+ cmd = subprocess.Popen(['git'] + list(args),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = popen_lines(cmd)
+ return stdout, stderr, cmd.returncode
+
+def git_get_current_branch():
+ git_dir = git_get_git_dir()
+ rebase_dir = os.path.join(git_dir, 'rebase-merge')
+ if os.path.exists(rebase_dir):
+ branch_path = os.path.join(rebase_dir, 'head-name')
+ prefix = 'refs/heads/'
+ # Path names are encoded in UTF-8 normalization form C.
+ with open(branch_path, encoding=GIT_ENCODING) as f:
+ branch = f.read().strip()
+ if branch.startswith(prefix):
+ return branch[len(prefix):]
+ return branch
+ else:
+ return _git_check('symbolic-ref', '--short', 'HEAD')[0]
+
+GIT_TOPLEVEL = None
+def git_get_toplevel_dir():
+ global GIT_TOPLEVEL
+ if GIT_TOPLEVEL is None:
+ GIT_TOPLEVEL = _git_check('rev-parse', '--show-toplevel')[0]
+ return GIT_TOPLEVEL
+
+GIT_DIR = None
+def git_get_git_dir():
+ global GIT_DIR
+ if GIT_DIR is None:
+ GIT_DIR = _git('rev-parse', '--git-dir')[0]
+ return GIT_DIR
+
+def git_branch_exists(branch):
+ '''Check if the given branch exists'''
+ try:
+ _git_check('rev-parse', '-q', '--verify', branch)
+ return True
+ except GitError:
+ return False
+
+def setup():
+ '''Add git alias in ~/.gitconfig'''
+ path = os.path.abspath(sys.argv[0])
+ ret = subprocess.call(['git', 'config', '--global',
+ 'alias.ghpr', '!' + path])
+ if ret == 0:
+ print('You can now use \'git ghpr\' like a built-in git command.')
+
+#git-publish-
+
+def git_checkout(*args):
+ '''Return status of the tree'''
+ return _git_check('checkout', *args)
+
+def parse_args():
+
+ parser = optparse.OptionParser(version='%%prog %s' % VERSION,
+ usage='%prog [options] -- [common format-patch options]',
+ description='Do all the MFC tweaks needed when merging from main to stable/XX.',
+ epilog='Please report bugs to Warner Losh <imp@freebsd.org>.')
+ parser.add_option('-b', '--branch', dest='branch', default='PR',
+ help='branch to use [defaults PR]')
+ parser.add_option('--pr', dest='pr', default=None,
+ help='Pull request to land')
+ parser.add_option('--setup', dest='setup', action='store_true', default=False,
+ help='add git alias in ~/.gitconfig')
+ parser.add_option('--upstream', dest='upstream', default='freebsd',
+ help='Upstream remote name, defaults to freebsd')
+ parser.add_option('-v', '--verbose', dest='verbose',
+ action='store_true', default=False,
+ help='show executed git commands (useful for troubleshooting)')
+
+ return parser.parse_args()
+
+class FetchError(Exception):
+ pass
+
+def fetch(url, dst):
+ '''Try to fetch the specified URL'''
+ cmdstr = 'fetch ' + '-o ' + dst + ' ' + url
+ if VERBOSE:
+ print(cmdstr)
+ cmd = subprocess.Popen(['fetch', '-o', dst, url],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = popen_lines(cmd)
+ if cmd.returncode != 0:
+ raise FetchError('ERROR: %s\n%s' % (cmdstr, '\n'.join(stderr)))
+ return stdout
+
+def main():
+ global VERBOSE
+
+ options, args = parse_args()
+ VERBOSE = options.verbose
+
+ # Keep this before any operations that call out to git(1) so that setup
+ # works when the current working directory is outside a git repo.
+ if options.setup:
+ setup()
+ return 0
+
+ try:
+ git_get_toplevel_dir()
+ except GitError:
+ print('Unable to find git directory, are you sure you are in a git repo?')
+ return 1
+
+ if options.pr is None:
+ print('--pr is mandatory')
+ return 1
+
+ branch = 'PR-%s' % options.pr
+ if git_branch_exists(branch):
+ print('Still lamely requires a unique branch, and %s exists' % options.branch)
+ return 1
+
+ git_checkout('-b', branch, 'main')
+ tmp = '/tmp/%s.patch' % options.pr
+ fetch('https://patch-diff.githubusercontent.com/raw/freebsd/freebsd-src/pull/%s.patch' % options.pr,
+ tmp)
+ _git_check('am', '--ignore-date', tmp)
+
+ # Now, rebase this to main to add the trailers we need, but with an editor
+ # that s/-/ / in those trailers because git doesn't like trailers with
+ # spaces in the key value.
+ _git_check('rebase', '-i', 'main',
+ '--exec',
+ 'env EDITOR=$HOME/bin/git-fixup-editor git commit --amend --trailer "Reviewed-by: imp" --trailer "Pull-Request: https://github.com/freebsd/freebsd-src/pull/%s"' % options.pr,
+ )
+ print('I claim PR %s is now a series of commits ready for closer review' % options.pr)
+
+if __name__ == '__main__':
+ sys.exit(main())
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Apr 28, 8:22 AM (5 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32261374
Default Alt Text
D40023.diff (7 KB)
Attached To
Mode
D40023: git-ghpr: A script to land github pull requests
Attached
Detach File
Event Timeline
Log In to Comment