Skip to content

Instantly share code, notes, and snippets.

@patrickhulce
Last active February 7, 2020 13:18
Show Gist options
  • Save patrickhulce/ffe0f4a7eb0ead4da982c955b7fa6c49 to your computer and use it in GitHub Desktop.
Save patrickhulce/ffe0f4a7eb0ead4da982c955b7fa6c49 to your computer and use it in GitHub Desktop.
Lighthouse CI Get Diffs For Hashes (DISCLAIMER: untested)
const ApiClient = require('@lhci/utils/src/api-client')
const {findAuditDiffs} = require('@lhci/utils/src/audit-diff-finder')
const client = new ApiClient({rootURL: 'http://lhci-server.example.com'})
const PROJECT_ID = '<UUID of project>'
async function getLHR(hash, url) {
const [build] = await client.getBuilds(PROJECT_ID, {hash})
const [run] = await client.getRuns(PROJECT_ID, build.id, {representative: true, url})
return JSON.parse(run.lhr)
}
async function findDiffs(hashA, hashB, url) {
const lhrA = await getLHR(hashA, url)
const lhrB = await getLHR(hashB, url)
const diffs = []
for (const auditId of Object.keys(lhrA.audits)) {
diffs.push(findAuditDiffs(lhrA.audits[auditId], lhrB.audits[auditId]))
}
return diffs
}
@WebCloud
Copy link

WebCloud commented Feb 6, 2020

Nice! This is even better cause it is easier to automate by reading from the lighthouserc.json file on the project!

@WebCloud
Copy link

WebCloud commented Feb 7, 2020

Alright, so I've tweeked the script to fetch for the project's ligthhouserc.json to get the rootURL and the token for better automation. Also I've removed the url from the query so we can fetch diffs without that restriction and compare with different states of the application ๐Ÿ˜„

const ApiClient = require('@lhci/utils/src/api-client');
const { findAuditDiffs } = require('@lhci/utils/src/audit-diff-finder');
const {
  ci: {
    upload: { serverBaseUrl: rootURL, token },
  },
} = require('path to project lighthouserc.json');

const client = new ApiClient({ rootURL });

async function findProjectID(projectToken = token) {
  return await client.findProjectByToken(projectToken);
}

async function getLHR(hash, projectId) {
  const [build] = await client.getBuilds(projectId, { hash });
  const [run] = await client.getRuns(projectId, build.id, {
    representative: true,
  });
  return JSON.parse(run.lhr);
}

async function findDiffs(hashA, hashB, projectId) {
  const lhrA = await getLHR(hashA, projectId);
  const lhrB = await getLHR(hashB, projectId);

  const diffs = [];
  for (const auditId of Object.keys(lhrA.audits)) {
    // remove empty diffs
    const diff = findAuditDiffs(lhrA.audits[auditId], lhrB.audits[auditId]);

    if (diff.length) {
      diffs.push(diff);
    }
  }

  return diffs;
}

/* example usage, so far
findProjectID().then(({ id }) => {
  findDiffs(
    'HASH1',
    'HASH2,
    id,
  ).then(console.log);
});
*/

@WebCloud
Copy link

WebCloud commented Feb 7, 2020

Now I'm working on cleaning up the diffs to get a good summary for the feedback. Returning the scores diff and metrics alongside the link for the details should be enough to wrap this one up ๐Ÿ˜„

@WebCloud
Copy link

WebCloud commented Feb 7, 2020

What kind of metric is this value representing? It showed up on the diff but I have no clue what 'metric' would that be ๐Ÿ˜…

{
    "auditId": "metrics",
    "type": "numericValue",
    "baseValue": number,
    "compareValue": number
  },

@WebCloud
Copy link

WebCloud commented Feb 7, 2020

I think this is pretty close to done now, the results out of this is a pretty good list of entries that have been impacted, and we only show entries with numericValue type. Maybe we can add a list of audits that are 'key' to give feedback, such as first-cpu-idle as extra options for the findDiffs function ๐Ÿค”, cause even filtering out a lot of the entries by narrowing down to numericValue ones only, we still have quite a number of entries ๐Ÿ˜.

const ApiClient = require('@lhci/utils/src/api-client');
const { findAuditDiffs } = require('@lhci/utils/src/audit-diff-finder');
const {
  ci: {
    upload: { serverBaseUrl: rootURL, token },
  },
} = require('path to project lighthouserc.json');

const client = new ApiClient({ rootURL });

async function findProjectID(projectToken = token) {
  return await client.findProjectByToken(projectToken);
}

async function getLHR(hash, projectId) {
  const [build] = await client.getBuilds(projectId, { hash });
  const [run] = await client.getRuns(projectId, build.id, {
    representative: true,
  });
  return JSON.parse(run.lhr);
}

async function findDiffs(hashA, hashB, projectId) {
  const lhrA = await getLHR(hashA, projectId);
  const lhrB = await getLHR(hashB, projectId);

  const diffs = [];
  for (const auditId of Object.keys(lhrA.audits)) {
    // remove empty diffs
    const diff = findAuditDiffs(lhrA.audits[auditId], lhrB.audits[auditId]);

    if (diff.length) {
      // filter diff to only include entries with 'numericValue' so we can better determine impact
      // also, flatten out the array
      diffs.push(...diff.filter(({type}) => type === 'numericValue'));
    }
  }

  return diffs;
}

/* example usage, so far
findProjectID().then(({ id }) => {
  findDiffs(
    'HASH1',
    'HASH2,
    id,
  ).then(console.log);
});
*/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment