diff --git a/README.md b/README.md index 0417e52b..0bb26d87 100644 --- a/README.md +++ b/README.md @@ -1508,6 +1508,18 @@ Is is possible to commit generated metrics in a specific branch rather than defa committer_branch: my-branch ``` +#### 🍴 Including forked repositories + + 🚧 This feature is available as pre-release on @master branch (unstable) + +Is is possible to include forked repositories into generated metrics by adding the following to your workflow: +```yaml +- uses: lowlighter/metrics@master + with: + # ... other options + repositories_forks: yes +``` + #### 💱 Convert output to PNG/JPEG It is possible to convert output from SVG to PNG or JPEG images by adding the following to your workflow: diff --git a/action.yml b/action.yml index 6a3f9efb..3e84f9bb 100644 --- a/action.yml +++ b/action.yml @@ -84,6 +84,11 @@ inputs: description: Number of repositories to use default: 100 + # Whether to include forked repositories into metrics + repositories_forks: + description: Include forks in metrics + default: no + # Template to use # See https://github.com/lowlighter/metrics/tree/master/source/templates for supported templates template: diff --git a/source/app/action/index.mjs b/source/app/action/index.mjs index 9b9e77b5..e4be393c 100644 --- a/source/app/action/index.mjs +++ b/source/app/action/index.mjs @@ -238,7 +238,9 @@ //Repositories to use const repositories = input.number("repositories") + const forks = input.bool("repositories_forks") info("Repositories to process", repositories) + info("Include forked repositories", forks) //Die on plugins errors const die = input.bool("plugins_errors_fatal") @@ -247,7 +249,7 @@ //Build query const query = input.object("query") info("Query additional params", query) - q = {...query, ...q, base:false, ...base, ...config, repositories, template} + q = {...query, ...q, base:false, ...base, ...config, repositories, "repositories.forks":forks, template} //Render metrics const {rendered} = await metrics({login:user, q, dflags}, {graphql, rest, plugins, conf, die, verify}, {Plugins, Templates}) diff --git a/source/app/metrics.mjs b/source/app/metrics.mjs index e4b31c73..42f26cad 100644 --- a/source/app/metrics.mjs +++ b/source/app/metrics.mjs @@ -51,7 +51,8 @@ else { //Query data from GitHub API console.debug(`metrics/compute/${login} > graphql query`) - Object.assign(data, await graphql(queries.common({login, "calendar.from":new Date(Date.now()-14*24*60*60*1000).toISOString(), "calendar.to":(new Date()).toISOString()}))) + const forks = q["repositories.forks"] || false + Object.assign(data, await graphql(queries.common({login, "calendar.from":new Date(Date.now()-14*24*60*60*1000).toISOString(), "calendar.to":(new Date()).toISOString(), forks:forks ? "" : ", isFork: false"}))) //Query repositories from GitHub API { //Iterate through repositories @@ -59,7 +60,7 @@ let pushed = 0 do { console.debug(`metrics/compute/${login} > retrieving repositories after ${cursor}`) - const {user:{repositories:{edges, nodes}}} = await graphql(queries.repositories({login, after:cursor ? `after: "${cursor}"` : "", repositories:Math.min(repositories, 100)})) + const {user:{repositories:{edges, nodes}}} = await graphql(queries.repositories({login, after:cursor ? `after: "${cursor}"` : "", repositories:Math.min(repositories, 100), forks:forks ? "" : ", isFork: false"})) cursor = edges?.[edges?.length-1]?.cursor data.user.repositories.nodes.push(...nodes) pushed = nodes.length @@ -90,7 +91,7 @@ //Template rendering console.debug(`metrics/compute/${login} > render`) - let rendered = await ejs.render(image, {...data, s, style, fonts}, {views, async:true}) + let rendered = await ejs.render(image, {...data, s, f:format, style, fonts}, {views, async:true}) //Apply resizing const {resized, mime} = await svgresize(rendered, {paddings:q["config.padding"], convert}) rendered = resized @@ -129,11 +130,11 @@ } /** Formatter */ - function format(n) { + function format(n, {sign = false} = {}) { for (const {u, v} of [{u:"b", v:10**9}, {u:"m", v:10**6}, {u:"k", v:10**3}]) if (n/v >= 1) - return `${(n/v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")}${u}` - return n + return `${(sign)&&(n > 0) ? "+" : ""}${(n/v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")}${u}` + return `${(sign)&&(n > 0) ? "+" : ""}${n}` } /** Bytes formatter */ diff --git a/source/app/mocks.mjs b/source/app/mocks.mjs index 9846e5f6..fe6c7408 100644 --- a/source/app/mocks.mjs +++ b/source/app/mocks.mjs @@ -113,6 +113,7 @@ name:"metrics", watchers:{totalCount:Math.floor(Math.random()*100)}, stargazers:{totalCount:Math.floor(Math.random()*1000)}, + owner:{login:"lowlighter"}, languages:{ edges:[ {size:111733, node:{color:"#f1e05a", name:"JavaScript"} @@ -141,6 +142,7 @@ user:{ repository:{ name:"metrics", + owner:{login:"lowlighter"}, createdAt:new Date().toISOString(), diskUsage:Math.floor(Math.random()*10000), watchers:{totalCount:Math.floor(Math.random()*100)}, diff --git a/source/plugins/lines/index.mjs b/source/plugins/lines/index.mjs index 20078db8..26a56c08 100644 --- a/source/plugins/lines/index.mjs +++ b/source/plugins/lines/index.mjs @@ -6,11 +6,11 @@ if ((!enabled)||(!q.lines)) return null //Repositories - const repositories = data.user.repositories.nodes.map(({name}) => name) ?? [] + const repositories = data.user.repositories.nodes.map(({name:repo, owner:{login:owner}}) => ({repo, owner})) ?? [] //Get contributors stats from repositories console.debug(`metrics/compute/${login}/plugins > lines > querying api`) const lines = {added:0, deleted:0} - const response = await Promise.all(repositories.map(async repo => await rest.repos.getContributorsStats({owner:login, repo}))) + const response = await Promise.all(repositories.map(async ({repo, owner}) => await rest.repos.getContributorsStats({owner, repo}))) //Compute changed lines console.debug(`metrics/compute/${login}/plugins > lines > computing total diff`) response.map(({data:repository}) => { @@ -23,9 +23,6 @@ if (contributor) contributor.weeks.forEach(({a, d}) => (lines.added += a, lines.deleted += d)) }) - //Format values - lines.added = imports.format(lines.added) - lines.deleted = imports.format(lines.deleted) //Results return lines } diff --git a/source/plugins/stargazers/index.mjs b/source/plugins/stargazers/index.mjs index 46dce80a..c6c09466 100644 --- a/source/plugins/stargazers/index.mjs +++ b/source/plugins/stargazers/index.mjs @@ -47,11 +47,6 @@ } total.min = Math.min(...Object.values(total.dates)) total.max = Math.max(...Object.values(total.dates)) - //Format values - for (const date in increments.dates) - increments.dates[date] = {value:increments.dates[date], text:`${increments.dates[date] > 0 ? "+" : ""}${imports.format(increments.dates[date])}`} - for (const date in total.dates) - total.dates[date] = {value:total.dates[date], text:imports.format(total.dates[date])} //Months name const months = ["", "Jan.", "Feb.", "Mar.", "Apr.", "May", "June", "July", "Aug.", "Sep.", "Oct.", "Nov.", "Dec."] //Results diff --git a/source/plugins/stars/index.mjs b/source/plugins/stars/index.mjs index d26450e6..8a8e4f99 100644 --- a/source/plugins/stars/index.mjs +++ b/source/plugins/stars/index.mjs @@ -14,9 +14,6 @@ const {user:{starredRepositories:{edges:repositories}}} = await graphql(queries.starred({login, limit})) //Format starred repositories for (const edge of repositories) { - //Formats values - edge.node.stargazers = imports.format(edge.node.stargazerCount) - edge.node.forks = imports.format(edge.node.forkCount) //Format date const time = (Date.now()-new Date(edge.starredAt).getTime())/(24*60*60*1000) let updated = new Date(edge.starredAt).toDateString().substring(4) diff --git a/source/plugins/traffic/index.mjs b/source/plugins/traffic/index.mjs index 397e5b79..5d78bd64 100644 --- a/source/plugins/traffic/index.mjs +++ b/source/plugins/traffic/index.mjs @@ -6,17 +6,14 @@ if ((!enabled)||(!q.traffic)) return null //Repositories - const repositories = data.user.repositories.nodes.map(({name}) => name) ?? [] + const repositories = data.user.repositories.nodes.map(({name:repo, owner:{login:owner}}) => ({repo, owner})) ?? [] //Get views stats from repositories console.debug(`metrics/compute/${login}/plugins > traffic > querying api`) const views = {count:0, uniques:0} - const response = await Promise.all(repositories.map(async repo => await rest.repos.getViews({owner:login, repo}))) + const response = await Promise.all(repositories.map(async ({repo, owner}) => await rest.repos.getViews({owner, repo}))) //Compute views console.debug(`metrics/compute/${login}/plugins > traffic > computing stats`) response.filter(({data}) => data).map(({data:{count, uniques}}) => (views.count += count, views.uniques += uniques)) - //Format values - views.count = imports.format(views.count) - views.uniques = imports.format(views.uniques) //Results return {views} } diff --git a/source/queries/common.graphql b/source/queries/common.graphql index f29488e2..f7334c55 100644 --- a/source/queries/common.graphql +++ b/source/queries/common.graphql @@ -8,7 +8,7 @@ query Metrics { websiteUrl isHireable twitterUsername - repositories(last: 0, isFork: false, ownerAffiliations: OWNER) { + repositories(last: 0 $forks) { totalCount totalDiskUsage nodes { diff --git a/source/queries/repositories.graphql b/source/queries/repositories.graphql index 04355b3e..c22469b1 100644 --- a/source/queries/repositories.graphql +++ b/source/queries/repositories.graphql @@ -1,11 +1,15 @@ query Repositories { user(login: "$login") { - repositories($after first: $repositories, isFork: false, ownerAffiliations: OWNER, orderBy: {field: UPDATED_AT, direction: DESC}) { + repositories($after first: $repositories $forks, orderBy: {field: UPDATED_AT, direction: DESC}) { edges { cursor } nodes { name + owner { + login + } + isFork watchers { totalCount } diff --git a/source/queries/repository.graphql b/source/queries/repository.graphql index e18683e2..ad919e94 100644 --- a/source/queries/repository.graphql +++ b/source/queries/repository.graphql @@ -2,6 +2,10 @@ query Repository { user(login: "$login") { repository(name: "$repo") { name + owner { + login + } + isFork createdAt diskUsage homepageUrl diff --git a/source/queries/starred.graphql b/source/queries/starred.graphql index 21342557..35e5c137 100644 --- a/source/queries/starred.graphql +++ b/source/queries/starred.graphql @@ -14,6 +14,7 @@ query Starred { openGraphImageUrl licenseInfo { nickname + spdxId name } pullRequests { diff --git a/source/templates/classic/partials/base.repositories.ejs b/source/templates/classic/partials/base.repositories.ejs index 8bc79dce..05d30986 100644 --- a/source/templates/classic/partials/base.repositories.ejs +++ b/source/templates/classic/partials/base.repositories.ejs @@ -2,7 +2,7 @@

