Run prettier on the whole repo

This commit is contained in:
Marco Castelluccio 2024-10-21 16:41:45 +02:00
Родитель d2cb6398a0
Коммит 1d016a2eb6
38 изменённых файлов: 982 добавлений и 923 удалений

140
.github/dependabot.yml поставляемый
Просмотреть файл

@ -1,72 +1,72 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/addon"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- addon
- package-ecosystem: pip
directory: "/bot"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- bot
- package-ecosystem: docker
directory: "/events"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- events
- package-ecosystem: docker
directory: "/backend"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- backend
- package-ecosystem: docker
directory: "/bot"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- bot
- package-ecosystem: pip
directory: "/tools"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- tools
- package-ecosystem: pip
directory: "/events"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- events
- package-ecosystem: pip
directory: "/backend"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- backend
- package-ecosystem: npm
directory: "/frontend"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- frontend
- package-ecosystem: pip
directory: "/report"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- report
- package-ecosystem: npm
directory: "/addon"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- addon
- package-ecosystem: pip
directory: "/bot"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- bot
- package-ecosystem: docker
directory: "/events"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- events
- package-ecosystem: docker
directory: "/backend"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- backend
- package-ecosystem: docker
directory: "/bot"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- bot
- package-ecosystem: pip
directory: "/tools"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- tools
- package-ecosystem: pip
directory: "/events"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- events
- package-ecosystem: pip
directory: "/backend"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- backend
- package-ecosystem: npm
directory: "/frontend"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- frontend
- package-ecosystem: pip
directory: "/report"
schedule:
interval: weekly
open-pull-requests-limit: 99
labels:
- report

Просмотреть файл

@ -23,7 +23,7 @@ repos:
- id: check-yaml
- id: mixed-line-ending
- id: name-tests-test
args: ['--django']
args: ["--django"]
- id: check-json
- id: requirements-txt-fixer
- id: check-vcs-permalinks
@ -44,7 +44,7 @@ repos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.12.1
hooks:
- id: mypy
- id: mypy
name: mypy-backend
files: ^backend/
entry: mypy backend/
@ -54,7 +54,7 @@ repos:
- types-redis==3.5.1
- types-python-dateutil==0.1.3
- types-PyYAML==5.4.0
- id: mypy
- id: mypy
name: mypy-bot
files: ^bot/
entry: mypy bot/
@ -63,21 +63,21 @@ repos:
- types-requests==0.1.11
- types-pytz==2022.6.0.1
- types-PyYAML==5.4.0
- id: mypy
- id: mypy
name: mypy-events
files: ^events/
entry: mypy events/
pass_filenames: false
additional_dependencies:
- types-requests==0.1.11
- id: mypy
- id: mypy
name: mypy-report
files: ^report/
entry: mypy report/
pass_filenames: false
additional_dependencies:
- types-requests==0.1.11
- id: mypy
- id: mypy
name: mypy-tools
files: ^tools/
entry: mypy tools/

Просмотреть файл

@ -34,8 +34,8 @@ tasks:
then:
$if: 'event.ref in ["refs/heads/testing", "refs/heads/production"]'
then: ${event.ref[11:]}
else: 'dev'
else: 'dev'
else: "dev"
else: "dev"
channel_short:
# Special case where naming is limited:
@ -44,24 +44,24 @@ tasks:
$if: 'tasks_for == "github-push"'
then:
$if: 'event.ref == "refs/heads/production"'
then: 'prod'
then: "prod"
else: ${event.ref[11:]}
else: 'dev'
else: "dev"
backend_url:
$if: 'tasks_for == "github-push"'
then:
$if: 'event.ref == "refs/heads/testing"'
then: 'https://api.coverage.testing.moz.tools'
else: 'https://api.coverage.moz.tools'
else: 'https://api.coverage.moz.tools'
then: "https://api.coverage.testing.moz.tools"
else: "https://api.coverage.moz.tools"
else: "https://api.coverage.moz.tools"
provisionerId:
$if: 'taskcluster_root_url == "https://firefox-ci-tc.services.mozilla.com"'
then:
$if: 'tasks_for == "github-push"'
then: 'code-analysis-3'
else: 'code-analysis-1'
$if: 'tasks_for == "github-push"'
then: "code-analysis-3"
else: "code-analysis-1"
else: proj-relman
workerType:
@ -77,11 +77,11 @@ tasks:
$match:
# Always run those tasks
"true":
- taskId: {$eval: as_slugid("check_lint")}
- taskId: { $eval: as_slugid("check_lint") }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
payload:
maxRunTime: 3600
image: python:3.9
@ -100,11 +100,11 @@ tasks:
# Run only on firefoxci Taskcluster
'taskcluster_root_url == "https://firefox-ci-tc.services.mozilla.com"':
- taskId: {$eval: as_slugid("bot_check_tests")}
- taskId: { $eval: as_slugid("bot_check_tests") }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
payload:
maxRunTime: 3600
image: python:3.9
@ -122,14 +122,14 @@ tasks:
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-coverage
- taskId: {$eval: as_slugid("bot_build")}
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
- taskId: { $eval: as_slugid("bot_build") }
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
dependencies:
- {$eval: as_slugid("check_lint")}
- {$eval: as_slugid("bot_check_tests")}
- { $eval: as_slugid("check_lint") }
- { $eval: as_slugid("bot_check_tests") }
payload:
features:
dind: true
@ -152,7 +152,7 @@ tasks:
- bot/Dockerfile
artifacts:
public/code-coverage-bot.tar.zst:
expires: {$fromNow: '6 months'}
expires: { $fromNow: "6 months" }
path: /bot.tar.zst
type: file
routes:
@ -169,14 +169,13 @@ tasks:
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-coverage
# Run only on community Taskcluster
'taskcluster_root_url == "https://community-tc.services.mozilla.com"':
- taskId: {$eval: as_slugid("backend_check_tests")}
- taskId: { $eval: as_slugid("backend_check_tests") }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
payload:
maxRunTime: 3600
image: python:3.9
@ -193,11 +192,11 @@ tasks:
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-coverage
- taskId: {$eval: as_slugid("events_check_tests")}
- taskId: { $eval: as_slugid("events_check_tests") }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
payload:
maxRunTime: 3600
image: python:3.9
@ -213,11 +212,11 @@ tasks:
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-coverage
- taskId: {$eval: as_slugid("report_check_tests")}
- taskId: { $eval: as_slugid("report_check_tests") }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
payload:
features:
taskclusterProxy: true
@ -234,14 +233,14 @@ tasks:
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-coverage
- taskId: {$eval: as_slugid("backend_build")}
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
- taskId: { $eval: as_slugid("backend_build") }
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
dependencies:
- {$eval: as_slugid("check_lint")}
- {$eval: as_slugid("backend_check_tests")}
- { $eval: as_slugid("check_lint") }
- { $eval: as_slugid("backend_check_tests") }
payload:
capabilities:
privileged: true
@ -264,7 +263,7 @@ tasks:
- backend/Dockerfile
artifacts:
public/code-coverage-backend.tar.zst:
expires: {$fromNow: '2 weeks'}
expires: { $fromNow: "2 weeks" }
path: /backend.tar.zst
type: file
scopes:
@ -275,14 +274,14 @@ tasks:
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-coverage
- taskId: {$eval: as_slugid("events_build")}
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
- taskId: { $eval: as_slugid("events_build") }
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
dependencies:
- {$eval: as_slugid("check_lint")}
- {$eval: as_slugid("events_check_tests")}
- { $eval: as_slugid("check_lint") }
- { $eval: as_slugid("events_check_tests") }
payload:
capabilities:
privileged: true
@ -305,7 +304,7 @@ tasks:
- events/Dockerfile
artifacts:
public/code-coverage-events.tar.zst:
expires: {$fromNow: '2 weeks'}
expires: { $fromNow: "2 weeks" }
path: /events.tar.zst
type: file
scopes:
@ -316,11 +315,11 @@ tasks:
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-coverage
- taskId: {$eval: as_slugid("addon_build")}
- taskId: { $eval: as_slugid("addon_build") }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
payload:
maxRunTime: 3600
image: node:20-alpine
@ -335,7 +334,7 @@ tasks:
npm run export"
artifacts:
public/addon:
expires: {$fromNow: '2 weeks'}
expires: { $fromNow: "2 weeks" }
path: /src/addon/web-ext-artifacts
type: directory
metadata:
@ -344,11 +343,11 @@ tasks:
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-coverage
- taskId: {$eval: as_slugid("frontend_build")}
- taskId: { $eval: as_slugid("frontend_build") }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
payload:
maxRunTime: 3600
image: node:20
@ -361,7 +360,7 @@ tasks:
npm install --no-progress && npm run release"
artifacts:
public/frontend:
expires: {$fromNow: '2 weeks'}
expires: { $fromNow: "2 weeks" }
path: /src/frontend/dist
type: directory
metadata:
@ -372,13 +371,13 @@ tasks:
- $if: 'channel in ["testing", "production"]'
then:
taskId: {$eval: as_slugid("backend_deploy")}
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
taskId: { $eval: as_slugid("backend_deploy") }
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
dependencies:
- {$eval: as_slugid("backend_build")}
- { $eval: as_slugid("backend_build") }
payload:
features:
taskclusterProxy: true
@ -402,13 +401,13 @@ tasks:
- $if: 'channel in ["testing", "production"]'
then:
taskId: {$eval: as_slugid("events_deploy")}
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
taskId: { $eval: as_slugid("events_deploy") }
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
dependencies:
- {$eval: as_slugid("events_build")}
- { $eval: as_slugid("events_build") }
payload:
features:
taskclusterProxy: true
@ -432,13 +431,13 @@ tasks:
- $if: 'channel in ["testing", "production"]'
then:
taskId: {$eval: as_slugid("frontend_deploy")}
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
taskId: { $eval: as_slugid("frontend_deploy") }
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
dependencies:
- {$eval: as_slugid("frontend_build")}
- { $eval: as_slugid("frontend_build") }
payload:
features:
# Needed for access to secret
@ -465,18 +464,18 @@ tasks:
- $if: 'tasks_for == "github-push" && head_branch[:10] == "refs/tags/"'
then:
$let:
version: {$eval: 'head_branch[10:]'}
version: { $eval: "head_branch[10:]" }
in:
taskId: {$eval: as_slugid("release")}
taskId: { $eval: as_slugid("release") }
dependencies:
- {$eval: as_slugid("addon_build")}
- {$eval: as_slugid("backend_build")}
- {$eval: as_slugid("frontend_build")}
- {$eval: as_slugid("report_check_tests")}
- { $eval: as_slugid("addon_build") }
- { $eval: as_slugid("backend_build") }
- { $eval: as_slugid("frontend_build") }
- { $eval: as_slugid("report_check_tests") }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
payload:
features:
# Needed for access to secret
@ -500,13 +499,13 @@ tasks:
- $if: 'tasks_for == "github-push" && head_branch[:10] == "refs/tags/"'
then:
taskId: {$eval: as_slugid("report_deploy_pypi")}
taskId: { $eval: as_slugid("report_deploy_pypi") }
dependencies:
- {$eval: as_slugid("report_check_tests")}
- { $eval: as_slugid("report_check_tests") }
provisionerId: "${provisionerId}"
workerType: "${workerType}"
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
created: { $fromNow: "" }
deadline: { $fromNow: "1 hour" }
payload:
features:
# Needed for access to secret
@ -521,7 +520,7 @@ tasks:
- "git clone ${repository} /project && cd /project && git checkout ${head_rev} -b release &&
taskboot --target=/project/report deploy-pypi"
scopes:
- "secrets:get:project/relman/code-coverage/release"
- "secrets:get:project/relman/code-coverage/release"
metadata:
name: "Code Coverage Report: publish on pypi"
description: Code Coverage Github Pypi publication for report

