mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-22 09:57:41 +00:00
- C0115: Missing class docstring (missing-class-docstring) - C0123: Use isinstance() rather than type() for a typecheck. (unidiomatic-typecheck) - C0201: Consider iterating the dictionary directly instead of calling .keys() (consider-iterating-dictionary) - C0206: Consider iterating with .items() (consider-using-dict-items) - C0411: standard import "..." should be placed before "..." (wrong-import-order) - C0415: Import outside toplevel (...) (import-outside-toplevel) - C1802: Do not use `len(SEQUENCE)` without comparison to determine if a sequence is empty (use-implicit-booleaness-not-len) - E0001: Parsing failed: 'invalid syntax (<unknown>, line 2313)' (syntax-error) - E0401: Unable to import '...' (import-error) - E0602: Undefined variable 'l' (undefined-variable) - R0205: Class 'VagrantEnv' inherits from object, can be safely removed from bases in python3 (useless-object-inheritance) - E1101: Instance of 'NSECBASE' has no 'dump_fixedpart' member (no-member) - E1123: Unexpected keyword argument 'capture' in method call (unexpected-keyword-arg) - R0902: Too many instance attributes (too-many-instance-attributes) - R0913: Too many arguments (too-many-arguments) - R0916: Too many boolean expressions in if statement (6/5) (too-many-boolean-expressions) - R1717: Consider using a dictionary comprehension (consider-using-dict-comprehension) - R1722: Consider using 'sys.exit' instead (consider-using-sys-exit) - R1732: Consider using 'with' for resource-allocating operations (consider-using-with) - R1735: Consider using '{}' instead of a call to 'dict'. (use-dict-literal) - W0102: Dangerous default value sys.argv[1:] (builtins.list) as argument (dangerous-default-value) - W0102: Dangerous default value {} as argument (dangerous-default-value) - W0106: Expression "[f.write('%02x' % x) for x in bin_address]" is assigned to nothing (expression-not-assigned) - W0107: Unnecessary pass statement (unnecessary-pass) - W0201: Attribute 'config' defined outside __init__ (attribute-defined-outside-init) - W0404: Reimport '...' (imported line ...) (reimported) - W0611: Unused import ... (unused-import) - W0612: Unused variable '...' (unused-variable) - W0613: Unused argument '...' (unused-argument) - W0621: Redefining name '...' from outer scope (line 1471) (redefined-outer-name) - W0622: Redefining built-in '...' (redefined-builtin) - W0707: Consider explicitly re-raising using 'raise ... from ...' (raise-missing-from) - W0718: Catching too general exception Exception (broad-exception-caught) - W1202: Use lazy % formatting in logging functions (logging-format-interpolation) - W1203: Use lazy % formatting in logging functions (logging-fstring-interpolation) - W1308: Duplicate string formatting argument 'connection_type', consider passing as named argument (duplicate-string-formatting-argument) - W1401: Anomalous backslash in string: '\/'. String constant might be missing an r prefix. (anomalous-backslash-in-string) - W1406: The u prefix for strings is no longer necessary in Python >=3.0 (redundant-u-string-prefix) - W1514: Using open without explicitly specifying an encoding (unspecified-encoding) - W4901: Deprecated module 'optparse' (deprecated-module) - W4904: Using deprecated class SafeConfigParser of module configparser (deprecated-class)
194 lines
6.3 KiB
Python
Executable File
194 lines
6.3 KiB
Python
Executable File
#!/usr/bin/python
|
|
#
|
|
# Copyright (C) 2012-2024 Internet Systems Consortium, Inc. ("ISC")
|
|
#
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
#
|
|
# This script lists obsolete (fully merged) branches. It is useful for periodic
|
|
# maintenance of our GIT tree.
|
|
#
|
|
# It is good idea to use following command before running this script:
|
|
#
|
|
# git pull
|
|
# git remote prune origin
|
|
#
|
|
# This script requires python 3.
|
|
#
|
|
# I have limited experience in Python. If things are done in a strange or
|
|
# uncommon way, there are no obscure reasons to do it that way, just plain
|
|
# lack of experience.
|
|
#
|
|
# tomek
|
|
|
|
import argparse
|
|
|
|
# [B404:blacklist] Consider possible security implications associated with subprocess module.
|
|
import subprocess # nosec B404
|
|
|
|
|
|
class Branch:
|
|
MERGED = 1
|
|
NOTMERGED = 2
|
|
name = None
|
|
status = NOTMERGED
|
|
last_commit = None
|
|
|
|
|
|
def branch_list_get(verbose):
|
|
""" Generates a list of available remote branches and
|
|
checks their status (merged/unmerged). A branch is merged
|
|
if all changes on that branch are also on master. """
|
|
|
|
# call git branch -r (list of remote branches)
|
|
txt_list = check_output(["git", "branch", "-r"])
|
|
|
|
txt_list = txt_list.split(b"\n")
|
|
|
|
# we will store list of suitable branches here
|
|
out = []
|
|
for branch in txt_list:
|
|
# skip empty lines
|
|
if len(branch) == 0:
|
|
continue
|
|
|
|
# skip branches that are aliases (something -> something_else)
|
|
if branch.find(b"->") != -1:
|
|
continue
|
|
|
|
# don't complain about master
|
|
if branch == b"origin/master":
|
|
continue
|
|
|
|
branch_info = Branch()
|
|
|
|
# get branch name
|
|
branch_info.name = branch.strip(b" ")
|
|
branch_info.name = branch_info.name.decode("utf-8")
|
|
|
|
# check if branch is merged or not
|
|
if verbose:
|
|
print("Checking branch %s" % branch_info.name)
|
|
|
|
# get a diff with changes that are on that branch only
|
|
# i.e. all unmerged code.
|
|
# Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input.
|
|
cmd = ["git", "diff", "master..." + branch_info.name]
|
|
diff = check_output(cmd)
|
|
if len(diff) == 0:
|
|
# No diff? Then all changes from that branch are on master as well.
|
|
branch_info.status = Branch.MERGED
|
|
|
|
# let's get the last contributor with extra formatting
|
|
# see man git-log and search for PRETTY FORMATS.
|
|
# %ai = date, %ae = author e-mail, %an = author name
|
|
cmd = ["git", "log", "-n", "1", "--pretty=\"%ai,%ae,%an\"", branch_info.name]
|
|
# Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted
|
|
# input.
|
|
offender = check_output(cmd)
|
|
offender = offender.strip(b"\n\"")
|
|
|
|
# comment out this 2 lines to disable obfuscation
|
|
offender = offender.replace(b"@", b"(at)")
|
|
# Obfuscating a dot does not work too well for folks that use
|
|
# initials
|
|
# offender = offender.replace(b".", b"(dot)")
|
|
|
|
branch_info.last_commit = offender.decode("utf-8")
|
|
|
|
else:
|
|
# diff is not empty, so there is something to merge
|
|
branch_info.status = Branch.NOTMERGED
|
|
|
|
out.append(branch_info)
|
|
return out
|
|
|
|
|
|
def branch_print(branches, csv, print_merged, print_notmerged, print_stats):
|
|
""" prints out list of branches with specified details (using
|
|
human-readable (or CSV) format. It is possible to specify,
|
|
which branches should be printed (merged, notmerged) and
|
|
also print out summary statistics """
|
|
|
|
# counters used for statistics
|
|
merged = 0
|
|
notmerged = 0
|
|
|
|
# compact list of merged/notmerged branches
|
|
merged_str = ""
|
|
notmerged_str = ""
|
|
for branch in branches:
|
|
if branch.status == Branch.MERGED:
|
|
merged = merged + 1
|
|
if not print_merged:
|
|
continue
|
|
if csv:
|
|
print("%s,merged,%s" % (branch.name, branch.last_commit))
|
|
else:
|
|
merged_str = merged_str + " " + branch.name
|
|
else:
|
|
# NOT MERGED
|
|
notmerged = notmerged + 1
|
|
if not print_notmerged:
|
|
continue
|
|
if csv:
|
|
print("%s,notmerged,%s" % (branch.name, branch.last_commit))
|
|
else:
|
|
notmerged_str = notmerged_str + " " + branch.name
|
|
|
|
if not csv:
|
|
if print_merged:
|
|
print("Merged branches : %s" % (merged_str))
|
|
if print_notmerged:
|
|
print("NOT merged branches: %s" % (notmerged_str))
|
|
|
|
if print_stats:
|
|
print("#----------")
|
|
print("#Merged : %d" % merged)
|
|
print("#Not merged: %d" % notmerged)
|
|
|
|
|
|
def check_output(cmd):
|
|
# Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input.
|
|
return subprocess.check_output(cmd) # nosec B603
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(
|
|
description="This script prints out merged and/or unmerged branches of a GIT tree.",
|
|
usage="""%prog
|
|
Lists all obsolete (fully merged into master) branches.
|
|
""")
|
|
|
|
parser.add_argument("-c", "--csv", action="store_true",
|
|
default=False, help="generates CSV output")
|
|
parser.add_argument("-u", "--unmerged", action="store_true",
|
|
default=False, help="lists unmerged branches")
|
|
parser.add_argument("-m", "--skip-merged", action="store_true",
|
|
default=False, help="omits listing merged branches")
|
|
parser.add_argument("-s", "--stats", action="store_true",
|
|
default=False, help="prints also statistics")
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
csv = args.csv
|
|
merged = not args.skip_merged
|
|
unmerged = args.unmerged
|
|
stats = args.stats
|
|
|
|
if csv:
|
|
print("branch name,status,date,last commit(mail),last commit(name)")
|
|
|
|
branch_list = branch_list_get(not csv)
|
|
|
|
branch_print(branch_list, csv, merged, unmerged, stats)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|