From 76e0013f0075f89545fcaf3fb7da2db77a5c171e Mon Sep 17 00:00:00 2001 From: Simon Lecoq <22963968+lowlighter@users.noreply.github.com> Date: Tue, 26 Jan 2021 18:16:48 +0100 Subject: [PATCH] Better organization support (#81) --- README.md | 74 +++++++---- source/app/metrics.mjs | 2 +- source/queries/common.organization.graphql | 4 +- source/templates/classic/image.svg | 4 +- .../partials/base.activity+community.ejs | 116 +++++++++--------- .../classic/partials/base.header.ejs | 114 ++++++++++------- source/templates/classic/style.css | 4 + source/templates/common.mjs | 2 +- .../partials/base.activity+community.ejs | 2 +- .../terminal/partials/base.header.ejs | 7 +- 10 files changed, 202 insertions(+), 127 deletions(-) diff --git a/README.md b/README.md index 6d4703a5..c9fef052 100644 --- a/README.md +++ b/README.md @@ -563,26 +563,26 @@ The default template is `classic`. - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -656,7 +656,9 @@ The default template is `classic`. * **P**: Partial support *(Hover cell for more informations)* * **M**: Feature is not released yet but is available on `@master` * **N**: Feature is already released, but new ones are available on `@master` -* **R**: Repository template (all plugins content will be restricted to related repository) +* **R**: Repository template (all plugins content will be scoped to related repository) +* **Ø**: Feature is not supported for organization accounts +* **ØP**: Feature is supported partially for organization accounts
💬 Using community templates @@ -712,6 +714,36 @@ Add the following to your workflow:
+
+💬 Generating metrics for organizations + + 🚧 This feature is available as pre-release on @master branch (unstable) + +It is also possible to generate metrics for organization accounts. +Setup is the same as for user accounts (i.e. a personal token from an user account and use of `GITHUB_TOKEN` for commits) but you'll need to change `user` option to your organization name. + +Additionally, you'll need to add the `read:org` scope to your personal token, *whether you're member of target organization or not*. + +![Add read:org scope to personal token](.github/readme/imgs/setup_token_org_read_scope.png) + +Resulting workflow should look like below: +```yaml +- uses: lowlighter/metrics@master + with: + # ... other options + token: ${{ secrets.METRICS_TOKEN }} # A personal token from an user account with read:org scope + committer_token: ${{ secrets.GITHUB_TOKEN }} + user: "organization-name" +``` + +You may also need to [authorize your personal token](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/authorizing-a-personal-access-token-for-use-with-saml-single-sign-on) if you're using single sign-on and are encounting errors. + +Note that `repositories` option will be capped to 25 repositories to ensure that GraphQL queries does not timeout, so you may end up using more requests than for user accounts. + +Although some plugins may be noted as compatible with an organization account, it may not be actually possible to run them successfully depending of your organization size. As some of plugins use a lot of requests, you'll eventually reach the rate-limiter before all of your metrics are generated for large organizations. + +
+ ## 🧩 Plugins Plugins are features which can provide additional metrics and features. diff --git a/source/app/metrics.mjs b/source/app/metrics.mjs index 26e9bcd1..74fa1d6f 100644 --- a/source/app/metrics.mjs +++ b/source/app/metrics.mjs @@ -122,7 +122,7 @@ let pushed = 0 do { console.debug(`metrics/compute/${login}/common > retrieving repositories after ${cursor}`) - const {[account]:{repositories:{edges, nodes}}} = await graphql(queries.repositories({login, account, after:cursor ? `after: "${cursor}"` : "", repositories:Math.min(repositories, 100), forks:forks ? "" : ", isFork: false"})) + const {[account]:{repositories:{edges, nodes}}} = await graphql(queries.repositories({login, account, after:cursor ? `after: "${cursor}"` : "", repositories:Math.min(repositories, {user:100, organization:25}[account]), forks:forks ? "" : ", isFork: false"})) cursor = edges?.[edges?.length-1]?.cursor data.user.repositories.nodes.push(...nodes) pushed = nodes.length diff --git a/source/queries/common.organization.graphql b/source/queries/common.organization.graphql index 4166f7aa..c26b42b7 100644 --- a/source/queries/common.organization.graphql +++ b/source/queries/common.organization.graphql @@ -24,6 +24,8 @@ query MetricsOrganization { sponsorshipsAsMaintainer { totalCount } - + membersWithRole { + totalCount + } } } diff --git a/source/templates/classic/image.svg b/source/templates/classic/image.svg index 5e9b5755..5aff309e 100644 --- a/source/templates/classic/image.svg +++ b/source/templates/classic/image.svg @@ -11,7 +11,9 @@ <% if (base.metadata) { %> <% } %> diff --git a/source/templates/classic/partials/base.activity+community.ejs b/source/templates/classic/partials/base.activity+community.ejs index 1fc505b9..f5665b26 100644 --- a/source/templates/classic/partials/base.activity+community.ejs +++ b/source/templates/classic/partials/base.activity+community.ejs @@ -1,57 +1,59 @@ -
- <% if (base.activity) { %> -
-

- - Activity -

-
- - <%= computed.commits %> Commit<%= s(computed.commits) %> -
-
- - <%= user.contributionsCollection.totalPullRequestReviewContributions %> Pull request<%= s(user.contributionsCollection.totalPullRequestReviewContributions) %> reviewed -
-
- - <%= user.contributionsCollection.totalPullRequestContributions %> Pull request<%= s(user.contributionsCollection.totalPullRequestContributions) %> opened -
-
- - <%= user.contributionsCollection.totalIssueContributions %> Issue<%= s(user.contributionsCollection.totalIssueContributions) %> opened -
-
- - <%= user.issueComments.totalCount %> issue comment<%= s(user.issueComments.totalCount) %> -
-
- <% } %> - <% if (base.community) { %> -
-

- Community stats -

-
- - Member of <%= user.organizations.totalCount %> organization<%= s(user.organizations.totalCount) %> -
-
- - Following <%= user.following.totalCount %> user<%= s(user.followers.totalCount) %> -
-
- - Sponsoring <%= user.sponsorshipsAsSponsor.totalCount %> repositor<%= s(user.sponsorshipsAsSponsor.totalCount, "y") %> -
-
- - Starred <%= user.starredRepositories.totalCount %> repositor<%= s(user.starredRepositories.totalCount, "y") %> -
-
- - Watching <%= user.watching.totalCount %> repositor<%= s(user.watching.totalCount, "y") %> -
-
- <% } %> -
\ No newline at end of file +<% if (account === "user") { %> +
+ <% if (base.activity) { %> +
+

+ + Activity +

+
+ + <%= computed.commits %> Commit<%= s(computed.commits) %> +
+
+ + <%= user.contributionsCollection.totalPullRequestReviewContributions %> Pull request<%= s(user.contributionsCollection.totalPullRequestReviewContributions) %> reviewed +
+
+ + <%= user.contributionsCollection.totalPullRequestContributions %> Pull request<%= s(user.contributionsCollection.totalPullRequestContributions) %> opened +
+
+ + <%= user.contributionsCollection.totalIssueContributions %> Issue<%= s(user.contributionsCollection.totalIssueContributions) %> opened +
+
+ + <%= user.issueComments.totalCount %> issue comment<%= s(user.issueComments.totalCount) %> +
+
+ <% } %> + <% if (base.community) { %> +
+

+ Community stats +

+
+ + Member of <%= user.organizations.totalCount %> organization<%= s(user.organizations.totalCount) %> +
+
+ + Following <%= user.following.totalCount %> user<%= s(user.followers.totalCount) %> +
+
+ + Sponsoring <%= user.sponsorshipsAsSponsor.totalCount %> repositor<%= s(user.sponsorshipsAsSponsor.totalCount, "y") %> +
+
+ + Starred <%= user.starredRepositories.totalCount %> repositor<%= s(user.starredRepositories.totalCount, "y") %> +
+
+ + Watching <%= user.watching.totalCount %> repositor<%= s(user.watching.totalCount, "y") %> +
+
+ <% } %> +
+<% } %> \ No newline at end of file diff --git a/source/templates/classic/partials/base.header.ejs b/source/templates/classic/partials/base.header.ejs index 7405d6fc..4ba5bb35 100644 --- a/source/templates/classic/partials/base.header.ejs +++ b/source/templates/classic/partials/base.header.ejs @@ -1,46 +1,74 @@ <% if (base.header) { %> -
-

- - <%= user.name || user.login %> -

-
-
-
- <% if (computed.cakeday) { %> - - Joined GitHub <%= computed.registration %> - <% } else { %> - - Joined GitHub <%= computed.registration %> - <% } %> -
-
- - Followed by <%= user.followers.totalCount %> user<%= s(user.followers.totalCount) %> -
- <% if (user.isHireable) { %> -
- - Available for hire! + <% if (account === "user") { %> +
+

+ + <%= user.name || user.login %> +

+
+
+
+ <% if (computed.cakeday) { %> + + Joined GitHub <%= computed.registration %> + <% } else { %> + + Joined GitHub <%= computed.registration %> + <% } %>
- <% } %> -
-
-
- - - <% for (const [x, {color}] of Object.entries(computed.calendar)) { %> - - <% } %> - - -
-
- - Contributed to <%= user.repositoriesContributedTo.totalCount %> repositor<%= s(user.repositoriesContributedTo.totalCount, "y") %> -
-
-
-
+
+ + Followed by <%= user.followers.totalCount %> user<%= s(user.followers.totalCount) %> +
+ <% if (user.isHireable) { %> +
+ + Available for hire! +
+ <% } %> +
+
+
+ + + <% for (const [x, {color}] of Object.entries(computed.calendar)) { %> + + <% } %> + + +
+
+ + Contributed to <%= user.repositoriesContributedTo.totalCount %> repositor<%= s(user.repositoriesContributedTo.totalCount, "y") %> +
+
+
+
+ <% } else if (account === "organization") { %> +
+

+ + <%= user.name || user.login %> +

+
+
+
+ <% if (computed.cakeday) { %> + + Joined GitHub <%= computed.registration %> + <% } else { %> + + Joined GitHub <%= computed.registration %> + <% } %> +
+
+
+
+ + <%= user.membersWithRole.totalCount %> member<%= s(user.membersWithRole.totalCount) %> +
+
+
+
+ <% } %> <% } %> \ No newline at end of file diff --git a/source/templates/classic/style.css b/source/templates/classic/style.css index 06855c2f..64b2984d 100644 --- a/source/templates/classic/style.css +++ b/source/templates/classic/style.css @@ -89,6 +89,10 @@ margin: 0 6px; } + .avatar.organization { + border-radius: 15%; + } + /* Commit calendar */ .calendar.field { margin: 4px 0; diff --git a/source/templates/common.mjs b/source/templates/common.mjs index ac213974..1ae99cba 100644 --- a/source/templates/common.mjs +++ b/source/templates/common.mjs @@ -75,7 +75,7 @@ const years = Math.floor(diff) const months = Math.floor((diff-years)*12) computed.registration = years ? `${years} year${s(years)} ago` : months ? `${months} month${s(months)} ago` : `${Math.ceil(diff*365)} day${s(Math.ceil(diff*365))} ago` - computed.cakeday = [new Date(), new Date(data.user.createdAt)].map(date => date.toISOString().match(/(?\d{2}-\d{2})(?=T)/)?.groups?.mmdd).every((v, _, a) => v === a[0]) + computed.cakeday = years > 1 ? [new Date(), new Date(data.user.createdAt)].map(date => date.toISOString().match(/(?\d{2}-\d{2})(?=T)/)?.groups?.mmdd).every((v, _, a) => v === a[0]) : false //Compute calendar computed.calendar = data.user.calendar.contributionCalendar.weeks.flatMap(({contributionDays}) => contributionDays).slice(0, 14).reverse() diff --git a/source/templates/terminal/partials/base.activity+community.ejs b/source/templates/terminal/partials/base.activity+community.ejs index 04fb46e5..cc337c41 100644 --- a/source/templates/terminal/partials/base.activity+community.ejs +++ b/source/templates/terminal/partials/base.activity+community.ejs @@ -1,4 +1,4 @@ -<% if ((base.activity)||(base.community)) { %> +<% if ((account === "user")&&((base.activity)||(base.community))) { %>
<%- meta.$ %> git status
<%# -%>
<%# -%> <% if (base.activity) { -%> diff --git a/source/templates/terminal/partials/base.header.ejs b/source/templates/terminal/partials/base.header.ejs index d1b51798..819ff122 100644 --- a/source/templates/terminal/partials/base.header.ejs +++ b/source/templates/terminal/partials/base.header.ejs @@ -1,7 +1,12 @@ -<% if (base.header) { %> +<% if ((account === "user")&&(base.header)) { %>
<%- meta.$ %> whoami
<%# -%>
<%# -%> <%= user.name || user.login %> registered=<%= computed.registration.match(/^.+? [ymd]/)?.[0].replace(/ /g, "") %>, uid=<%= `${user.databaseId}`.substr(-4) %>, gid=<%= user.organizations.totalCount %> contributed to <%= user.repositoriesContributedTo.totalCount %> repositor<%= s(user.repositoriesContributedTo.totalCount, "y") %> <% for (const [x, {color}] of Object.entries(computed.calendar)) { -%>#<% } %> followed by <%= user.followers.totalCount %> user<%= s(user.followers.totalCount) %> +
<% } else if ((account === "organization")&&(base.header)) { %><%# -%> +
<%- meta.$ %> whoami
<%# -%> +
<%# -%> +<%= user.name || user.login %> registered=<%= computed.registration.match(/^.+? [ymd]/)?.[0].replace(/ /g, "") %>, uid=0, gid=<%= `${user.databaseId}`.substr(-4) %> + organization with <%= user.membersWithRole.totalCount %> member<%= s(user.membersWithRole.totalCount) %>
<% } -%> \ No newline at end of file
Template\Plugin🗃️⏱️📅🎼🈷️🎟️📌🗂️👨‍💻🧮🐤✒️💡📰🌟🎫🧑‍🤝‍🧑🌸Template\Plugin🗃️ØP⏱️📅Ø🎼🈷️🎟️📌Ø🗂️👨‍💻🧮🐤✒️💡📰🌟Ø🎫Ø🧑‍🤝‍🧑🌸
Classic