зеркало из https://github.com/mozilla/bugbug.git
Import changes UI (#1940)
This commit is contained in:
Родитель
a670b89e47
Коммит
be258faf40
|
@ -44,8 +44,9 @@ share/python-wheels/
|
|||
*.egg
|
||||
MANIFEST
|
||||
cache/
|
||||
node_modules/
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
# Desktop Service Store
|
||||
*.DS_Store
|
||||
*.DS_Store
|
||||
|
|
|
@ -208,12 +208,41 @@ tasks:
|
|||
owner: mcastelluccio@mozilla.com
|
||||
source: ${repository}/raw/${head_rev}/.taskcluster.yml
|
||||
|
||||
- taskId: {$eval: as_slugid("frontend_build")}
|
||||
created: {$fromNow: ''}
|
||||
deadline: {$fromNow: '1 hour'}
|
||||
provisionerId: proj-bugbug
|
||||
workerType: batch
|
||||
payload:
|
||||
maxRunTime: 3600
|
||||
image: node
|
||||
command:
|
||||
- "/bin/sh"
|
||||
- "-lcxe"
|
||||
- "git clone --quiet ${repository} /bugbug &&
|
||||
cd /bugbug &&
|
||||
git -c advice.detachedHead=false checkout ${head_rev} &&
|
||||
cd ui/changes &&
|
||||
npm install --no-progress &&
|
||||
npm run release"
|
||||
artifacts:
|
||||
public/frontend:
|
||||
expires: {$fromNow: '2 weeks'}
|
||||
path: /bugbug/ui/changes/dist
|
||||
type: directory
|
||||
metadata:
|
||||
name: bugbug ui build
|
||||
description: bugbug ui build
|
||||
owner: mcastelluccio@mozilla.com
|
||||
source: ${repository}/raw/${head_rev}/.taskcluster.yml
|
||||
|
||||
- $if: 'tasks_for == "github-push" && head_branch[:10] == "refs/tags/"'
|
||||
then:
|
||||
dependencies:
|
||||
- {$eval: as_slugid("lint_task")}
|
||||
- {$eval: as_slugid("tests_task")}
|
||||
- {$eval: as_slugid("http_tests_task")}
|
||||
- {$eval: as_slugid("frontend_build")}
|
||||
- {$eval: as_slugid("packaging_test_task")}
|
||||
- {$eval: as_slugid("version_check_task")}
|
||||
- {$eval: as_slugid("integration_test")}
|
||||
|
@ -250,6 +279,7 @@ tasks:
|
|||
- {$eval: as_slugid("version_check_task")}
|
||||
- {$eval: as_slugid("tests_task")}
|
||||
- {$eval: as_slugid("http_tests_task")}
|
||||
- {$eval: as_slugid("frontend_build")}
|
||||
- {$eval: as_slugid("packaging_test_task")}
|
||||
scopes:
|
||||
- secrets:get:project/bugbug/deploy
|
||||
|
|
|
@ -1,40 +1,71 @@
|
|||
version: 1
|
||||
tasks:
|
||||
- ID: landings-risk-report-generator
|
||||
created: {$fromNow: ''}
|
||||
deadline: {$fromNow: '2 hours'}
|
||||
expires: {$fromNow: '2 weeks'}
|
||||
provisionerId: proj-bugbug
|
||||
workerType: compute-small
|
||||
payload:
|
||||
features:
|
||||
taskclusterProxy:
|
||||
true
|
||||
maxRunTime: 7200
|
||||
image: mozilla/bugbug-commit-retrieval
|
||||
env:
|
||||
TC_SECRET_ID: project/bugbug/production
|
||||
command:
|
||||
- bugbug-generate-landings-risk-report
|
||||
- /cache/mozilla-central
|
||||
- --days=365
|
||||
- --meta-bugs
|
||||
$let:
|
||||
repository: https://github.com/mozilla/bugbug
|
||||
in:
|
||||
- ID: landings-risk-report-generator
|
||||
created: {$fromNow: ''}
|
||||
deadline: {$fromNow: '2 hours'}
|
||||
expires: {$fromNow: '2 weeks'}
|
||||
provisionerId: proj-bugbug
|
||||
workerType: compute-small
|
||||
payload:
|
||||
features:
|
||||
taskclusterProxy:
|
||||
true
|
||||
maxRunTime: 7200
|
||||
image: mozilla/bugbug-commit-retrieval
|
||||
env:
|
||||
TC_SECRET_ID: project/bugbug/production
|
||||
command:
|
||||
- bugbug-generate-landings-risk-report
|
||||
- /cache/mozilla-central
|
||||
- --days=365
|
||||
- --meta-bugs
|
||||
|
||||
artifacts:
|
||||
public/landings_by_date.json:
|
||||
path: /landings_by_date.json
|
||||
type: file
|
||||
public/component_connections.json:
|
||||
path: /component_connections.json
|
||||
type: file
|
||||
cache:
|
||||
bugbug-mercurial-repository: /cache
|
||||
routes:
|
||||
- notify.email.release-mgmt-analysis@mozilla.com.on-failed
|
||||
- notify.irc-channel.#bugbug.on-failed
|
||||
- index.project.bugbug.landings_risk_report.latest
|
||||
metadata:
|
||||
name: BugBug landings risk report
|
||||
description: BugBug landings risk report
|
||||
owner: release-mgmt-analysis@mozilla.com
|
||||
source: https://github.com/mozilla/bugbug/raw/master/infra/landings-pipeline.yml
|
||||
artifacts:
|
||||
public/landings_by_date.json:
|
||||
path: /landings_by_date.json
|
||||
type: file
|
||||
public/component_connections.json:
|
||||
path: /component_connections.json
|
||||
type: file
|
||||
cache:
|
||||
bugbug-mercurial-repository: /cache
|
||||
routes:
|
||||
- notify.email.release-mgmt-analysis@mozilla.com.on-failed
|
||||
- notify.irc-channel.#bugbug.on-failed
|
||||
- index.project.bugbug.landings_risk_report.latest
|
||||
metadata:
|
||||
name: BugBug landings risk report
|
||||
description: BugBug landings risk report
|
||||
owner: release-mgmt-analysis@mozilla.com
|
||||
source: https://github.com/mozilla/bugbug/raw/${version}/infra/landings-pipeline.yml
|
||||
|
||||
- ID: frontend-build
|
||||
created: {$fromNow: ''}
|
||||
deadline: {$fromNow: '1 hour'}
|
||||
expires: {$fromNow: '2 weeks'}
|
||||
provisionerId: proj-bugbug
|
||||
workerType: batch
|
||||
payload:
|
||||
maxRunTime: 3600
|
||||
image: node
|
||||
command:
|
||||
- "/bin/sh"
|
||||
- "-lcxe"
|
||||
- "git clone --quiet ${repository} /bugbug &&
|
||||
cd /bugbug &&
|
||||
git -c advice.detachedHead=false checkout ${version} &&
|
||||
cd ui/changes &&
|
||||
npm install --no-progress &&
|
||||
npm run release"
|
||||
artifacts:
|
||||
public/frontend:
|
||||
path: /bugbug/ui/changes/dist
|
||||
type: directory
|
||||
metadata:
|
||||
name: bugbug ui build
|
||||
description: bugbug ui build
|
||||
owner: mcastelluccio@mozilla.com
|
||||
source: https://github.com/mozilla/bugbug/raw/${version}/infra/landings-pipeline.yml
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
env:
|
||||
browser: true
|
||||
es6: true
|
||||
plugins:
|
||||
- prettier
|
||||
- mozilla
|
||||
extends:
|
||||
- standard
|
||||
- prettier
|
||||
- plugin:mozilla/recommended
|
||||
parserOptions:
|
||||
ecmaVersion: 2018
|
||||
sourceType: module
|
||||
rules:
|
||||
max-len: off
|
||||
prettier/prettier: "error"
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "changes",
|
||||
"version": "1.0.0",
|
||||
"description": "To update Temporal polyfill:",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "webpack --config webpack.dev.js",
|
||||
"release": "webpack --config webpack.prod.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^6.3.2",
|
||||
"css-minimizer-webpack-plugin": "^1.1.5",
|
||||
"eslint-config-standard": "^16.0.2",
|
||||
"eslint-plugin-mozilla": "^2.9.1",
|
||||
"eslint-webpack-plugin": "^2.4.0",
|
||||
"html-webpack-plugin": "^4.5.0",
|
||||
"prettier": "^1.19.1",
|
||||
"webpack": "^5.6.0",
|
||||
"webpack-cli": "^4.2.0",
|
||||
"webpack-merge": "^5.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"apexcharts": "^3.6.12",
|
||||
"localforage": "^1.9.0",
|
||||
"proposal-temporal": "^0.6.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
import { Temporal } from "proposal-temporal/lib/index.mjs";
|
||||
import localForage from "localforage";
|
||||
|
||||
// let METABUGS_URL =
|
||||
// "https://bugzilla.mozilla.org/rest/bug?include_fields=id,summary,status&keywords=feature-testing-meta%2C%20&keywords_type=allwords";
|
||||
let LANDINGS_URL =
|
||||
"https://community-tc.services.mozilla.com/api/index/v1/task/project.bugbug.landings_risk_report.latest/artifacts/public/landings_by_date.json";
|
||||
|
||||
function getCSSVariableValue(name) {
|
||||
return getComputedStyle(document.documentElement)
|
||||
.getPropertyValue(name)
|
||||
.trim();
|
||||
}
|
||||
|
||||
const EXPIRE_CACHE = (() => {
|
||||
localForage.config({
|
||||
driver: localForage.INDEXEDDB,
|
||||
});
|
||||
return {
|
||||
get: async (key) => {
|
||||
let data;
|
||||
try {
|
||||
data = await localForage.getItem(key);
|
||||
} catch (e) {}
|
||||
|
||||
if (!data) return data;
|
||||
|
||||
const { expire, value } = data;
|
||||
|
||||
if (expire < Date.now()) {
|
||||
localForage.removeItem(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
set: (key, value, expire = false, callback = false) => {
|
||||
if (expire && typeof expire === "number")
|
||||
expire = Math.round(expire * 1000 + Date.now()); // * 1000 to use seconds
|
||||
|
||||
return localForage.setItem(key, { value, expire }, expire && callback);
|
||||
},
|
||||
};
|
||||
})();
|
||||
export const TESTING_TAGS = {
|
||||
"testing-approved": {
|
||||
color: getCSSVariableValue("--green-60"),
|
||||
label: "approved",
|
||||
},
|
||||
"testing-exception-unchanged": {
|
||||
color: getCSSVariableValue("--teal-60"),
|
||||
label: "unchanged",
|
||||
},
|
||||
"testing-exception-elsewhere": {
|
||||
color: getCSSVariableValue("--blue-50"),
|
||||
label: "elsewhere",
|
||||
},
|
||||
"testing-exception-ui": {
|
||||
color: getCSSVariableValue("--purple-50"),
|
||||
label: "ui",
|
||||
},
|
||||
"testing-exception-other": {
|
||||
color: getCSSVariableValue("--yellow-50"),
|
||||
label: "other",
|
||||
},
|
||||
none: {
|
||||
color: getCSSVariableValue("--red-60"),
|
||||
label: "missing",
|
||||
},
|
||||
unknown: {
|
||||
color: getCSSVariableValue("--grey-30"),
|
||||
label: "unknown",
|
||||
}
|
||||
};
|
||||
|
||||
let taskclusterLandingsArtifact = (async function () {
|
||||
let json = await EXPIRE_CACHE.get("taskclusterLandingsArtifact");
|
||||
if (!json) {
|
||||
let response = await fetch(LANDINGS_URL);
|
||||
json = await response.json();
|
||||
// 30 minutes
|
||||
EXPIRE_CACHE.set("taskclusterLandingsArtifact", json, 60 * 30);
|
||||
} else {
|
||||
console.log("cache hit", json);
|
||||
}
|
||||
|
||||
return json;
|
||||
})();
|
||||
|
||||
export let featureMetabugs = (async function () {
|
||||
let json = await taskclusterLandingsArtifact;
|
||||
return json.featureMetaBugs;
|
||||
})();
|
||||
|
||||
export let landingsData = (async function () {
|
||||
let json = await taskclusterLandingsArtifact;
|
||||
json = json.landings;
|
||||
|
||||
// Sort the dates so object iteration will be sequential:
|
||||
let orderedDates = [];
|
||||
for (let date in json) {
|
||||
orderedDates.push(date);
|
||||
}
|
||||
orderedDates.sort((a, b) => {
|
||||
return Temporal.PlainDate.compare(
|
||||
Temporal.PlainDate.from(a),
|
||||
Temporal.PlainDate.from(b)
|
||||
);
|
||||
});
|
||||
|
||||
let returnedObject = {};
|
||||
for (let date of orderedDates) {
|
||||
returnedObject[date] = json[date];
|
||||
}
|
||||
|
||||
document.body.classList.remove("loading-data");
|
||||
|
||||
return returnedObject;
|
||||
})();
|
||||
|
||||
export function getNewTestingTagCountObject() {
|
||||
let obj = {};
|
||||
for (let tag in TESTING_TAGS) {
|
||||
obj[tag] = 0;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
export async function getTestingPolicySummaryData(grouping = "daily", filter) {
|
||||
let data = await landingsData;
|
||||
|
||||
// console.log(data);
|
||||
// let startDate = grouping == "daily" ? "2020-09-15" : "2020-08-16";
|
||||
let startDate = "2020-09-01";
|
||||
let dailyData = {};
|
||||
for (let date in data) {
|
||||
// Ignore data before the testing policy took place.
|
||||
if (
|
||||
Temporal.PlainDate.compare(
|
||||
Temporal.PlainDate.from(date),
|
||||
Temporal.PlainDate.from(startDate)
|
||||
) < 1
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let returnedDataForDate = getNewTestingTagCountObject();
|
||||
|
||||
let originalData = data[date];
|
||||
for (let bug of originalData) {
|
||||
if (filter && !filter(bug)) {
|
||||
continue;
|
||||
}
|
||||
for (let commit of bug.commits) {
|
||||
if (!commit.testing ) {
|
||||
returnedDataForDate.unknown++;
|
||||
} else {
|
||||
returnedDataForDate[commit.testing] =
|
||||
returnedDataForDate[commit.testing] + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dailyData[date] = returnedDataForDate;
|
||||
}
|
||||
|
||||
console.log(dailyData);
|
||||
|
||||
if (grouping == "weekly") {
|
||||
let weeklyData = {};
|
||||
for (let daily in dailyData) {
|
||||
let date = Temporal.PlainDate.from(daily);
|
||||
let weekStart = date.minus({ days: date.dayOfWeek }).toString();
|
||||
|
||||
if (!weeklyData[weekStart]) {
|
||||
weeklyData[weekStart] = getNewTestingTagCountObject();
|
||||
}
|
||||
|
||||
for (let tag in dailyData[daily]) {
|
||||
weeklyData[weekStart][tag] += dailyData[daily][tag];
|
||||
}
|
||||
}
|
||||
|
||||
return weeklyData;
|
||||
} else if (grouping == "monthly") {
|
||||
let monthlyData = {};
|
||||
for (let daily in dailyData) {
|
||||
let date = Temporal.PlainDate.from(daily);
|
||||
let yearMonth = date.toYearMonth();
|
||||
|
||||
if (!monthlyData[yearMonth]) {
|
||||
monthlyData[yearMonth] = getNewTestingTagCountObject();
|
||||
}
|
||||
|
||||
for (let tag in dailyData[daily]) {
|
||||
monthlyData[yearMonth][tag] += dailyData[daily][tag];
|
||||
}
|
||||
}
|
||||
return monthlyData;
|
||||
}
|
||||
|
||||
return dailyData;
|
||||
}
|
|
@ -0,0 +1,342 @@
|
|||
|
||||
|
||||
/* Photon Colors CSS Variables v3.3.2:
|
||||
https://github.com/FirefoxUX/photon-colors/blob/master/photon-colors.css */
|
||||
html {
|
||||
--magenta-50: #ff1ad9;
|
||||
--magenta-60: #ed00b5;
|
||||
--magenta-70: #b5007f;
|
||||
--magenta-80: #7d004f;
|
||||
--magenta-90: #440027;
|
||||
|
||||
--purple-30: #c069ff;
|
||||
--purple-40: #ad3bff;
|
||||
--purple-50: #9400ff;
|
||||
--purple-60: #8000d7;
|
||||
--purple-70: #6200a4;
|
||||
--purple-80: #440071;
|
||||
--purple-90: #25003e;
|
||||
|
||||
--blue-40: #45a1ff;
|
||||
--blue-50: #0a84ff;
|
||||
--blue-50-a30: rgba(10, 132, 255, 0.3);
|
||||
--blue-60: #0060df;
|
||||
--blue-70: #003eaa;
|
||||
--blue-80: #002275;
|
||||
--blue-90: #000f40;
|
||||
|
||||
--teal-50: #00feff;
|
||||
--teal-60: #00c8d7;
|
||||
--teal-70: #008ea4;
|
||||
--teal-80: #005a71;
|
||||
--teal-90: #002d3e;
|
||||
|
||||
--green-50: #30e60b;
|
||||
--green-60: #12bc00;
|
||||
--green-70: #058b00;
|
||||
--green-80: #006504;
|
||||
--green-90: #003706;
|
||||
|
||||
--yellow-50: #ffe900;
|
||||
--yellow-60: #d7b600;
|
||||
--yellow-60-a30: rgba(215, 182, 0, 0.3);
|
||||
--yellow-70: #a47f00;
|
||||
--yellow-80: #715100;
|
||||
--yellow-90: #3e2800;
|
||||
|
||||
--red-50: #ff0039;
|
||||
--red-60: #d70022;
|
||||
--red-60-a30: rgba(215, 0, 34, 0.3);
|
||||
--red-70: #a4000f;
|
||||
--red-80: #5a0002;
|
||||
--red-90: #3e0200;
|
||||
|
||||
--orange-50: #ff9400;
|
||||
--orange-60: #d76e00;
|
||||
--orange-70: #a44900;
|
||||
--orange-80: #712b00;
|
||||
--orange-90: #3e1300;
|
||||
|
||||
--grey-10: #f9f9fa;
|
||||
--grey-10-a10: rgba(249, 249, 250, 0.1);
|
||||
--grey-10-a20: rgba(249, 249, 250, 0.2);
|
||||
--grey-10-a40: rgba(249, 249, 250, 0.4);
|
||||
--grey-10-a60: rgba(249, 249, 250, 0.6);
|
||||
--grey-10-a80: rgba(249, 249, 250, 0.8);
|
||||
--grey-20: #ededf0;
|
||||
--grey-30: #d7d7db;
|
||||
--grey-40: #b1b1b3;
|
||||
--grey-50: #737373;
|
||||
--grey-60: #4a4a4f;
|
||||
--grey-70: #38383d;
|
||||
--grey-80: #2a2a2e;
|
||||
--grey-90: #0c0c0d;
|
||||
--grey-90-a05: rgba(12, 12, 13, 0.05);
|
||||
--grey-90-a10: rgba(12, 12, 13, 0.1);
|
||||
--grey-90-a20: rgba(12, 12, 13, 0.2);
|
||||
--grey-90-a30: rgba(12, 12, 13, 0.3);
|
||||
--grey-90-a40: rgba(12, 12, 13, 0.4);
|
||||
--grey-90-a50: rgba(12, 12, 13, 0.5);
|
||||
--grey-90-a60: rgba(12, 12, 13, 0.6);
|
||||
--grey-90-a70: rgba(12, 12, 13, 0.7);
|
||||
--grey-90-a80: rgba(12, 12, 13, 0.8);
|
||||
--grey-90-a90: rgba(12, 12, 13, 0.9);
|
||||
|
||||
--ink-40: #7175A8;
|
||||
--ink-50: #595E91;
|
||||
--ink-60: #464B76;
|
||||
--ink-70: #363959;
|
||||
--ink-80: #202340;
|
||||
--ink-90: #0f1126;
|
||||
}
|
||||
|
||||
html {
|
||||
--main-background: white;
|
||||
--main-text-color: var(--ink-90);
|
||||
--main-font-family: 'Fira Sans', 'Open Sans', sans-serif, Arial;
|
||||
--main-font: 400 14px/1.5 var(--main-font-family);
|
||||
|
||||
--mono-font-family: 'Fira Mono', monospace;
|
||||
--mono-font: 400 14px/1.5 var(--mono-font-family);
|
||||
|
||||
--heading-color: var(--ink-70);
|
||||
--heading-background: var(--grey-20);
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: 'Fira Sans', 'Open Sans', sans-serif, Arial;
|
||||
font: 400 14px/1.5 "Fira Sans";
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--main-background);
|
||||
color: var(--main-text-color);
|
||||
font: var(--main-font);
|
||||
}
|
||||
|
||||
hr {
|
||||
color: rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 300;
|
||||
color: var(--heading-color);
|
||||
background: var(--heading-background);
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.iframe-container {
|
||||
width: 50%;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.iframe-container > div {
|
||||
height: 0;
|
||||
padding-bottom: 50%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.iframe-container > div > iframe {
|
||||
border: none;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.summary-box {
|
||||
width: 95%;
|
||||
margin: 0 auto;
|
||||
padding-left: 33px;
|
||||
padding-right: 17px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.summary-box h2 {
|
||||
text-align: center;
|
||||
border-bottom: solid 1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.desc-box {
|
||||
width: 230px;
|
||||
padding-left: 33px;
|
||||
padding-right: 17px;
|
||||
padding-bottom: 30px;
|
||||
box-shadow: 1px 2px 2px 2px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.milestones {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
width: 90%;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.milestones > .desc-box {
|
||||
width: auto;
|
||||
margin: 10px;
|
||||
padding-bottom: 18px;
|
||||
}
|
||||
|
||||
.desc-box h2,
|
||||
.summary-box h2 {
|
||||
font-size: 22px;
|
||||
font-weight: 400;
|
||||
line-height: 33px;
|
||||
}
|
||||
|
||||
.desc-box p,
|
||||
.summary-box p {
|
||||
font-size: 15px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.arewe-timeline {
|
||||
position: relative;
|
||||
padding: 1em 10px;
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
margin-top: 10px;
|
||||
border: solid 1px #d7e4ed;
|
||||
color: #7f8c97;
|
||||
background-color: #e9f0f5;
|
||||
}
|
||||
|
||||
.arewe-timeline h2 {
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.arewe-date {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.arewe-timeline::before {
|
||||
/* this is the vertical line */
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 28px;
|
||||
height: 100%;
|
||||
width: 4px;
|
||||
background: #d7e4ed;
|
||||
}
|
||||
|
||||
.arewe-timeline-block {
|
||||
position: relative;
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
.arewe-timeline-block:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.arewe-timeline-block:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.arewe-timeline-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 0 4px white, inset 0 2px 0 rgba(0, 0, 0, 0.08), 0 3px 0 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.arewe-timeline-img.arewe-subtraction {
|
||||
background: var(--green-50);
|
||||
}
|
||||
.arewe-timeline-img.arewe-addition {
|
||||
background: var(--red-50);
|
||||
}
|
||||
.arewe-timeline-content {
|
||||
position: relative;
|
||||
margin-left: 60px;
|
||||
background: white;
|
||||
border-radius: 0.25em;
|
||||
padding: .5em;
|
||||
box-shadow: 0 3px 0 #d7e4ed;
|
||||
}
|
||||
.arewe-timeline-content h2 {
|
||||
color: #303e49;
|
||||
}
|
||||
.arewe-timeline-content p {
|
||||
margin: 1em 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.arewe-timeline-content .arewe-read-more {
|
||||
float: right;
|
||||
padding: .8em 1em;
|
||||
background: #acb7c0;
|
||||
color: white;
|
||||
border-radius: 0.25em;
|
||||
}
|
||||
.arewe-timeline-content::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 100%;
|
||||
height: 0;
|
||||
width: 0;
|
||||
border: 7px solid transparent;
|
||||
border-right: 7px solid white;
|
||||
}
|
||||
|
||||
.arewe-timeline-content small {
|
||||
border: solid 1px;
|
||||
border-radius: 5px;
|
||||
background: rgba(0, 0, 255, .05);
|
||||
font-size: 90%;
|
||||
vertical-align: middle;
|
||||
margin-right: 2px;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.arewe-timeline-path {
|
||||
font: var(--mono-font);
|
||||
}
|
||||
|
||||
.arewe-timeline-details {
|
||||
margin: 0 auto;
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.arewe-timeline-details summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.arewe-timeline-details h2 {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.arewe-update {
|
||||
position: relative;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
padding: 16px;
|
||||
color: #032f62;
|
||||
background-color: #dbedff;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.arewe-update-warn {
|
||||
color: #735c0f;
|
||||
background-color: #fff3dd;
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
@import url("./common.css");
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
table td,
|
||||
table th {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
}
|
||||
table tr td:nth-child(1),
|
||||
table tr th:nth-child(1) {
|
||||
width: 3em;
|
||||
}
|
||||
table tr td:nth-child(2),
|
||||
table tr th:nth-child(2) {
|
||||
text-align: left;
|
||||
}
|
||||
table tr td:nth-child(3),
|
||||
table tr th:nth-child(3),
|
||||
table tr td:nth-child(4),
|
||||
table tr th:nth-child(4),
|
||||
table tr td:nth-child(5),
|
||||
table tr th:nth-child(5) {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
table td ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
tr {
|
||||
padding: 4px 0;
|
||||
border-bottom: solid 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
td .desc-box {
|
||||
width: auto;
|
||||
padding: 3px;
|
||||
}
|
||||
td .desc-box ul {
|
||||
margin: 0;
|
||||
padding-inline-start: 20px;
|
||||
}
|
||||
|
||||
#links {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
border-bottom: solid 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
details h3 {
|
||||
display: inline-block;
|
||||
border-bottom: none;
|
||||
}
|
||||
details summary {
|
||||
border-bottom: solid 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
#grid {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
padding: 0 5px;
|
||||
max-width: 100vw;
|
||||
overflow: hidden;
|
||||
}
|
||||
#grid aside {
|
||||
padding-right: 5px;
|
||||
}
|
||||
#grid main {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#filter-container input:not([type="checkbox"]),
|
||||
#filter-container select {
|
||||
width: 180px;
|
||||
display: block;
|
||||
margin: 2px 0;
|
||||
padding: 0;
|
||||
}
|
||||
#filter-container label {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* For testing/ graph page */
|
||||
aside ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
aside ul li {
|
||||
list-style: none;
|
||||
}
|
||||
/*
|
||||
.chart-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
*/
|
||||
|
||||
.loading-data #grid,
|
||||
.loader {
|
||||
display: none;
|
||||
}
|
||||
.loading-data .loader {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Spinner */
|
||||
.loader,
|
||||
.loader:before,
|
||||
.loader:after {
|
||||
background: var(--heading-color);
|
||||
-webkit-animation: load1 1s infinite ease-in-out;
|
||||
animation: load1 1s infinite ease-in-out;
|
||||
width: 1em;
|
||||
height: 4em;
|
||||
}
|
||||
.loader {
|
||||
color: var(--heading-color);
|
||||
text-indent: -9999em;
|
||||
margin: 88px auto;
|
||||
position: relative;
|
||||
font-size: 11px;
|
||||
-webkit-transform: translateZ(0);
|
||||
-ms-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
-webkit-animation-delay: -0.16s;
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
.loader:before,
|
||||
.loader:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
content: "";
|
||||
}
|
||||
.loader:before {
|
||||
left: -1.5em;
|
||||
-webkit-animation-delay: -0.32s;
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
.loader:after {
|
||||
left: 1.5em;
|
||||
}
|
||||
@-webkit-keyframes load1 {
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
box-shadow: 0 0;
|
||||
height: 4em;
|
||||
}
|
||||
40% {
|
||||
box-shadow: 0 -2em;
|
||||
height: 5em;
|
||||
}
|
||||
}
|
||||
@keyframes load1 {
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
box-shadow: 0 0;
|
||||
height: 4em;
|
||||
}
|
||||
40% {
|
||||
box-shadow: 0 -2em;
|
||||
height: 5em;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>testing policy - mc-changes</title>
|
||||
<link href='css/page.css' rel='stylesheet' type='text/css'>
|
||||
<link rel="icon"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>➲</text></svg>">
|
||||
</head>
|
||||
|
||||
<body class="loading-data">
|
||||
<h1>mc changes</h1>
|
||||
<div id="links">
|
||||
<a href="index.html">Changes</a> |
|
||||
<a href="testing.html">Testing Policy</a>
|
||||
</div>
|
||||
<div class="loader"></div>
|
||||
<div id="grid">
|
||||
<aside>
|
||||
<h3>Controls</h3>
|
||||
<ul>
|
||||
<li><label><input name="grouping" type="radio" value="daily" />Daily</label></li>
|
||||
<li><label><input name="grouping" type="radio" value="weekly" checked />Weekly</label></li>
|
||||
<li><label><input name="grouping" type="radio" value="monthly" />Monthly</label></li>
|
||||
</ul>
|
||||
</aside>
|
||||
<main>
|
||||
<div class="chart-container">
|
||||
<div id="chart"></div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="graph.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,135 @@
|
|||
import ApexCharts from 'apexcharts'
|
||||
|
||||
// JSON from https://bugzilla.mozilla.org/show_bug.cgi?id=1669363
|
||||
import teamComponentMapping from './teams.json'
|
||||
|
||||
function generateData(count, yrange) {
|
||||
var i = 0;
|
||||
var series = [];
|
||||
while (i < count) {
|
||||
var x = (i + 1).toString();
|
||||
var y = Math.floor(Math.random() * (yrange.max - yrange.min + 1)) + yrange.min;
|
||||
|
||||
series.push({
|
||||
x: x,
|
||||
y: y
|
||||
});
|
||||
i++;
|
||||
}
|
||||
return series;
|
||||
}
|
||||
|
||||
function rerender() {
|
||||
var options = {
|
||||
series: [
|
||||
{
|
||||
name: "Metric1",
|
||||
data: generateData(20, {
|
||||
min: 0,
|
||||
max: 90,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Metric2",
|
||||
data: generateData(20, {
|
||||
min: 0,
|
||||
max: 90,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Metric3",
|
||||
data: generateData(20, {
|
||||
min: 0,
|
||||
max: 90,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Metric4",
|
||||
data: generateData(20, {
|
||||
min: 0,
|
||||
max: 90,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Metric5",
|
||||
data: generateData(20, {
|
||||
min: 0,
|
||||
max: 90,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Metric6",
|
||||
data: generateData(20, {
|
||||
min: 0,
|
||||
max: 90,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Metric7",
|
||||
data: generateData(20, {
|
||||
min: 0,
|
||||
max: 90,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Metric8",
|
||||
data: generateData(20, {
|
||||
min: 0,
|
||||
max: 90,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Metric8",
|
||||
data: generateData(20, {
|
||||
min: 0,
|
||||
max: 90,
|
||||
}),
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
height: 300,
|
||||
width: 800,
|
||||
type: "heatmap",
|
||||
},
|
||||
stroke: {
|
||||
width: 0,
|
||||
},
|
||||
plotOptions: {
|
||||
heatmap: {
|
||||
radius: 30,
|
||||
enableShades: false,
|
||||
colorScale: {
|
||||
ranges: [
|
||||
{
|
||||
from: 0,
|
||||
to: 50,
|
||||
color: "#008FFB",
|
||||
},
|
||||
{
|
||||
from: 51,
|
||||
to: 100,
|
||||
color: "#00E396",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
style: {
|
||||
colors: ["#fff"],
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
type: "category",
|
||||
},
|
||||
};
|
||||
|
||||
var chart = new ApexCharts(document.querySelector("#chart"), options);
|
||||
chart.render();
|
||||
}
|
||||
|
||||
(async function () {
|
||||
console.log(teamComponentMapping);
|
||||
rerender();
|
||||
})();
|
|
@ -0,0 +1,87 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>mc-changes</title>
|
||||
<link href='css/page.css' rel='stylesheet' type='text/css'>
|
||||
<link rel="icon"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>➲</text></svg>">
|
||||
</head>
|
||||
|
||||
<body class="loading-data">
|
||||
<h1>mc changes</h1>
|
||||
<div id="links">
|
||||
<a href="index.html">Changes</a> |
|
||||
<a href="testing.html">Testing Policy</a>
|
||||
</div>
|
||||
<div class="loader"></div>
|
||||
<div id="grid">
|
||||
<aside>
|
||||
<div id="filter-container">
|
||||
<h3>Filters</h3>
|
||||
<label>Metabug
|
||||
<select name="featureMetabugs" id="featureMetabugs">
|
||||
<option value="" selected>Choose a feature metabug</option>
|
||||
</select>
|
||||
<input type="text" name="metaBugID" id="metaBugID" placeholder="…or enter bug ID">
|
||||
</label>
|
||||
<hr />
|
||||
<label>Start date<br />
|
||||
<input id="startDate" type="date" value="2020-10-01">
|
||||
</label>
|
||||
<label>End date<br />
|
||||
<input id="endDate" type="date">
|
||||
</label>
|
||||
<hr />
|
||||
<label>Testing Tags<br />
|
||||
<select name="testingTags" id="testingTags" multiple>
|
||||
<option value="testing-approved" selected>testing-approved</option>
|
||||
<option value="testing-exception-elsewhere" selected>exception-elsewhere</option>
|
||||
<option value="testing-exception-other" selected>exception-other</option>
|
||||
<option value="testing-exception-ui" selected>exception-ui</option>
|
||||
<option value="testing-exception-unchanged" selected>exception-unchanged</option>
|
||||
<option value="missing" selected>missing</option>
|
||||
<option value="unknown" selected>unknown</option>
|
||||
</select>
|
||||
</label>
|
||||
<hr />
|
||||
<label>
|
||||
<input type="checkbox" id="riskinessEnabled" checked>Riskiness
|
||||
</label>
|
||||
</div>
|
||||
</aside>
|
||||
<main>
|
||||
<details open>
|
||||
<summary>
|
||||
<h3>Summary</h3>
|
||||
</summary>
|
||||
<div id="result-summary"></div>
|
||||
</details>
|
||||
<details open>
|
||||
<summary>
|
||||
<h3>Bugs</h3>
|
||||
</summary>
|
||||
|
||||
<table id="datatable"></table>
|
||||
<table id="table" class="table table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Bug</th>
|
||||
<th scope="col">Date</th>
|
||||
<th scope="col">Testing Tags</th>
|
||||
<th scope="col" id="riskinessColumn">Riskiness</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</details>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,395 @@
|
|||
// TODO: On click, show previous components affected by similar patches.
|
||||
// TODO: On click, show previous bugs caused by similar patches.
|
||||
|
||||
import { Temporal } from 'proposal-temporal/lib/index.mjs';
|
||||
|
||||
import ApexCharts from 'apexcharts'
|
||||
|
||||
import {
|
||||
TESTING_TAGS,
|
||||
featureMetabugs,
|
||||
landingsData,
|
||||
getNewTestingTagCountObject,
|
||||
} from "./common.js";
|
||||
|
||||
const HIGH_RISK_COLOR = "rgb(255, 13, 87)";
|
||||
const MEDIUM_RISK_COLOR = "darkkhaki";
|
||||
const LOW_RISK_COLOR = "green";
|
||||
|
||||
let options = {
|
||||
metaBugID: {
|
||||
value: null,
|
||||
type: "text",
|
||||
},
|
||||
testingTags: {
|
||||
value: null,
|
||||
type: "select",
|
||||
},
|
||||
startDate: {
|
||||
value: null,
|
||||
type: "text",
|
||||
},
|
||||
endDate: {
|
||||
value: null,
|
||||
type: "text",
|
||||
},
|
||||
riskinessEnabled: {
|
||||
value: null,
|
||||
type: "checkbox",
|
||||
},
|
||||
};
|
||||
|
||||
if (new URLSearchParams(window.location.search).has("riskiness")) {
|
||||
document.querySelector("#riskinessEnabled").checked = true;
|
||||
}
|
||||
let resultSummary = document.getElementById("result-summary");
|
||||
let metabugsDropdown = document.querySelector("#featureMetabugs");
|
||||
|
||||
// TODO: port this to an option maybe
|
||||
async function buildMetabugsDropdown() {
|
||||
metabugsDropdown.addEventListener("change", () => {
|
||||
setOption("metaBugID", metabugsDropdown.value);
|
||||
rebuildTable();
|
||||
});
|
||||
let bugs = await featureMetabugs;
|
||||
metabugsDropdown.innerHTML = `<option value="" selected>Choose a feature metabug</option>`;
|
||||
for (let bug of bugs) {
|
||||
let option = document.createElement("option");
|
||||
option.setAttribute("value", bug.id);
|
||||
option.textContent = bug.summary;
|
||||
metabugsDropdown.append(option);
|
||||
}
|
||||
}
|
||||
|
||||
function getOption(name) {
|
||||
return options[name].value;
|
||||
}
|
||||
|
||||
function getOptionType(name) {
|
||||
return options[name].type;
|
||||
}
|
||||
|
||||
function setOption(name, value) {
|
||||
return (options[name].value = value);
|
||||
}
|
||||
|
||||
function addRow(bugSummary) {
|
||||
let table = document.getElementById("table");
|
||||
|
||||
let row = table.insertRow(table.rows.length);
|
||||
|
||||
let num_column = document.createElement("td");
|
||||
num_column.append(document.createTextNode(table.rows.length - 1));
|
||||
row.append(num_column);
|
||||
|
||||
let bug_column = row.insertCell(1);
|
||||
let bug_link = document.createElement("a");
|
||||
bug_link.textContent = `Bug ${bugSummary["id"]}`;
|
||||
bug_link.href = `https://bugzilla.mozilla.org/show_bug.cgi?id=${bugSummary["id"]}`;
|
||||
bug_link.target = "_blank";
|
||||
bug_column.append(bug_link);
|
||||
bug_column.append(document.createTextNode(` - ${bugSummary["summary"]}`));
|
||||
|
||||
let components_percentages = Object.entries(
|
||||
bugSummary["most_common_regression_components"]
|
||||
);
|
||||
if (components_percentages.length > 0) {
|
||||
let component_container = document.createElement("div");
|
||||
component_container.classList.add("desc-box");
|
||||
bug_column.append(component_container);
|
||||
components_percentages.sort(
|
||||
([component1, percentage1], [component2, percentage2]) =>
|
||||
percentage2 - percentage1
|
||||
);
|
||||
component_container.append(
|
||||
document.createTextNode("Most common regression components:")
|
||||
);
|
||||
let component_list = document.createElement("ul");
|
||||
for (let [component, percentage] of components_percentages.slice(0, 3)) {
|
||||
let component_list_item = document.createElement("li");
|
||||
component_list_item.append(
|
||||
document.createTextNode(
|
||||
`${component} - ${Math.round(100 * percentage)}%`
|
||||
)
|
||||
);
|
||||
component_list.append(component_list_item);
|
||||
}
|
||||
component_container.append(component_list);
|
||||
}
|
||||
|
||||
/*<hr>
|
||||
The patches have a high chance of causing regressions of type <b>crash</b> and <b>high severity</b>.
|
||||
<br><br>
|
||||
The patches could affect the <b>Search</b> and <b>Bookmarks</b> features.
|
||||
<br><br>
|
||||
Examples of previous bugs caused by similar patches:
|
||||
<ul>
|
||||
<li>Bug 1 - Can"t bookmark pages</li>
|
||||
<li>Bug 7 - Search doesn"t work anymore <span style="background-color:gold;color:yellow;">STR</span></li>
|
||||
</ul>*/
|
||||
|
||||
let date_column = row.insertCell(2);
|
||||
date_column.textContent = bugSummary.date;
|
||||
|
||||
let testing_tags_column = row.insertCell(3);
|
||||
testing_tags_column.classList.add("testing-tags");
|
||||
let testing_tags_list = document.createElement("ul");
|
||||
for (let commit of bugSummary.commits) {
|
||||
let testing_tags_list_item = document.createElement("li");
|
||||
if (!commit.testing) {
|
||||
testing_tags_list_item.append(document.createTextNode("unknown"));
|
||||
} else {
|
||||
testing_tags_list_item.append(
|
||||
document.createTextNode(TESTING_TAGS[commit.testing].label)
|
||||
);
|
||||
}
|
||||
testing_tags_list.append(testing_tags_list_item);
|
||||
}
|
||||
testing_tags_column.append(testing_tags_list);
|
||||
|
||||
if (getOption("riskinessEnabled")) {
|
||||
let risk_list = document.createElement("ul");
|
||||
let risk_column = row.insertCell(4);
|
||||
|
||||
for (let commit of bugSummary.commits) {
|
||||
let risk = commit.risk;
|
||||
let risk_list_item = document.createElement("li");
|
||||
let riskText = document.createElement("a");
|
||||
riskText.setAttribute(
|
||||
"href",
|
||||
`https://hg.mozilla.org/mozilla-central/rev/${commit.id}`
|
||||
);
|
||||
riskText.setAttribute("target", "_blank");
|
||||
riskText.textContent = Math.round(100 * risk);
|
||||
if (risk > 0.8) {
|
||||
riskText.style.color = HIGH_RISK_COLOR;
|
||||
} else if (risk > 0.5) {
|
||||
riskText.style.color = MEDIUM_RISK_COLOR;
|
||||
} else {
|
||||
riskText.style.color = LOW_RISK_COLOR;
|
||||
}
|
||||
risk_list_item.append(riskText);
|
||||
risk_list.append(risk_list_item);
|
||||
}
|
||||
risk_column.append(risk_list);
|
||||
}
|
||||
}
|
||||
|
||||
function renderTestingSummary(bugSummaries) {
|
||||
let metaBugID = getOption("metaBugID");
|
||||
|
||||
let changesets = [];
|
||||
if (bugSummaries.length) {
|
||||
changesets = bugSummaries
|
||||
.map((summary) => summary.commits.length)
|
||||
.reduce((a, b) => a + b);
|
||||
}
|
||||
|
||||
let testingCounts = getNewTestingTagCountObject();
|
||||
bugSummaries.forEach((summary) => {
|
||||
summary.commits.forEach((commit) => {
|
||||
if (!commit.testing) {
|
||||
testingCounts.unknown++;
|
||||
} else {
|
||||
testingCounts[commit.testing] = testingCounts[commit.testing] + 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let bugText = metaBugID ? `For bug ${metaBugID}: ` : ``;
|
||||
let summaryText = `${bugText}There are ${bugSummaries.length} bugs with ${changesets} changesets.`;
|
||||
resultSummary.textContent = summaryText;
|
||||
|
||||
// let pre = document.createElement("pre");
|
||||
// pre.textContent = `${JSON.stringify(
|
||||
// testingCounts
|
||||
// )}`;
|
||||
// resultSummary.append(pre);
|
||||
|
||||
let categories = [];
|
||||
let colors = [];
|
||||
let data = [];
|
||||
for (let tag in testingCounts) {
|
||||
categories.push(TESTING_TAGS[tag].label);
|
||||
data.push(testingCounts[tag]);
|
||||
colors.push(TESTING_TAGS[tag].color);
|
||||
}
|
||||
|
||||
var options = {
|
||||
series: [
|
||||
{
|
||||
name: "Tags",
|
||||
data,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
height: 150,
|
||||
type: "bar",
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
dataLabels: {
|
||||
position: "top", // top, center, bottom
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
xaxis: {
|
||||
categories,
|
||||
// position: "bottom",
|
||||
axisBorder: {
|
||||
show: false,
|
||||
},
|
||||
axisTicks: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
axisBorder: {
|
||||
show: false,
|
||||
},
|
||||
axisTicks: {
|
||||
show: false,
|
||||
},
|
||||
labels: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let chartEl = document.createElement("div");
|
||||
resultSummary.append(chartEl);
|
||||
|
||||
var chart = new ApexCharts(chartEl, options);
|
||||
chart.render();
|
||||
}
|
||||
|
||||
async function buildTable() {
|
||||
let data = await landingsData;
|
||||
let metaBugID = getOption("metaBugID");
|
||||
let testingTags = getOption("testingTags");
|
||||
let includeUnknown = testingTags.includes("unknown");
|
||||
if (testingTags.includes("missing")) {
|
||||
testingTags[testingTags.indexOf("missing")] = "none";
|
||||
}
|
||||
|
||||
let bugSummaries = [].concat.apply([], Object.values(data));
|
||||
if (metaBugID) {
|
||||
bugSummaries = bugSummaries.filter((bugSummary) =>
|
||||
bugSummary["meta_ids"].includes(Number(metaBugID))
|
||||
);
|
||||
}
|
||||
|
||||
let startDate = getOption("startDate");
|
||||
if (startDate) {
|
||||
startDate = Temporal.PlainDate.from(startDate);
|
||||
bugSummaries = bugSummaries.filter((bugSummary) => {
|
||||
return (
|
||||
Temporal.PlainDate.compare(
|
||||
Temporal.PlainDate.from(bugSummary.date),
|
||||
startDate
|
||||
) >= 0
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
let endDate = getOption("endDate");
|
||||
if (endDate) {
|
||||
endDate = Temporal.PlainDate.from(endDate);
|
||||
bugSummaries = bugSummaries.filter((bugSummary) => {
|
||||
return (
|
||||
Temporal.PlainDate.compare(
|
||||
Temporal.PlainDate.from(bugSummary.date),
|
||||
endDate
|
||||
) <= 0
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (testingTags) {
|
||||
bugSummaries = bugSummaries.filter((bugSummary) =>
|
||||
bugSummary.commits.some((commit) => {
|
||||
if (includeUnknown && !commit.testing) {
|
||||
return true;
|
||||
}
|
||||
return commit.testing && testingTags.includes(commit.testing);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
bugSummaries.reverse();
|
||||
if (getOption("riskinessEnabled")) {
|
||||
// bugSummaries.sort(
|
||||
// (bugSummary1, bugSummary2) => bugSummary2["risk"] - bugSummary1["risk"]
|
||||
// );
|
||||
document.getElementById("riskinessColumn").style.removeProperty("display");
|
||||
} else {
|
||||
document.getElementById("riskinessColumn").style.display = "none";
|
||||
}
|
||||
|
||||
renderTestingSummary(bugSummaries);
|
||||
|
||||
for (let bugSummary of bugSummaries) {
|
||||
addRow(bugSummary);
|
||||
}
|
||||
}
|
||||
|
||||
function rebuildTable() {
|
||||
let table = document.getElementById("table");
|
||||
let summary = resultSummary;
|
||||
summary.textContent = "";
|
||||
|
||||
while (table.rows.length > 1) {
|
||||
table.deleteRow(table.rows.length - 1);
|
||||
}
|
||||
|
||||
buildTable();
|
||||
}
|
||||
|
||||
(function init() {
|
||||
buildMetabugsDropdown();
|
||||
|
||||
Object.keys(options).forEach(function (optionName) {
|
||||
let optionType = getOptionType(optionName);
|
||||
let elem = document.getElementById(optionName);
|
||||
|
||||
if (optionType === "text") {
|
||||
setOption(optionName, elem.value);
|
||||
elem.addEventListener("change", function () {
|
||||
setOption(optionName, elem.value);
|
||||
rebuildTable();
|
||||
});
|
||||
} else if (optionType === "checkbox") {
|
||||
setOption(optionName, elem.checked);
|
||||
|
||||
elem.onchange = function () {
|
||||
setOption(optionName, elem.checked);
|
||||
rebuildTable();
|
||||
};
|
||||
} else if (optionType === "select") {
|
||||
let value = [];
|
||||
for (let option of elem.options) {
|
||||
if (option.selected) {
|
||||
value.push(option.value);
|
||||
}
|
||||
}
|
||||
|
||||
setOption(optionName, value);
|
||||
|
||||
elem.onchange = function () {
|
||||
let value = [];
|
||||
for (let option of elem.options) {
|
||||
if (option.selected) {
|
||||
value.push(option.value);
|
||||
}
|
||||
}
|
||||
|
||||
setOption(optionName, value);
|
||||
rebuildTable();
|
||||
};
|
||||
} else {
|
||||
throw new Error("Unexpected option type.");
|
||||
}
|
||||
});
|
||||
buildTable();
|
||||
})();
|
|
@ -0,0 +1,421 @@
|
|||
{
|
||||
"Crypto": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Security: PSM"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
},
|
||||
"JSS": {
|
||||
"all_components": true
|
||||
},
|
||||
"NSS": {
|
||||
"all_components": true
|
||||
}
|
||||
},
|
||||
"DOM": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Image Blocking",
|
||||
"Security: CAPS",
|
||||
"XBL",
|
||||
"XML",
|
||||
"XPConnect",
|
||||
"XSLT",
|
||||
"XUL"
|
||||
],
|
||||
"prefixed_components": [
|
||||
"DOM",
|
||||
"Storage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"DevTools": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Gecko Profiler",
|
||||
"Web Replay"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
},
|
||||
"DevTools": {
|
||||
"all_components": true
|
||||
}
|
||||
},
|
||||
"Frontend": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"AutoConfig (Mission Control Desktop)",
|
||||
"Find Backend",
|
||||
"Window Management"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
},
|
||||
"Firefox": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"about:logins",
|
||||
"Address Bar",
|
||||
"Bookmarks & History",
|
||||
"Disability Access",
|
||||
"Distributions",
|
||||
"Downloads Panel",
|
||||
"Enterprise Policies",
|
||||
"File Handling",
|
||||
"General",
|
||||
"Installer",
|
||||
"Keyboard Navigation",
|
||||
"Menus",
|
||||
"Migration",
|
||||
"Page Info Window",
|
||||
"Preferences",
|
||||
"Search",
|
||||
"Session Restore",
|
||||
"Tabbed Browser",
|
||||
"Theme",
|
||||
"Toolbars and Customization",
|
||||
"Tours",
|
||||
"Translation",
|
||||
"WebPayments UI"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
},
|
||||
"Toolkit": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Application Update",
|
||||
"Autocomplete",
|
||||
"Downloads API",
|
||||
"Find Toolbar",
|
||||
"Form Autofill",
|
||||
"Form Manager",
|
||||
"General",
|
||||
"Notifications and Alerts",
|
||||
"Password Manager",
|
||||
"Password Manager: Site Compatibility",
|
||||
"Places",
|
||||
"Preferences",
|
||||
"Printing",
|
||||
"Reader Mode",
|
||||
"Startup and Profile System",
|
||||
"Storage",
|
||||
"Themes",
|
||||
"Toolbars and Toolbar Customization",
|
||||
"Video/Audio Controls",
|
||||
"View Source",
|
||||
"WebPayments UI",
|
||||
"XUL Widgets"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
}
|
||||
},
|
||||
"GFX": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Canvas: 2D",
|
||||
"ImageLib",
|
||||
"Panning and Zooming",
|
||||
"Web Painting"
|
||||
],
|
||||
"prefixed_components": [
|
||||
"GFX",
|
||||
"Graphics"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Javascript": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"js-ctypes"
|
||||
],
|
||||
"prefixed_components": [
|
||||
"Javascript"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Layout": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Internationalization",
|
||||
"MathML",
|
||||
"SVG"
|
||||
],
|
||||
"prefixed_components": [
|
||||
"CSS",
|
||||
"Layout",
|
||||
"Print"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Media": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Web Audio"
|
||||
],
|
||||
"prefixed_components": [
|
||||
"Audio/Video",
|
||||
"WebRTC"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Mobile": {
|
||||
"Emerging Markets": {
|
||||
"all_components": true
|
||||
},
|
||||
"Fenix": {
|
||||
"all_components": true
|
||||
},
|
||||
"Firefox for Android": {
|
||||
"all_components": true
|
||||
},
|
||||
"Firefox for Echo Show": {
|
||||
"all_components": true
|
||||
},
|
||||
"Firefox for FireTV": {
|
||||
"all_components": true
|
||||
},
|
||||
"Firefox for iOS": {
|
||||
"all_components": true
|
||||
},
|
||||
"Focus": {
|
||||
"all_components": true
|
||||
},
|
||||
"Focus-iOS": {
|
||||
"all_components": true
|
||||
},
|
||||
"GeckoView": {
|
||||
"all_components": true
|
||||
}
|
||||
},
|
||||
"Networking": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
|
||||
],
|
||||
"prefixed_components": [
|
||||
"Networking"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Other": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Disability Access APIs",
|
||||
"General",
|
||||
"Performance",
|
||||
"Platform Fuzzing Team",
|
||||
"Spelling checker",
|
||||
"Web Speech",
|
||||
"WebVR",
|
||||
"Untriaged"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
},
|
||||
"External Software Affecting Firefox": {
|
||||
"all_components": true
|
||||
},
|
||||
"Firefox": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Headless",
|
||||
"Normandy Client",
|
||||
"Normandy Server",
|
||||
"PDF Viewer",
|
||||
"Screenshots",
|
||||
"Shell Integration",
|
||||
"System Add-ons: Off-train Deployment",
|
||||
"Untriaged"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
},
|
||||
"Firefox Build System": {
|
||||
"all_components": true
|
||||
},
|
||||
"NSPR": {
|
||||
"all_components": true
|
||||
},
|
||||
"Toolkit": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"about:memory",
|
||||
"Crash Reporting",
|
||||
"FeatureGate",
|
||||
"Performance Monitoring",
|
||||
"Telemetry"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
}
|
||||
},
|
||||
"Platform": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Canvas: WebGL",
|
||||
"DMD",
|
||||
"Hardware Abstraction Layer (HAL)",
|
||||
"IPC",
|
||||
"IPC: MSCOM",
|
||||
"MFBT",
|
||||
"Memory Allocator",
|
||||
"Plug-ins",
|
||||
"Preferences: Backend",
|
||||
"Security: Process Sandboxing",
|
||||
"String",
|
||||
"XPCOM",
|
||||
"mfbt",
|
||||
"mozglue"
|
||||
],
|
||||
"prefixed_components": [
|
||||
"Embedding",
|
||||
"Widget"
|
||||
]
|
||||
},
|
||||
"Firefox": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Launcher Process"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
},
|
||||
"Toolkit": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Async Tooling",
|
||||
"NSIS Installer",
|
||||
"OS.File"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
}
|
||||
},
|
||||
"Pocket and User Journey": {
|
||||
"Firefox": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Messaging System",
|
||||
"New Tab Page",
|
||||
"Pocket"
|
||||
],
|
||||
"prefixed_components": [
|
||||
"Activity Stream"
|
||||
]
|
||||
},
|
||||
"Pocket": {
|
||||
"all_components": true
|
||||
}
|
||||
},
|
||||
"Privacy and Security": {
|
||||
"Core": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Image Blocking",
|
||||
"Permission Manager",
|
||||
"Privacy: Anti-Tracking",
|
||||
"Security",
|
||||
"Security Blacklists, Whitelists, and other State"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
},
|
||||
"Firefox": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Firefox Monitor",
|
||||
"Private Browsing",
|
||||
"Protections UI",
|
||||
"Site Identity",
|
||||
"Site Permissions"
|
||||
],
|
||||
"prefixed_components": [
|
||||
"Security"
|
||||
]
|
||||
},
|
||||
"Firefox Private Network": {
|
||||
"all_components": true
|
||||
},
|
||||
"Lockwise": {
|
||||
"all_components": true
|
||||
},
|
||||
"Toolkit": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Data Sanitization",
|
||||
"Safe Browsing"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
}
|
||||
},
|
||||
"Services": {
|
||||
"Cloud Services": {
|
||||
"all_components": true
|
||||
},
|
||||
"Firefox": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Firefox Accounts",
|
||||
"Remote Settings Client",
|
||||
"Sync"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
}
|
||||
},
|
||||
"Web Extensions": {
|
||||
"WebExtensions": {
|
||||
"all_components": true
|
||||
},
|
||||
"Firefox": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Extension Compatibility"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
},
|
||||
"Toolkit": {
|
||||
"all_components": false,
|
||||
"named_components": [
|
||||
"Add-ons Manager",
|
||||
"Blocklist Implementation",
|
||||
"Blocklist Policy Requests"
|
||||
],
|
||||
"prefixed_components": [
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>testing policy - mc-changes</title>
|
||||
<link href='css/page.css' rel='stylesheet' type='text/css'>
|
||||
<link rel="icon"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>➲</text></svg>">
|
||||
</head>
|
||||
|
||||
<body class="loading-data">
|
||||
<h1>mc changes</h1>
|
||||
<div id="links">
|
||||
<a href="index.html">Changes</a> |
|
||||
<a href="testing.html">Testing Policy</a>
|
||||
</div>
|
||||
<div class="loader"></div>
|
||||
<div id="grid">
|
||||
<aside>
|
||||
<h3>Controls</h3>
|
||||
<ul>
|
||||
<li><label><input name="grouping" type="radio" value="daily" />Daily</label></li>
|
||||
<li><label><input name="grouping" type="radio" value="weekly" checked />Weekly</label></li>
|
||||
<li><label><input name="grouping" type="radio" value="monthly" />Monthly</label></li>
|
||||
</ul>
|
||||
</aside>
|
||||
<main>
|
||||
<div class="arewe-update">
|
||||
See the <a href="https://firefox-source-docs.mozilla.org/testing/testing-policy/">Testing Policy for code landing in mozilla-central</a> for a description of each tag.
|
||||
In addition to these:
|
||||
<ul>
|
||||
<li>`unknown` is for commits that don't have an accessible phabricator revision associated with them (i.e. automated wpt vendoring or restricted bugs).</li>
|
||||
<li>`missing` is for commits that haven't had any tags applied.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<details open>
|
||||
<summary>
|
||||
<h3>All Commits</h3>
|
||||
</summary>
|
||||
<div id="all-chart" class="chart-container">
|
||||
<div class="chart"></div>
|
||||
</div>
|
||||
<textarea id="all-data">
|
||||
</textarea>
|
||||
</details>
|
||||
<details open>
|
||||
<summary>
|
||||
<h3>Backed Out Commits</h3>
|
||||
</summary>
|
||||
<div class="arewe-update arewe-update-warn">
|
||||
Note that this includes _all_ commits in a bug that gets backed out,
|
||||
so if there are a stack of commits this can overestimate tags.
|
||||
</div>
|
||||
<div id="backedout-chart" class="chart-container">
|
||||
<div class="chart"></div>
|
||||
</div>
|
||||
<textarea id="backedout-data">
|
||||
</textarea>
|
||||
</details>
|
||||
|
||||
<details open>
|
||||
<summary>
|
||||
<h3>Commits that caused a regression</h3>
|
||||
</summary>
|
||||
<div class="arewe-update arewe-update-warn">
|
||||
Note that this includes _all_ commits in a bug that gets backed out,
|
||||
so if there are a stack of commits this can overestimate tags.
|
||||
</div>
|
||||
<div id="regression-chart" class="chart-container">
|
||||
<div class="chart"></div>
|
||||
</div>
|
||||
<textarea id="regression-data">
|
||||
</textarea>
|
||||
</details>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="testing.js"></script>
|
||||
<script>
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,144 @@
|
|||
import ApexCharts from 'apexcharts'
|
||||
|
||||
import { TESTING_TAGS, getTestingPolicySummaryData } from "./common.js";
|
||||
|
||||
|
||||
(function () {
|
||||
let charts = {
|
||||
all: null,
|
||||
backedout: null,
|
||||
regression: null,
|
||||
};
|
||||
let radios = [...document.querySelectorAll("input[name=grouping]")];
|
||||
var previouslySelected = document.querySelector(
|
||||
"input[name=grouping]:checked"
|
||||
);
|
||||
for (let radio of radios) {
|
||||
radio.addEventListener("change", function () {
|
||||
if (this !== previouslySelected) {
|
||||
previouslySelected = this;
|
||||
rerender(this.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function rerenderChart(name, data, grouping) {
|
||||
let series = [];
|
||||
let colors = [];
|
||||
for (let tag in TESTING_TAGS) {
|
||||
series.push({ name: TESTING_TAGS[tag].label, data: [] });
|
||||
colors.push(TESTING_TAGS[tag].color);
|
||||
}
|
||||
|
||||
let dataContainer = document.querySelector(`#${name}-data`);
|
||||
dataContainer.textContent = "\t";
|
||||
|
||||
dataContainer.textContent += "total commits\t";
|
||||
for (let tag in TESTING_TAGS) {
|
||||
dataContainer.textContent += `${tag}\t`;
|
||||
}
|
||||
|
||||
for (let date in data) {
|
||||
dataContainer.textContent += `\n`;
|
||||
dataContainer.textContent += `${date}\t`;
|
||||
|
||||
let total = 0;
|
||||
for (let tag in data[date]) {
|
||||
total += data[date][tag];
|
||||
}
|
||||
dataContainer.textContent += `${total}\t`;
|
||||
for (let tag in data[date]) {
|
||||
// dataContainer.textContent += `${Math.round(parseFloat((data[date][tag] / total) * 100))}% (${data[date][tag]})\t`;
|
||||
// dataContainer.textContent += `${Math.round(parseFloat((data[date][tag] / total) * 100))}%\t`;
|
||||
dataContainer.textContent += `${data[date][tag]}\t`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let xaxisCategories = [];
|
||||
for (let date in data) {
|
||||
xaxisCategories.push(date);
|
||||
let i = 0;
|
||||
for (let tag in data[date]) {
|
||||
series[i].data.push(data[date][tag]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
let annotations =
|
||||
grouping === "monthly"
|
||||
? undefined
|
||||
: {
|
||||
xaxis: [
|
||||
{
|
||||
x: "2020-09-20",
|
||||
borderColor: "#775DD0aa",
|
||||
offsetX: 0,
|
||||
label: {
|
||||
style: {
|
||||
color: "orange",
|
||||
},
|
||||
text: "rollout",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
var options = {
|
||||
series,
|
||||
colors,
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 300,
|
||||
stacked: true,
|
||||
toolbar: {
|
||||
show: true,
|
||||
},
|
||||
zoom: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: false,
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
categories: xaxisCategories,
|
||||
},
|
||||
annotations,
|
||||
};
|
||||
|
||||
// TODO: Print summary percentages etc on top of graph
|
||||
let chartContainer = document.querySelector(`#${name}-chart`);
|
||||
if (charts[name]) {
|
||||
charts[name].destroy();
|
||||
}
|
||||
|
||||
charts[name] = new ApexCharts(
|
||||
chartContainer.querySelector(".chart"),
|
||||
options
|
||||
);
|
||||
charts[name].render();
|
||||
}
|
||||
|
||||
async function rerender(grouping) {
|
||||
let allData = await getTestingPolicySummaryData(grouping);
|
||||
rerenderChart("all", allData, grouping);
|
||||
|
||||
let backedoutData = await getTestingPolicySummaryData(grouping, (bug) => {
|
||||
return bug.commits.some((c) => {
|
||||
return c.backedout;
|
||||
});
|
||||
});
|
||||
rerenderChart("backedout", backedoutData, grouping);
|
||||
|
||||
let regressionData = await getTestingPolicySummaryData(grouping, (bug) => {
|
||||
return bug.commits.some((c) => {
|
||||
return c.regressor;
|
||||
});
|
||||
});
|
||||
rerenderChart("regression", regressionData, grouping);
|
||||
}
|
||||
rerender(previouslySelected ? previouslySelected.value : undefined);
|
||||
})();
|
|
@ -0,0 +1,28 @@
|
|||
const path = require('path');
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const ESLintPlugin = require('eslint-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
entry: {
|
||||
index: './src/index.js',
|
||||
testing: './src/testing.js',
|
||||
graph: './src/graph.js',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
plugins: [
|
||||
// TODO: Fix eslint errors.
|
||||
// new ESLintPlugin(),
|
||||
new CleanWebpackPlugin(),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ context: "src", from: "*.html" },
|
||||
{ from: "src/css", to: "css" },
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
devServer: {
|
||||
contentBase: './dist'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
optimization: {
|
||||
minimizer: [
|
||||
`...`,
|
||||
new CssMinimizerPlugin(),
|
||||
],
|
||||
},
|
||||
});
|
Загрузка…
Ссылка в новой задаче