Просмотреть файл

@ -5,4 +5,5 @@ For more details, please read the
[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/).
## How to Report
For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page.

Просмотреть файл

@ -2,10 +2,10 @@
This project has 4 parts:
* `bot` is a Python script running as a Taskcluster hook, aggregating code coverage data from Mozilla repositories,
* `backend` is a Python API built with Flask, that serves the aggregated code coverage data, in an efficient way,
* `frontend` is a vanilla Javascript SPA displaying code coverage data in your browser,
* `addon` is a Web Extension for Firefox, extending several Mozilla websites with code coverage data. Published at https://addons.mozilla.org/firefox/addon/gecko-code-coverage/.
- `bot` is a Python script running as a Taskcluster hook, aggregating code coverage data from Mozilla repositories,
- `backend` is a Python API built with Flask, that serves the aggregated code coverage data, in an efficient way,
- `frontend` is a vanilla Javascript SPA displaying code coverage data in your browser,
- `addon` is a Web Extension for Firefox, extending several Mozilla websites with code coverage data. Published at https://addons.mozilla.org/firefox/addon/gecko-code-coverage/.
## Help

Просмотреть файл

@ -1,35 +1,26 @@
module.exports = {
"globals": {
globals: {},
env: {
es6: true,
node: true,
webextensions: true,
},
plugins: ["mozilla"],
extends: ["plugin:mozilla/recommended", "eslint:recommended"],
parserOptions: {
ecmaVersion: 8,
ecmaFeatures: {
jsx: true,
},
"env": {
"es6": true,
"node": true,
"webextensions": true
},
"plugins": [
"mozilla"
sourceType: "module",
},
rules: {
indent: ["error", 2],
"no-console": [
"error",
{
allow: ["error"],
},
],
"extends": [
"plugin:mozilla/recommended",
"eslint:recommended"
],
"parserOptions": {
"ecmaVersion": 8,
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"rules": {
"indent": [
"error",
2
],
"no-console": [
"error",
{
"allow": ["error"]
}
]
}
},
};

Просмотреть файл

@ -4,4 +4,4 @@
Extension that augments several Mozilla websites (DXR, Searchfox) with code coverage information.
The extension can be found at https://addons.mozilla.org/firefox/addon/gecko-code-coverage/.
The extension can be found at https://addons.mozilla.org/firefox/addon/gecko-code-coverage/.

Просмотреть файл

@ -1,18 +1,18 @@
[
"c",
"h",
"cpp",
"cc",
"cxx",
"hh",
"hpp",
"hxx",
"js",
"jsm",
"mjs",
"jsx",
"xul",
"xml",
"html",
"xhtml"
"c",
"h",
"cpp",
"cc",
"cxx",
"hh",
"hpp",
"hxx",
"js",
"jsm",
"mjs",
"jsx",
"xul",
"xml",
"html",
"xhtml"
]

Просмотреть файл

@ -27,8 +27,10 @@
"run_at": "document_end"
},
{
"matches": ["*://hg.mozilla.org/mozilla-central/file/*",
"*://hg.mozilla.org/mozilla-central/annotate/*"],
"matches": [
"*://hg.mozilla.org/mozilla-central/file/*",
"*://hg.mozilla.org/mozilla-central/annotate/*"
],
"js": ["build/hgmo.js"],
"css": ["src/spinner.css", "src/dxr.css"],
"run_at": "document_end"

Просмотреть файл

@ -2,14 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
"use strict";
import {fetchCoverage} from './coverage';
import { fetchCoverage } from "./coverage";
let resultPromise;
export async function getCoverage(revPromise, path) {
if (!resultPromise) {
resultPromise = (async function() {
resultPromise = (async function () {
const rev = await revPromise;
return fetchCoverage(rev, path);
})();
@ -19,8 +19,8 @@ export async function getCoverage(revPromise, path) {
}
function disableButton(button, text) {
button.setAttribute('disabled', 'disabled');
button.style['cursor'] = 'not-allowed';
button.setAttribute("disabled", "disabled");
button.style["cursor"] = "not-allowed";
button.title = text;
}
@ -28,13 +28,13 @@ export function injectToggle(revPromise, path, applyOverlay, removeOverlay) {
// Preload coverage data.
getCoverage(revPromise, path);
const spinner = document.createElement('div');
spinner.classList.add('gecko_coverage_loader', 'gecko_coverage_loader_dxr');
const spinner = document.createElement("div");
spinner.classList.add("gecko_coverage_loader", "gecko_coverage_loader_dxr");
let button = document.createElement('button');
button.type = 'button';
button.textContent = 'Code Coverage ';
button.className = 'gecko_code_coverage_toggle_button';
let button = document.createElement("button");
button.type = "button";
button.textContent = "Code Coverage ";
button.className = "gecko_code_coverage_toggle_button";
let enabled = false;
async function toggle() {
@ -43,16 +43,19 @@ export function injectToggle(revPromise, path, applyOverlay, removeOverlay) {
button.appendChild(spinner);
try {
await applyOverlay(revPromise, path);
button.style.backgroundColor = 'lightgrey';
button.style.backgroundColor = "lightgrey";
} catch (ex) {
button.style.backgroundColor = 'red';
disableButton(button, 'Error retrieving coverage information for this file');
button.style.backgroundColor = "red";
disableButton(
button,
"Error retrieving coverage information for this file",
);
} finally {
button.removeChild(spinner);
}
} else {
removeOverlay();
button.style.backgroundColor = 'white';
button.style.backgroundColor = "white";
}
}

Просмотреть файл

@ -1 +1 @@
export const BACKEND_URL = 'https://api.coverage.moz.tools';
export const BACKEND_URL = "https://api.coverage.moz.tools";

Просмотреть файл

@ -2,25 +2,29 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
"use strict";
import {BACKEND_URL} from './config';
const extensions = require('extensions.json')
import { BACKEND_URL } from "./config";
const extensions = require("extensions.json");
export async function fetchCoverage(rev, path) {
let response = await fetch(`${BACKEND_URL}/v2/path?path=${path}&changeset=${rev}`);
let response = await fetch(
`${BACKEND_URL}/v2/path?path=${path}&changeset=${rev}`,
);
return await response.json();
}
export async function gitToHg(gitrev) {
let response = await fetch(`https://mapper.mozilla-releng.net/gecko-dev/rev/git/${gitrev}`);
let response = await fetch(
`https://mapper.mozilla-releng.net/gecko-dev/rev/git/${gitrev}`,
);
if (!response.ok) {
throw new Error(`Error retrieving git to mercurial mapping for ${gitrev}.`);
}
let text = await response.text();
return text.split(' ')[1];
return text.split(" ")[1];
}
export function isCoverageSupported(path) {
return extensions.findIndex(ext => path.endsWith(`.${ext}`)) != -1;
return extensions.findIndex((ext) => path.endsWith(`.${ext}`)) != -1;
}

Просмотреть файл

@ -2,21 +2,21 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
"use strict";
import {getCoverage} from './button';
import { getCoverage } from "./button";
let lineNoMap = (function() {
let lineNoMap = (function () {
let mapper;
return function(l) {
return function (l) {
if (!mapper) {
if (document.getElementById('l1')) {
mapper = l => `l${l}`;
} else if (document.getElementById('1')) {
mapper = l => l;
if (document.getElementById("l1")) {
mapper = (l) => `l${l}`;
} else if (document.getElementById("1")) {
mapper = (l) => l;
} else {
throw new Error('Unknown line number element.');
throw new Error("Unknown line number element.");
}
}
@ -27,19 +27,19 @@ let lineNoMap = (function() {
export async function applyOverlay(revPromise, path) {
let result = await getCoverage(revPromise, path);
if (!result.hasOwnProperty('coverage')) {
throw new Error('No \'coverage\' field');
if (!result.hasOwnProperty("coverage")) {
throw new Error("No 'coverage' field");
}
for (var l in result.coverage) {
l = parseInt(l) + 1;
const line_no = document.getElementById(lineNoMap(l));
const line = document.getElementById(`line-${l}`);
if (result.coverage[l] > 0) {
line_no.style.backgroundColor = 'greenyellow';
line.style.backgroundColor = 'greenyellow';
line_no.style.backgroundColor = "greenyellow";
line.style.backgroundColor = "greenyellow";
} else {
line_no.style.backgroundColor = 'tomato';
line.style.backgroundColor = 'tomato';
line_no.style.backgroundColor = "tomato";
line.style.backgroundColor = "tomato";
}
}
}
@ -54,8 +54,8 @@ export function removeOverlay() {
}
const line = document.getElementById(`line-${l}`);
line_no.style.backgroundColor = '';
line.style.backgroundColor = '';
line_no.style.backgroundColor = "";
line.style.backgroundColor = "";
l += 1;
}
@ -63,14 +63,14 @@ export function removeOverlay() {
// Get the currently open file path.
export function getPath() {
const breadcrumbs = document.querySelector('.breadcrumbs');
const breadcrumbs = document.querySelector(".breadcrumbs");
if (!breadcrumbs) {
return;
}
return breadcrumbs.lastElementChild.href.split('/mozilla-central/source/')[1];
return breadcrumbs.lastElementChild.href.split("/mozilla-central/source/")[1];
}
export function getNavigationPanel() {
return document.getElementById('panel-content');
return document.getElementById("panel-content");
}

Просмотреть файл

@ -4,12 +4,12 @@
.gecko_code_coverage_toggle_button {
background-color: white;
margin-bottom: .2rem;
margin-right: .2rem;
padding: .3rem;
margin-bottom: 0.2rem;
margin-right: 0.2rem;
padding: 0.3rem;
border: 1px solid #999;
width: auto;
min-width: 100px;
border-radius: .2rem;
border-radius: 0.2rem;
cursor: pointer;
}

Просмотреть файл

@ -2,13 +2,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
"use strict";
import {injectToggle} from './button';
import {isCoverageSupported} from './coverage';
import {applyOverlay, removeOverlay, getPath, getNavigationPanel} from './dxr-common';
import { injectToggle } from "./button";
import { isCoverageSupported } from "./coverage";
import {
applyOverlay,
removeOverlay,
getPath,
getNavigationPanel,
} from "./dxr-common";
(function() {
(function () {
// Don't do anything if this isn't a file.
const panel = getNavigationPanel();
if (!panel) {
@ -21,7 +26,7 @@ import {applyOverlay, removeOverlay, getPath, getNavigationPanel} from './dxr-co
}
// Get the current revision.
const revPattern = new RegExp('Mercurial \\(([0-9a-f]+)\\)');
const revPattern = new RegExp("Mercurial \\(([0-9a-f]+)\\)");
const m = panel.innerHTML.match(revPattern);
const revPromise = Promise.resolve(m[1]);
@ -30,6 +35,6 @@ import {applyOverlay, removeOverlay, getPath, getNavigationPanel} from './dxr-co
return;
}
let treeSelector = document.getElementById('tree-selector');
let treeSelector = document.getElementById("tree-selector");
treeSelector.appendChild(button);
})();

Просмотреть файл

@ -4,14 +4,16 @@
"use strict";
import {getCoverage, injectToggle} from './button';
import { getCoverage, injectToggle } from "./button";
let filename = "";
let revision = "";
const linePattern = new RegExp("^l([0-9]+)$");
document.querySelectorAll("title").forEach(title => {
const titlePattern = new RegExp("^mozilla-central: ([^@]+)@([0-9a-f]+)(?: \\(annotated\\))?$");
document.querySelectorAll("title").forEach((title) => {
const titlePattern = new RegExp(
"^mozilla-central: ([^@]+)@([0-9a-f]+)(?: \\(annotated\\))?$",
);
const m = title.innerText.match(titlePattern);
if (m) {
filename = m[1];
@ -25,20 +27,20 @@ async function applyOverlay(revPromise, path) {
throw new Error("No 'coverage' field");
}
const data = result["coverage"];
document.querySelectorAll("[id^='l']").forEach(e => {
document.querySelectorAll("[id^='l']").forEach((e) => {
const m = e.id.match(linePattern);
if (!m) {
return;
}
const linenum = m[1];
if (data.hasOwnProperty(linenum)) {
e.style.backgroundColor = (data[linenum] > 0) ? "greenyellow" : "tomato";
e.style.backgroundColor = data[linenum] > 0 ? "greenyellow" : "tomato";
}
});
}
function removeOverlay() {
document.querySelectorAll("[id^='l']").forEach(e => {
document.querySelectorAll("[id^='l']").forEach((e) => {
const m = e.id.match(linePattern);
if (m) {
e.style.backgroundColor = "";

Просмотреть файл

@ -2,13 +2,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
"use strict";
import {injectToggle} from './button';
import {gitToHg, isCoverageSupported} from './coverage';
import {applyOverlay, removeOverlay, getPath, getNavigationPanel} from './dxr-common';
import { injectToggle } from "./button";
import { gitToHg, isCoverageSupported } from "./coverage";
import {
applyOverlay,
removeOverlay,
getPath,
getNavigationPanel,
} from "./dxr-common";
(async function() {
(async function () {
// Don't do anything if this isn't a file.
if (!getNavigationPanel()) {
return;
@ -21,7 +26,7 @@ import {applyOverlay, removeOverlay, getPath, getNavigationPanel} from './dxr-co
// Get the current revision.
const revPattern = new RegExp('/mozilla-central/commit/([0-9a-f]+)"');
const revSpan = document.getElementById('rev-id');
const revSpan = document.getElementById("rev-id");
const m = revSpan.innerHTML.match(revPattern);
const gitRev = m[1];
const revPromise = gitToHg(gitRev);
@ -31,7 +36,7 @@ import {applyOverlay, removeOverlay, getPath, getNavigationPanel} from './dxr-co
return;
}
const breadcrumbs = document.querySelector('.breadcrumbs');
const breadcrumbs = document.querySelector(".breadcrumbs");
if (!breadcrumbs) {
return;
}

Просмотреть файл

@ -3,10 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.codecov-icon {
background: url("codecov.png");
background-repeat: no-repeat;
background-size: auto 1.3em;
width: 1.3em;
height: 1.3em;
display: inline-block;
background: url("codecov.png");
background-repeat: no-repeat;
background-size: auto 1.3em;
width: 1.3em;
height: 1.3em;
display: inline-block;
}

Просмотреть файл

@ -4,45 +4,55 @@
"use strict";
import {isCoverageSupported, fetchCoverage} from './coverage';
import { isCoverageSupported, fetchCoverage } from "./coverage";
const hgurlPattern = new RegExp("^http[s]?://hg\\.mozilla\\.org/mozilla-central/annotate/([0-9a-f]+)/([^#]+)#l([0-9]+)$");
const hgurlPattern = new RegExp(
"^http[s]?://hg\\.mozilla\\.org/mozilla-central/annotate/([0-9a-f]+)/([^#]+)#l([0-9]+)$",
);
// fileinfo: filename => { revision => [{line, element}, ...] }
const fileinfo = {};
document.querySelectorAll("#frames table:first-of-type td > a[href^='https://hg.mozilla.org/mozilla-central/annotate/']").forEach(a => {
const m = a.href.match(hgurlPattern);
if (!m) {
return;
}
const filename = m[2];
if (!isCoverageSupported(filename)) {
return;
}
const line = m[3];
if (line === "0") { // shouldn't happen... but irl it happens
return;
}
const revision = m[1].slice(0, 12); // shorten the revision
const info = {
"line": line,
"element": a.parentNode
};
let finfo;
if (filename in fileinfo) {
finfo = fileinfo[filename];
} else {
finfo = fileinfo[filename] = {};
}
if (revision in finfo) {
finfo[revision].push(info);
} else {
finfo[revision] = [info];
}
});
document
.querySelectorAll(
"#frames table:first-of-type td > a[href^='https://hg.mozilla.org/mozilla-central/annotate/']",
)
.forEach((a) => {
const m = a.href.match(hgurlPattern);
if (!m) {
return;
}
const filename = m[2];
if (!isCoverageSupported(filename)) {
return;
}
const line = m[3];
if (line === "0") {
// shouldn't happen... but irl it happens
return;
}
const revision = m[1].slice(0, 12); // shorten the revision
const info = {
line: line,
element: a.parentNode,
};
let finfo;
if (filename in fileinfo) {
finfo = fileinfo[filename];
} else {
finfo = fileinfo[filename] = {};
}
if (revision in finfo) {
finfo[revision].push(info);
} else {
finfo[revision] = [info];
}
});
if (Object.keys(fileinfo).length != 0) {
const spinnerDiv = document.createElement("div");
spinnerDiv.classList.add("gecko_coverage_loader", "gecko_coverage_loader_socorro");
spinnerDiv.classList.add(
"gecko_coverage_loader",
"gecko_coverage_loader_socorro",
);
spinnerDiv.style.display = "inline-block";
const linkToCodecov = document.createElement("a");
@ -59,31 +69,34 @@ if (Object.keys(fileinfo).length != 0) {
le.element.append(e);
le.element = e;
}
fetchCoverage(revision, filename).then(data => {
if (data !== null && !data.hasOwnProperty("error")) {
if (!data.hasOwnProperty("coverage")) {
throw new Error("No 'data' field");
}
const covData = data["coverage"];
for (const le of lineElements) {
const line = le.line;
if (line in covData) {
// line is covered or uncovered
le.element.parentNode.style.backgroundColor = covData[line] == 0 ? "tomato" : "greenyellow";
const gitBuildChangeset = data["git_build_changeset"];
const codecovUrl = `https://codecov.io/gh/mozilla/gecko-dev/src/${gitBuildChangeset}/${filename}#L${line}`;
const a = linkToCodecov.cloneNode(true);
a.setAttribute("href", codecovUrl);
le.element.parentNode.append(a);
fetchCoverage(revision, filename)
.then((data) => {
if (data !== null && !data.hasOwnProperty("error")) {
if (!data.hasOwnProperty("coverage")) {
throw new Error("No 'data' field");
}
const covData = data["coverage"];
for (const le of lineElements) {
const line = le.line;
if (line in covData) {
// line is covered or uncovered
le.element.parentNode.style.backgroundColor =
covData[line] == 0 ? "tomato" : "greenyellow";
const gitBuildChangeset = data["git_build_changeset"];
const codecovUrl = `https://codecov.io/gh/mozilla/gecko-dev/src/${gitBuildChangeset}/${filename}#L${line}`;
const a = linkToCodecov.cloneNode(true);
a.setAttribute("href", codecovUrl);
le.element.parentNode.append(a);
}
}
}
}
}).finally(() => {
// Remove the spinners
for (const le of lineElements) {
le.element.remove();
}
});
})
.finally(() => {
// Remove the spinners
for (const le of lineElements) {
le.element.remove();
}
});
}
}
}

Просмотреть файл

@ -3,8 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@keyframes gecko_coverage_loader_spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.gecko_coverage_loader {

Просмотреть файл

@ -1,30 +1,30 @@
const path = require('path');
const webpack = require('webpack');
const path = require("path");
const webpack = require("webpack");
module.exports = {
mode: 'development',
mode: "development",
entry: {
'dxr': './src/dxr.js',
'searchfox': './src/searchfox.js',
'socorro': './src/socorro.js',
'hgmo': './src/hgmo.js',
dxr: "./src/dxr.js",
searchfox: "./src/searchfox.js",
socorro: "./src/socorro.js",
hgmo: "./src/hgmo.js",
},
plugins: [
// Since some NodeJS modules expect to be running in Node, it is helpful
// to set this environment var to avoid reference errors.
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
"process.env.NODE_ENV": JSON.stringify("production"),
}),
],
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js'
path: path.resolve(__dirname, "build"),
filename: "[name].js",
},
resolve : {
modules : ['src', 'assets'],
resolve: {
modules: ["src", "assets"],
},
// This will expose source map files so that errors will point to your
// original source files instead of the transpiled files.
devtool: 'source-map',
devtool: "source-map",
};

Просмотреть файл

@ -6,11 +6,10 @@ The production instance of this service is hosted on https://api.coverage.moz.to
We currently have several endpoints implemented:
* `/v2/extensions` lists all the file extensions supported by the code coverage suite,
* `/v2/latest` lists the 10 latest code coverage reports ingested on the backend and available to query,
* `/v2/history` shows the code coverage progression for a specific path in a repository,
* `/v2/path` provides the code coverage information for a directory or file in a repository, at a given revision.
- `/v2/extensions` lists all the file extensions supported by the code coverage suite,
- `/v2/latest` lists the 10 latest code coverage reports ingested on the backend and available to query,
- `/v2/history` shows the code coverage progression for a specific path in a repository,
- `/v2/path` provides the code coverage information for a directory or file in a repository, at a given revision.
## Setup instructions for developers

Просмотреть файл

@ -12,11 +12,11 @@ paths:
get:
operationId: "code_coverage_backend.api.coverage_latest"
parameters:
- name: repository
in: query
description: Mozilla repository for these reports (default to mozilla-central)
required: false
type: string
- name: repository
in: query
description: Mozilla repository for these reports (default to mozilla-central)
required: false
type: string
responses:
200:
description: Latest coverage builds
@ -27,31 +27,31 @@ paths:
get:
operationId: "code_coverage_backend.api.coverage_for_path"
parameters:
- name: changeset
in: query
description: Changeset
required: false
type: string
- name: path
in: query
description: File
required: false
type: string
- name: repository
in: query
description: Mozilla repository for this changeset (default to mozilla-central)
required: false
type: string
- name: suite
in: query
description: Filter the coverage using this test suite
required: false
type: string
- name: platform
in: query
description: Filter the coverage using this platform
required: false
type: string
- name: changeset
in: query
description: Changeset
required: false
type: string
- name: path
in: query
description: File
required: false
type: string
- name: repository
in: query
description: Mozilla repository for this changeset (default to mozilla-central)
required: false
type: string
- name: suite
in: query
description: Filter the coverage using this test suite
required: false
type: string
- name: platform
in: query
description: Filter the coverage using this platform
required: false
type: string
responses:
200:
description: Code coverage information for a given file or directory at a given changeset
@ -62,36 +62,36 @@ paths:
get:
operationId: "code_coverage_backend.api.coverage_history"
parameters:
- name: repository
in: query
description: Mozilla repository for these reports (default to mozilla-central)
required: false
type: string
- name: start
in: query
description: Start timestamp for the history date range (default to a year before end)
required: false
type: string
- name: end
in: query
description: End timestamp for the history date range (default to current timestamp)
required: false
type: string
- name: path
in: query
description: Path of the repository folder to get coverage info on.
required: false
type: string
- name: suite
in: query
description: Filter the coverage using this test suite
required: false
type: string
- name: platform
in: query
description: Filter the coverage using this platform
required: false
type: string
- name: repository
in: query
description: Mozilla repository for these reports (default to mozilla-central)
required: false
type: string
- name: start
in: query
description: Start timestamp for the history date range (default to a year before end)
required: false
type: string
- name: end
in: query
description: End timestamp for the history date range (default to current timestamp)
required: false
type: string
- name: path
in: query
description: Path of the repository folder to get coverage info on.
required: false
type: string
- name: suite
in: query
description: Filter the coverage using this test suite
required: false
type: string
- name: platform
in: query
description: Filter the coverage using this platform
required: false
type: string
responses:
200:
description: Overall coverage of specified path over a period of time
@ -111,11 +111,11 @@ paths:
get:
operationId: "code_coverage_backend.api.coverage_filters"
parameters:
- name: repository
in: query
description: Mozilla repository for these reports (default to mozilla-central)
required: false
type: string
- name: repository
in: query
description: Mozilla repository for these reports (default to mozilla-central)
required: false
type: string
responses:
200:
description: Available filters on the endpoints

Просмотреть файл

@ -44,11 +44,11 @@ Write your local configuration as YAML:
common:
APP_CHANNEL: dev
bot:
BACKEND_HOST: 'http://localhost:8000'
BACKEND_HOST: "http://localhost:8000"
EMAIL_ADDRESSES: []
PHABRICATOR_TOKEN: api-xxx
PHABRICATOR_ENABLED: false
PHABRICATOR_URL: 'https://phabricator-dev.allizom.org/api/'
PHABRICATOR_URL: "https://phabricator-dev.allizom.org/api/"
GOOGLE_CLOUD_STORAGE: null
```

Просмотреть файл

@ -1,85 +1,83 @@
{
"bindings": [],
"bindings": [],
"metadata": {
"description": "Automatically build code coverage reports",
"emailOnError": true,
"name": "Code coverage hook (CHANNEL)",
"owner": "mcastelluccio@mozilla.com"
},
"schedule": ["0 0 0 * * *"],
"task": {
"created": {
"$fromNow": "0 seconds"
},
"deadline": {
"$fromNow": "4 hours"
},
"expires": {
"$fromNow": "1 month"
},
"extra": {},
"metadata": {
"description": "Automatically build code coverage reports",
"emailOnError": true,
"name": "Code coverage hook (CHANNEL)",
"owner": "mcastelluccio@mozilla.com"
"description": "",
"name": "Code Coverage aggregation task - cron (CHANNEL)",
"owner": "mcastelluccio@mozilla.com",
"source": "https://github.com/mozilla/code-coverage"
},
"schedule": [
"0 0 0 * * *"
"payload": {
"artifacts": {
"public/chunk_mapping.tar.xz": {
"path": "/chunk_mapping.tar.xz",
"type": "file"
},
"public/per_chunk_mapping.tar.xz": {
"path": "/per_chunk_mapping.tar.xz",
"type": "file"
},
"public/zero_coverage_report.json": {
"path": "/zero_coverage_report.json",
"type": "file"
},
"public/commit_coverage.json.zst": {
"path": "/commit_coverage.json.zst",
"type": "file"
}
},
"cache": {
"code-coverage-bot-CHANNEL": "/cache"
},
"capabilities": {},
"command": [
"code-coverage-cron",
"--taskcluster-secret",
"project/relman/code-coverage/runtime-CHANNEL",
"--cache-root",
"/cache",
"--working-dir",
"/build"
],
"env": {},
"features": {
"taskclusterProxy": true
},
"image": "mozilla/code-coverage:bot-REVISION",
"maxRunTime": 14400
},
"priority": "normal",
"provisionerId": "aws-provisioner-v1",
"retries": 5,
"routes": [],
"schedulerId": "-",
"scopes": [
"secrets:get:project/relman/code-coverage/runtime-CHANNEL",
"docker-worker:cache:code-coverage-bot-CHANNEL",
"index:insert-task:project.relman.code-coverage.CHANNEL.cron.*"
],
"task": {
"created": {
"$fromNow": "0 seconds"
},
"deadline": {
"$fromNow": "4 hours"
},
"expires": {
"$fromNow": "1 month"
},
"extra": {},
"metadata": {
"description": "",
"name": "Code Coverage aggregation task - cron (CHANNEL)",
"owner": "mcastelluccio@mozilla.com",
"source": "https://github.com/mozilla/code-coverage"
},
"payload": {
"artifacts": {
"public/chunk_mapping.tar.xz": {
"path": "/chunk_mapping.tar.xz",
"type": "file"
},
"public/per_chunk_mapping.tar.xz": {
"path": "/per_chunk_mapping.tar.xz",
"type": "file"
},
"public/zero_coverage_report.json": {
"path": "/zero_coverage_report.json",
"type": "file"
},
"public/commit_coverage.json.zst": {
"path": "/commit_coverage.json.zst",
"type": "file"
}
},
"cache": {
"code-coverage-bot-CHANNEL": "/cache"
},
"capabilities": {},
"command": [
"code-coverage-cron",
"--taskcluster-secret",
"project/relman/code-coverage/runtime-CHANNEL",
"--cache-root",
"/cache",
"--working-dir",
"/build"
],
"env": {},
"features": {
"taskclusterProxy": true
},
"image": "mozilla/code-coverage:bot-REVISION",
"maxRunTime": 14400
},
"priority": "normal",
"provisionerId": "aws-provisioner-v1",
"retries": 5,
"routes": [],
"schedulerId": "-",
"scopes": [
"secrets:get:project/relman/code-coverage/runtime-CHANNEL",
"docker-worker:cache:code-coverage-bot-CHANNEL",
"index:insert-task:project.relman.code-coverage.CHANNEL.cron.*"
],
"tags": {},
"workerType": "relman-svc-memory"
},
"triggerSchema": {
"additionalProperties": true,
"type": "object"
}
"tags": {},
"workerType": "relman-svc-memory"
},
"triggerSchema": {
"additionalProperties": true,
"type": "object"
}
}

Просмотреть файл

@ -1,94 +1,93 @@
{
"bindings": [],
"metadata": {
"description": "Automatically build code coverage reports",
"emailOnError": true,
"name": "Code coverage hook (CHANNEL)",
"owner": "mcastelluccio@mozilla.com"
},
"task": {
"$merge": [
{
"$if": "'taskGroupId' in payload",
"else": {},
"then": {
"taskGroupId": {
"$eval": "payload.taskGroupId"
}
}
},
{
"created": {
"$fromNow": "0 seconds"
},
"deadline": {
"$fromNow": "4 hours"
},
"expires": {
"$fromNow": "1 month"
},
"extra": {},
"metadata": {
"description": "",
"name": {
"$if": "'taskName' in payload",
"else": "Code Coverage aggregation task - repo (CHANNEL)",
"then": {
"$eval": "payload.taskName"
}
},
"owner": "mcastelluccio@mozilla.com",
"source": "https://github.com/mozilla/code-coverage"
},
"payload": {
"artifacts": {
"public/code-coverage-report.json": {
"expires": {"$fromNow": "2 weeks"},
"path": "/build/ccov-reports/all.all.json",
"type": "file"
}
},
"cache": {
"code-coverage-bot-CHANNEL": "/cache"
},
"capabilities": {},
"command": [
"code-coverage-repo",
"--taskcluster-secret",
"project/relman/code-coverage/runtime-CHANNEL",
"--cache-root",
"/cache",
"--working-dir",
"/build"
],
"env": {
"$eval": "payload"
},
"features": {
"taskclusterProxy": true
},
"image": "mozilla/code-coverage:bot-REVISION",
"maxRunTime": 14400
},
"priority": "normal",
"provisionerId": "aws-provisioner-v1",
"retries": 5,
"routes": [],
"schedulerId": "-",
"scopes": [
"secrets:get:project/relman/code-coverage/runtime-CHANNEL",
"notify:email:*",
"docker-worker:cache:code-coverage-bot-CHANNEL",
"index:insert-task:project.relman.code-coverage.CHANNEL.repo.*"
],
"tags": {},
"workerType": "relman-svc-memory"
"bindings": [],
"metadata": {
"description": "Automatically build code coverage reports",
"emailOnError": true,
"name": "Code coverage hook (CHANNEL)",
"owner": "mcastelluccio@mozilla.com"
},
"task": {
"$merge": [
{
"$if": "'taskGroupId' in payload",
"else": {},
"then": {
"taskGroupId": {
"$eval": "payload.taskGroupId"
}
}
},
{
"created": {
"$fromNow": "0 seconds"
},
"deadline": {
"$fromNow": "4 hours"
},
"expires": {
"$fromNow": "1 month"
},
"extra": {},
"metadata": {
"description": "",
"name": {
"$if": "'taskName' in payload",
"else": "Code Coverage aggregation task - repo (CHANNEL)",
"then": {
"$eval": "payload.taskName"
}
]
},
"triggerSchema": {
"additionalProperties": true,
"type": "object"
}
},
"owner": "mcastelluccio@mozilla.com",
"source": "https://github.com/mozilla/code-coverage"
},
"payload": {
"artifacts": {
"public/code-coverage-report.json": {
"expires": { "$fromNow": "2 weeks" },
"path": "/build/ccov-reports/all.all.json",
"type": "file"
}
},
"cache": {
"code-coverage-bot-CHANNEL": "/cache"
},
"capabilities": {},
"command": [
"code-coverage-repo",
"--taskcluster-secret",
"project/relman/code-coverage/runtime-CHANNEL",
"--cache-root",
"/cache",
"--working-dir",
"/build"
],
"env": {
"$eval": "payload"
},
"features": {
"taskclusterProxy": true
},
"image": "mozilla/code-coverage:bot-REVISION",
"maxRunTime": 14400
},
"priority": "normal",
"provisionerId": "aws-provisioner-v1",
"retries": 5,
"routes": [],
"schedulerId": "-",
"scopes": [
"secrets:get:project/relman/code-coverage/runtime-CHANNEL",
"notify:email:*",
"docker-worker:cache:code-coverage-bot-CHANNEL",
"index:insert-task:project.relman.code-coverage.CHANNEL.repo.*"
],
"tags": {},
"workerType": "relman-svc-memory"
}
]
},
"triggerSchema": {
"additionalProperties": true,
"type": "object"
}
}

Просмотреть файл

@ -1,10 +1,21 @@
{
"plugins": [
["prismjs", {
"languages": ["javascript", "clike", "python", "cpp", "c", "css", "java"],
[
"prismjs",
{
"languages": [
"javascript",
"clike",
"python",
"cpp",
"c",
"css",
"java"
],
"plugins": ["line-numbers"],
"theme": "solarizedlight",
"css": true
}]
}
]
]
}

Просмотреть файл

@ -1,7 +1,8 @@
# Mozilla Code Coverage frontend
This is a simple JavaScript application displaying information from the Mozilla code coverage backend (hosted as https://coverage.moz.tools)
You can use it right now from [coverage.moz.tools](https://coverage.moz.tools/)
You can use it right now from [coverage.moz.tools](https://coverage.moz.tools/)
## File viewer

Просмотреть файл

@ -1,181 +1,196 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>mozilla-central coverage</title>
<link rel="icon" href="<%=require('../assets/moz-fav-bw-rgb.png').default%>" type="image/png" />
</head>
<body>
<script id="zerocoverage" type="x-tmpl-mustache">
<div id="browser">
<h2>
<nav>
{{#navbar}}
<a href="{{ route }}">{{ name }}</a>
{{/navbar}}
</nav>
<span> : {{ total }} files</span>
</h2>
<div class="table">
<div class="header">
<span class="filename">File name</span>
<span>Children</span>
<span>Functions</span>
<span>First push</span>
<span>Last push</span>
<span>Size</span>
<span>Commits</span>
</div>
{{#entries}}
<div class="row">
<span class="filename"><a href="{{ entry_url }}">{{ dir }}</a></span>
<span>{{ stats.children }}</span>
<span>{{ stats.funcs }}</span>
<span>{{ stats.first_push_date }}</span>
<span>{{ stats.last_push_date }}</span>
<span>{{ stats.size }}</span>
<span>{{ stats.commits }}</span>
</div>
{{/entries}}
</div>
</div>
</script>
<script id="file_coverage" type="x-tmpl-mustache">
<div id="file">
<h2>
<nav>
{{#navbar}}
<a href="{{ route }}">{{ name }}</a>
{{/navbar}}
</nav>
</h2>
<div class="help">
<p class="no_data"><samp>&nbsp;</samp><span>Non-instrumented</span></p>
<p class="uncovered"><samp>&nbsp;</samp><span>Uncovered</span></p>
<p class="covered"><samp>&nbsp;</samp><span>Covered</span></p>
</div>
<table>
<tbody>
{{#lines}}
<tr class="{{ css_class }}" id="l{{ nb }}">
<td><a class="scroll" href="{{ route }}">{{ nb }}</a></td>
<td>
<pre class="language-{{ language }}"><code>{{ line }}</code></pre>
</td>
<td>
{{#hits}}
<span class="{{ hits.unit }}" title="This line has been hit {{ coverage }} times.">{{ hits.nb }} {{ hits.unit }}</span>
{{/hits}}
</td>
</tr>
{{/lines}}
</tbody>
</table>
</div>
</script>
<script id="file_browser" type="x-tmpl-mustache">
<div id="browser">
<h2>
<nav>
{{#navbar}}
<a href="{{ route }}">{{ name }}</a>
{{/navbar}}
</nav>
<span> : {{ files.length }} files</span>
</h2>
<div class="table">
<div class="header">
<span class="filename">File name</span>
<span>Children</span>
<span>Coverage</span>
</div>
{{#files}}
<div class="row">
<span class="filename"><a href="{{ route }}">{{ file_name }}</a></span>
<span>{{ children }}</span>
<span class="coverage_{{ range }}">{{ coveragePercent }} %</span>
</div>
{{/files}}
</div>
</div>
</script>
<script id="history_point" type="x-tmpl-mustache">
<span>Revision <samp>{{ revision }}</samp> from {{ date }}</span>
</script>
<script id="menu_browser" type="x-tmpl-mustache">
<a class="item" href="#view=zero">View the zero coverage report</a>
<input class="revision" type="text" name="revision" placeholder="Mercurial revision" value="{{revision}}"></input>
<select name="platform">
<option value="all">All platforms</option>
{{#platforms}}
<option {{#selected}}selected="selected"{{/selected}} value="{{name}}">{{name}}</option>
{{/platforms}}
</select>
<select name="suite">
<option value="all">All test suites</option>
{{#suites}}
<option {{#selected}}selected="selected"{{/selected}} value="{{name}}">{{name}}</option>
{{/suites}}
</select>
</script>
<script id="menu_zero" type="x-tmpl-mustache">
{{#filters}}
<input type="checkbox" name="{{ key }}" id="{{ key }}" {{#checked}}checked="checked"{{/checked}}>
<label for="{{ key }}">{{ message }}</label>
{{#needs_explanation}}
<div class="tooltip">
<span class="questionbox">?</span>
<span class="tooltiptext">For <strong>JavaScript</strong>, files with at least one function where all functions are uncovered.
<br />For <strong>C/C++/other languages</strong>, files which have no covered lines.</span>
</div>
{{/needs_explanation}}
{{/filters}}
<select name="last_push" id="last_push">
{{#last_pushes}}
<option {{#selected}}selected="selected"{{/selected}} value="{{value}}">{{message}}</option>
{{/last_pushes}}
</select>
</script>
<header>
<div class="logo">
<img src="<%=require('../assets/moz-logo-black.png').default%>" alt="Moz://a"/>
<a href="#view=directory">Code Coverage</a>
</div>
<div id="menu"></div>
</header>
<main id="main">
<div id="message" class="message loading">Loading...</div>
<div id="history">
<div class="ct-chart"></div>
<div id="history_details">Hover a point to see its details</div>
</div>
<div id="output"></div>
</main>
<footer>
<a target="_blank" href="https://github.com/mozilla/code-coverage">
<img src="<%=require('../assets/github.png').default%>" alt="GitHub" />
</a>
<a target="_blank" href="https://github.com/mozilla/code-coverage/issues/new?labels=frontend,bug&title=Issue+with+the+frontend">Report an issue</a>
&bull;
<a target="_blank" href="https://github.com/mozilla/code-coverage/fork" aria-label="Fork mozilla/code-coverage on GitHub">Fork mozilla/code-coverage</a>
</footer>
</body>
</html>
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>mozilla-central coverage</title>
<link
rel="icon"
href="<%=require('../assets/moz-fav-bw-rgb.png').default%>"
type="image/png"
/>
</head>
<body>
<script id="zerocoverage" type="x-tmpl-mustache">
<div id="browser">
<h2>
<nav>
{{#navbar}}
<a href="{{ route }}">{{ name }}</a>
{{/navbar}}
</nav>
<span> : {{ total }} files</span>
</h2>
<div class="table">
<div class="header">
<span class="filename">File name</span>
<span>Children</span>
<span>Functions</span>
<span>First push</span>
<span>Last push</span>
<span>Size</span>
<span>Commits</span>
</div>
{{#entries}}
<div class="row">
<span class="filename"><a href="{{ entry_url }}">{{ dir }}</a></span>
<span>{{ stats.children }}</span>
<span>{{ stats.funcs }}</span>
<span>{{ stats.first_push_date }}</span>
<span>{{ stats.last_push_date }}</span>
<span>{{ stats.size }}</span>
<span>{{ stats.commits }}</span>
</div>
{{/entries}}
</div>
</div>
</script>
<script id="file_coverage" type="x-tmpl-mustache">
<div id="file">
<h2>
<nav>
{{#navbar}}
<a href="{{ route }}">{{ name }}</a>
{{/navbar}}
</nav>
</h2>
<div class="help">
<p class="no_data"><samp>&nbsp;</samp><span>Non-instrumented</span></p>
<p class="uncovered"><samp>&nbsp;</samp><span>Uncovered</span></p>
<p class="covered"><samp>&nbsp;</samp><span>Covered</span></p>
</div>
<table>
<tbody>
{{#lines}}
<tr class="{{ css_class }}" id="l{{ nb }}">
<td><a class="scroll" href="{{ route }}">{{ nb }}</a></td>
<td>
<pre class="language-{{ language }}"><code>{{ line }}</code></pre>
</td>
<td>
{{#hits}}
<span class="{{ hits.unit }}" title="This line has been hit {{ coverage }} times.">{{ hits.nb }} {{ hits.unit }}</span>
{{/hits}}
</td>
</tr>
{{/lines}}
</tbody>
</table>
</div>
</script>
<script id="file_browser" type="x-tmpl-mustache">
<div id="browser">
<h2>
<nav>
{{#navbar}}
<a href="{{ route }}">{{ name }}</a>
{{/navbar}}
</nav>
<span> : {{ files.length }} files</span>
</h2>
<div class="table">
<div class="header">
<span class="filename">File name</span>
<span>Children</span>
<span>Coverage</span>
</div>
{{#files}}
<div class="row">
<span class="filename"><a href="{{ route }}">{{ file_name }}</a></span>
<span>{{ children }}</span>
<span class="coverage_{{ range }}">{{ coveragePercent }} %</span>
</div>
{{/files}}
</div>
</div>
</script>
<script id="history_point" type="x-tmpl-mustache">
<span>Revision <samp>{{ revision }}</samp> from {{ date }}</span>
</script>
<script id="menu_browser" type="x-tmpl-mustache">
<a class="item" href="#view=zero">View the zero coverage report</a>
<input class="revision" type="text" name="revision" placeholder="Mercurial revision" value="{{revision}}"></input>
<select name="platform">
<option value="all">All platforms</option>
{{#platforms}}
<option {{#selected}}selected="selected"{{/selected}} value="{{name}}">{{name}}</option>
{{/platforms}}
</select>
<select name="suite">
<option value="all">All test suites</option>
{{#suites}}
<option {{#selected}}selected="selected"{{/selected}} value="{{name}}">{{name}}</option>
{{/suites}}
</select>
</script>
<script id="menu_zero" type="x-tmpl-mustache">
{{#filters}}
<input type="checkbox" name="{{ key }}" id="{{ key }}" {{#checked}}checked="checked"{{/checked}}>
<label for="{{ key }}">{{ message }}</label>
{{#needs_explanation}}
<div class="tooltip">
<span class="questionbox">?</span>
<span class="tooltiptext">For <strong>JavaScript</strong>, files with at least one function where all functions are uncovered.
<br />For <strong>C/C++/other languages</strong>, files which have no covered lines.</span>
</div>
{{/needs_explanation}}
{{/filters}}
<select name="last_push" id="last_push">
{{#last_pushes}}
<option {{#selected}}selected="selected"{{/selected}} value="{{value}}">{{message}}</option>
{{/last_pushes}}
</select>
</script>
<header>
<div class="logo">
<img
src="<%=require('../assets/moz-logo-black.png').default%>"
alt="Moz://a"
/>
<a href="#view=directory">Code Coverage</a>
</div>
<div id="menu"></div>
</header>
<main id="main">
<div id="message" class="message loading">Loading...</div>
<div id="history">
<div class="ct-chart"></div>
<div id="history_details">Hover a point to see its details</div>
</div>
<div id="output"></div>
</main>
<footer>
<a target="_blank" href="https://github.com/mozilla/code-coverage">
<img src="<%=require('../assets/github.png').default%>" alt="GitHub" />
</a>
<a
target="_blank"
href="https://github.com/mozilla/code-coverage/issues/new?labels=frontend,bug&title=Issue+with+the+frontend"
>Report an issue</a
>
&bull;
<a
target="_blank"
href="https://github.com/mozilla/code-coverage/fork"
aria-label="Fork mozilla/code-coverage on GitHub"
>Fork mozilla/code-coverage</a
>
</footer>
</body>
</html>

Просмотреть файл

@ -5,8 +5,8 @@ import { ZERO_COVERAGE_FILTERS } from "./zero_coverage_report.js";
export const REV_LATEST = "latest";
function domContentLoaded() {
return new Promise(resolve =>
document.addEventListener("DOMContentLoaded", resolve)
return new Promise((resolve) =>
document.addEventListener("DOMContentLoaded", resolve),
);
}
export const DOM_READY = domContentLoaded();
@ -21,7 +21,7 @@ export async function main(load, display) {
// Full workflow, loading then displaying data
// used for following updates
const full = async function() {
const full = async function () {
const data = await load();
await display(data);
};
@ -56,7 +56,7 @@ function cacheSet(cache, key, value) {
cache[key] = {
val: value,
time: now
time: now,
};
}
@ -79,7 +79,7 @@ export async function getPathCoverage(path, changeset, platform, suite) {
params += `&suite=${suite}`;
}
const response = await fetch(
`${COVERAGE_BACKEND_HOST}/v2/path?${params}`
`${COVERAGE_BACKEND_HOST}/v2/path?${params}`,
).catch(alert);
if (response.status !== 200) {
throw new Error(response.status + " - " + response.statusText);
@ -118,7 +118,7 @@ export async function getHistory(path, platform, suite) {
// Check data has coverage values
// These values are missing when going above 2 levels right now
const coverage = data.filter(point => {
const coverage = data.filter((point) => {
return point.coverage !== null;
});
if (coverage.length === 0) {
@ -137,7 +137,7 @@ export async function getZeroCoverageData() {
}
const response = await fetch(
"https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/project.relman.code-coverage.production.cron.latest/artifacts/public/zero_coverage_report.json"
"https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/project.relman.code-coverage.production.cron.latest/artifacts/public/zero_coverage_report.json",
);
data = await response.json();
@ -198,12 +198,12 @@ export async function getSource(file, revision) {
// Filtering.
const getThirdPartyPaths = (function() {
const getThirdPartyPaths = (function () {
let paths = null;
return async function() {
return async function () {
if (!paths) {
const response = await getSource("tools/rewriting/ThirdPartyPaths.txt");
paths = response.split("\n").filter(path => path !== "");
paths = response.split("\n").filter((path) => path !== "");
}
return paths;
@ -217,7 +217,7 @@ export async function filterThirdParty(files) {
const paths = await getThirdPartyPaths();
return files.filter(file => {
return files.filter((file) => {
for (const path of paths) {
if (file.path.startsWith(path)) {
return false;
@ -240,7 +240,7 @@ export function filterLanguages(files) {
"hxx",
"hpp",
"inl",
"inc"
"inc",
];
const js = isEnabled("js");
const jsExtensions = [
@ -251,23 +251,23 @@ export function filterLanguages(files) {
"xml",
"xul",
"xhtml",
"html"
"html",
];
const java = isEnabled("java");
const javaExtensions = ["java"];
const rust = isEnabled("rust");
const rustExtensions = ["rs"];
return files.filter(file => {
return files.filter((file) => {
if (file.type === "directory") {
return true;
} else if (cppExtensions.find(ext => file.path.endsWith("." + ext))) {
} else if (cppExtensions.find((ext) => file.path.endsWith("." + ext))) {
return cpp;
} else if (jsExtensions.find(ext => file.path.endsWith("." + ext))) {
} else if (jsExtensions.find((ext) => file.path.endsWith("." + ext))) {
return js;
} else if (rustExtensions.find(ext => file.path.endsWith("." + ext))) {
} else if (rustExtensions.find((ext) => file.path.endsWith("." + ext))) {
return rust;
} else if (javaExtensions.find(ext => file.path.endsWith("." + ext))) {
} else if (javaExtensions.find((ext) => file.path.endsWith("." + ext))) {
return java;
}
console.warn("Unknown language for " + file.path);
@ -280,7 +280,7 @@ export function filterHeaders(files) {
return files;
}
return files.filter(file => !file.path.endsWith(".h"));
return files.filter((file) => !file.path.endsWith(".h"));
}
export function filterCompletelyUncovered(files) {
@ -288,7 +288,7 @@ export function filterCompletelyUncovered(files) {
return files;
}
return files.filter(file => file.uncovered);
return files.filter((file) => file.uncovered);
}
export function filterLastPushDate(files) {
@ -308,7 +308,7 @@ export function filterLastPushDate(files) {
return files;
}
return files.filter(file => {
return files.filter((file) => {
const lastPushDate = new Date(file.lastPushDate);
if (
lastPushDate.getTime() <= upperLimit.getTime() &&
@ -329,17 +329,17 @@ export function buildNavbar(path, revision) {
const links = [
{
name: "mozilla-central",
route: buildRoute({ path: "", revision })
}
route: buildRoute({ path: "", revision }),
},
];
return links.concat(
path.split("/").map(file => {
path.split("/").map((file) => {
base += (base ? "/" : "") + file;
return {
name: file,
route: buildRoute({ path: base, view: "directory", revision })
route: buildRoute({ path: base, view: "directory", revision }),
};
})
}),
);
}
@ -384,7 +384,7 @@ export function show(id, node) {
export function render(template, data, target) {
const output = Mustache.render(
document.getElementById(template).innerHTML,
data
data,
);
const box = document.getElementById(target);

Просмотреть файл

@ -11,12 +11,12 @@ import {
buildNavbar,
render,
getSource,
getFilters
getFilters,
} from "./common.js";
import { buildRoute, monitorOptions, readRoute, updateRoute } from "./route.js";
import {
zeroCoverageDisplay,
zeroCoverageMenu
zeroCoverageMenu,
} from "./zero_coverage_report.js";
import "normalize.css/normalize.css";
import "./style.scss";
@ -31,18 +31,18 @@ const VIEW_FILE = "file";
function browserMenu(revision, filters, route) {
const context = {
revision,
platforms: filters.platforms.map(p => {
platforms: filters.platforms.map((p) => {
return {
name: p,
selected: p === route.platform
selected: p === route.platform,
};
}),
suites: filters.suites.map(s => {
suites: filters.suites.map((s) => {
return {
name: s,
selected: s === route.suite
selected: s === route.suite,
};
})
}),
};
render("menu_browser", context, "menu");
}
@ -53,7 +53,7 @@ async function graphHistory(history, path) {
return;
}
const dateStr = function(timestamp) {
const dateStr = function (timestamp) {
const date = new Date(timestamp);
return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`;
};
@ -62,44 +62,44 @@ async function graphHistory(history, path) {
series: [
{
name: "History",
data: history.map(push => {
data: history.map((push) => {
return {
x: push.date * 1000,
y: push.coverage
y: push.coverage,
};
})
}
]
}),
},
],
};
const config = {
// Display dates on a linear scale
axisX: {
type: Chartist.FixedScaleAxis,
divisor: 20,
labelInterpolationFnc: dateStr
labelInterpolationFnc: dateStr,
},
// Fix display bug when points are too close
lineSmooth: Chartist.Interpolation.cardinal({
tension: 1
})
tension: 1,
}),
};
const elt = show("history").querySelector(".ct-chart");
const chart = new Chartist.Line(elt, data, config);
chart.on("draw", function(evt) {
chart.on("draw", function (evt) {
if (evt.type === "point") {
// Load revision from graph when a point is clicked
const revision = history[evt.index].changeset;
evt.element._node.onclick = function() {
evt.element._node.onclick = function () {
updateRoute({ revision });
};
// Display revision from graph when a point is overed
evt.element._node.onmouseover = function() {
evt.element._node.onmouseover = function () {
const ctx = {
revision: revision.substring(0, 12),
date: dateStr(evt.value.x)
date: dateStr(evt.value.x),
};
render("history_point", ctx, "history_details");
};
@ -110,10 +110,10 @@ async function graphHistory(history, path) {
async function showDirectory(dir, revision, files) {
const context = {
navbar: buildNavbar(dir, revision),
files: files.map(file => {
files: files.map((file) => {
file.route = buildRoute({
path: file.path,
view: file.type
view: file.type,
});
// Calc decimal range to make a nice coloration
@ -131,7 +131,7 @@ async function showDirectory(dir, revision, files) {
}
return this.path;
}
},
};
render("file_browser", context, "output");
}
@ -173,17 +173,17 @@ async function showFile(source, file, revision, selectedLine) {
if (coverage >= 1000000) {
hits = {
nb: parseInt(coverage / 1000000),
unit: "M"
unit: "M",
};
} else if (coverage >= 1000) {
hits = {
nb: parseInt(coverage / 1000),
unit: "k"
unit: "k",
};
} else if (coverage > 0) {
hits = {
nb: coverage,
unit: ""
unit: "",
};
}
}
@ -201,9 +201,9 @@ async function showFile(source, file, revision, selectedLine) {
coverage,
line: line || " ",
css_class: cssClass,
route: buildRoute({ line: nb })
route: buildRoute({ line: nb }),
};
})
}),
};
hide("message");
@ -215,7 +215,7 @@ async function showFile(source, file, revision, selectedLine) {
const line = output.querySelector("#l" + selectedLine);
line.scrollIntoView({
behavior: "smooth",
block: "center"
block: "center",
});
}
@ -234,7 +234,7 @@ async function load() {
"Loading coverage data for " +
(route.path || "mozilla-central") +
" @ " +
(route.revision || REV_LATEST)
(route.revision || REV_LATEST),
);
// Load only zero coverage for that specific view
@ -244,7 +244,7 @@ async function load() {
view: VIEW_ZERO_COVERAGE,
path: route.path,
zeroCoverage,
route
route,
};
}
@ -261,7 +261,7 @@ async function load() {
const [coverage, filters, viewData] = await Promise.all([
getPathCoverage(route.path, route.revision, route.platform, route.suite),
getFilters(),
viewContent
viewContent,
]);
return {
@ -271,7 +271,7 @@ async function load() {
route,
coverage,
filters,
viewData
viewData,
};
} catch (err) {
console.warn("Failed to load coverage", err);
@ -296,7 +296,7 @@ export async function display(data) {
data.viewData,
data.coverage,
data.revision,
data.route.line
data.route.line,
);
} else {
message("error", "Invalid view : " + data.view);

Просмотреть файл

@ -6,7 +6,7 @@ export function readRoute() {
const hash = window.location.hash.substring(1);
const pairs = hash.split("&");
const out = {};
pairs.forEach(pair => {
pairs.forEach((pair) => {
const [key, value] = pair.split("=");
if (!key) {
return;
@ -36,7 +36,7 @@ export function buildRoute(params) {
return (
"#" +
Object.keys(route)
.map(k => encodeURIComponent(k) + "=" + encodeURIComponent(route[k]))
.map((k) => encodeURIComponent(k) + "=" + encodeURIComponent(route[k]))
.join("&")
);
}
@ -64,13 +64,13 @@ export function monitorOptions(currentData) {
for (const field of fields) {
if (field.classList.contains("scroll")) {
// On a scroll event, update display without any data loading
field.onclick = async evt => {
field.onclick = async (evt) => {
evt.preventDefault();
updateRouteImmediate(evt.target.hash, currentData);
};
} else if (field.type === "text") {
// React on enter
field.onkeydown = async evt => {
field.onkeydown = async (evt) => {
if (evt.keyCode === 13) {
const params = {};
params[evt.target.name] = evt.target.value;
@ -79,7 +79,7 @@ export function monitorOptions(currentData) {
};
} else {
// React on change
field.onchange = async evt => {
field.onchange = async (evt) => {
let value = evt.target.value;
if (evt.target.type === "checkbox") {
value = evt.target.checked ? "on" : "off";

Просмотреть файл

@ -18,7 +18,20 @@ body {
font-weight: 400;
line-height: 1.5;
text-rendering: optimizeLegibility;
font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-family:
BlinkMacSystemFont,
-apple-system,
"Segoe UI",
Roboto,
Oxygen,
Ubuntu,
Cantarell,
"Fira Sans",
"Droid Sans",
"Helvetica Neue",
Helvetica,
Arial,
sans-serif;
background-color: white;
@ -135,7 +148,7 @@ nav {
a:not(:last-child)::after {
content: "/";
color: #CCC;
color: #ccc;
margin: 0 2px;
}
}
@ -144,7 +157,7 @@ nav {
#browser {
max-width: $small_screen;
margin: 0 auto;
padding: .5em;
padding: 0.5em;
.table {
display: table;
@ -214,7 +227,7 @@ nav {
}
&.row {
&:nth-child(2n+3) {
&:nth-child(2n + 3) {
background: hsl(0, 0%, 98%);
}
@ -229,7 +242,8 @@ nav {
h2 {
width: 100%;
nav, span {
nav,
span {
display: inline-block;
margin-right: 3px;
}
@ -310,7 +324,7 @@ $samp_size: 20px;
color: grey;
font-size: 1em;
vertical-align: middle;
border-right: 1px solid #CCC;
border-right: 1px solid #ccc;
font-family: monospace;
background: #f5f2f0;
padding: 0 2px;
@ -438,7 +452,7 @@ $samp_size: 20px;
&::after {
content: " ";
position: absolute;
bottom: 100%; /* At the top of the tooltip */
bottom: 100%; /* At the top of the tooltip */
left: 50%;
margin-left: -5px;
border-width: 5px;

Просмотреть файл

@ -8,45 +8,45 @@ import {
filterLanguages,
filterHeaders,
filterCompletelyUncovered,
filterLastPushDate
filterLastPushDate,
} from "./common.js";
import { buildRoute } from "./route.js";
export const ZERO_COVERAGE_FILTERS = {
third_party: {
name: "Show third-party files",
default_value: "on"
default_value: "on",
},
headers: {
name: "Show headers",
default_value: "off"
default_value: "off",
},
completely_uncovered: {
name: "Show completely uncovered files only",
default_value: "off"
default_value: "off",
},
cpp: {
name: "C/C++",
default_value: "on"
default_value: "on",
},
js: {
name: "JavaScript",
default_value: "on"
default_value: "on",
},
java: {
name: "Java",
default_value: "on"
default_value: "on",
},
rust: {
name: "Rust",
default_value: "on"
}
default_value: "on",
},
};
const ZERO_COVERAGE_PUSHES = {
all: "All",
one_year: "0 < 1 year",
two_years: "1 < 2 years",
older_than_two_years: "Older than 2 years"
older_than_two_years: "Older than 2 years",
};
export function zeroCoverageMenu(route) {
@ -56,7 +56,7 @@ export function zeroCoverageMenu(route) {
key,
message: filter.name,
checked: isEnabled(key),
needs_explanation: key === "completely_uncovered"
needs_explanation: key === "completely_uncovered",
};
}),
last_pushes: Object.entries(ZERO_COVERAGE_PUSHES).map(
@ -64,10 +64,10 @@ export function zeroCoverageMenu(route) {
return {
value,
message,
selected: route.last_push === value
selected: route.last_push === value,
};
}
)
},
),
};
render("menu_zero", context, "menu");
}
@ -108,7 +108,7 @@ function getBaseStats(file, children) {
first_push_date: file.first_push_date,
last_push_date: file.last_push_date,
size: file.size,
commits: file.commits
commits: file.commits,
};
}
@ -119,11 +119,11 @@ function cumStats(prevStats, newStats) {
prevStats.commits += newStats.commits;
prevStats.first_push_date = getMinDate(
prevStats.first_push_date,
newStats.first_push_date
newStats.first_push_date,
);
prevStats.last_push_date = getMinDate(
prevStats.last_push_date,
newStats.last_push_date
newStats.last_push_date,
);
}
@ -132,7 +132,7 @@ export async function zeroCoverageDisplay(data, dir) {
hide("history");
message(
"loading",
"Loading zero coverage report for " + (dir || "mozilla-central")
"Loading zero coverage report for " + (dir || "mozilla-central"),
);
while (dir.endsWith("/")) {
@ -143,9 +143,9 @@ export async function zeroCoverageDisplay(data, dir) {
dir = "";
}
let files = data.files.filter(file => file.name.startsWith(dir));
let files = data.files.filter((file) => file.name.startsWith(dir));
// TODO: Do this in the backend directly!
files.forEach(file => {
files.forEach((file) => {
file.path = file.name;
});
files = await filterThirdParty(files);
@ -183,14 +183,14 @@ export async function zeroCoverageDisplay(data, dir) {
if (this.stats.children !== 0) {
return buildRoute({
view: "zero",
path
path,
});
}
// Fully reset the url when moving back to file view
return `#view=file&revision=${revision}&path=${path}`;
},
navbar: buildNavbar(dir),
total: files.length
total: files.length,
};
hide("message");

Просмотреть файл

@ -1,29 +1,28 @@
const path = require('path');
const webpack = require('webpack');
const ESLintPlugin = require('eslint-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require("path");
const webpack = require("webpack");
const ESLintPlugin = require("eslint-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: ['babel-polyfill', 'index.js'],
entry: ["babel-polyfill", "index.js"],
output: {
path: __dirname + '/dist',
publicPath: '',
filename: 'coverage-[hash].js'
path: __dirname + "/dist",
publicPath: "",
filename: "coverage-[hash].js",
},
plugins: [
new ESLintPlugin(),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: 'src/base.html',
template: "src/base.html",
}),
new MiniCssExtractPlugin({
filename: 'coverage-[hash].css',
filename: "coverage-[hash].css",
}),
new webpack.EnvironmentPlugin({
BACKEND_URL: 'http://localhost:8000',
BACKEND_URL: "http://localhost:8000",
}),
],
module: {
@ -32,42 +31,36 @@ module.exports = {
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
loader: "babel-loader",
options: {
presets: ['@babel/preset-env']
}
}
presets: ["@babel/preset-env"],
},
},
},
{
test: /\.s[ac]ss$/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
],
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
use: ["file-loader"],
},
],
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 9000
port: 9000,
},
resolve: {
modules: [
path.join(__dirname, 'node_modules'),
path.join(__dirname, 'assets'),
path.join(__dirname, 'src'),
path.join(__dirname, "node_modules"),
path.join(__dirname, "assets"),
path.join(__dirname, "src"),
],
},
}
};

Просмотреть файл

@ -1,10 +1,10 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
mode: "development",
devtool: "inline-source-map",
devServer: {
contentBase: './dist'
}
contentBase: "./dist",
},
});

Просмотреть файл

@ -1,10 +1,10 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserJSPlugin = require("terser-webpack-plugin");
module.exports = merge(common, {
mode: 'production',
mode: "production",
optimization: {
minimizer: [
new TerserJSPlugin({

Просмотреть файл

@ -1,5 +1,5 @@
<!DOCTYPE html>
<meta charset="utf-8">
<!doctype html>
<meta charset="utf-8" />
<title>Redirecting to zero coverage report</title>
<meta http-equiv="refresh" content="0; URL=index.html#zero:">
<link rel="canonical" href="index.html#zero:">
<meta http-equiv="refresh" content="0; URL=index.html#zero:" />
<link rel="canonical" href="index.html#zero:" />