mirror of
https://github.com/haproxy/haproxy.git
synced 2026-07-13 11:09:54 -04:00
This adds the read side of the review syncing to the generated page: a "Get updates" button at the top right retrieves the shared state from update.cgi (reached by a bare relative URL, so it must be in a cgi-bin directory next to the page) and applies it. Nothing is fetched automatically, not even at load time: it's up to the user to explicitly click to resynchronize, and without it (or with the server down) the page keeps behaving fully standalone as today. Three states exist per line to make this work. The original state is the verdict the bot chose, captured at load time and constant. The reference state is the last known shared state, on top of which the user's edits sit; it starts equal to the original. The local state is the DOM itself (the checked radios). Applying a fetched overlay recomputes every line's reference as "the server's entry if any, otherwise the bot's verdict", so a removed override properly falls back to the original; the reference always advances but the displayed state only moves where the user had no local edit: local edits win, and re-applying the same overlay twice changes nothing. The received commit ids are resolved exactly first, then by symmetric prefix (one id being a prefix of the other, for mixed-length ids), first line wins. The shared notes land in a dedicated container below the AI explanation, rendered via innerText (no HTML injection) and replaced wholesale so the operation stays idempotent; entries for commits absent from the page are simply ignored. The whole exchange was tested with the real generated page's scripts running against a stubbed DOM covering load capture, prefix resolution, adopt-vs-keep on both changed and disappeared entries, idempotent re-application, and silent degradation on fetch failure.
611 lines
22 KiB
Bash
Executable file
611 lines
22 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
####
|
|
#### Todo:
|
|
#### - change line color based on the selected radio button
|
|
#### - support collapsing lines per color/category (show/hide for each)
|
|
#### - add category "next" and see if the prompt can handle that (eg: d3e379b3)
|
|
#### - produce multiple lists on output (per category) allowing to save batches
|
|
####
|
|
|
|
die() {
|
|
[ "$#" -eq 0 ] || echo "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
err() {
|
|
echo "$*" >&2
|
|
}
|
|
|
|
quit() {
|
|
[ "$#" -eq 0 ] || echo "$*"
|
|
exit 0
|
|
}
|
|
|
|
#### Main
|
|
|
|
USAGE="Usage: ${0##*/} [ -h ] [ -b 'bkp_list' ] [ -v version ] patch..."
|
|
MYSELF="$0"
|
|
GITURL="http://git.haproxy.org/?p=haproxy.git;a=commitdiff;h="
|
|
ISSUES="https://github.com/haproxy/haproxy/issues/"
|
|
BKP=""
|
|
VERSION=""
|
|
|
|
while [ -n "$1" -a -z "${1##-*}" ]; do
|
|
case "$1" in
|
|
-h|--help) quit "$USAGE" ;;
|
|
-b) BKP="$2"; shift 2 ;;
|
|
-v) VERSION="$2"; shift 2 ;;
|
|
*) die "$USAGE" ;;
|
|
esac
|
|
done
|
|
|
|
# VERSION is the branch this page covers (eg: 3.5). It is only used by the
|
|
# in-page JS to sync the review state with the server-side update.cgi, which
|
|
# strictly validates it, so let's check it here as well. When empty, the
|
|
# syncing UI is not emitted at all and the page keeps working standalone.
|
|
if [ -n "$VERSION" ] && ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+$ ]]; then
|
|
die "Invalid version '$VERSION', expected <digits>.<digits>"
|
|
fi
|
|
|
|
PATCHES=( "$@" )
|
|
|
|
if [ ${#PATCHES[@]} = 0 ]; then
|
|
die "$USAGE"
|
|
fi
|
|
|
|
# BKP is a space-delimited list of 8-char commit IDs, we'll
|
|
# assign them to the local bkp[] associative array.
|
|
|
|
declare -A bkp
|
|
|
|
for cid in $BKP; do
|
|
bkp[$cid]=1
|
|
done
|
|
|
|
# some colors
|
|
BG_B="#e0e0e0"
|
|
BT_N="gray"; BG_N="white"
|
|
BT_U="#00e000"; BG_U="#e0ffe0"
|
|
BT_W="#0060ff"; BG_W="#e0e0ff"
|
|
BT_Y="red"; BG_Y="#ffe0e0"
|
|
|
|
echo "<HTML>"
|
|
|
|
cat <<- EOF
|
|
<HEAD><style>
|
|
input.n[type="radio"] {
|
|
appearance: none;
|
|
width: 1.25em;
|
|
height: 1.25em;
|
|
border-radius: 50%;
|
|
border: 3px solid $BT_N;
|
|
background-color: transparent;
|
|
}
|
|
input.n[type="radio"]:checked {
|
|
appearance: none;
|
|
width: 1.25em;
|
|
height: 1.25em;
|
|
border-radius: 50%;
|
|
border: 2px solid black;
|
|
background-color: $BT_N;
|
|
}
|
|
|
|
input.u[type="radio"] {
|
|
appearance: none;
|
|
width: 1.25em;
|
|
height: 1.25em;
|
|
border-radius: 50%;
|
|
border: 3px solid $BT_U;
|
|
background-color: transparent;
|
|
}
|
|
input.u[type="radio"]:checked {
|
|
appearance: none;
|
|
width: 1.25em;
|
|
height: 1.25em;
|
|
border-radius: 50%;
|
|
border: 2px solid black;
|
|
background-color: $BT_U;
|
|
}
|
|
|
|
input.w[type="radio"] {
|
|
appearance: none;
|
|
width: 1.25em;
|
|
height: 1.25em;
|
|
border-radius: 50%;
|
|
border: 3px solid $BT_W;
|
|
background-color: transparent;
|
|
}
|
|
input.w[type="radio"]:checked {
|
|
appearance: none;
|
|
width: 1.25em;
|
|
height: 1.25em;
|
|
border-radius: 50%;
|
|
border: 2px solid black;
|
|
background-color: $BT_W;
|
|
}
|
|
|
|
input.y[type="radio"] {
|
|
appearance: none;
|
|
width: 1.25em;
|
|
height: 1.25em;
|
|
border-radius: 50%;
|
|
border: 3px solid $BT_Y;
|
|
background-color: transparent;
|
|
}
|
|
input.y[type="radio"]:checked {
|
|
appearance: none;
|
|
width: 1.25em;
|
|
height: 1.25em;
|
|
border-radius: 50%;
|
|
border: 2px solid black;
|
|
background-color: $BT_Y;
|
|
}
|
|
|
|
/* shared reviewers' notes, shown below the AI explanation */
|
|
div.notes {
|
|
font-style: italic;
|
|
margin-top: 2px;
|
|
}
|
|
</style>
|
|
|
|
<script type="text/javascript"><!--
|
|
|
|
var cgi_url = "cgi-bin/update.cgi";
|
|
var nb_patches = 0;
|
|
var cid = [];
|
|
var bkp = [];
|
|
|
|
// the branch this page covers (eg: "3.5"), used to sync the review state
|
|
// with the server-side update.cgi; empty when generated without -v, in
|
|
// which case no syncing is possible and the page works standalone.
|
|
var branch = '$VERSION';
|
|
|
|
// Three states exist per line. The original state (orig[]) is the verdict
|
|
// the bot chose, captured at load time and constant. The reference state
|
|
// (ref_state[]/ref_notes[]) is the last known shared state, i.e. what the
|
|
// server last told us, on top of which the user's edits sit; it starts
|
|
// equal to the original and is only advanced by "Get updates" and by a
|
|
// successful save. The local state is the DOM itself (the checked radios),
|
|
// there is no separate copy. Nothing is fetched automatically: the user
|
|
// explicitly clicks "Get updates" to retrieve the shared state.
|
|
var orig = [];
|
|
var ref_state = [];
|
|
var ref_notes = [];
|
|
var cidmap = {};
|
|
|
|
// returns the letter of the checked verdict radio of line <i>, or ""
|
|
function cur_state(i) {
|
|
if (document.getElementById("bt_" + i + "_n").checked) return "n";
|
|
if (document.getElementById("bt_" + i + "_u").checked) return "u";
|
|
if (document.getElementById("bt_" + i + "_w").checked) return "w";
|
|
if (document.getElementById("bt_" + i + "_y").checked) return "y";
|
|
return "";
|
|
}
|
|
|
|
// checks the verdict radio <s> of line <i> (authoritative set, idempotent)
|
|
function set_state(i, s) {
|
|
var el = document.getElementById("bt_" + i + "_" + s);
|
|
if (el)
|
|
el.checked = true;
|
|
}
|
|
|
|
// Returns the verdict letter emitted in the page for line <i>, i.e. the
|
|
// bot's verdict. It relies on defaultChecked, which reflects the "checked"
|
|
// attribute present in the HTML and not the radio's current state: across
|
|
// a reload, the browser restores the radios to the user's last local
|
|
// state, so looking at cur_state() at load time would wrongly capture the
|
|
// user's own edits as being the original state.
|
|
function gen_state(i) {
|
|
if (document.getElementById("bt_" + i + "_n").defaultChecked) return "n";
|
|
if (document.getElementById("bt_" + i + "_u").defaultChecked) return "u";
|
|
if (document.getElementById("bt_" + i + "_w").defaultChecked) return "w";
|
|
if (document.getElementById("bt_" + i + "_y").defaultChecked) return "y";
|
|
return "";
|
|
}
|
|
|
|
// captures the bot's verdicts once the table is fully loaded: they preset
|
|
// both the original and the reference states. After a reload, the radios
|
|
// (and thus the local state) may differ from the bot's verdicts since the
|
|
// browser restores them: this is desired, such differences are unsaved
|
|
// local edits and must remain detected as such.
|
|
function init_ref() {
|
|
var i;
|
|
|
|
for (i = 1; i < nb_patches; i++) {
|
|
orig[i] = gen_state(i);
|
|
ref_state[i] = orig[i];
|
|
ref_notes[i] = "";
|
|
cidmap[cid[i]] = i;
|
|
}
|
|
}
|
|
|
|
function sync_msg(m) {
|
|
var el = document.getElementById("sync_msg");
|
|
if (el)
|
|
el.innerText = m;
|
|
}
|
|
|
|
// renders the reference notes of line <i> by replacing the whole container
|
|
// (never appending), so that re-applying the same notes is idempotent.
|
|
function show_notes(i) {
|
|
var el = document.getElementById("notes_" + i);
|
|
if (el)
|
|
el.innerText = ref_notes[i] ? "Notes: " + ref_notes[i] : "";
|
|
}
|
|
|
|
// resolves a commit id received from the server to a line number: exact
|
|
// match first (the normal case), then symmetric-prefix (one id is a prefix
|
|
// of the other, which only happens with mixed-length ids), first line wins.
|
|
// Returns 0 when unknown (eg: a commit which is not on this page).
|
|
function find_line(ocid) {
|
|
var i;
|
|
|
|
if (cidmap[ocid])
|
|
return cidmap[ocid];
|
|
for (i = 1; i < nb_patches; i++)
|
|
if (cid[i].startsWith(ocid) || ocid.startsWith(cid[i]))
|
|
return i;
|
|
return 0;
|
|
}
|
|
|
|
// Applies a freshly fetched overlay (the complete list of shared entries).
|
|
// The new reference of every line is recomputed as "the server's entry if
|
|
// any, otherwise the bot's original verdict", so that an entry removed on
|
|
// the server properly falls back to the original. The reference always
|
|
// advances, but the displayed state only moves where the user had no local
|
|
// edit: local edits win and will overwrite the shared state at save time.
|
|
function apply_ref(list) {
|
|
var over_state = [], over_notes = [], claimed = [];
|
|
var i, j, e, newref, newnotes;
|
|
|
|
for (j = 0; j < list.length; j++) {
|
|
e = list[j];
|
|
i = find_line(String(e.cid));
|
|
if (!i || claimed[i])
|
|
continue;
|
|
claimed[i] = 1;
|
|
if (e.state)
|
|
over_state[i] = String(e.state);
|
|
if (e.notes)
|
|
over_notes[i] = String(e.notes);
|
|
}
|
|
|
|
for (i = 1; i < nb_patches; i++) {
|
|
newref = over_state[i] ? over_state[i] : orig[i];
|
|
if (newref != ref_state[i] && ref_state[i] == cur_state(i))
|
|
set_state(i, newref);
|
|
ref_state[i] = newref;
|
|
|
|
newnotes = over_notes[i] ? over_notes[i] : "";
|
|
if (newnotes != ref_notes[i]) {
|
|
ref_notes[i] = newnotes;
|
|
show_notes(i);
|
|
}
|
|
}
|
|
updt_table(0);
|
|
updt_output();
|
|
}
|
|
|
|
// "Get updates" button: fetches the current shared state from the server
|
|
function fetch_ref() {
|
|
if (!branch)
|
|
return;
|
|
sync_msg("fetching...");
|
|
fetch(cgi_url + "?branch=" + branch)
|
|
.then(function(r) { if (!r.ok) throw 0; return r.json(); })
|
|
.then(function(list) { apply_ref(list); sync_msg("reference updated"); })
|
|
.catch(function() { sync_msg("fetch failed (server unreachable?)"); });
|
|
}
|
|
|
|
// first line to review
|
|
var review = 0;
|
|
|
|
// show/hide table lines and update their color
|
|
function updt_table(line) {
|
|
var b = document.getElementById("sh_b").checked;
|
|
var n = document.getElementById("sh_n").checked;
|
|
var u = document.getElementById("sh_u").checked;
|
|
var w = document.getElementById("sh_w").checked;
|
|
var y = document.getElementById("sh_y").checked;
|
|
var tn = 0, tu = 0, tw = 0, ty = 0;
|
|
var bn = 0, bu = 0, bw = 0, by = 0;
|
|
var i, el;
|
|
|
|
for (i = 1; i < nb_patches; i++) {
|
|
if (document.getElementById("bt_" + i + "_n").checked) {
|
|
tn++;
|
|
if (bkp[i])
|
|
bn++;
|
|
if (line && i != line)
|
|
continue;
|
|
el = document.getElementById("tr_" + i);
|
|
el.style.backgroundColor = "$BG_N";
|
|
el.style.display = n && (b || !bkp[i]) && i >= review ? "" : "none";
|
|
}
|
|
else if (document.getElementById("bt_" + i + "_u").checked) {
|
|
tu++;
|
|
if (bkp[i])
|
|
bu++;
|
|
if (line && i != line)
|
|
continue;
|
|
el = document.getElementById("tr_" + i);
|
|
el.style.backgroundColor = "$BG_U";
|
|
el.style.display = u && (b || !bkp[i]) && i >= review ? "" : "none";
|
|
}
|
|
else if (document.getElementById("bt_" + i + "_w").checked) {
|
|
tw++;
|
|
if (bkp[i])
|
|
bw++;
|
|
if (line && i != line)
|
|
continue;
|
|
el = document.getElementById("tr_" + i);
|
|
el.style.backgroundColor = "$BG_W";
|
|
el.style.display = w && (b || !bkp[i]) && i >= review ? "" : "none";
|
|
}
|
|
else if (document.getElementById("bt_" + i + "_y").checked) {
|
|
ty++;
|
|
if (bkp[i])
|
|
by++;
|
|
if (line && i != line)
|
|
continue;
|
|
el = document.getElementById("tr_" + i);
|
|
el.style.backgroundColor = "$BG_Y";
|
|
el.style.display = y && (b || !bkp[i]) && i >= review ? "" : "none";
|
|
}
|
|
else {
|
|
// bug
|
|
if (line && i != line)
|
|
continue;
|
|
el = document.getElementById("tr_" + i);
|
|
el.style.backgroundColor = "red";
|
|
el.style.display = "";
|
|
}
|
|
}
|
|
document.getElementById("cnt_n").innerText = tn;
|
|
document.getElementById("cnt_u").innerText = tu;
|
|
document.getElementById("cnt_w").innerText = tw;
|
|
document.getElementById("cnt_y").innerText = ty;
|
|
|
|
document.getElementById("cnt_bn").innerText = bn;
|
|
document.getElementById("cnt_bu").innerText = bu;
|
|
document.getElementById("cnt_bw").innerText = bw;
|
|
document.getElementById("cnt_by").innerText = by;
|
|
document.getElementById("cnt_bt").innerText = bn + bu + bw + by;
|
|
|
|
document.getElementById("cnt_nbn").innerText = tn - bn;
|
|
document.getElementById("cnt_nbu").innerText = tu - bu;
|
|
document.getElementById("cnt_nbw").innerText = tw - bw;
|
|
document.getElementById("cnt_nby").innerText = ty - by;
|
|
document.getElementById("cnt_nbt").innerText = tn - bn + tu - bu + tw - bw + ty - by;
|
|
}
|
|
|
|
function updt_output() {
|
|
var b = document.getElementById("sh_b").checked;
|
|
var i, y = "", w = "", u = "", n = "";
|
|
|
|
for (i = 1; i < nb_patches; i++) {
|
|
if (i < review)
|
|
continue;
|
|
if (bkp[i])
|
|
continue;
|
|
if (document.getElementById("bt_" + i + "_y").checked)
|
|
y = y + " " + cid[i];
|
|
else if (document.getElementById("bt_" + i + "_w").checked)
|
|
w = w + " " + cid[i];
|
|
else if (document.getElementById("bt_" + i + "_u").checked)
|
|
u = u + " " + cid[i];
|
|
else if (document.getElementById("bt_" + i + "_n").checked)
|
|
n = n + " " + cid[i];
|
|
}
|
|
|
|
// update the textarea
|
|
document.getElementById("output").value =
|
|
"cid_y=(" + y + " )\n" +
|
|
"cid_w=(" + w + " )\n" +
|
|
"cid_u=(" + u + " )\n" +
|
|
"cid_n=(" + n + " )\n";
|
|
}
|
|
|
|
function updt(line,value) {
|
|
if (value == "r") {
|
|
review = line;
|
|
line = 0; // redraw everything
|
|
}
|
|
updt_table(line);
|
|
updt_output();
|
|
}
|
|
|
|
function show_only(b,n,u,w,y) {
|
|
document.getElementById("sh_b").checked = !!b;
|
|
document.getElementById("sh_n").checked = !!n;
|
|
document.getElementById("sh_u").checked = !!u;
|
|
document.getElementById("sh_w").checked = !!w;
|
|
document.getElementById("sh_y").checked = !!y;
|
|
document.getElementById("show_all").checked = true;
|
|
updt(0,"r");
|
|
}
|
|
|
|
// Resynchronizes the review variable with the checked review radio: across
|
|
// a reload, the browser restores the radios to the user's last selection
|
|
// (e.g. "All") while the variable is regenerated to the default first line
|
|
// to review, and the listing would not match the checked radio anymore.
|
|
function init_review() {
|
|
var i, el;
|
|
|
|
if (document.getElementById("show_all").checked) {
|
|
review = 0;
|
|
return;
|
|
}
|
|
for (i = 1; i <= nb_patches; i++) {
|
|
el = document.getElementById("rv_" + i);
|
|
if (el && el.checked) {
|
|
review = i;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// -->
|
|
</script>
|
|
</HEAD>
|
|
EOF
|
|
|
|
echo "<BODY>"
|
|
|
|
# the syncing UI is only emitted when the branch is known; the page reaches
|
|
# update.cgi with a bare relative URL so it must sit in the same directory.
|
|
if [ -n "$VERSION" ]; then
|
|
echo -n "<div style='float: right; text-align: right;'>"
|
|
echo -n "<button onclick='fetch_ref();' title='Retrieve the latest shared review state'>Get updates</button>"
|
|
echo "<br/><small id='sync_msg'></small></div>"
|
|
fi
|
|
|
|
echo -n "<table cellpadding=3 cellspacing=5 style='font-size: 150%;'><tr><th align=left>Backported</th>"
|
|
echo -n "<td style='background-color:$BG_N'><a href='#' onclick='show_only(1,1,0,0,0);'> N: <span id='cnt_bn'>0</span> </a></td>"
|
|
echo -n "<td style='background-color:$BG_U'><a href='#' onclick='show_only(1,0,1,0,0);'> U: <span id='cnt_bu'>0</span> </a></td>"
|
|
echo -n "<td style='background-color:$BG_W'><a href='#' onclick='show_only(1,0,0,1,0);'> W: <span id='cnt_bw'>0</span> </a></td>"
|
|
echo -n "<td style='background-color:$BG_Y'><a href='#' onclick='show_only(1,0,0,0,1);'> Y: <span id='cnt_by'>0</span> </a></td>"
|
|
echo -n "<td>total: <span id='cnt_bt'>0</span></td>"
|
|
echo "</tr><tr>"
|
|
echo -n "<th align=left>Not backported</th>"
|
|
echo -n "<td style='background-color:$BG_N'><a href='#' onclick='show_only(0,1,0,0,0);'> N: <span id='cnt_nbn'>0</span> </a></td>"
|
|
echo -n "<td style='background-color:$BG_U'><a href='#' onclick='show_only(0,0,1,0,0);'> U: <span id='cnt_nbu'>0</span> </a></td>"
|
|
echo -n "<td style='background-color:$BG_W'><a href='#' onclick='show_only(0,0,0,1,0);'> W: <span id='cnt_nbw'>0</span> </a></td>"
|
|
echo -n "<td style='background-color:$BG_Y'><a href='#' onclick='show_only(0,0,0,0,1);'> Y: <span id='cnt_nby'>0</span> </a></td>"
|
|
echo -n "<td>total: <span id='cnt_nbt'>0</span></td>"
|
|
echo "</tr></table><P/>"
|
|
echo -n "<big><big>Show:"
|
|
echo -n " <span style='background-color:$BG_B'><input type='checkbox' onclick='updt_table(0);' id='sh_b' checked />B (${#bkp[*]})</span> "
|
|
echo -n " <span style='background-color:$BG_N'><input type='checkbox' onclick='updt_table(0);' id='sh_n' checked />N (<span id='cnt_n'>0</span>)</span> "
|
|
echo -n " <span style='background-color:$BG_U'><input type='checkbox' onclick='updt_table(0);' id='sh_u' checked />U (<span id='cnt_u'>0</span>)</span> "
|
|
echo -n " <span style='background-color:$BG_W'><input type='checkbox' onclick='updt_table(0);' id='sh_w' checked />W (<span id='cnt_w'>0</span>)</span> "
|
|
echo -n " <span style='background-color:$BG_Y'><input type='checkbox' onclick='updt_table(0);' id='sh_y' checked />Y (<span id='cnt_y'>0</span>)</span> "
|
|
echo -n "</big/></big><br/>(B=show backported, N=no/drop, U=uncertain, W=wait/next, Y=yes/pick"
|
|
echo ")<P/>"
|
|
|
|
echo "<TABLE COLS=5 BORDER=1 CELLSPACING=0 CELLPADDING=3>"
|
|
echo "<TR><TH>All<br/><input type='radio' name='review' id='show_all' onclick='updt(0,\"r\");' checked title='Start review here'/></TH><TH>CID</TH><TH>Subject</TH><TH>Verdict<BR>N U W Y</BR></TH><TH>Reason</TH></TR>"
|
|
seq_num=1; do_check=1; review=0;
|
|
for patch in "${PATCHES[@]}"; do
|
|
# try to retrieve the patch's numbering (0001-9999)
|
|
pnum="${patch##*/}"
|
|
pnum="${pnum%%[^0-9]*}"
|
|
|
|
id=$(sed -ne 's/^#id: \(.*\)/\1/p' "$patch")
|
|
resp=$(grep -v ^llama "$patch" | sed -ne '/^Explanation:/,$p' | sed -z 's/\n[\n]*/\n/g' | sed -z 's/\([^. ]\)\n\([A-Z]\)/\1.\n\2/' | tr '\012' ' ')
|
|
resp="${resp#Explanation:}";
|
|
while [ -n "$resp" -a -z "${resp##[ .]*}" ]; do
|
|
resp="${resp#[ .]}"
|
|
done
|
|
|
|
respl=$(echo -- "$resp" | tr 'A-Z' 'a-z')
|
|
|
|
if [[ "${respl}" =~ (conclusion|verdict)[:\ ][^.]*yes ]]; then
|
|
verdict=yes
|
|
elif [[ "${respl}" =~ (conclusion|verdict)[:\ ][^.]*wait ]]; then
|
|
verdict=wait
|
|
elif [[ "${respl}" =~ (conclusion|verdict)[:\ ][^.]*no ]]; then
|
|
verdict=no
|
|
elif [[ "${respl}" =~ (conclusion|verdict)[:\ ][^.]*uncertain ]]; then
|
|
verdict=uncertain
|
|
elif [[ "${respl}" =~ (\"wait\"|\"yes\"|\"no\"|\"uncertain\")[^\"]*$ ]]; then
|
|
# last word under quotes in the response, sometimes happens as
|
|
# in 'thus I would conclude "no"'.
|
|
verdict=${BASH_REMATCH[1]}
|
|
else
|
|
verdict=uncertain
|
|
fi
|
|
|
|
verdict="${verdict//[\"\',;:. ]}"
|
|
verdict=$(echo -n "$verdict" | tr '[A-Z]' '[a-z]')
|
|
|
|
# There are two formats for the ID line:
|
|
# - old: #id: cid subject
|
|
# - new: #id: cid author date subject
|
|
# We can detect the 2nd one as the date starts with a series of digits
|
|
# followed by "-" then an upper case letter (eg: "18-Dec23").
|
|
set -- $id
|
|
cid="$1"
|
|
author=""
|
|
date=""
|
|
if [ -n "$3" ] && [ -z "${3##[1-9]-[A-Z]*}" -o -z "${3##[0-3][0-9]-[A-Z]*}" ]; then
|
|
author="$2"
|
|
date="$3"
|
|
subj="${id#$cid $author $date }"
|
|
else
|
|
subj="${id#$cid }"
|
|
fi
|
|
|
|
if [ -z "$cid" ]; then
|
|
echo "ERROR: commit ID not found in patch $pnum: $patch" >&2
|
|
continue
|
|
fi
|
|
|
|
echo "<script type='text/javascript'>cid[$seq_num]='$cid'; bkp[$seq_num]=${bkp[$cid]:+1}+0;</script>"
|
|
|
|
echo -n "<TR id='tr_$seq_num' name='$cid'"
|
|
|
|
# highlight unqualified docs and bugs
|
|
if [ "$verdict" != "no" ]; then
|
|
: # no special treatment for accepted/uncertain elements
|
|
elif [ -z "${subj##BUG*}" ] && ! [[ "${respl}" =~ (explicitly|specifically|clearly|also|commit\ message|does)[\ ]*(state|mention|say|request) ]]; then
|
|
# bold for BUG marked "no" with no "explicitly states that ..."
|
|
echo -n " style='font-weight:bold'"
|
|
elif [ -z "${subj##DOC*}" ]; then # && ! [[ "${respl}" =~ (explicitly|specifically|clearly|also|commit\ message|does)[\ ]*(state|mention|say|request) ]]; then
|
|
# gray for DOC marked "no"
|
|
echo -n " style='font-weight:bold'"
|
|
#echo -n " bgcolor=#E0E0E0" #"$BG_U"
|
|
fi
|
|
|
|
echo -n ">"
|
|
|
|
# HTMLify subject and summary
|
|
subj="${subj//&/&}"; subj="${subj//</<}"; subj="${subj//>/>}";
|
|
resp="${resp//&/&}"; resp="${resp//</<}"; resp="${resp//>/>}";
|
|
|
|
# turn "#XXXX" to a link to an issue
|
|
resp=$(echo "$resp" | sed -e "s|#\([0-9]\{1,5\}\)|<a href='${ISSUES}\1'>#\1</a>|g")
|
|
|
|
# put links to commit IDs
|
|
resp=$(echo "$resp" | sed -e "s|\([0-9a-f]\{7,40\}\)|<a href='${GITURL}\1'>\1</a>|g")
|
|
|
|
echo -n "<TD nowrap align=center ${bkp[$cid]:+style='background-color:${BG_B}'}>$seq_num<BR/>"
|
|
echo -n "<input type='radio' name='review' id='rv_$seq_num' onclick='updt($seq_num,\"r\");' ${do_check:+checked} title='Start review here'/></TD>"
|
|
# only the first 8 chars of the commit id are displayed (enough to be
|
|
# unambiguous on one page); everything keyed (href, name=, cid[])
|
|
# carries the full id produced by the pipeline, whatever its length.
|
|
echo -n "<TD nowrap ${bkp[$cid]:+style='background-color:${BG_B}'}><tt><a href='${GITURL}${cid}'>${cid:0:8}</a></tt>${date:+<br/><small style='font-weight:normal'>$date</small>}</TD>"
|
|
echo -n "<TD nowrap><a href='${GITURL}${cid}'>${pnum:+$pnum }$subj</a>${author:+<br/><div align=right><small style='font-weight:normal'>$author</small></div>}</TD>"
|
|
echo -n "<TD nowrap align=center>"
|
|
echo -n "<input type='radio' onclick='updt($seq_num,\"n\");' id='bt_${seq_num}_n' class='n' name='$cid' value='n' title='Drop' $( [ "$verdict" != no ] || echo -n checked) />"
|
|
echo -n "<input type='radio' onclick='updt($seq_num,\"u\");' id='bt_${seq_num}_u' class='u' name='$cid' value='u' title='Uncertain' $( [ "$verdict" != uncertain ] || echo -n checked) />"
|
|
echo -n "<input type='radio' onclick='updt($seq_num,\"w\");' id='bt_${seq_num}_w' class='w' name='$cid' value='w' title='wait in -next' $([ "$verdict" != wait ] || echo -n checked) />"
|
|
echo -n "<input type='radio' onclick='updt($seq_num,\"y\");' id='bt_${seq_num}_y' class='y' name='$cid' value='y' title='Pick' $( [ "$verdict" != yes ] || echo -n checked) />"
|
|
echo -n "</TD>"
|
|
|
|
# the div is the dedicated container for the shared reviewers' notes,
|
|
# filled by full replacement (never appended to) by the JS
|
|
echo -n "<TD>$resp<div class='notes' id='notes_$seq_num'></div></TD>"
|
|
echo "</TR>"
|
|
echo
|
|
((seq_num++))
|
|
|
|
# if this patch was already backported, make the review start on the next
|
|
if [ -n "${bkp[$cid]}" ]; then
|
|
review=$seq_num
|
|
do_check=1
|
|
else
|
|
do_check=
|
|
fi
|
|
done
|
|
|
|
echo "<TR><TH>New<br/><input type='radio' name='review' id='rv_$seq_num' onclick='updt($seq_num,\"r\");' ${do_check:+checked} title='Nothing to backport'/></TH><TH>CID</TH><TH>Subject</TH><TH>Verdict<BR>N U W Y</BR></TH><TH>Reason</TH></TR>"
|
|
|
|
echo "</TABLE>"
|
|
echo "<P/>"
|
|
echo "<H3>Output:</H3>"
|
|
echo "<textarea cols=120 rows=10 id='output'></textarea>"
|
|
echo "<P/>"
|
|
echo "<script type='text/javascript'>nb_patches=$seq_num; review=$review; init_review(); init_ref(); updt_table(0); updt_output();</script>"
|
|
echo "</BODY></HTML>"
|