Add templates metadata (#273)

This commit is contained in:
Simon Lecoq
2021-04-27 22:53:15 +02:00
committed by GitHub
parent c4af6f67fd
commit 1ca0c9973f
17 changed files with 142 additions and 17 deletions

View File

@@ -75,7 +75,7 @@
...config
} = metadata.plugins.core.inputs.action({core})
const q = {...query, ...(_repo ? {repo:_repo} : null), template}
const _output = ["jpeg", "png", "json", "markdown", "markdown-pdf"].includes(config["config.output"]) ? config["config.output"] : null
const _output = ["svg", "jpeg", "png", "json", "markdown", "markdown-pdf"].includes(config["config.output"]) ? config["config.output"] : metadata.templates[template].formats[0] ?? null
const filename = _filename.replace(/[*]/g, {jpeg:"jpg", markdown:"md", "markdown-pdf":"pdf"}[_output] ?? _output)
//Docker image

View File

@@ -21,6 +21,8 @@
throw new Error("unsupported template")
const {image, style, fonts, views, partials} = conf.templates[template]
const computer = Templates[template].default || Templates[template]
convert = convert ?? conf.metadata.templates[template].formats[0] ?? null
console.debug(`metrics/compute/${login} > output format set to ${convert}`)
//Initialization
const pending = []
@@ -45,7 +47,7 @@
//Executing base plugin and compute metrics
console.debug(`metrics/compute/${login} > compute`)
await Plugins.base({login, q, data, rest, graphql, plugins, queries, pending, imports}, conf)
await computer({login, q}, {conf, data, rest, graphql, plugins, queries, account:data.account}, {pending, imports})
await computer({login, q}, {conf, data, rest, graphql, plugins, queries, account:data.account, convert, template}, {pending, imports})
const promised = await Promise.all(pending)
//Check plugins errors
@@ -150,7 +152,7 @@
console.debug(`metrics/compute/${login} > verified SVG, no parsing errors found`)
}
//Resizing
const {resized, mime} = await imports.svg.resize(rendered, {paddings:q["config.padding"] || conf.settings.padding, convert})
const {resized, mime} = await imports.svg.resize(rendered, {paddings:q["config.padding"] || conf.settings.padding, convert:convert === "svg" ? null : convert})
rendered = resized
//Result

View File

