385 строки
9.8 KiB
JavaScript
385 строки
9.8 KiB
JavaScript
let options = {
|
|
beta1: {
|
|
value: null,
|
|
type: "option",
|
|
},
|
|
beta2: {
|
|
value: null,
|
|
type: "option",
|
|
},
|
|
product: {
|
|
value: null,
|
|
type: "option",
|
|
},
|
|
};
|
|
|
|
function getOption(name) {
|
|
return options[name].value;
|
|
}
|
|
|
|
function getOptionType(name) {
|
|
return options[name].type;
|
|
}
|
|
|
|
function setOption(name, value) {
|
|
return (options[name].value = value);
|
|
}
|
|
|
|
let onLoad = new Promise(function (resolve, reject) {
|
|
window.onload = resolve;
|
|
});
|
|
|
|
function dateToStr(date) {
|
|
let month = "" + (date.getMonth() + 1);
|
|
let day = "" + date.getDate();
|
|
let year = date.getFullYear();
|
|
|
|
if (month.length < 2) {
|
|
month = "0" + month;
|
|
}
|
|
|
|
if (day.length < 2) {
|
|
day = "0" + day;
|
|
}
|
|
|
|
return year + "-" + month + "-" + day;
|
|
}
|
|
|
|
function addDays(date, days) {
|
|
let result = new Date(date);
|
|
result.setDate(result.getDate() + days);
|
|
return result;
|
|
}
|
|
|
|
function getBaseVersion(version) {
|
|
return version.substring(0, version.indexOf(".0b"));
|
|
}
|
|
|
|
function getReleaseDate(version, build_id, release_history) {
|
|
if (build_id) {
|
|
// XXX: Assume release date is the build ID. Remove this
|
|
// hack when https://bugzilla.mozilla.org/show_bug.cgi?id=1192197 is fixed.
|
|
return new Date(
|
|
build_id.substring(0, 4) +
|
|
"-" +
|
|
build_id.substring(4, 6) +
|
|
"-" +
|
|
build_id.substring(6, 8)
|
|
);
|
|
}
|
|
|
|
if (!(version in release_history)) {
|
|
return new Date();
|
|
}
|
|
|
|
return new Date(release_history[version]);
|
|
}
|
|
|
|
function getComparison() {
|
|
if (!getOption("beta1") || !getOption("beta2")) {
|
|
return;
|
|
}
|
|
|
|
let version1 = getOption("beta1");
|
|
let version2 = getOption("beta2");
|
|
let build_id1 = "";
|
|
let build_id2 = "";
|
|
if (version1.includes(" - ")) {
|
|
let vals = version1.split(" - ");
|
|
version1 = vals[0];
|
|
build_id1 = vals[1];
|
|
}
|
|
if (version2.includes(" - ")) {
|
|
let vals = version2.split(" - ");
|
|
version2 = vals[0];
|
|
build_id2 = vals[1];
|
|
}
|
|
|
|
fetch(
|
|
"https://product-details.mozilla.org/1.0/firefox_history_development_releases.json"
|
|
)
|
|
.then((response) => response.json())
|
|
.then((release_history) => {
|
|
let date1 = dateToStr(
|
|
getReleaseDate(version1, build_id1, release_history)
|
|
);
|
|
let date2 = dateToStr(
|
|
getReleaseDate(version2, build_id2, release_history)
|
|
);
|
|
|
|
let url = new URL(location.href);
|
|
url.search =
|
|
"?product=" +
|
|
getOption("product") +
|
|
"&beta1=" +
|
|
getOption("beta1") +
|
|
"&beta2=" +
|
|
getOption("beta2");
|
|
history.replaceState({}, document.title, url.href);
|
|
|
|
let signatureNumberElem = document.getElementById("signatureNumber");
|
|
let signatureNumber = Number(signatureNumberElem.value);
|
|
if (!signatureNumber || isNaN(signatureNumber)) {
|
|
signatureNumber = 20;
|
|
}
|
|
|
|
document.getElementById("frame").src =
|
|
"scomp.html?limit=" +
|
|
signatureNumber +
|
|
"&common=product%3D" +
|
|
getOption("product") +
|
|
"&p1=version%3D" +
|
|
version1 +
|
|
(build_id1 ? "%26build_id=" + build_id1 : "") +
|
|
"%26date%3D%3E" +
|
|
date1 +
|
|
"&p2=version%3D" +
|
|
version2 +
|
|
(build_id2 ? "%26build_id=" + build_id2 : "") +
|
|
"%26date%3D%3E" +
|
|
date2;
|
|
|
|
let total1, total2;
|
|
Promise.all([
|
|
fetch(
|
|
"https://crash-stats.mozilla.org/api/SuperSearch/?product=" +
|
|
getOption("product") +
|
|
"&version=" +
|
|
version1 +
|
|
(build_id1 ? "&build_id=" + build_id1 : "") +
|
|
"&_results_number=0&_facets_size=0" +
|
|
"&date=>%3D" +
|
|
date1
|
|
)
|
|
.then((response) => response.json())
|
|
.then((results) => (total1 = results["total"] || 0)),
|
|
fetch(
|
|
"https://crash-stats.mozilla.org/api/SuperSearch/?product=" +
|
|
getOption("product") +
|
|
"&version=" +
|
|
version2 +
|
|
(build_id2 ? "&build_id=" + build_id2 : "") +
|
|
"&_results_number=0&_facets_size=0" +
|
|
"&date=>%3D" +
|
|
date2
|
|
)
|
|
.then((response) => response.json())
|
|
.then((results) => (total2 = results["total"] || 0)),
|
|
]).then(() => {
|
|
let warning = "";
|
|
if (total1 < total2 * 0.2) {
|
|
warning =
|
|
"WARNING: Number of crash reports for " +
|
|
getOption("beta1") +
|
|
" (" +
|
|
total1 +
|
|
") are way lower than for " +
|
|
getOption("beta2") +
|
|
" (" +
|
|
total2 +
|
|
"); the comparison might be skewed.";
|
|
} else if (total2 < total1 * 0.2) {
|
|
warning =
|
|
"WARNING: Number of crash reports for " +
|
|
getOption("beta2") +
|
|
" (" +
|
|
total2 +
|
|
") are way lower than for " +
|
|
getOption("beta1") +
|
|
" (" +
|
|
total1 +
|
|
"); the comparison might be skewed.";
|
|
}
|
|
document.getElementById("warning").textContent = warning;
|
|
});
|
|
});
|
|
}
|
|
|
|
function compareBuildIDs(build_id1, build_id2) {
|
|
let year1 = Number(build_id1.substring(0, 4));
|
|
let year2 = Number(build_id2.substring(0, 4));
|
|
if (year1 > year2) {
|
|
return 1;
|
|
} else if (year1 < year2) {
|
|
return -1;
|
|
}
|
|
|
|
let month1 = Number(build_id1.substring(4, 6));
|
|
let month2 = Number(build_id2.substring(4, 6));
|
|
if (month1 > month2) {
|
|
return 1;
|
|
} else if (month1 < month2) {
|
|
return -1;
|
|
}
|
|
|
|
let day1 = Number(build_id1.substring(6, 8));
|
|
let day2 = Number(build_id2.substring(6, 8));
|
|
if (day1 > day2) {
|
|
return 1;
|
|
} else if (day1 < day2) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
function compareVersions(versionA, versionB) {
|
|
let majorA = Number(versionA.substring(0, versionA.indexOf(".")));
|
|
let majorB = Number(versionB.substring(0, versionB.indexOf(".")));
|
|
|
|
if (majorA > majorB) {
|
|
return 1;
|
|
} else if (majorA < majorB) {
|
|
return -1;
|
|
}
|
|
|
|
let minorA;
|
|
let minorB;
|
|
if (!versionA.includes(" - ")) {
|
|
minorA = Number(versionA.substring(versionA.indexOf("b") + 1));
|
|
} else {
|
|
minorA = Number(
|
|
versionA.substring(versionA.indexOf("b") + 1, versionA.indexOf(" "))
|
|
);
|
|
}
|
|
if (!versionB.includes(" - ")) {
|
|
minorB = Number(versionB.substring(versionB.indexOf("b") + 1));
|
|
} else {
|
|
minorB = Number(
|
|
versionB.substring(versionB.indexOf("b") + 1, versionB.indexOf(" "))
|
|
);
|
|
}
|
|
|
|
if (minorA > minorB) {
|
|
return 1;
|
|
} else if (minorA < minorB) {
|
|
return -1;
|
|
}
|
|
|
|
let buildIDA = versionA.substring(versionA.indexOf(" - ") + 3);
|
|
let buildIDB = versionB.substring(versionB.indexOf(" - ") + 3);
|
|
|
|
return compareBuildIDs(buildIDA, buildIDB);
|
|
}
|
|
|
|
onLoad
|
|
.then(() =>
|
|
fetch(
|
|
"https://product-details.mozilla.org/1.0/firefox_history_development_releases.json"
|
|
)
|
|
)
|
|
.then((response) => response.json())
|
|
.then((data) => {
|
|
let versions = Object.keys(data);
|
|
|
|
let rc = versions.find((version) => version.endsWith("b99"));
|
|
if (rc) {
|
|
return fetch(
|
|
"https://crash-stats.mozilla.org/api/SuperSearch/?version=" +
|
|
rc +
|
|
"&product=Firefox&_facets=build_id&_results_number=0"
|
|
)
|
|
.then((response) => response.json())
|
|
.then((data) => {
|
|
return data["facets"]["build_id"]
|
|
.map((elem) => rc + " - " + elem["term"])
|
|
.concat(versions.filter((version) => !version.endsWith("b99")));
|
|
});
|
|
} else {
|
|
return versions;
|
|
}
|
|
})
|
|
.then((versions) => {
|
|
return versions.sort(compareVersions);
|
|
})
|
|
.then((versions) => {
|
|
// Only consider the latest 10 builds.
|
|
if (versions.length > 10) {
|
|
versions = versions.slice(versions.length - 10);
|
|
}
|
|
|
|
return versions;
|
|
})
|
|
.then((versions) => {
|
|
let betas1 = document.getElementById("beta1");
|
|
let betas2 = document.getElementById("beta2");
|
|
|
|
for (let i = 0; i < versions.length; i++) {
|
|
let version = versions[i];
|
|
|
|
var opt = document.createElement("option");
|
|
opt.value = opt.textContent = version;
|
|
|
|
if (i != versions.length - 1) {
|
|
betas1.appendChild(opt);
|
|
}
|
|
|
|
if (i != 0) {
|
|
betas2.appendChild(opt.cloneNode(true));
|
|
}
|
|
}
|
|
|
|
betas1.selectedIndex = betas1.options.length - 1;
|
|
betas2.selectedIndex = betas2.options.length - 1;
|
|
})
|
|
.then(function () {
|
|
let queryVars = new URL(location.href).search.substring(1).split("&");
|
|
|
|
Object.keys(options).forEach(function (optionName) {
|
|
let optionType = getOptionType(optionName);
|
|
let elem = document.getElementById(optionName);
|
|
|
|
for (let queryVar of queryVars) {
|
|
if (queryVar.startsWith(optionName + "=")) {
|
|
let option = queryVar.substring((optionName + "=").length).trim();
|
|
setOption(optionName, option);
|
|
}
|
|
}
|
|
|
|
if (optionType === "select") {
|
|
if (getOption(optionName)) {
|
|
elem.checked = getOption(optionName);
|
|
}
|
|
|
|
setOption(optionName, elem.checked);
|
|
} else if (optionType === "option") {
|
|
if (getOption(optionName)) {
|
|
for (let i = 0; i < elem.options.length; i++) {
|
|
if (
|
|
elem.options[i].value ===
|
|
decodeURIComponent(getOption(optionName))
|
|
) {
|
|
elem.selectedIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
setOption(optionName, elem.options[elem.selectedIndex].value);
|
|
|
|
elem.onchange = function () {
|
|
setOption(optionName, elem.options[elem.selectedIndex].value);
|
|
};
|
|
} else if (optionType === "button") {
|
|
if (getOption(optionName)) {
|
|
elem.value = getOption(optionName);
|
|
}
|
|
|
|
setOption(optionName, elem.value.trim());
|
|
} else {
|
|
throw new Error("Unexpected option type.");
|
|
}
|
|
|
|
document.getElementById("compareButton").onclick = function () {
|
|
getComparison();
|
|
};
|
|
});
|
|
|
|
if (queryVars.length >= 2) {
|
|
getComparison();
|
|
}
|
|
})
|
|
.catch(function (err) {
|
|
console.error(err);
|
|
});
|