From 63c194924c1f7fbb8144db09f05fa2ef80f1fb96 Mon Sep 17 00:00:00 2001 From: Simon Lecoq <22963968+lowlighter@users.noreply.github.com> Date: Sun, 7 Aug 2022 17:05:21 +0200 Subject: [PATCH] feat(plugins/repositories): add options for starred/random repositories (#1179) --- source/plugins/repositories/index.mjs | 67 ++++++++++++++++--- source/plugins/repositories/metadata.yml | 46 +++++++++++++ .../repositories/queries/random.graphql | 14 ++++ .../repositories/queries/starred.graphql | 14 ++++ .../github/graphql/repositories.random.mjs | 13 ++++ .../github/graphql/repositories.starred.mjs | 13 ++++ 6 files changed, 157 insertions(+), 10 deletions(-) create mode 100644 source/plugins/repositories/queries/random.graphql create mode 100644 source/plugins/repositories/queries/starred.graphql create mode 100644 tests/mocks/api/github/graphql/repositories.random.mjs create mode 100644 tests/mocks/api/github/graphql/repositories.starred.mjs diff --git a/source/plugins/repositories/index.mjs b/source/plugins/repositories/index.mjs index 0f133d9d..e0f3a661 100644 --- a/source/plugins/repositories/index.mjs +++ b/source/plugins/repositories/index.mjs @@ -7,24 +7,67 @@ export default async function({login, q, imports, graphql, queries, data, accoun return null //Load inputs - let {featured, pinned} = imports.metadata.plugins.repositories.inputs({data, account, q}) + let {featured, pinned, starred, random, order, affiliations:_affiliations} = imports.metadata.plugins.repositories.inputs({data, account, q}) + const affiliations = _affiliations?.length ? `ownerAffiliations: [${_affiliations.map(x => x.toLocaleUpperCase()).join(", ")}]` : "" //Initialization const repositories = {list: []} + const processed = new Set() - //Fetch pinned repositories - if (pinned) { - const {user: {pinnedItems: {edges}}} = await graphql(queries.repositories.pinned({login, limit: pinned})) - repositories.list.push(...edges.map(({node}) => format(node))) - } - - //Fetch repositories informations + //Featured repositories for (const repo of featured) { const {owner = login, name} = repo.match(/^(?:(?[\s\S]*)[/])?(?[\s\S]+)$/)?.groups ?? {} const {repository} = await graphql(queries.repositories.repository({owner, name})) - repositories.list.push(format(repository)) + repositories.list.push(format(repository, {sorting:"featured"})) + processed.add(repository.nameWithOwner) } + //Fetch pinned repositories + if (pinned) { + const {user: {pinnedItems: {edges}}} = await graphql(queries.repositories.pinned({login, limit: 6})) + repositories.list.push(...edges.map(({node}) => { + if (processed.has(node.nameWithOwner)) + return null + processed.add(node.nameWithOwner) + return format(node, {sorting: "pinned"}) + }).filter(repository => repository).slice(0, pinned)) + } + + //Fetch starred repositories + if (starred) { + const {user:{ repositories: {nodes}}} = await graphql(queries.repositories.starred({login, limit: Math.min(starred+10, 100), affiliations})) + let count = 0 + for (const node of nodes) { + if (processed.has(node.nameWithOwner)) + continue + const [owner, name] = node.nameWithOwner.split("/") + const {repository} = await graphql(queries.repositories.repository({owner, name})) + repositories.list.push(format(repository, {sorting:"starred"})) + processed.add(repository.nameWithOwner) + if (++count >= starred) + break + } + } + + //Fetch random repositories + if (random) { + const {user:{ repositories: {nodes}}} = await graphql(queries.repositories.random({login, affiliations})) + let count = 0 + for (const node of imports.shuffle(nodes)) { + if (processed.has(node.nameWithOwner)) + continue + const [owner, name] = node.nameWithOwner.split("/") + const {repository} = await graphql(queries.repositories.repository({owner, name})) + repositories.list.push(format(repository, {sorting:"random"})) + processed.add(repository.nameWithOwner) + if (++count >= random) + break + } + } + + //Sorting + repositories.list = repositories.list.sort((a, b) => order.indexOf(a.sorting) - order.indexOf(b.sorting)) + //Results return repositories } @@ -35,7 +78,7 @@ export default async function({login, q, imports, graphql, queries, data, accoun } /**Format repository data */ -function format(repository) { +function format(repository, {sorting} = {}) { //Format date const time = (Date.now() - new Date(repository.createdAt).getTime()) / (24 * 60 * 60 * 1000) let created = new Date(repository.createdAt).toDateString().substring(4) @@ -45,5 +88,9 @@ function format(repository) { created = `${Math.floor(time)} day${time >= 2 ? "s" : ""} ago` repository.created = created + //Sorting + if (sorting) + repository.sorting = sorting + return repository } diff --git a/source/plugins/repositories/metadata.yml b/source/plugins/repositories/metadata.yml index 9157ce77..9a90e3e7 100644 --- a/source/plugins/repositories/metadata.yml +++ b/source/plugins/repositories/metadata.yml @@ -41,3 +41,49 @@ inputs: default: 0 min: 0 max: 6 + + plugin_repositories_starred: + description: | + Featured most starred repositories + type: number + default: 0 + min: 0 + max: 100 + + plugin_repositories_random: + description: | + Featured random repositories + type: number + default: 0 + min: 0 + max: 100 + + plugin_repositories_order: + description: | + Featured repositories display order + type: array + values: + - featured + - pinned + - starred + - random + default: featured, pinned, starred, random + + plugin_repositories_affiliations: + description: | + Repositories affiliations + + - `owner`: owned repositories + - `collaborator`: repositories with push access + - `organization_member`: repositories from an organization where user is a member + + Set to `""` to disable and fetch all repositories related to given account. + + This option changes which repositories will be fetched by [`plugin_repositories_starred`](/source/plugins/projects/README.md#plugin_repositories_starred) and [`plugin_repositories_random`](/source/plugins/projects/README.md#plugin_repositories_random) options + type: array + format: comma-separated + default: owner + values: + - owner + - collaborator + - organization_member \ No newline at end of file diff --git a/source/plugins/repositories/queries/random.graphql b/source/plugins/repositories/queries/random.graphql new file mode 100644 index 00000000..1e151b08 --- /dev/null +++ b/source/plugins/repositories/queries/random.graphql @@ -0,0 +1,14 @@ +query RepositoriesRandom { + user(login: "$login") { + repositories( + orderBy: {field: UPDATED_AT, direction: DESC} + first: 100 + privacy: PUBLIC + $affiliations + ) { + nodes { + nameWithOwner + } + } + } +} diff --git a/source/plugins/repositories/queries/starred.graphql b/source/plugins/repositories/queries/starred.graphql new file mode 100644 index 00000000..435be443 --- /dev/null +++ b/source/plugins/repositories/queries/starred.graphql @@ -0,0 +1,14 @@ +query RepositoriesStarred { + user(login: "$login") { + repositories( + orderBy: {field: STARGAZERS, direction: DESC} + first: $limit + privacy: PUBLIC + $affiliations + ) { + nodes { + nameWithOwner + } + } + } +} diff --git a/tests/mocks/api/github/graphql/repositories.random.mjs b/tests/mocks/api/github/graphql/repositories.random.mjs new file mode 100644 index 00000000..41885cee --- /dev/null +++ b/tests/mocks/api/github/graphql/repositories.random.mjs @@ -0,0 +1,13 @@ +/**Mocked data */ +export default function({faker, query, login = faker.internet.userName()}) { + console.debug("metrics/compute/mocks > mocking graphql api result > repositories/randodm") + return ({ + user: { + repositories: { + nodes: [ + {nameWithOwner: "lowlighter/metrics"}, + ] + } + }, + }) +} diff --git a/tests/mocks/api/github/graphql/repositories.starred.mjs b/tests/mocks/api/github/graphql/repositories.starred.mjs new file mode 100644 index 00000000..f7ef3918 --- /dev/null +++ b/tests/mocks/api/github/graphql/repositories.starred.mjs @@ -0,0 +1,13 @@ +/**Mocked data */ +export default function({faker, query, login = faker.internet.userName()}) { + console.debug("metrics/compute/mocks > mocking graphql api result > repositories/starred") + return ({ + user: { + repositories: { + nodes: [ + {nameWithOwner: "lowlighter/metrics"}, + ] + } + }, + }) +}