Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fixed dashboard scripts #3304

Merged
merged 10 commits into from
Oct 23, 2024
8 changes: 4 additions & 4 deletions .github/workflows/regenerate-meetings-and-videos.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: List everyday latest list of AsyncAPI Meetings, Newsroom Videos and Dashboard data.

on:
on:
workflow_dispatch:
schedule:
#every day at midnight
Expand All @@ -23,7 +23,7 @@ jobs:
- name: Check package-lock version
uses: asyncapi/.github/.github/actions/get-node-version-from-package-lock@master
id: lockversion

- name: Use Node.js
uses: actions/setup-node@v3
with:
Expand All @@ -45,7 +45,7 @@ jobs:
committer: asyncapi-bot <[email protected]>
author: asyncapi-bot <[email protected]>
title: 'chore: update meetings.json and newsrooom_videos.json'
branch: update-meetings/${{ github.job }}
branch: update-meetings/${{ github.sha }}
- if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel
name: Report workflow run status to Slack
uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 #using https://github.com/8398a7/action-slack/releases/tag/v3.15.1
Expand All @@ -54,4 +54,4 @@ jobs:
fields: repo,action,workflow
text: 'AsyncAPI Meetings and Videos workflow failed'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }}
10 changes: 2 additions & 8 deletions components/newsroom/Newsroom.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import { TwitterTimelineEmbed } from 'react-twitter-embed';

