From eda42574075a8e1517644846a29694a1664bb965 Mon Sep 17 00:00:00 2001 From: Simon Lecoq <22963968+lowlighter@users.noreply.github.com> Date: Wed, 8 Nov 2023 23:35:08 -0500 Subject: [PATCH] continue compat layer --- Dockerfile | 4 +- action.yml | 6 +- deno.jsonc | 16 +- deno.lock | 3 + source/engine/components/tests/context.ts | 2 +- source/engine/utils/browser.ts | 6 +- source/engine/utils/browser_test.ts | 13 + source/engine/utils/deno/command_test.ts | 8 +- source/engine/utils/deno/io.ts | 8 +- source/engine/utils/deno/server.ts | 2 +- source/engine/utils/testing_test.ts | 4 + source/plugins/rss/mod.ts | 2 +- source/run/compat.ts | 734 +++++++++++++++++++--- source/run/mod.ts | 6 +- 14 files changed, 703 insertions(+), 111 deletions(-) diff --git a/Dockerfile b/Dockerfile index d6a5966997a..1c7c37c4c2d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,8 +20,9 @@ RUN apk add --no-cache chromium ttf-freefont font-noto-emoji \ # Install deno ENV DENO_INSTALL / ENV DENO_NO_UPDATE_CHECK true +ENV DENO_VERSION 1.38.0 ENV GLIBC_VERSION 2.34-r0 -RUN apk add --no-cache --virtual .deno curl wget \ +RUN apk add --no-cache --virtual .deno curl wget unzip \ && wget --no-hsts --quiet --output-document /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub \ && wget --no-hsts --quiet https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-${GLIBC_VERSION}.apk \ && wget --no-hsts --quiet https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-bin-${GLIBC_VERSION}.apk \ @@ -35,6 +36,7 @@ RUN apk add --no-cache --virtual .deno curl wget \ && apk del glibc-i18n \ && (curl -fsSL https://deno.land/x/install/install.sh | sh) \ && apk del .deno \ + && deno upgrade --version ${DENO_VERSION} \ && deno --version # Install lighthouse diff --git a/action.yml b/action.yml index 648c71dbc93..7e4ae5042ae 100644 --- a/action.yml +++ b/action.yml @@ -33,10 +33,10 @@ runs: cd ${{ github.action_path }} DOCKER_IMAGE="${{ inputs.docker_image }}" if [ -f "$DOCKER_IMAGE" ]; then + DOCKER_LOCAL=metrics:local echo "Using local docker image: $DOCKER_IMAGE" - deno task btr docker:build - DOCKER_IMAGE=metrics:dev - # TODO(@lowlighter): pass the docker file as input + deno task make docker --tag $DOCKER_LOCAL --file $DOCKER_IMAGE + DOCKER_IMAGE=$DOCKER_LOCAL else echo "Pulling remote docker image: $DOCKER_IMAGE" docker pull $DOCKER_IMAGE diff --git a/deno.jsonc b/deno.jsonc index e5744cdd6fa..b7581762dbe 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -120,7 +120,10 @@ // processors/render.twemojis "cdn.jsdelivr.net/gh/jdecked/twemoji@latest/assets", // Testing - "example.com" + "example.com", + // Browser downloads + "googlechromelabs.github.io/chrome-for-testing", + "edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing" ], "run": [ "deno", @@ -132,6 +135,7 @@ ], "write": [ ".test", + ".cache", "$HOME/.config/chromium/SingletonLock" ], "env": [ @@ -200,7 +204,7 @@ "task": [ "deno task make docker &&", "docker run --entrypoint='' metrics:dev sh -c 'deno task make test && deno task make coverage'" - ], + ] }, "deploy:deno": { "description": "🦕 Deploy metrics on https://deno.com/deploy", @@ -242,7 +246,7 @@ "deno eval \"console.log($ASTRAL_INSTALL)\"" ], "env": { - "ASTRAL_INSTALL": "await import('@engine/utils/browser.ts').then(({Browser}) => Browser.getBinary('chrome'))" + "ASTRAL_INSTALL": "(Deno.stdout = Deno.stderr, await import('@engine/utils/browser.ts').then(({Browser}) => Browser.getBinary('chrome')))" }, "deno": { "eval": { @@ -253,14 +257,14 @@ ], "write": [ ".cache" + ], + "env": [ + "CHROME_BIN" ] } } } }, - "xx": { - "task": "export TEST=$(deno task make get:cache) && echo $TEST" - }, "get:cache": { "description": "🏗️ Get cache path", "task": [ diff --git a/deno.lock b/deno.lock index a0c365d3714..cf9595277c6 100644 --- a/deno.lock +++ b/deno.lock @@ -103,6 +103,7 @@ "https://deno.land/std@0.205.0/async/debounce.ts": "adab11d04ca38d699444ac8a9d9856b4155e8dda2afd07ce78276c01ea5a4332", "https://deno.land/std@0.205.0/async/deferred.ts": "42790112f36a75a57db4a96d33974a936deb7b04d25c6084a9fa8a49f135def8", "https://deno.land/std@0.205.0/async/delay.ts": "a6142eb44cdd856b645086af2b811b1fcce08ec06bb7d50969e6a872ee9b8659", + "https://deno.land/std@0.205.0/bytes/concat.ts": "d26d6f3d7922e6d663dacfcd357563b7bf4a380ce5b9c2bbe0c8586662f25ce2", "https://deno.land/std@0.205.0/collections/_utils.ts": "5114abc026ddef71207a79609b984614e66a63a4bda17d819d56b0e72c51527e", "https://deno.land/std@0.205.0/collections/deep_merge.ts": "9db788ba56cb05b65c77166b789e58e125dff159b7f41bf4d19dc1cba19ecb8b", "https://deno.land/std@0.205.0/collections/filter_keys.ts": "a29cfe8730ddb54e9e071ea45e8a82e166c7629d18675652def70c1bf80e2ef6", @@ -215,6 +216,7 @@ "https://deno.land/std@0.205.0/semver/types.ts": "d44f442c2f27dd89bd6695b369e310b80549746f03c38f241fe28a83b33dd429", "https://deno.land/std@0.205.0/streams/_common.ts": "3b2c1f0287ce2ad51fff4091a7d0f48375c85b0ec341468e76d5ac13bb0014dd", "https://deno.land/std@0.205.0/streams/byte_slice_stream.ts": "c46d7c74836fc8c1a9acd9fe211cbe1bbaaee1b36087c834fb03af4991135c3a", + "https://deno.land/std@0.205.0/streams/delimiter_stream.ts": "ea793d21bfaae27163f0b50d26298a2ad543803283aeaff082df50dd9c08614f", "https://deno.land/std@0.205.0/streams/text_delimiter_stream.ts": "f0dc8ff953a8a77f0d1fa8db1fee62de817f36e20d79b00b1362847e30fbdd90", "https://deno.land/std@0.205.0/version.ts": "c692162c2e110d6cc88fcb27e1ae47434360d2ec2930950f5c1a6ee0addf8ea7", "https://deno.land/std@0.205.0/yaml/_dumper/dumper.ts": "717403d0e700de783f2ef5c906b3d7245383e1509fc050e7ff5d4a53a03dbf40", @@ -419,6 +421,7 @@ "https://esm.sh/remark-parse@11.0.0": "4ef4281ab5905ec27cccc541b0b8eee92d4bbd1dfedc4a0180c273f46c165994", "https://esm.sh/remark-rehype@11.0.0": "3a16e7e344b79c09983bb8e2d0b3969a410e59c6719940bba01ba1901f0d0562", "https://esm.sh/rss-parser@3.13.0": "f8cd3d7e5d265c8ac4375b02265e068dc0edfbcaf636536c5246d67d70db2469", + "https://esm.sh/rss-parser@3.13.0?pin=v133": "f8cd3d7e5d265c8ac4375b02265e068dc0edfbcaf636536c5246d67d70db2469", "https://esm.sh/string-argv@0.3.1?pin=v133": "aa97f90fbf02b0bccb7537a5123610a1796f1db8e5cccea8b59eb22ec3a2079b", "https://esm.sh/svgo@3.0.2": "57dee35934ccbbcdbb57cba30a8d53facec9b9c06379a9639e9cba2d4f2c196c", "https://esm.sh/unified@11.0.4": "3231f40ee8b1271cd4bdf777bab30d406dc7661859204704c4fac0ffbb72df91", diff --git a/source/engine/components/tests/context.ts b/source/engine/components/tests/context.ts index 874c310c321..7af27cc01cd 100644 --- a/source/engine/components/tests/context.ts +++ b/source/engine/components/tests/context.ts @@ -74,7 +74,7 @@ export async function getPermissions(test: Awaited { + await expect(Browser.getBinary("chrome")).to.eventually.be.a("string") +}) + for (const mode of ["local", "remote"]) { const setup = async () => { const remote = (mode === "remote") ? await new Browser({ log, bin }).ready : null diff --git a/source/engine/utils/deno/command_test.ts b/source/engine/utils/deno/command_test.ts index dc82afe8d07..5c4fc5c9261 100644 --- a/source/engine/utils/deno/command_test.ts +++ b/source/engine/utils/deno/command_test.ts @@ -6,15 +6,17 @@ import { DevNull } from "@engine/utils/log_test.ts" const stdio = new DevNull() const log = new Logger(import.meta, { level: Logger.channels.trace, tags: { foo: "bar" }, stdio }) -Deno.test.ignore(t(import.meta, "`command()` can execute commands"), { permissions: { run: ["deno"] } }, async () => { +// TODO(@lowlighter): Use `{ permissions: { run: ["deno"] } }` when https://github.com/denoland/deno/issues/21123 fixed + +Deno.test(t(import.meta, "`command()` can execute commands"), async () => { await expect(command("deno --version")).to.be.eventually.containSubset({ success: true, code: 0 }) }) -Deno.test.ignore(t(import.meta, "`command()` returns stdio content instead if asked"), { permissions: { run: ["deno"] } }, async () => { +Deno.test(t(import.meta, "`command()` returns stdio content instead if asked"), async () => { await expect(command("deno --version", { return: "stdout" })).to.eventually.include("deno") }) -Deno.test.ignore(t(import.meta, "`command()` returns stdio content instead if asked"), { permissions: { run: ["deno"] } }, async () => { +Deno.test(t(import.meta, "`command()` returns stdio content instead if asked"), async () => { stdio.flush() await expect(command("deno --version", { log })).to.be.fulfilled expect(stdio.messages).to.not.be.empty diff --git a/source/engine/utils/deno/io.ts b/source/engine/utils/deno/io.ts index a539513575a..1e9c8b1a462 100644 --- a/source/engine/utils/deno/io.ts +++ b/source/engine/utils/deno/io.ts @@ -36,13 +36,9 @@ export async function write(path: string, data: string | Uint8Array | ReadableSt export async function list(glob: string) { const files = [] const base = glob.match(/(?.*\/)\*/)?.groups?.base - const prefix = base ? new RegExp(`.*?${base}`) : null + const prefix = new RegExp(`.*?${base}`) for await (const { path } of expandGlob(glob, { extended: true, globstar: true })) { - let file = path.replaceAll("\\", "/") - if (prefix) { - file = file.replace(prefix, "") - } - files.push(file) + files.push(path.replaceAll("\\", "/").replace(prefix, "")) } return files } diff --git a/source/engine/utils/deno/server.ts b/source/engine/utils/deno/server.ts index bde55877994..ec141ef880e 100644 --- a/source/engine/utils/deno/server.ts +++ b/source/engine/utils/deno/server.ts @@ -4,7 +4,7 @@ import { throws } from "@engine/utils/errors.ts" /** Port listener */ export function listen(options: Deno.ServeOptions, handler: Deno.ServeHandler) { - return Deno.serve(options, handler) + return Deno.serve({ ...options, onListen: () => void null }, handler) } /** KV storage */ diff --git a/source/engine/utils/testing_test.ts b/source/engine/utils/testing_test.ts index bb8630d9367..a41e118e55e 100644 --- a/source/engine/utils/testing_test.ts +++ b/source/engine/utils/testing_test.ts @@ -1,5 +1,9 @@ import { expect, is, MetricsValidationError, mock, t } from "@engine/utils/testing.ts" +Deno.test(t(import.meta, "`t()` warns when no tests are present"), { permissions: "none" }, () => { + expect(t(import.meta, null)).to.match(/NO TESTS FOUND/i) +}) + Deno.test(t(import.meta, "`mock()` validates inputs and returns mocked data"), { permissions: "none" }, () => { const mocked = mock({ foo: is.string() }, ({ foo }) => foo) expect(mocked({ foo: "bar" })).to.equal("bar") diff --git a/source/plugins/rss/mod.ts b/source/plugins/rss/mod.ts index 28df6427cb1..19e507c610d 100644 --- a/source/plugins/rss/mod.ts +++ b/source/plugins/rss/mod.ts @@ -1,6 +1,6 @@ // Imports import { is, parse, Plugin } from "@engine/components/plugin.ts" -import RSS from "y/rss-parser@3.13.0" +import RSS from "y/rss-parser@3.13.0?pin=v133" /** Plugin */ export default class extends Plugin { diff --git a/source/run/compat.ts b/source/run/compat.ts index 8afca1f328f..94370efd0bf 100644 --- a/source/run/compat.ts +++ b/source/run/compat.ts @@ -1,144 +1,714 @@ -// deno-lint-ignore-file no-explicit-any +// Imports //import { env } from "@engine/utils/io.ts" -import core from "y/@actions/core@1.10.1?pin=v133" import * as YAML from "std/yaml/mod.ts" -import { brightRed as r, cyan, gray, white, yellow } from "std/fmt/colors.ts" +import { bgWhite, black, brightGreen, brightRed, brightYellow, cyan, gray, white, yellow } from "std/fmt/colors.ts" +import { deepMerge } from "std/collections/deep_merge.ts" + +/** Compatibility type */ +// deno-lint-ignore no-explicit-any type compat = any -function deprecated(input: string, replacement: Record | null) { - if (replacement === null) { - core.warning(`${r(input)} is not supported anymore`) - } else { - core.warning(`${r(input)} is deprecated, use the following configuration snippet instead:\n\n${yaml({ config: replacement })}`) +/** Compatibility report */ +class Report { + /** Messages */ + readonly messages = [] as Array<{ type: string; message: string }> + + /** Register error message */ + error(message: string) { + this.messages.push({ type: "error", message }) + } + + /** Register warning message */ + warning(message: string) { + this.messages.push({ type: "warning", message }) + } + + /** Register info message */ + info(message: string) { + this.messages.push({ type: "info", message }) + } + + /** Print messages to console */ + console() { + for (const { type, message } of this.messages) { + const icon = { error: "❌", warning: "⚠️", info: "💡" }[type] + const text = `${icon} ${message}` + .replaceAll(/^```\w*([\s\S]+?)```/gm, (_, text: string) => text.split("\n").map((line) => ` ${line}`).join("\n")) + .replaceAll(/`([\s\S]+?)`/g, (_, text) => bgWhite(` ${black(text)} `)) + .split("\n").map((line) => `▓ ${line}`).join("\n") + const color = { error: brightRed, warning: brightYellow, info: brightGreen }[type]! + console.log(color(text)) + } + } + + /** Print messages to markdown */ + markdown() { + return "" } } -function yaml(content: Record) { - const regex = { - kv: /^(?\s*)(?\-\s+)?'?(?\w[.\w-]*)'?(?:(?:)(?\s.+)?)?$/, +/** Compatibility config */ +class Config { + /** Config content */ + readonly content = {} as Record + + /** Report */ + readonly report = new Report() + + /** Patch config */ + patch(inputs: string | string[], snippet: Record | null) { + if (snippet) { + this.report.warning( + `${ + Array.isArray(inputs) ? `\`${[inputs.slice(0, -1).join(", "), inputs.slice(-1)].join(" and ")}\` are` : `\`${inputs}\` is` + } deprecated, use the following configuration snippet instead:\n\`\`\`yaml\n${yaml(snippet)}\`\`\``, + ) + Object.assign(this.content, deepMerge(this.content, snippet, { arrays: "merge" })) + } else { + this.report.error(`${Array.isArray(inputs) ? `\`${[inputs.slice(0, -1).join(", "), inputs.slice(-1)].join(" and ")}\` have` : `\`${inputs}\` has`} been removed`) + } } - const lines = [] - for (const line of YAML.stringify(content).split("\n")) { - if (regex.kv.test(line)) { - let { indent, array = "", kv, key, value } = line.match(regex.kv)!.groups! - let color = white - if (!kv) { - value = key - } - value = value?.trim() - switch (true) { - case ["null"].includes(value): - color = gray - break - case ["{}", "[]", "true", "false"].includes(value): - color = yellow - break - case !Number.isNaN(Number(value)): - color = yellow - break - case /^'.+'$/.test(value): - value = value.replace(/^'|'$/g, "") - color = yellow - break + + /** Print config */ + print() { + console.log(yaml(this.content)) + } +} + +/** Compatibility layer */ +export async function compat(inputs: compat) { + const config = new Config() + + const { Requests } = await import("@engine/components/requests.ts") + const requests = new Requests(import.meta, { logs: "none", mock: false, api: "https://api.github.com", timezone: "Europe/Paris", token: { read: () => inputs.token } } as compat) + //api + + // 🗝️ Token + if (inputs.token) { + const snippet = { config: { presets: { default: { plugins: { token: inputs.token } } } } } + config.patch("token", snippet) + config.report.info("Token should now be set at preset or plugin level") + if (!inputs.token.startsWith("github_pat_")) { + config.report.info("Metrics now supports supports fine-grained personal access tokens and recommends to use them") + } + } + + if (inputs.user) { + const options = ["user"] + const snippet = { config: { presets: { default: { plugins: { handle: inputs.user, entity: "user" } } } } } + if (inputs.repo) { + snippet.config.presets.default.plugins.handle = `${inputs.user}/${inputs.repo}` + snippet.config.presets.default.plugins.entity = "repository" + options.push("repo") + } else { + try { + const { data: { type: entity } } = await requests.rest(requests.api.users.getByUsername, { username: inputs.user }) + snippet.config.presets.default.plugins.entity = entity.toLocaleLowerCase() + } catch { + // Ignore } - lines.push(`${indent}${array}${kv ? `${cyan(key)}: ${color(value ?? "")}` : color(value ?? "")}`) - continue } - lines.push(line) + config.patch(options, snippet) + config.report.info("User, organization and repository handles should now be set at preset or plugin level") + config.report.warning("Entity type is not inferred anymore and should now be set manually at preset or plugin level") + } + + if ((inputs.github_api_rest) || (inputs.github_api_graphql)) { + if (inputs.github_api_rest !== inputs.github_api_graphql) { + config.report.error("GitHub API REST and GraphQL endpoints cannot be different anymore") + } + const snippet = { config: { presets: { default: { plugins: { api: inputs.github_api_rest || inputs.github_api_graphql } } } } } + config.patch(["github_api_rest", "github_api_graphql"], snippet) + config.report.info("GitHub API endpoints should now be set at preset or plugin level") } - return lines.join("\n") -} -export function compat(inputs: compat) { - const config = { plugins: [] } as compat + // 🧩 Plugins ========================================================================================= // 🙋 Introduction if (inputs.plugin_introduction) { - const plugin = { introduction: {} } as compat - if (!inputs.plugin_introduction_title) { - plugin.processors = [{ "inject.style": { style: ".introduction .title { display: none }" } }] + const options = ["plugin_introduction"] + const snippet = { config: { plugins: [{ introduction: {} }] } } as compat + if (inputs.plugin_introduction_title === false) { + snippet.config.plugins[0].processors = [{ "inject.style": { style: ".introduction .title { display: none }" } }] + options.push("plugin_introduction_title") } - config.plugins.push(plugin) - deprecated("plugin_introduction", { plugins: [plugin] }) + config.patch(options, snippet) } // 📅 Isometric commit calendar if (inputs.plugin_isocalendar) { - const plugin = { calendar: { view: "isometric" } } as compat - plugin.calendar.duration = { "half-year": "last-180-days", "full-year": "last-365-days" }[inputs.plugin_isocalendar_duration as string] ?? "last-180-days" + const options = ["plugin_isocalendar"] + const snippet = { config: { plugins: [{ calendar: { view: "isometric", range: "last-180-days" } }] } } as compat + if (inputs.plugin_isocalendar_duration) { + snippet.config.plugins[0].calendar.range = { "half-year": "last-180-days", "full-year": "last-365-days" }[inputs.plugin_isocalendar_duration as string] + options.push("plugin_isocalendar_duration") + } if (inputs.debug_flags.find((f: string) => ["--halloween", "--winter"].includes(f))) { - plugin.calendar.colors = inputs.debug_flags.find((f: string) => ["--halloween", "--winter"].includes(f)).replace("--", "") + snippet.config.plugins[0].calendar.colors = inputs.debug_flags.find((f: string) => ["--halloween", "--winter"].includes(f)).replace("--", "") + options.push("debug_flags") } - config.plugins.push(plugin) - deprecated("plugin_isocalendar", { plugins: [plugin] }) + config.patch(options, snippet) } // 📅 Commit calendar if (inputs.plugin_calendar) { - const plugin = { calendar: { view: "top-down" } } as compat + const options = ["plugin_calendar", "plugin_calendar_limit"] + const snippet = { config: { plugins: [{ calendar: { view: "top-down" } }] } } as compat switch (true) { case inputs.plugin_calendar_limit === 0: - plugin.calendar.range = { from: "registration", to: "current-year" } + snippet.config.plugins[0].calendar.range = { from: "registration", to: "current-year" } break case inputs.plugin_calendar_limit > 0: - plugin.calendar.range = { from: -inputs.plugin_calendar_limit, to: "current-year" } + snippet.config.plugins[0].calendar.range = { from: -inputs.plugin_calendar_limit, to: "current-year" } break - case inputs.plugin_calendar_limit < 0: - //TODO(@lowlighter): from = registration - n - plugin.calendar.range = { from: -inputs.plugin_calendar_limit, to: "current-year" } + case inputs.plugin_calendar_limit < 0: { + let from = -inputs.plugin_calendar_limit + try { + const { data: { created_at: timestamp } } = await requests.rest(requests.api.users.getByUsername, { username: inputs.user }) + from = new Date(timestamp).getFullYear() - inputs.plugin_calendar_limit + } catch { + // Ignore + } + snippet.config.plugins[0].calendar.range = { from, to: "current-year" } + config.report.warning("`plugin_calendar_limit` for negative values behavior has changed and may need to be adjusted manually") break + } } if (inputs.debug_flags.find((f: string) => ["--halloween", "--winter"].includes(f))) { - plugin.calendar.colors = inputs.debug_flags.find((f: string) => ["--halloween", "--winter"].includes(f)).replace("--", "") + snippet.config.plugins[0].calendar.colors = inputs.debug_flags.find((f: string) => ["--halloween", "--winter"].includes(f)).replace("--", "") + options.push("debug_flags") } - config.plugins.push(plugin) - deprecated("plugin_calendar", { plugins: [plugin] }) + config.patch(options, snippet) } // 🎫 Gists if (inputs.plugin_gists) { - const plugin = { gists: {} } as compat - config.plugins.push(plugin) - deprecated("plugin_gists", { plugins: [plugin] }) + const options = ["plugin_gists"] + const snippet = { config: { plugins: [{ gists: {} }] } } as compat + config.patch(options, snippet) } // 🗼 Rss feed if (inputs.plugin_rss) { - const plugin = { rss: {} } as compat - plugin.rss.feed = inputs.plugin_rss_source - plugin.rss.limit = (inputs.plugin_rss_limit > 0) ? inputs.plugin_rss_limit : null - config.plugins.push(plugin) - deprecated("plugin_rss", { plugins: [plugin] }) + const options = ["plugin_rss", "plugin_rss_source"] + const snippet = { config: { plugins: [{ rss: {} }] } } as compat + snippet.config.plugins[0].rss.feed = inputs.plugin_rss_source + if (typeof inputs.plugin_rss_limit === "number") { + snippet.config.plugins[0].rss.limit = (inputs.plugin_rss_limit > 0) ? inputs.plugin_rss_limit : null + options.push("plugin_rss_limit") + } + config.patch(options, snippet) } // 📸 Website screenshot if (inputs.plugin_screenshot) { - const plugin = { webscraping: {} } as compat - plugin.webscraping.url = inputs.plugin_screenshot_url - plugin.webscraping.select = inputs.plugin_screenshot_selector - plugin.webscraping.mode = inputs.plugin_screenshot_mode - plugin.webscraping.viewport = { width: inputs.plugin_screenshot_viewport_width, height: inputs.plugin_screenshot_viewport_height } - plugin.webscraping.wait = inputs.plugin_screenshot_wait - plugin.webscraping.background = inputs.plugin_screenshot_background - config.plugins.push(plugin) - deprecated("plugin_screenshot", { plugins: [plugin] }) + const options = ["plugin_screenshot", "plugin_screenshot_url"] + const snippet = { config: { plugins: [{ webscraping: {} }] } } as compat + snippet.config.plugins[0].webscraping.url = inputs.plugin_screenshot_url + if (inputs.plugin_screenshot_selector) { + snippet.config.plugins[0].webscraping.select = inputs.plugin_screenshot_selector + options.push("plugin_screenshot_selector") + } + if (inputs.plugin_screenshot_mode) { + snippet.config.plugins[0].webscraping.mode = inputs.plugin_screenshot_mode + options.push("plugin_screenshot_mode") + } + if (inputs.plugin_screenshot_viewport) { + snippet.config.plugins[0].webscraping.viewport = inputs.plugin_screenshot_viewport + options.push("plugin_screenshot_viewport_width", "plugin_screenshot_viewport_height") + } + if (inputs.plugin_screenshot_wait) { + snippet.config.plugins[0].webscraping.wait = inputs.plugin_screenshot_wait + options.push("plugin_screenshot_wait") + } + if (inputs.plugin_screenshot_background === false) { + snippet.config.plugins[0].webscraping.background = inputs.plugin_screenshot_background + options.push("plugin_screenshot_background") + } + config.patch(options, snippet) } // 💭 GitHub Community Support if (inputs.plugin_support) { - deprecated("plugin_support", null) + config.patch("plugin_support", null) } - // ❌ Removed options + // ⚙️ Config ========================================================================================== + + if (inputs.config_timezone) { + const snippet = { config: { presets: { default: { plugins: { timezone: inputs.config_timezone } } } } } + config.patch("config_timezone", snippet) + config.report.info("Timezone should now be set at preset or plugin level") + } + + if ((inputs.config_twemoji) || (inputs.config_gemoji) || (inputs.config_octicon)) { + const options = [] + const snippet = { config: { plugins: [{ processors: [] }] } } as compat + for (const type of ["twemoji", "gemoji", "octicon"]) { + snippet.config.plugins[0].processors.push({ [`render.${type}s`]: {} }) + options.push(`config_${type}`) + } + config.patch(options, snippet) + } + + if (inputs.config_presets) { + config.patch("config_presets", null) + config.report.info("Presets are now handled directly at configuration level") + // TODO(@lowlighter): Should it be backwards compatible? + } + + if (inputs.config_order) { + // TODO(@lowlighter): fetch order from partial + config.patch("config_order", null) + config.report.info("Plugins order are now handled directly at configuration level") + } + + if ((inputs.config_display) || (inputs.config_animations === false) || (inputs.config_padding)) { + const options = [] + for (const key of ["config_display", "config_animations", "config_padding"]) { + if (inputs[key]) { + options.push(key) + } + } + config.patch(options, null) + config.report.warning("") + } + + //config_output + //config_base64 + + // 🎁 Extras ========================================================================================== + + if ((inputs.extras_css) || (inputs.extras_js)) { + const options = [] + const snippet = { config: { plugins: [{ processors: [] }] } } as compat + for (const { type, arg } of [{ type: "css", arg: "style" }, { type: "js", arg: "script" }]) { + snippet.config.plugins[0].processors.push({ [`inject.${arg}`]: { [arg]: inputs[`extras_${type}`] } }) + options.push(`extras_${type}`) + } + config.patch(options, snippet) + } + + if (inputs.delay) { + const snippet = { config: { plugins: [{ processors: [{ "control.delay": { duration: inputs.delay } }] }] } } + config.patch("delay", snippet) + } + + if (inputs.debug) { + const snippet = { config: { presets: { default: { plugins: { logs: "debug" }, processors: { logs: "debug" } } } } } + config.patch("debug", snippet) + config.report.info("Logs level can now be set at preset or plugin level, and supports different levels of logging") + } + + if (inputs.verify) { + config.patch("verify", null) + } if (inputs.debug_flags) { - deprecated("debug_flags", null) + config.patch("debug_flags", null) } if (inputs.dryrun) { - deprecated("dryrun", null) + config.patch("dryrun", null) + config.report.warning("While dryrun mode has been removed, the same behavior can be achieved by not using the `render` processor") } if (inputs.experimental_features) { - deprecated("experimental_features", null) + config.patch("experimental_features", null) } + /* + committer_token: + committer_branch: + committer_message: + committer_gist: + filename: + markdown: + markdown_cache: + output_action: + output_condition: + optimize: + setup_community_templates: + template: + query: + retries: + retries_delay: + retries_output_action: + retries_delay_output_action: + clean_workflows: + quota_required_rest: + quota_required_graphql: + quota_required_search: + notice_releases: + use_prebuilt_image: + plugins_errors_fatal: + debug_print: + use_mocked_data: + */ + + config.report.console() + config.print() + return config } + +if (import.meta.main) { + await compat({ + token: "github_pat_xxxx", + user: "lowlighter", + repo: "metrics", + github_api_rest: "https://api.github.com", + plugin_introduction: true, + plugin_introduction_title: false, + plugin_isocalendar: true, + plugin_isocalendar_duration: "full-year", + debug_flags: ["--halloween"], + plugin_calendar: true, + plugin_calendar_limit: -1, + plugin_gists: true, + plugin_rss: true, + plugin_rss_source: "https://news.ycombinator.com/rss", + plugin_rss_limit: 0, + plugin_screenshot: true, + plugin_screenshot_url: "https://example.com", + plugin_screenshot_selector: "body", + plugin_screenshot_mode: "image", + plugin_screenshot_viewport: { width: 1280, height: 1280 }, + plugin_screenshot_wait: 100, + plugin_screenshot_background: false, + plugin_support: true, + extras_css: "body { background: red }", + extras_js: "console.log('hello world')", + debug: true, + verify: true, + dryrun: true, + experimental_features: ["test"], + config_timezone: "Europe/Paris", + config_twemoji: true, + config_gemoji: true, + config_octicon: true, + config_presets: "@lunar-red", + config_order: ["introduction", "isocalendar", "calendar", "gists", "rss", "webscraping", "support"], + config_display: "large", + config_animations: true, + config_padding: ["5%", "10%"], + delay: 5, + }) +} + +/* + base: + base_indepth: + base_hireable: + base_skip: + repositories: + repositories_batch: + repositories_forks: + repositories_affiliations: + repositories_skipped: + users_ignored: + commits_authoring: + plugin_isocalendar: + plugin_isocalendar_duration: + plugin_languages: + plugin_languages_ignored: + plugin_languages_skipped: + plugin_languages_limit: + plugin_languages_threshold: + plugin_languages_other: + plugin_languages_colors: + plugin_languages_aliases: + plugin_languages_sections: + plugin_languages_details: + plugin_languages_indepth: + plugin_languages_indepth_custom: + plugin_languages_analysis_timeout: + plugin_languages_analysis_timeout_repositories: + plugin_languages_categories: + plugin_languages_recent_categories: + plugin_languages_recent_load: + plugin_languages_recent_days: + plugin_stargazers: + plugin_stargazers_days: + plugin_stargazers_charts: + plugin_stargazers_charts_type: + plugin_stargazers_worldmap: + plugin_stargazers_worldmap_token: + plugin_stargazers_worldmap_sample: + plugin_lines: + plugin_lines_skipped: + plugin_lines_sections: + plugin_lines_repositories_limit: + plugin_lines_history_limit: + plugin_lines_delay: + plugin_topics: + plugin_topics_mode: + plugin_topics_sort: + plugin_topics_limit: + plugin_stars: + plugin_stars_limit: + plugin_licenses: + plugin_licenses_setup: + plugin_licenses_ratio: + plugin_licenses_legal: + plugin_habits: + plugin_habits_from: + plugin_habits_skipped: + plugin_habits_days: + plugin_habits_facts: + plugin_habits_charts: + plugin_habits_charts_type: + plugin_habits_trim: + plugin_habits_languages_limit: + plugin_habits_languages_threshold: + plugin_contributors: + plugin_contributors_base: + plugin_contributors_head: + plugin_contributors_ignored: + plugin_contributors_contributions: + plugin_contributors_sections: + plugin_contributors_categories: + plugin_followup: + plugin_followup_sections: + plugin_followup_indepth: + plugin_followup_archived: + plugin_reactions: + plugin_reactions_limit: + plugin_reactions_limit_issues: + plugin_reactions_limit_discussions: + plugin_reactions_limit_discussions_comments: + plugin_reactions_days: + plugin_reactions_display: + plugin_reactions_details: + plugin_reactions_ignored: + plugin_people: + plugin_people_limit: + plugin_people_identicons: + plugin_people_identicons_hide: + plugin_people_size: + plugin_people_types: + plugin_people_thanks: + plugin_people_sponsors_custom: + plugin_people_shuffle: + plugin_sponsorships: + plugin_sponsorships_sections: + plugin_sponsorships_size: + plugin_sponsors: + plugin_sponsors_sections: + plugin_sponsors_past: + plugin_sponsors_size: + plugin_sponsors_title: + plugin_repositories: + plugin_repositories_featured: + plugin_repositories_pinned: + plugin_repositories_starred: + plugin_repositories_random: + plugin_repositories_order: + plugin_repositories_forks: + plugin_repositories_affiliations: + plugin_discussions: + plugin_discussions_categories: + plugin_discussions_categories_limit: + plugin_starlists: + plugin_starlists_limit: + plugin_starlists_limit_repositories: + plugin_starlists_languages: + plugin_starlists_limit_languages: + plugin_starlists_languages_ignored: + plugin_starlists_languages_aliases: + plugin_starlists_shuffle_repositories: + plugin_starlists_ignored: + plugin_starlists_only: + plugin_calendar: + plugin_calendar_limit: + plugin_achievements: + plugin_achievements_threshold: + plugin_achievements_secrets: + plugin_achievements_display: + plugin_achievements_limit: + plugin_achievements_ignored: + plugin_achievements_only: + plugin_notable: + plugin_notable_filter: + plugin_notable_skipped: + plugin_notable_from: + plugin_notable_repositories: + plugin_notable_indepth: + plugin_notable_types: + plugin_notable_self: + plugin_activity: + plugin_activity_limit: + plugin_activity_load: + plugin_activity_days: + plugin_activity_visibility: + plugin_activity_timestamps: + plugin_activity_skipped: + plugin_activity_ignored: + plugin_activity_filter: + plugin_traffic: + plugin_traffic_skipped: + plugin_code: + plugin_code_lines: + plugin_code_load: + plugin_code_days: + plugin_code_visibility: + plugin_code_skipped: + plugin_code_languages: + plugin_gists: + plugin_projects: + plugin_projects_limit: + plugin_projects_repositories: + plugin_projects_descriptions: + plugin_introduction: + plugin_introduction_title: + plugin_skyline: + plugin_skyline_year: + plugin_skyline_frames: + plugin_skyline_quality: + plugin_skyline_compatibility: + plugin_skyline_settings: + plugin_support: + plugin_pagespeed: + plugin_pagespeed_token: + plugin_pagespeed_url: + plugin_pagespeed_detailed: + plugin_pagespeed_screenshot: + plugin_pagespeed_pwa: + plugin_tweets: + plugin_tweets_token: + plugin_tweets_user: + plugin_tweets_attachments: + plugin_tweets_limit: + plugin_stackoverflow: + plugin_stackoverflow_user: + plugin_stackoverflow_sections: + plugin_stackoverflow_limit: + plugin_stackoverflow_lines: + plugin_stackoverflow_lines_snippet: + plugin_anilist: + plugin_anilist_user: + plugin_anilist_medias: + plugin_anilist_sections: + plugin_anilist_limit: + plugin_anilist_limit_characters: + plugin_anilist_shuffle: + plugin_music: + plugin_music_provider: + plugin_music_token: + plugin_music_user: + plugin_music_mode: + plugin_music_playlist: + plugin_music_limit: + plugin_music_played_at: + plugin_music_time_range: + plugin_music_top_type: + plugin_posts: + plugin_posts_source: + plugin_posts_user: + plugin_posts_descriptions: + plugin_posts_covers: + plugin_posts_limit: + plugin_rss: + plugin_rss_source: + plugin_rss_limit: + plugin_wakatime: + plugin_wakatime_token: + plugin_wakatime_url: + plugin_wakatime_user: + plugin_wakatime_sections: + plugin_wakatime_days: + plugin_wakatime_limit: + plugin_wakatime_languages_other: + plugin_wakatime_languages_ignored: + plugin_wakatime_repositories_visibility: + plugin_leetcode: + plugin_leetcode_user: + plugin_leetcode_sections: + plugin_leetcode_limit_skills: + plugin_leetcode_ignored_skills: + plugin_leetcode_limit_recent: + plugin_steam: + plugin_steam_token: + plugin_steam_sections: + plugin_steam_user: + plugin_steam_games_ignored: + plugin_steam_games_limit: + plugin_steam_recent_games_limit: + plugin_steam_achievements_limit: + plugin_steam_playtime_threshold: + plugin_16personalities: + plugin_16personalities_url: + plugin_16personalities_sections: + plugin_16personalities_scores: + plugin_chess: + plugin_chess_token: + plugin_chess_user: + plugin_chess_platform: + plugin_chess_animation: + plugin_fortune: + plugin_nightscout: + plugin_nightscout_url: + plugin_nightscout_datapoints: + plugin_nightscout_lowalert: + plugin_nightscout_highalert: + plugin_nightscout_urgentlowalert: + plugin_nightscout_urgenthighalert: + plugin_poopmap: + plugin_poopmap_token: + plugin_poopmap_days: + plugin_screenshot: + plugin_screenshot_title: + plugin_screenshot_url: + plugin_screenshot_selector: + plugin_screenshot_mode: + plugin_screenshot_viewport: + plugin_screenshot_wait: + plugin_screenshot_background: + plugin_splatoon: + plugin_splatoon_token: + plugin_splatoon_sections: + plugin_splatoon_versus_limit: + plugin_splatoon_salmon_limit: + plugin_splatoon_statink: + plugin_splatoon_statink_token: + plugin_splatoon_source: + plugin_stock: + plugin_stock_token: + plugin_stock_symbol: + plugin_stock_duration: + plugin_stock_interval: +*/ + +/** YAML formatter for console */ +function yaml(content: Record) { + const regex = { + kv: /^(?\s*)(?\-\s+)?'?(?\w[.\w-]*)'?(?:(?:)(?\s.+)?)?$/, + } + const lines = [] + for (const line of YAML.stringify(content).split("\n")) { + if (regex.kv.test(line)) { + let { indent, array = "", kv, key, value } = line.match(regex.kv)!.groups! + let color = white + if (!kv) { + value = key + } + value = value?.trim() + switch (true) { + case ["null"].includes(value): + color = gray + break + case ["{}", "[]", "true", "false"].includes(value): + color = yellow + break + case !Number.isNaN(Number(value)): + color = yellow + break + case /^'.+'$/.test(value): + value = value.replace(/^'|'$/g, "") + color = yellow + break + } + lines.push(`${indent}${array}${kv ? `${cyan(key)}: ${color(value ?? "")}` : color(value ?? "")}`) + continue + } + lines.push(line) + } + return lines.join("\n") +} diff --git a/source/run/mod.ts b/source/run/mod.ts index 4591986b5e8..f056c9ce959 100644 --- a/source/run/mod.ts +++ b/source/run/mod.ts @@ -41,9 +41,7 @@ class CLI extends Internal { env.set(`INPUT_${key.replace(/ /g, "_").toUpperCase()}`, `${value}`) } console.log("config", core.getInput("config")) - console.log("deprecated_test", core.getInput("deprecated_test")) - core.warning("test **markdown**\n```yaml\nfoo: true\n```", { title: "test" }) - console.log("compat >>>>>>>>>>", compat(inputs)) + await compat(inputs) } // Check for updates if (this.context.check_updates) { @@ -52,7 +50,7 @@ class CLI extends Internal { core.info(`Version ${upstream} is available!`) } } - // + // Run metrics await process(this.context.config) }