@@ -43,8 +43,8 @@
Templates[name] = await metadata.template({__templates, name, plugins, logger})
}
//Reorder keys
const {classic, repository, markdown, community, ...templates} = Templates
Templates = {classic, repository, ...templates, markdown, community}
const {community, ...templates} = Templates
Templates = {...Object.fromEntries(Object.entries(templates).sort(([_an, a], [_bn, b]) => (a.index ?? Infinity) - (b.index ?? Infinity))), community}
//Packaged metadata
const packaged = JSON.parse(`${await fs.promises.readFile(__package)}`)
@@ -254,7 +254,9 @@
metadata.template = async function({__templates, name, plugins, logger}) {
try {
//Load meta descriptor
const raw = `${await fs.promises.readFile(path.join(__templates, name, "README.md"), "utf-8")}`
const raw = fs.existsSync(path.join(__templates, name, "metadata.yml")) ? `${await fs.promises.readFile(path.join(__templates, name, "metadata.yml"), "utf-8")}` : ""
const readme = `${await fs.promises.readFile(path.join(__templates, name, "README.md"), "utf-8")}`
const meta = yaml.load(raw) ?? {}
//Compatibility
const partials = path.join(__templates, name, "partials")
@@ -269,11 +271,25 @@
//Result
return {
name:raw.match(/^### (?<name>[\s\S]+?)\n/)?.groups?.name?.trim(),
name:meta.name ?? readme.match(/^### (?<name>[\s\S]+?)\n/)?.groups?.name?.trim(),
index:meta.index ?? null,
formats:meta.formats ?? null,
supports:meta.supports ?? null,
readme:{
demo:raw.match(/(?<demo><table>[\s\S]*?<[/]table>)/)?.groups?.demo?.replace(/<[/]?(?:table|tr)>/g, "")?.trim() ?? (name === "community" ? '<td align="center" colspan="2">See <a href="/source/templates/community/README.md">documentation</a> 🌍</td>' : "<td></td>"),
demo:readme.match(/(?<demo><table>[\s\S]*?<[/]table>)/)?.groups?.demo?.replace(/<[/]?(?:table|tr)>/g, "")?.trim() ?? (name === "community" ? '<td align="center" colspan="2">See <a href="/source/templates/community/README.md">documentation</a> 🌍</td>' : "<td></td>"),
compatibility:{...compatibility, base:true},
},
check({q, account = "bypass", format = null}) {
//Support check
if (account !== "bypass") {
const context = q.repo ? "repository" : account
if ((Array.isArray(this.supports))&&(!this.supports.includes(context)))
throw new Error(`not supported for: ${context}`)
}
//Format check
if ((format)&&(Array.isArray(this.formats))&&(!this.formats.includes(format)))
throw new Error(`not supported for: ${format}`)
},
}
}
catch (error) {

View File

@@ -5,6 +5,7 @@
import processes from "child_process"
import util from "util"
import url from "url"
import yaml from "js-yaml"
import OctokitRest from "@octokit/rest"
//Templates and plugins
@@ -94,6 +95,16 @@
else if (fs.existsSync(path.join(__templates, `@${name}`, "template.mjs"))) {
logger(`metrics/setup > removing @${name}/template.mjs`)
await fs.promises.unlink(path.join(__templates, `@${name}`, "template.mjs"))
const inherit = yaml.load(`${fs.promises.readFile(path.join(__templates, `@${name}`, "metadata.yml"))}`).extends ?? null
if (inherit) {
logger(`metrics/setup > @${name} extends from ${inherit}`)
if (fs.existsSync(path.join(__templates, inherit, "template.mjs"))) {
logger(`metrics/setup > @${name} extended from ${inherit}`)
await fs.promises.copyFile(path.join(__templates, inherit, "template.mjs"), path.join(__templates, `@${name}`, "template.mjs"))
}
else
logger(`metrics/setup > @${name} could not extends ${inherit} as it does not exist`)
}
}
else
logger(`metrics/setup > @${name}/template.mjs does not exist`)
@@ -194,7 +205,7 @@
}
}
//Load metadata (plugins)
//Load metadata
conf.metadata = await metadata({log})
//Store authenticated user

View File

@@ -261,7 +261,7 @@
graphql, rest, plugins, conf,
die:q["plugins.errors.fatal"] ?? false,
verify:q.verify ?? false,
convert:["jpeg", "png", "json", "markdown", "markdown-pdf"].includes(q["config.output"]) ? q["config.output"] : null,
convert:["svg", "jpeg", "png", "json", "markdown", "markdown-pdf"].includes(q["config.output"]) ? q["config.output"] : null,
}, {Plugins, Templates})
//Cache
if ((!debug)&&(cached)) {
@@ -284,6 +284,11 @@
console.debug(`metrics/app/${login} > 400 (bad request)`)
return res.status(400).send("Bad request: unsupported template")
}
//Unsupported output format or account type
if ((error instanceof Error)&&(/^not supported for: [\s\S]*$/.test(error.message))) {
console.debug(`metrics/app/${login} > 406 (Not Acceptable)`)
return res.status(406).send("Not Acceptable: unsupported output format or account type for specified parameters")
}
//GitHub failed request
if ((error instanceof Error)&&(/this may be the result of a timeout, or it could be a GitHub bug/i.test(error.errors?.[0]?.message))) {
console.debug(`metrics/app/${login} > 502 (bad gateway from GitHub)`)

View File

@@ -4,9 +4,10 @@
*/
//Setup
export default async function({login, q}, {conf, data, rest, graphql, plugins, queries, account}, {pending, imports}) {
export default async function({login, q}, {conf, data, rest, graphql, plugins, queries, account, convert, template}, {pending, imports}) {
//Load inputs
const {"config.animations":animations, "config.timezone":_timezone, "debug.flags":dflags} = imports.metadata.plugins.core.inputs({data, account, q})
imports.metadata.templates[template].check({q, account, format:convert})
//Init
const computed = {commits:0, sponsorships:0, licenses:{favorite:"", used:{}}, token:{}, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_closed:0, pr_merged:0, forks:0, forked:0, releases:0}}

View File

@@ -186,8 +186,9 @@ inputs:
config_output:
description: Output image format
type: string
default: svg
default: auto
values:
- auto # Defaults to template default
- svg
- png # Does not support animations
- jpeg # Does not support animations and transparency

View File

@@ -1,4 +1,4 @@
### 📗 Classic
### 📗 Classic template
Default template, mimicking GitHub visual identity.
@@ -11,6 +11,8 @@ Default template, mimicking GitHub visual identity.
#### Examples workflows
[➡️ Supported formats and inputs](metadata.yml)
```yaml
- uses: lowlighter/metrics@latest
with:

View File

@@ -0,0 +1,10 @@
name: "📗 Classic template"
index: 0
supports:
- user
- organization
formats:
- svg
- png
- jpeg
- json

View File

@@ -1,4 +1,4 @@
### 📒 Markdown
### 📒 Markdown template
Markdown template can render a **markdown template** by interpreting **templating brackets** `{{` and `}}`.
@@ -24,6 +24,8 @@ For convenience, several useful properties are aliased in [/source/templates/mar
#### Examples workflows
[➡️ Supported formats and inputs](metadata.yml)
```yaml
# Markdown output
- uses: lowlighter/metrics@latest
@@ -33,7 +35,6 @@ For convenience, several useful properties are aliased in [/source/templates/mar
filename: README.md # Output file
markdown: TEMPLATE.md # Template file
markdown_cache: .cache # Cache folder
config_output: markdown # Output as markdown file
```
```yaml

View File

@@ -0,0 +1,9 @@
name: "📒 Markdown template"
index: 3
supports:
- user
- organization
formats:
- markdown
- markdown-pdf
- json

View File

@@ -1,4 +1,4 @@
### 📘 Repository
### 📘 Repository template
Template crafted for repositories, mimicking GitHub visual identity.
@@ -11,6 +11,8 @@ Template crafted for repositories, mimicking GitHub visual identity.
#### Examples workflows
[➡️ Supported formats and inputs](metadata.yml)
```yaml
- uses: lowlighter/metrics@latest
with:

View File

@@ -0,0 +1,9 @@
name: "📘 Repository template"
index: 1
supports:
- repository
formats:
- svg
- png
- jpeg
- json

View File

@@ -1,4 +1,4 @@
### 📙 Terminal
### 📙 Terminal template
Terminal template, mimicking a SSH session.
@@ -11,6 +11,8 @@ Terminal template, mimicking a SSH session.
#### Examples workflows
[➡️ Supported formats and inputs](metadata.yml)
```yaml
- uses: lowlighter/metrics@latest
with:

View File

@@ -0,0 +1,10 @@
name: "📙 Terminal template"
index: 2
supports:
- user
- organization
formats:
- svg
- png
- jpeg
- json