// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
const crbugApi = require('./crbug.js');
const tryrequire = require('../perfbot-analysis/try-require.js');
const pinpointApi = require('./pinpoint.js');
const yargs = tryrequire.tryrequire('yargs');
if (!yargs) {
console.error('Please install the `yargs` package from npm (`npm i yargs`).');
return;
}
function toCSV(dict) {
const rows = ['date,link'];
const dates = Object.keys(dict).sort(
(a, b) => (new Date(a)).valueOf() - (new Date(b)).valueOf());
for (const date of dates) {
const links = [...dict[date]];
for (const link of links) {
rows.push(`${date},${link}`);
}
}
return rows;
}
async function main() {
const argv =
yargs
.option('user-email', {
alias: 'u',
description:
'The email address(es) of the developer (comma-separated).',
type: 'string',
})
.option('project', {
alias: 'p',
description:
'The comma-separated list of projects (default: chromium).',
type: 'string',
default: 'chromium',
})
.option('since', {
alias: 's',
description: 'Starting date (e.g. 2021-09-01).',
})
.usage('Usage: $0 -u <emails> -s <since> [-p <projects>]')
.example(
'$0 -u [email protected],[email protected] -s 2022-01-01 -p chromium,v8,skia')
.wrap(null)
.argv;
if (!argv.u) {
console.error(
'Please specify the username(s) (using -u), e.g. `-u [email protected],[email protected]`');
return;
}
if (!argv.s || argv.s.split('-').length !== 3) {
console.error(
'Please specify the starting date (using `-s YYYY-MM-DD`), e.g. `-s 2021-09-30`');
return;
}
const usernames = argv.u.split(',');
const diary = {};
const timestamps = new Set();
const since = argv.s;
const sinceDate = new Date(since);
function addActivity(timestamp, url) {
if (timestamp < sinceDate) {
return;
}
if (timestamps.has(timestamp.valueOf())) {
return;
}
const d = timestamp.toLocaleDateString();
if (!(d in diary)) {
diary[d] = new Set();
}
diary[d].add(url);
timestamps.add(timestamp.valueOf());
}
const projects = argv.p.split(',');
for (const project of projects) {
console.log(`Exploring project: ${project} ...`);
const crbug = new crbugApi.CrBug(`projects/${project}`);
const users = await Promise.all(usernames.map(u => crbug.getUser(u)));
const ids = users.map(u => u.id);
const issues = await crbug.search(`commentby:${argv.u} modified>${since}`);
let count = 0;
for (const issue of issues) {
++count;
process.stdout.write(`\r Inspecting ${count}/${issues.length} issues.`);
const comments = await crbug.getComments(issue);
for (const comment of comments) {
if (ids.indexOf(comment.user_id) < 0) {
continue;
}
if (!comment.isActivity()) {
continue;
}
addActivity(comment.timestamp, issue.url);
}
}
if (issues.length === 0) {
console.log(' No issues found.');
} else {
console.log('');
}
}
// Now find pinpoint jobs triggered by the user against a bug.
console.log('Looking for pinpoint jobs ...');
const pinpoint = new pinpointApi.Pinpoint();
for (const email of usernames) {
const jobs = pinpoint.listJobs(email);
console.log(` Found ${jobs.length} jobs for ${email}.`);
for (const job of jobs) {
if (projects.indexOf(job.project) >= 0) {
addActivity(job.timestamp, job.url);
}
}
}
console.log(toCSV(diary).join('\n'));
console.log(
'Activity score: ' +
Object.values(diary).reduce((c, i) => c + i.size, 0));
}
main();