- <%= user.repositories.totalCount %> Repositor<%= s(user.repositories.totalCount, "y") %> + <%= user.repositories.totalCount %> Repositor<%= s(user.repositories.totalCount, "y") %> <%= computed.repositories.forked ? `(including ${computed.repositories.forked} fork${s(computed.repositories.forked)})` : "" %>

@@ -32,7 +32,7 @@ <% if (plugins.lines.error) { %> <%= plugins.lines.error.message %> <% } else { %> - <%= plugins.lines.added %> added, <%= plugins.lines.deleted %> removed + <%= f(plugins.lines.added) %> added, <%= f(plugins.lines.deleted) %> removed <% } %>
<% } %> @@ -60,7 +60,7 @@ <% if (plugins.traffic.error) { %> <%= plugins.traffic.error.message %> <% } else { %> - <%= plugins.traffic.views.count %> view<%= s(plugins.traffic.views.count) %> in last two weeks + <%= f(plugins.traffic.views.count) %> view<%= s(plugins.traffic.views.count) %> in last two weeks <% } %> <% } %> diff --git a/source/templates/classic/partials/stargazers.ejs b/source/templates/classic/partials/stargazers.ejs index 86e13d67..3468b7ff 100644 --- a/source/templates/classic/partials/stargazers.ejs +++ b/source/templates/classic/partials/stargazers.ejs @@ -14,9 +14,9 @@

