From f60db1b9b48bea23c0393fbabbe9683d40e99f19 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Wed, 19 Jul 2023 23:31:52 -0400 Subject: [PATCH] Updated GitHub progress query & caching --- src/cache.js | 221 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 140 insertions(+), 81 deletions(-) diff --git a/src/cache.js b/src/cache.js index d22f61b..68f8838 100644 --- a/src/cache.js +++ b/src/cache.js @@ -1,106 +1,173 @@ const { GraphQLClient, gql } = require('graphql-request'); const Stripe = require('stripe'); +const logger = require('./logger'); const config = require('../config.json'); -const graphql = new GraphQLClient('https://api.github.com/graphql', { +const github = new GraphQLClient('https://api.github.com/graphql', { headers: { Authorization: `bearer ${config.github.graphql_token}`, } }); + const stripe = new Stripe(config.stripe.secret_key); -const getProjectCards = gql` - fragment ItemContent on Node { - __typename - ... on DraftIssue { - title - } - ... on Issue { - title - } - } - - fragment Itemfields on Node { - __typename - ... on ProjectV2ItemFieldSingleSelectValue { - name, - field { - ... on ProjectV2SingleSelectField { - name - } - } - } - } - - query getProjectCards($orgName: String!) { - organization(login: $orgName) { - projectsV2(first: 100) { - nodes { - repositories(first: 1) { - nodes { - url - } - } - title - items(first: 100) { - nodes { - id - content { - ...ItemContent - } - fieldValues(first: 20) { - nodes { - ...Itemfields - } - } - } - } - } - } - } - } +const getProjectsV2GQL = gql` +query getProjectsV2($orgName: String!, $cursor: String!) { + organization(login: $orgName) { + projectsV2(first: 10, after: $cursor) { + nodes { + id + title + repositories(first: 1) { + nodes { + url + } + } + } + pageInfo { + hasNextPage + endCursor + } + } + } +} `; -let githubProjectsCache; -let stripeDonationCache; +const getProjectsV2FieldsGQL = gql` +query getProjectsV2Fields($id: ID!, $cursor: String!) { + node(id: $id) { + ... on ProjectV2 { + items(first: 10, after: $cursor) { + nodes { + content { + ... on DraftIssue { + title + } + ... on Issue { + title + } + } + fieldValues(first: 20) { + nodes { + ... on ProjectV2ItemFieldSingleSelectValue { + name + field { + ... on ProjectV2SingleSelectField { + name + } + } + } + } + } + } + pageInfo { + hasNextPage + endCursor + } + } + } + } +} +`; -async function getGithubProjectsCache() { - if (!githubProjectsCache) { - githubProjectsCache = await updateGithubProjectsCache(); +let githubProjectsCache = { + update_time: 0, + sections: [] +}; + +let githubCacheBeingFetched = false; + +let stripeDonationCache = { + update_time: 0, + sections: [] +}; + +async function getGitHubProjectsV2(after='') { + let projects = []; + + const data = await github.request(getProjectsV2GQL, { + orgName: 'PretendoNetwork', + cursor: after + }); + + for (const node of data.organization.projectsV2.nodes) { + projects.push({ + id: node.id, + title: node.title, + url: node.repositories.nodes[0]?.url, + }); } - if (githubProjectsCache.update_time < Date.now() - (1000 * 60 * 60)) { - githubProjectsCache = await updateGithubProjectsCache(); + const { hasNextPage, endCursor } = data.organization.projectsV2.pageInfo; + + if (hasNextPage) { + const nextPage = await getGitHubProjectsV2(endCursor); + projects = [...projects, ...nextPage]; + } + + return projects; +} + +async function getGitHubProjectsV2Fields(id, after='') { + let fields = []; + + const data = await github.request(getProjectsV2FieldsGQL, { + id: id, + cursor: after + }); + + for (const node of data.node.items.nodes) { + fields.push({ + title: node.content.title, + column: node.fieldValues.nodes.find(fieldValue => fieldValue.field?.name === 'Status')?.name + }); + } + + const { hasNextPage, endCursor } = data.node.items.pageInfo; + + if (hasNextPage) { + const nextPage = await getGitHubProjectsV2Fields(id, endCursor); + fields = [...fields, ...nextPage]; + } + + return fields; +} + +async function getGithubProjectsCache() { + if (githubCacheBeingFetched) { + return githubProjectsCache; + } + + try { + if (!githubCacheBeingFetched && githubProjectsCache.update_time < Date.now() - (1000 * 60 * 60)) { + githubCacheBeingFetched = true; + githubProjectsCache = await updateGithubProjectsCache(); + } + } catch (error) { + logger.error(error); + } finally { + githubCacheBeingFetched = false; } return githubProjectsCache; } -function getProgressField(fields) { - const found = fields.nodes.find(v => v.field?.name === 'Status'); - return found?.name ?? undefined; -} - async function updateGithubProjectsCache() { const projectsCacheData = { update_time: Date.now(), sections: [] }; - const data = await graphql.request(getProjectCards, { - orgName: 'PretendoNetwork', - }); - - const projects = data.organization.projectsV2.nodes; + const projects = await getGitHubProjectsV2(); for (const project of projects) { - if (!project.repositories.nodes[0]) { + if (!project.url) { continue; } const extractedData = { title: project.title, - url: project.repositories.nodes[0]?.url, + url: project.url, cards: { done: [], in_progress: [], @@ -108,18 +175,10 @@ async function updateGithubProjectsCache() { } }; - for (const { content, fieldValues } of project.items.nodes) { - const progress = getProgressField(fieldValues); + const fields = await getGitHubProjectsV2Fields(project.id); - if (!['DraftIssue'].includes(content.__typename)) { - continue; // not a supported card, skip - } - - if (!progress) { - continue; // entry does not have a status, skip - } - - extractedData.cards[progress.toLowerCase().replace(' ', '_')]?.push(content.title); + for (const field of fields) { + extractedData.cards[field.column.toLowerCase().replace(' ', '_')]?.push(field.title); } projectsCacheData.sections.push(extractedData);