1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 const crbugApi = require('./crbug.js');
8 const tryrequire = require('../perfbot-analysis/try-require.js');
9 const pinpointApi = require('./pinpoint.js');
11 const yargs = tryrequire.tryrequire('yargs');
13 console.error('Please install the `yargs` package from npm (`npm i yargs`).');
17 function toCSV(dict) {
18 const rows = ['date,link'];
19 const dates = Object.keys(dict).sort(
20 (a, b) => (new Date(a)).valueOf() - (new Date(b)).valueOf());
21 for (const date of dates) {
22 const links = [...dict[date]];
23 for (const link of links) {
24 rows.push(`${date},${link}`);
30 async function main() {
33 .option('user-email', {
36 'The email address(es) of the developer (comma-separated).',
42 'The comma-separated list of projects (default: chromium).',
48 description: 'Starting date (e.g. 2021-09-01).',
50 .usage('Usage: $0 -u <emails> -s <since> [-p <projects>]')
52 '$0 -u linus@chromium.org,linus@google.com -s 2022-01-01 -p chromium,v8,skia')
57 'Please specify the username(s) (using -u), e.g. `-u linus@chromium.org,linus@google.com`');
61 if (!argv.s || argv.s.split('-').length !== 3) {
63 'Please specify the starting date (using `-s YYYY-MM-DD`), e.g. `-s 2021-09-30`');
67 const usernames = argv.u.split(',');
70 const timestamps = new Set();
72 const sinceDate = new Date(since);
74 function addActivity(timestamp, url) {
75 if (timestamp < sinceDate) {
79 if (timestamps.has(timestamp.valueOf())) {
83 const d = timestamp.toLocaleDateString();
88 timestamps.add(timestamp.valueOf());
91 const projects = argv.p.split(',');
92 for (const project of projects) {
93 console.log(`Exploring project: ${project} ...`);
94 const crbug = new crbugApi.CrBug(`projects/${project}`);
95 const users = await Promise.all(usernames.map(u => crbug.getUser(u)));
96 const ids = users.map(u => u.id);
98 const issues = await crbug.search(`commentby:${argv.u} modified>${since}`);
101 for (const issue of issues) {
103 process.stdout.write(`\r Inspecting ${count}/${issues.length} issues.`);
104 const comments = await crbug.getComments(issue);
105 for (const comment of comments) {
106 if (ids.indexOf(comment.user_id) < 0) {
110 if (!comment.isActivity()) {
114 addActivity(comment.timestamp, issue.url);
117 if (issues.length === 0) {
118 console.log(' No issues found.');
124 // Now find pinpoint jobs triggered by the user against a bug.
125 console.log('Looking for pinpoint jobs ...');
126 const pinpoint = new pinpointApi.Pinpoint();
127 for (const email of usernames) {
128 const jobs = pinpoint.listJobs(email);
129 console.log(` Found ${jobs.length} jobs for ${email}.`);
130 for (const job of jobs) {
131 if (projects.indexOf(job.project) >= 0) {
132 addActivity(job.timestamp, job.url);
137 console.log(toCSV(diary).join('\n'));
140 Object.values(diary).reduce((c, i) => c + i.size, 0));