Skip to content

Commit

Permalink
feat: send slack notification
Browse files Browse the repository at this point in the history
  • Loading branch information
alinarublea committed Nov 30, 2023
1 parent e92ad99 commit c09e982
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 39 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "module",
"scripts": {
"start": "nodemon",
"test": "c8 mocha -i -g 'Post-Deploy' --spec=test/**/*.test.js",
"test": "c8 mocha --spec=test/**/*.test.js",
"test-postdeploy": "mocha -g 'Post-Deploy' --spec=test/**/*.test.js",
"lint": "eslint .",
"semantic-release": "semantic-release",
Expand Down Expand Up @@ -58,6 +58,7 @@
"@adobe/helix-shared-wrap": "2.0.0",
"@adobe/helix-status": "10.0.10",
"@adobe/helix-universal-logger": "3.0.11",
"@adobe/spacecat-shared-utils": "^1.1.0",
"comma-number": "2.1.0",
"human-format": "1.2.0"
},
Expand Down Expand Up @@ -94,4 +95,4 @@
"*.js": "eslint",
"*.cjs": "eslint"
}
}
}
62 changes: 34 additions & 28 deletions src/cwv/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import commaNumber from 'comma-number';
import { postSlackMessage, markdown, section } from '../support/slack.js';
import { generateDomainKey } from '../support/rumapi.js';

const RUM_API_URL = 'https://main--franklin-dashboard--adobe.hlx.live/views/rum-dashboard';
const COLOR_EMOJIS = {
gray: ':gray-circle:',
green: ':green:',
Expand Down Expand Up @@ -68,7 +69,7 @@ export function getColorEmoji(type, value) {
async function createBacklink(rumApiKey, finalUrl, log) {
try {
const domainkey = await generateDomainKey(rumApiKey, finalUrl);
return `https://main--franklin-dashboard--adobe.hlx.live/views/rum-dashboard?interval=7&offset=0&limit=100&url=${finalUrl}&domainkey=${domainkey}`;
return `${RUM_API_URL}?interval=7&offset=0&limit=100&url=${finalUrl}&domainkey=${domainkey}`;
} catch (e) {
log.info('Could not generate domain key. Will not add backlink to result');
return null;
Expand All @@ -82,7 +83,11 @@ async function buildSlackMessage(url, finalUrl, overThreshold, rumApiKey, log) {
text: markdown(`For *${url}*, ${overThreshold.length} page(s) had CWV over threshold in the *last week* for the real users.\n More information is below (up to three pages):`),
}));

for (let i = 0; i < Math.min(3, overThreshold.length); i += 1) {
const backlinks = await Promise.all(
overThreshold.slice(0, 3).map(async (ot) => createBacklink(rumApiKey, ot.url, log)),
);

overThreshold.slice(0, 3).forEach((ot, i) => {
const topLine = section({
text: markdown(`:arrow-green: *<${overThreshold[i].url}|${overThreshold[i].url}>*`),
});
Expand All @@ -95,43 +100,44 @@ async function buildSlackMessage(url, finalUrl, overThreshold, rumApiKey, log) {
markdown(`${getColorEmoji('inp', overThreshold[i].avginp)} *INP:* ${overThreshold[i].avginp === null ? 0 : overThreshold[i].avginp} ms`),
],
});

blocks.push(topLine);
blocks.push(stats);
}

const backlink = await createBacklink(rumApiKey, finalUrl, log);

if (backlink) {
blocks.push(section({
text: markdown(`*To access the full report <${backlink}|click here> :link:* _(expires in 7 days)_`),
}));
}
blocks.push(topLine, stats);
if (backlinks[i]) {
blocks.push(section({
text: markdown(`*To access the full report <${backlinks[i]}|click here> :link:* _(expires in 7 days)_`),
}));
}
});

return blocks;
}

export default async function cwvHandler(message, context) {
const { url, auditResult, auditContext } = message;
const { log, env: { RUM_API_UBER_KEY: rumApiKey, SLACK_BOT_TOKEN: token } } = context;
const { log } = context;
try {
const { url, auditResult, auditContext } = message;
const { env: { RUM_API_UBER_KEY: rumApiKey, SLACK_BOT_TOKEN: token } } = context;

verifyParameters(message, context);
verifyParameters(message, context);

const { finalUrl, slackContext: { channel, ts } } = auditContext;
const { finalUrl, slackContext: { channel, ts } } = auditContext;

const overThreshold = auditResult
.filter((result) => result.avglcp > 2500 || result.avgcls > 0.1 || result.avginp > 200);
const overThreshold = auditResult
.filter((result) => result.avglcp > 2500 || result.avgcls > 0.1 || result.avginp > 200);

if (overThreshold.length === 0) {
log.info(`All CWV values are below threshold for ${url}`);
return new Response(200);
}
if (overThreshold.length === 0) {
log.info(`All CWV values are below threshold for ${url}`);
return new Response(200);
}

const blocks = await buildSlackMessage(url, finalUrl, overThreshold, rumApiKey, log);
const blocks = await buildSlackMessage(url, finalUrl, overThreshold, rumApiKey, log);

await postSlackMessage(token, { blocks, channel, ts });
await postSlackMessage(token, { blocks, channel, ts });

log.info(`Slack notification sent for ${url}`);
log.info(`Slack notification sent for ${url}`);

return new Response(200);
return new Response(200);
} catch (error) {
log.error(`Error in cwvHandler: ${error.message}`);
return new Response(500);
}
}
9 changes: 8 additions & 1 deletion src/support/rumapi.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/

