mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 09:17:30 +03:00
bcd74ba1c5
Summary: rage is a basic tool to collect diagnostic information that should not break. To ensure it works all the time, this patch: - unbreaks hg rage from upstream change dad6404ccd - wraps every non-trivial functions with `try`, `catch` - adds a naive test about `hg rage --preview` Test Plan: Run `test-rage.t`. Comment out `import blackbox` and check: ``` hg blackbox -l20: --------------------------- (Failed. See footnote [1]) [1]: global name 'blackbox' is not defined Traceback (most recent call last): File "/home/quark/fb-hgext/rage.py", line 22, in _failsafe return func() File "/home/quark/fb-hgext/rage.py", line 97, in <lambda> _failsafe(lambda: hgcmd(blackbox.blackbox, limit=20))), NameError: global name 'blackbox' is not defined ``` Reviewers: #sourcecontrol, wez, ttung, durham Reviewed By: durham Subscribers: durham, wez, mjpieters Differential Revision: https://phabricator.fb.com/D2928778 Tasks: 10028490 Signature: t1:2928778:1455240651:d39ceed5d045e279160690e0a93a4e326d307db3
145 lines
4.5 KiB
Python
145 lines
4.5 KiB
Python
# Copyright 2014 Facebook Inc.
|
|
#
|
|
"""log useful diagnostics and file a task to source control oncall"""
|
|
|
|
from mercurial.i18n import _
|
|
from mercurial import cmdutil, util, commands, bookmarks, ui, extensions, error
|
|
from hgext import blackbox
|
|
import smartlog
|
|
import atexit, os, socket, re, time, traceback
|
|
|
|
cmdtable = {}
|
|
command = cmdutil.command(cmdtable)
|
|
|
|
_failsafeerrors = []
|
|
|
|
@atexit.register
|
|
def _printfailsafeerrors():
|
|
if _failsafeerrors:
|
|
print('\n'.join(_failsafeerrors))
|
|
|
|
def _failsafe(func):
|
|
try:
|
|
return func()
|
|
except Exception as ex:
|
|
index = len(_failsafeerrors) + 1
|
|
message = "[%d]: %s\n%s\n" % (index, str(ex), traceback.format_exc())
|
|
_failsafeerrors.append(message)
|
|
return '(Failed. See footnote [%d])' % index
|
|
|
|
@command('^rage',
|
|
[('p', 'preview', None,
|
|
_('print information generated locally, no paste or task created'))],
|
|
_('hg rage'))
|
|
def rage(ui, repo, *pats, **opts):
|
|
"""log useful diagnostics and file a task to source control oncall
|
|
|
|
The rage command is for logging useful diagnostics about various
|
|
environment information and filing a task to the source control oncall.
|
|
|
|
The following basic information is included in the task description:
|
|
|
|
- unixname
|
|
- hostname
|
|
- repo location
|
|
- active bookmark
|
|
|
|
Your configured editor will be invoked to let you edit the task title
|
|
and description.
|
|
|
|
The following detailed information is uploaded to a Phabricator paste:
|
|
|
|
- all the basic information (see above)
|
|
- 'df -h' output
|
|
- 'hg sl' output
|
|
- 'hg config'
|
|
- first 20 lines of 'hg status'
|
|
- last 20 events from 'hg blackbox' ('hg blackbox -l 20')
|
|
"""
|
|
|
|
def format(pair, basic=True):
|
|
if basic:
|
|
fmt = "%s: %s\n"
|
|
else:
|
|
fmt = "%s:\n---------------------------\n%s\n"
|
|
return fmt % pair
|
|
|
|
def hgcmd(func, *args, **opts):
|
|
ui.pushbuffer()
|
|
func(ui, repo, *args, **opts)
|
|
return ui.popbuffer()
|
|
|
|
def shcmd(cmd, input=None, check=True):
|
|
_, _, _, p = util.popen4(cmd)
|
|
out, err = p.communicate(input)
|
|
if check and p.returncode:
|
|
raise error.Abort(cmd + ' error: ' + err)
|
|
return out
|
|
|
|
basic = [
|
|
('date', time.ctime()),
|
|
('unixname', os.getenv('LOGNAME')),
|
|
('hostname', socket.gethostname()),
|
|
('repo location', _failsafe(lambda: repo.root)),
|
|
('active bookmark',
|
|
_failsafe(lambda: bookmarks._readactive(repo, repo._bookmarks))),
|
|
]
|
|
|
|
ui._colormode = None
|
|
|
|
detailed = [
|
|
('df -h', _failsafe(lambda: shcmd('df -h', check=False))),
|
|
('hg sl', _failsafe(lambda: hgcmd(smartlog.smartlog))),
|
|
('hg config', _failsafe(lambda: hgcmd(commands.config))),
|
|
('first 20 lines of "hg status"',
|
|
_failsafe(lambda:
|
|
'\n'.join(hgcmd(commands.status).splitlines()[:20]))),
|
|
('hg blackbox -l20',
|
|
_failsafe(lambda: hgcmd(blackbox.blackbox, limit=20))),
|
|
]
|
|
|
|
basic_msg = '\n'.join(map(format, basic))
|
|
detailed_msg = '\n'.join(map(lambda x: format(x, False), detailed))
|
|
if opts.get('preview'):
|
|
print(basic_msg + '\n' + detailed_msg)
|
|
return
|
|
|
|
prompt = '''Title: [hg rage] %s on %s by %s
|
|
|
|
Description:
|
|
|
|
%s
|
|
HG: Edit task title and description. Lines beginning with 'HG:' are removed."
|
|
HG: First line is the title followed by the description.
|
|
HG: Feel free to add relevant information.
|
|
''' % (repo.root, socket.gethostname(), os.getenv('LOGNAME'), basic_msg)
|
|
|
|
text = re.sub("(?m)^HG:.*(\n|$)", "", ui.edit(prompt, ui.username()))
|
|
lines = text.splitlines()
|
|
title = re.sub("(?m)^Title:\s+", "", lines[0])
|
|
desc = re.sub("(?m)^Description:\s+", "", '\n'.join(lines[1:]))
|
|
|
|
print 'pasting the rage info:'
|
|
paste_url = shcmd('arc paste', desc + detailed_msg).split()[1]
|
|
print paste_url
|
|
|
|
desc += '\ndetailed output @ ' + paste_url
|
|
tag = 'hg rage'
|
|
oncall = shcmd('oncalls --output unixname source_control').strip()
|
|
|
|
print 'filing a task for the oncall %s:' % oncall
|
|
task_id = shcmd(' '.join([
|
|
'tasks',
|
|
'create',
|
|
'--title=' + util.shellquote(title),
|
|
'--pri=low',
|
|
'--assign=' + oncall,
|
|
'--sub=' + oncall,
|
|
'--tag=' + util.shellquote(tag),
|
|
'--desc=' + util.shellquote(desc),
|
|
])
|
|
)
|
|
|
|
task_num = shcmd('tasks view ' + task_id).splitlines()[0].split()[0]
|
|
print 'https://our.intern.facebook.com/intern/tasks/?t=' + task_num
|