import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';
Expand Down Expand Up @@ -69,19 +68,14 @@ export default function Newsroom() {
</div>
</div>

<div className='w-full flex-row items-stretch justify-between md:flex lg:w-3/4'>
<div className='w-full flex-row items-stretch justify-between md:flex md:h-120 lg:w-3/4'>
<div className='relative flex w-full flex-col overflow-y-auto md:w-1/2'>
<div className='min-h-0'>
<div className='md:t-0 md:b-0 md:l-0 md:r-0 size-full max-h-120 md:absolute'>
<div className='md:t-0 md:b-0 md:l-0 md:r-0 size-full md:absolute'>
<NewsroomArticle />
</div>
</div>
</div>
<div className='w-full px-2 md:w-1/2 md:pl-4 md:pr-0'>
<div className='mx-auto mt-8 w-full rounded-xl shadow-md md:mt-0' data-testid='Newsroom-Twitter'>
<TwitterTimelineEmbed sourceType='profile' screenName='AsyncAPISpec' options={{ tweetLimit: '2' }} />
</div>
</div>
</div>
</div>

Expand Down
190 changes: 100 additions & 90 deletions scripts/dashboard/build-dashboard.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,90 @@
const { writeFileSync } = require('fs');
const { resolve } = require('path');
const { graphql } = require('@octokit/graphql');
const { Promise } = require('node-fetch');
const { Queries } = require('./issue-queries');

async function getHotDiscussions(discussions) {
const result = await Promise.all(
discussions.map(async (discussion) => {
/**
* Introduces a delay in the execution flow.
* @param {number} ms - The number of milliseconds to pause.
* @returns {Promise<void>} A promise that resolves after the specified delay.
*/
async function pause(ms) {
return new Promise((res) => {
setTimeout(res, ms);

Check warning on line 13 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L12-L13

Added lines #L12 - L13 were not covered by tests
});
}

async function getDiscussions(query, pageSize, endCursor = null) {
try {
const result = await graphql(query, {

Check warning on line 19 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L18-L19

Added lines #L18 - L19 were not covered by tests
first: pageSize,
after: endCursor,
headers: {
authorization: `token ${process.env.GITHUB_TOKEN}`
}
});

if (result.rateLimit.remaining <= 100) {
console.log(

Check warning on line 28 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L27-L28

Added lines #L27 - L28 were not covered by tests
`[WARNING] GitHub GraphQL rateLimit`,
`cost = ${result.rateLimit.cost}`,
`limit = ${result.rateLimit.limit}`,
`remaining = ${result.rateLimit.remaining}`,
`resetAt = ${result.rateLimit.resetAt}`
);
}

await pause(500);

Check warning on line 37 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L37

Added line #L37 was not covered by tests

const { hasNextPage } = result.search.pageInfo;

Check warning on line 39 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L39

Added line #L39 was not covered by tests

if (!hasNextPage) {
return result.search.nodes;

Check warning on line 42 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L41-L42

Added lines #L41 - L42 were not covered by tests
}
return result.search.nodes.concat(await getDiscussions(query, pageSize, result.search.pageInfo.endCursor));

Check warning on line 44 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L44

Added line #L44 was not covered by tests
} catch (e) {
console.error(e);

Check warning on line 46 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L46

Added line #L46 was not covered by tests

return Promise.reject(e);

Check warning on line 48 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L48

Added line #L48 was not covered by tests
Copy link

@coderabbitai coderabbitai bot Oct 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify Error Handling by Throwing Errors Directly

In async functions, instead of returning Promise.reject(e);, it's cleaner to throw the error directly using throw e;. This makes the code more idiomatic and easier to read.

Apply this diff:

// In the getDiscussions function
-    return Promise.reject(e);
+    throw e;

// In the getDiscussionByID function
-    return Promise.reject(e);
+    throw e;

Also applies to: 59-59

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 43-43: scripts/dashboard/build-dashboard.js#L43
Added line #L43 was not covered by tests

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will improve this readiness of the code in another PR.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akshatnema, understood. Would you like me to open a new GitHub issue to track this improvement?

🐰😔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure 👍 . Please do it.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akshatnema, I've opened a new GitHub issue to track this improvement: Issue #3305.

🐰😊

🔗 Analysis chain
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash

# Create a new GitHub issue to track the requested improvement.
gh issue create \
  --title "Simplify error handling in build-dashboard.js" \
  --body "As discussed in [PR #3304](https://github.com/asyncapi/website/pull/3304) ([comment](https://github.com/asyncapi/website/pull/3304#discussion_r1807819750)), @akshatnema agreed to improve the error handling by throwing errors directly instead of using \`Promise.reject(e);\` in the \`build-dashboard.js\` script.

We should update the error handling code to throw errors directly, making the asynchronous functions more idiomatic and easier to read." \
  --assignee akshatnema

Length of output: 597

}
}
async function getDiscussionByID(isPR, id) {
try {
const result = await graphql(isPR ? Queries.pullRequestById : Queries.issueById, {

Check warning on line 53 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L52-L53

Added lines #L52 - L53 were not covered by tests
id,
headers: {
authorization: `token ${process.env.GITHUB_TOKEN}`
}
});

return result;

Check warning on line 60 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L60

Added line #L60 was not covered by tests
} catch (e) {
console.error(e);

Check warning on line 62 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L62

Added line #L62 was not covered by tests

return Promise.reject(e);

Check warning on line 64 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L64

Added line #L64 was not covered by tests
}
}

async function processHotDiscussions(batch) {
return Promise.all(

Check warning on line 69 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L69

Added line #L69 was not covered by tests
batch.map(async (discussion) => {
try {
// eslint-disable-next-line no-underscore-dangle
const isPR = discussion.__typename === 'PullRequest';
if (discussion.comments.pageInfo.hasNextPage) {
let fetchedDiscussion = await getDiscussionByID(isPR, discussion.id);
const fetchedDiscussion = await getDiscussionByID(isPR, discussion.id);

Check warning on line 75 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L75

Added line #L75 was not covered by tests
discussion = fetchedDiscussion.node;
}

const interactionsCount =
discussion.reactions.totalCount +
discussion.comments.totalCount +
discussion.comments.nodes.reduce(
(acc, curr) => acc + curr.reactions.totalCount,
0
);
discussion.comments.nodes.reduce((acc, curr) => acc + curr.reactions.totalCount, 0);

Check warning on line 82 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L82

Added line #L82 was not covered by tests

const finalInteractionsCount = isPR
? interactionsCount +
discussion.reviews.totalCount +
discussion.reviews.nodes.reduce(
(acc, curr) => acc + curr.comments.totalCount,
0
)
discussion.reviews.totalCount +
discussion.reviews.nodes.reduce((acc, curr) => acc + curr.comments.totalCount, 0)

Check warning on line 87 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L87

Added line #L87 was not covered by tests
: interactionsCount;
return {
id: discussion.id,
Expand All @@ -37,130 +93,84 @@
title: discussion.title,
author: discussion.author ? discussion.author.login : '',
resourcePath: discussion.resourcePath,
repo: 'asyncapi/' + discussion.repository.name,
repo: `asyncapi/${discussion.repository.name}`,
labels: discussion.labels ? discussion.labels.nodes : [],
score:
finalInteractionsCount /
Math.pow(monthsSince(discussion.timelineItems.updatedAt) + 2, 1.8),
score: finalInteractionsCount / (monthsSince(discussion.timelineItems.updatedAt) + 2) ** 1.8
};
} catch (e) {
console.error(
`there was some issues while parsing this item: ${JSON.stringify(
discussion
)}`
);
console.error(`there was some issues while parsing this item: ${JSON.stringify(discussion)}`);

Check warning on line 101 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L101

Added line #L101 was not covered by tests
throw e;
}
})
);
}

async function getHotDiscussions(discussions) {
const result = [];
const batchSize = 5;

Check warning on line 110 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L109-L110

Added lines #L109 - L110 were not covered by tests

for (let i = 0; i < discussions.length; i += batchSize) {
const batch = discussions.slice(i, i + batchSize);

Check warning on line 113 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L112-L113

Added lines #L112 - L113 were not covered by tests
// eslint-disable-next-line no-await-in-loop
const batchResults = await processHotDiscussions(batch);

Check warning on line 115 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L115

Added line #L115 was not covered by tests

// eslint-disable-next-line no-await-in-loop
await pause(1000);

Check warning on line 118 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L118

Added line #L118 was not covered by tests
Comment on lines +110 to +118
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider making batch parameters configurable.

The batch size and pause duration are currently hardcoded. Consider making these configurable through environment variables for easier tuning:

+const BATCH_SIZE = parseInt(process.env.GITHUB_API_BATCH_SIZE, 10) || 5;
+const BATCH_PAUSE_MS = parseInt(process.env.GITHUB_API_BATCH_PAUSE_MS, 10) || 1000;
-  const batchSize = 5;
+  const batchSize = BATCH_SIZE;
-    await pause(1000);
+    await pause(BATCH_PAUSE_MS);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const batchSize = 5;
for (let i = 0; i < discussions.length; i += batchSize) {
const batch = discussions.slice(i, i + batchSize);
// eslint-disable-next-line no-await-in-loop
const batchResults = await processHotDiscussions(batch);
// eslint-disable-next-line no-await-in-loop
await pause(1000);
const BATCH_SIZE = parseInt(process.env.GITHUB_API_BATCH_SIZE, 10) || 5;
const BATCH_PAUSE_MS = parseInt(process.env.GITHUB_API_BATCH_PAUSE_MS, 10) || 1000;
for (let i = 0; i < discussions.length; i += batchSize) {
const batch = discussions.slice(i, i + batchSize);
// eslint-disable-next-line no-await-in-loop
const batchResults = await processHotDiscussions(batch);
// eslint-disable-next-line no-await-in-loop
await pause(BATCH_PAUSE_MS);
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 112-113: scripts/dashboard/build-dashboard.js#L112-L113
Added lines #L112 - L113 were not covered by tests


[warning] 115-115: scripts/dashboard/build-dashboard.js#L115
Added line #L115 was not covered by tests


[warning] 118-118: scripts/dashboard/build-dashboard.js#L118
Added line #L118 was not covered by tests


result.push(...batchResults);

Check warning on line 120 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L120

Added line #L120 was not covered by tests
}
result.sort((ElemA, ElemB) => ElemB.score - ElemA.score);
const filteredResult = result.filter(issue => issue.author !== 'asyncapi-bot');
const filteredResult = result.filter((issue) => issue.author !== 'asyncapi-bot');

Check warning on line 123 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L123

Added line #L123 was not covered by tests
return filteredResult.slice(0, 12);
}
async function writeToFile(content) {
writeFileSync(
resolve(__dirname, '..', '..', 'dashboard.json'),
JSON.stringify(content, null, ' ')
);
writeFileSync(resolve(__dirname, '..', '..', 'dashboard.json'), JSON.stringify(content, null, ' '));

Check warning on line 127 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L127

Added line #L127 was not covered by tests
}
async function mapGoodFirstIssues(issues) {
return issues.map((issue) => ({
id: issue.id,
title: issue.title,
isAssigned: !!issue.assignees.totalCount,
resourcePath: issue.resourcePath,
repo: 'asyncapi/' + issue.repository.name,
repo: `asyncapi/${issue.repository.name}`,
author: issue.author.login,
area: getLabel(issue, 'area/') || 'Unknown',
labels: issue.labels.nodes.filter(
(label) =>
!label.name.startsWith('area/') &&
!label.name.startsWith('good first issue')
),
(label) => !label.name.startsWith('area/') && !label.name.startsWith('good first issue')

Check warning on line 139 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L139

Added line #L139 was not covered by tests
)
}));
}

function getLabel(issue, filter) {
const result = issue.labels.nodes.find((label) =>
label.name.startsWith(filter)
);
return result && result.name.split('/')[1];
const result = issue.labels.nodes.find((label) => label.name.startsWith(filter));
return result?.name.split('/')[1];

Check warning on line 146 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L145-L146

Added lines #L145 - L146 were not covered by tests
}


function monthsSince(date) {
const seconds = Math.floor((new Date() - new Date(date)) / 1000);
// 2592000 = number of seconds in a month = 30 * 24 * 60 * 60
const months = seconds / 2592000;
return Math.floor(months);
}

async function getDiscussions(query, pageSize, endCursor = null) {
try {
let result = await graphql(query, {
first: pageSize,
after: endCursor,
headers: {
authorization: `token ${process.env.GITHUB_TOKEN}`,
},
});

if (result.rateLimit.remaining <= 100) {
console.log(
`[WARNING] GitHub GraphQL rateLimit`,
`cost = ${result.rateLimit.cost}`,
`limit = ${result.rateLimit.limit}`,
`remaining = ${result.rateLimit.remaining}`,
`resetAt = ${result.rateLimit.resetAt}`
)
}

const hasNextPage = result.search.pageInfo.hasNextPage;

if (!hasNextPage) {
return result.search.nodes;
} else {
return result.search.nodes.concat(
await getDiscussions(query, pageSize, result.search.pageInfo.endCursor)
);
}
} catch (e) {
console.error(e);
}
}
async function getDiscussionByID(isPR, id) {
try {
let result = await graphql(isPR ? Queries.pullRequestById : Queries.issueById, {
id,
headers: {
authorization: `token ${process.env.GITHUB_TOKEN}`,
},

}
);
return result;
} catch (e) {
console.error(e);
}
}
async function start() {
try {
const [issues, PRs, rawGoodFirstIssues] = await Promise.all([
getDiscussions(Queries.hotDiscussionsIssues, 20),
getDiscussions(Queries.hotDiscussionsPullRequests, 20),
getDiscussions(Queries.goodFirstIssues, 20),
getDiscussions(Queries.goodFirstIssues, 20)
]);
const discussions = issues.concat(PRs);
const [hotDiscussions, goodFirstIssues] = await Promise.all([
getHotDiscussions(discussions),
mapGoodFirstIssues(rawGoodFirstIssues),
mapGoodFirstIssues(rawGoodFirstIssues)
]);
writeToFile({ hotDiscussions, goodFirstIssues });
} catch (e) {
console.log('There were some issues parsing data from github.')
console.log('There were some issues parsing data from github.');

Check warning on line 170 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L170

Added line #L170 was not covered by tests
console.log(e);
}
}
start();

module.exports = { getLabel, monthsSince, mapGoodFirstIssues, getHotDiscussions, getDiscussionByID }
module.exports = { getLabel, monthsSince, mapGoodFirstIssues, getHotDiscussions, getDiscussionByID };

Check warning on line 176 in scripts/dashboard/build-dashboard.js

View check run for this annotation

Codecov / codecov/patch

scripts/dashboard/build-dashboard.js#L176

Added line #L176 was not covered by tests
Loading