Total stargazers

- <% { let previous = null; for (const [date, {value, text}] of Object.entries(plugins.stargazers.total.dates)) { const p = 0.05+0.95*(value-plugins.stargazers.total.min)/(plugins.stargazers.total.max-plugins.stargazers.total.min); const [y, m, d] = date.split("-").map(Number) %> + <% { let previous = null; for (const [date, value] of Object.entries(plugins.stargazers.total.dates)) { const p = 0.05+0.95*(value-plugins.stargazers.total.min)/(plugins.stargazers.total.max-plugins.stargazers.total.min); const [y, m, d] = date.split("-").map(Number) %>
- <%= (value-(previous ?? 0)) ? text : "" %> + <%= (value-(previous ?? 0)) ? f(value) : "" %>
<%= d %> <% if ((previous === null)||(d === 1)) { %> @@ -29,9 +29,9 @@

New stargazers per day

- <% { let previous = null; for (const [date, {value, text}] of Object.entries(plugins.stargazers.increments.dates)) { const p = value/plugins.stargazers.increments.max; const [y, m, d] = date.split("-").map(Number) %> + <% { let previous = null; for (const [date, value] of Object.entries(plugins.stargazers.increments.dates)) { const p = value/plugins.stargazers.increments.max; const [y, m, d] = date.split("-").map(Number) %>
- <%= value != 0 ? text : "" %> + <%= value != 0 ? f(value, {sign:true}) : "" %>
<%= d %> <% if ((previous === null)||(d === 1)) { %> diff --git a/source/templates/classic/partials/stars.ejs b/source/templates/classic/partials/stars.ejs index b0f1af9f..e4368b90 100644 --- a/source/templates/classic/partials/stars.ejs +++ b/source/templates/classic/partials/stars.ejs @@ -39,24 +39,24 @@ <% if (repository.licenseInfo) { %>
- <%= repository.licenseInfo.nickname ?? repository.licenseInfo.name %> + <%= repository.licenseInfo.nickname ?? repository.licenseInfo.spdxId ?? repository.licenseInfo.name %>
<% } %>
- <%= repository.stargazers %> + <%= f(repository.stargazerCount) %>
- <%= repository.forks %> + <%= f(repository.forkCount) %>
- <%= repository.issues.totalCount %> + <%= f(repository.issues.totalCount) %>
- <%= repository.pullRequests.totalCount %> + <%= f(repository.pullRequests.totalCount) %>
diff --git a/source/templates/common.mjs b/source/templates/common.mjs index 10fe0e46..07156c43 100644 --- a/source/templates/common.mjs +++ b/source/templates/common.mjs @@ -2,7 +2,7 @@ export default async function ({login, q, dflags}, {conf, data, rest, graphql, plugins, queries}, {s, pending, imports}) { //Init - const computed = data.computed = {commits:0, sponsorships:0, licenses:{favorite:"", used:{}}, token:{}, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_merged:0, forks:0, releases:0}} + const computed = data.computed = {commits:0, sponsorships:0, licenses:{favorite:"", used:{}}, token:{}, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_merged:0, forks:0, forked:0, releases:0}} const avatar = imports.imgb64(data.user.avatarUrl) console.debug(`metrics/compute/${login} > formatting common metrics`) @@ -54,6 +54,8 @@ computed.repositories[property] += repository[property].totalCount //Forks computed.repositories.forks += repository.forkCount + if (repository.isFork) + computed.repositories.forked++ //License if (repository.licenseInfo) computed.licenses.used[repository.licenseInfo.spdxId] = (computed.licenses.used[repository.licenseInfo.spdxId] ?? 0) + 1 diff --git a/source/templates/repository/partials/base.header.ejs b/source/templates/repository/partials/base.header.ejs index 24b94a1d..97a7a5b6 100644 --- a/source/templates/repository/partials/base.header.ejs +++ b/source/templates/repository/partials/base.header.ejs @@ -25,7 +25,7 @@ <% if (plugins.traffic.error) { %> <%= plugins.traffic.error.message %> <% } else { %> - <%= plugins.traffic.views.count %> view<%= s(plugins.traffic.views.count) %> in last two weeks + <%= f(plugins.traffic.views.count) %> view<%= s(plugins.traffic.views.count) %> in last two weeks <% } %>
<% } %> @@ -46,7 +46,7 @@ <% if (plugins.lines.error) { %> <%= plugins.lines.error.message %> <% } else { %> - <%= plugins.lines.added %> added, <%= plugins.lines.deleted %> removed + <%= f(plugins.lines.added) %> added, <%= f(plugins.lines.deleted) %> removed <% } %>
<% } %> diff --git a/source/templates/terminal/partials/base.repositories.ejs b/source/templates/terminal/partials/base.repositories.ejs index 3885c3d0..8da6610f 100644 --- a/source/templates/terminal/partials/base.repositories.ejs +++ b/source/templates/terminal/partials/base.repositories.ejs @@ -1,11 +1,11 @@ <% if (base.repositories) { %>
<%- meta.$ %> ls -lh github/repositories
<%# -%>
<%# -%> -Total <%= user.repositories.totalCount %> repositor<%= s(user.repositories.totalCount, "y") %> - <%= computed.diskUsage %> +Total <%= user.repositories.totalCount %> repositor<%= s(user.repositories.totalCount, "y") %><%= computed.repositories.forked ? ` - ${computed.repositories.forked} fork${s(computed.repositories.forked)}` : "" %> - <%= computed.diskUsage %> <% if (plugins.traffic) { if (plugins.traffic.error) { -%> ---- views (<%= plugins.traffic.error.message %>) <% } else { -%> --r-- <%= `${plugins.traffic.views.count}`.padStart(5) %> views +-r-- <%= `${f(plugins.traffic.views.count)}`.padStart(5) %> views <% }} -%> -r-- <%= `${computed.repositories.stargazers}`.padStart(5) %> stargazer<%= s(computed.repositories.stargazers) %> -r-- <%= `${computed.repositories.forks}`.padStart(5) %> fork<%= s(computed.repositories.forks) %> @@ -28,6 +28,6 @@ dr-x LICENSE <% } -%> <% if (plugins.lines) { if (plugins.lines.error) { %> @@ <%= plugins.lines.error.message %> @@<% } else { %> -@@ -<%= plugins.lines.deleted %> +<%= plugins.lines.added %> @@ +@@ -<%= f(plugins.lines.deleted) %> +<%= f(plugins.lines.added) %> @@ <% }} -%>
<% } -%> \ No newline at end of file