import { createUrl } from '@adobe/fetch';
import { hasText } from '@adobe/spacecat-shared-utils';
import { fetch } from './utils.js';

const API = 'https://helix-pages.anywhere.run/helix-services/run-query@v3/rotate-domainkeys';
Expand All @@ -22,6 +23,9 @@ function getExpirationDate() {
}

export async function generateDomainKey(rumApiKey, finalUrl) {
if (!hasText(rumApiKey) || !hasText(finalUrl)) {
throw new Error('Invalid input: rumApiKey and finalUrl are required');
}
const params = {
domainkey: rumApiKey,
url: finalUrl,
Expand All @@ -32,7 +36,10 @@ export async function generateDomainKey(rumApiKey, finalUrl) {
let respJson;

try {
const resp = await fetch(createUrl(API, params));
const resp = await fetch(createUrl(API, params), { method: 'POST' });
if (!resp.ok) {
throw new Error(`Request failed with status ${resp.status}: ${resp.statusText}`);
}
respJson = await resp.json();
} catch (e) {
throw new Error(`Error during rum/rotate-domainkeys api call: ${e.message}`);
Expand Down
4 changes: 2 additions & 2 deletions test/cwv/handler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ describe('cwv handler', () => {
const { channel, ts } = message.auditContext.slackContext;

nock('https://helix-pages.anywhere.run')
.get('/helix-services/run-query@v3/rotate-domainkeys')
.post('/helix-services/run-query@v3/rotate-domainkeys')
.query(true)
.reply(200, successKeyResponse);
nock('https://slack.com', {
Expand All @@ -190,7 +190,7 @@ describe('cwv handler', () => {
const { channel, ts } = message.auditContext.slackContext;

nock('https://helix-pages.anywhere.run')
.get('/helix-services/run-query@v3/rotate-domainkeys')
.post('/helix-services/run-query@v3/rotate-domainkeys')
.query(true)
.reply(200, wrongKeyResponse);
nock('https://slack.com', {
Expand Down
12 changes: 6 additions & 6 deletions test/support/rumapi.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('rum api', () => {

it('rejects when rum api returns 500', async () => {
nock('https://helix-pages.anywhere.run')
.get('/helix-services/run-query@v3/rotate-domainkeys')
.post('/helix-services/run-query@v3/rotate-domainkeys')
.query(params)
.reply(500);

Expand All @@ -68,7 +68,7 @@ describe('rum api', () => {

it('rejects when rum api returns invalid json', async () => {
nock('https://helix-pages.anywhere.run')
.get('/helix-services/run-query@v3/rotate-domainkeys')
.post('/helix-services/run-query@v3/rotate-domainkeys')
.query(params)
.reply(200, 'invalid-json');

Expand All @@ -78,7 +78,7 @@ describe('rum api', () => {

it('rejects when rum api returns unexpected format', async () => {
nock('https://helix-pages.anywhere.run')
.get('/helix-services/run-query@v3/rotate-domainkeys')
.post('/helix-services/run-query@v3/rotate-domainkeys')
.query(params)
.reply(200, '{ "key": "value" }');

Expand All @@ -88,7 +88,7 @@ describe('rum api', () => {

it('rejects when rum api returns unsuccessful repsonse', async () => {
nock('https://helix-pages.anywhere.run')
.get('/helix-services/run-query@v3/rotate-domainkeys')
.post('/helix-services/run-query@v3/rotate-domainkeys')
.query(params)
.reply(200, wrongKeyResponse);

Expand All @@ -98,7 +98,7 @@ describe('rum api', () => {

it('rejects when rum api returns null key', async () => {
nock('https://helix-pages.anywhere.run')
.get('/helix-services/run-query@v3/rotate-domainkeys')
.post('/helix-services/run-query@v3/rotate-domainkeys')
.query(params)
.reply(200, nullKeyResponse);

Expand All @@ -108,7 +108,7 @@ describe('rum api', () => {

it('returns scoped domain key when successful', async () => {
nock('https://helix-pages.anywhere.run')
.get('/helix-services/run-query@v3/rotate-domainkeys')
.post('/helix-services/run-query@v3/rotate-domainkeys')
.query(params)
.reply(200, successKeyResponse);

Expand Down

0 comments on commit c09e982

Please sign in to comment.