From 4d3b6943434e2a7e6c3894c9e64bee102a07b1b1 Mon Sep 17 00:00:00 2001 From: Simon Lecoq <22963968+lowlighter@users.noreply.github.com> Date: Sun, 16 Oct 2022 21:27:29 -0400 Subject: [PATCH] feat: advanced pattern matching support (#1260) --- source/app/metrics/metadata.mjs | 24 ++++++++++-- source/app/metrics/utils.mjs | 29 +++++++++++++- source/plugins/activity/metadata.yml | 4 +- source/plugins/base/metadata.yml | 4 +- source/plugins/code/metadata.yml | 4 +- source/plugins/core/README.md | 54 +++++++++++++++++++++++++++ source/plugins/core/metadata.yml | 3 +- source/plugins/habits/metadata.yml | 4 +- source/plugins/languages/metadata.yml | 4 +- source/plugins/lines/metadata.yml | 4 +- source/plugins/notable/metadata.yml | 4 +- source/plugins/traffic/metadata.yml | 4 +- 12 files changed, 127 insertions(+), 15 deletions(-) diff --git a/source/app/metrics/metadata.mjs b/source/app/metrics/metadata.mjs index 771e7064..6da91319 100644 --- a/source/app/metrics/metadata.mjs +++ b/source/app/metrics/metadata.mjs @@ -170,9 +170,25 @@ metadata.plugin = async function({__plugins, __templates, name, logger}) { logger(`metrics/inputs > failed to decode uri : ${value}`) value = defaulted } - const separators = {"comma-separated": ",", "space-separated": " "} - const separator = separators[[format].flat().filter(s => s in separators)[0]] ?? "," - return value.split(separator).map(v => replacer(v).toLocaleLowerCase()).filter(v => Array.isArray(values) ? values.includes(v) : true).filter(v => v) + const separators = {"comma-separated": ",", "space-separated": " ", "newline-separated": "\n"} + const formats = [format, "comma-separated"].flat(Infinity).filter(s => s in separators) + let parsed = [], used = "comma-separated" + for (const separation of formats) { + parsed = value + .split(separators[separation]) + .map(v => replacer(v).toLocaleLowerCase()) + .filter(v => Array.isArray(values) ? values.includes(v) : true) + .filter(v => v) + //Conditional below serves as auto-detection when multiple formats are provided + //To force a specific format one should use the separator as the first character + //so that the parsed.length is greater than 1 (empty values are filtered anyways) + if (parsed.length > 1) { + used = separation + break + } + } + logger(`metrics/inputs > used ${used} format to decode ${value}`) + return parsed } //String case "string": { @@ -625,7 +641,7 @@ metadata.to = { yaml(key, {name = ""} = {}) { const parts = [] if (key !== "enabled") - parts.unshift(key.replaceAll(".", "_")) + parts.unshift(key.replace(/\./g, "_")) if (name) parts.unshift((name === "base") ? name : `plugin_${name}`) return parts.join("_") diff --git a/source/app/metrics/utils.mjs b/source/app/metrics/utils.mjs index 5976e0be..cba9e158 100644 --- a/source/app/metrics/utils.mjs +++ b/source/app/metrics/utils.mjs @@ -391,9 +391,36 @@ export const filters = { } user = (user ?? repository.split("/")[0]).toLocaleLowerCase() repo = (repo ?? repository.split("/")[1]).toLocaleLowerCase() + const handle = `${user}/${repo}` + let include = true + //Advanced pattern matching + if (patterns[0] === "@use.patterns") { + if (debug) + console.debug(`metrics/filters/repo > ${repo} > using advanced pattern matching`) + const options = {nocase:true} + for (let pattern of patterns) { + if (pattern.startsWith("#")) + continue + let action = false + if ((pattern.startsWith("+"))||(pattern.startsWith("-"))) { + action = pattern.charAt(0) === "+" + pattern = pattern.substring(1) + } + if (minimatch(handle, pattern, options)) { + if (debug) + console.debug(`metrics/filters/repo > ${repo} matches ${action ? "including" : "excluding"} pattern ${pattern}`) + include = action + } + } + } //Basic pattern matching - const include = (!patterns.includes(repo)) && (!patterns.includes(`${user}/${repo}`)) + else { + if (debug) + console.debug(`metrics/filters/repo > ${repo} > using basic pattern matching`) + include = (!patterns.includes(repo)) && (!patterns.includes(handle)) + } + if (debug) console.debug(`metrics/filters/repo > filter ${repo} (${include ? "included" : "excluded"})`) return include diff --git a/source/plugins/activity/metadata.yml b/source/plugins/activity/metadata.yml index 3f0ca6bb..367bf657 100644 --- a/source/plugins/activity/metadata.yml +++ b/source/plugins/activity/metadata.yml @@ -65,7 +65,9 @@ inputs: description: | Skipped repositories type: array - format: comma-separated + format: + - newline-separated + - comma-separated default: "" example: my-repo-1, my-repo-2, owner/repo-3, ... inherits: repositories_skipped diff --git a/source/plugins/base/metadata.yml b/source/plugins/base/metadata.yml index 6e9c259f..0bff48e2 100644 --- a/source/plugins/base/metadata.yml +++ b/source/plugins/base/metadata.yml @@ -115,7 +115,9 @@ inputs: description: | Default skipped repositories type: array - format: comma-separated + format: + - newline-separated + - comma-separated default: "" example: my-repo-1, my-repo-2, owner/repo-3, ... global: yes diff --git a/source/plugins/code/metadata.yml b/source/plugins/code/metadata.yml index 130c47ec..b46be51e 100644 --- a/source/plugins/code/metadata.yml +++ b/source/plugins/code/metadata.yml @@ -62,7 +62,9 @@ inputs: description: | Skipped repositories type: array - format: comma-separated + format: + - newline-separated + - comma-separated default: "" example: my-repo-1, my-repo-2, owner/repo-3, ... inherits: repositories_skipped diff --git a/source/plugins/core/README.md b/source/plugins/core/README.md index 2e00c40e..39953cd0 100644 --- a/source/plugins/core/README.md +++ b/source/plugins/core/README.md @@ -57,6 +57,60 @@ Content can be manually ordered using `config_order` option. > ℹ️ The handles to use for each plugin and sections is based on the [`partials/_.json`](/source/templates/classic/partials/_.json) of the template. > It may not necessarily be the plugin id (e.g. `base.header`, `base.activity+community`, `base.repositories`, etc.). +## 🔕 Skipping repositories in plugins + +Some plugins support a `plugin_*_skipped` option which is used to skipped repositories from result. It inherits the global option [`repositories_skipped`](/source/plugins/base/README.md#repositories_skipped) which makes it easier to ignore repositories from all plugins at once. + +These options support two different syntaxes: + +### Basic pattern matching + +Skip repositories by: +- using their full handle (e.g. `user/repo`) +- using only their name (e.g. `repo`) + - *in this case, the owner may be implicitly set to current `user` option* + +*Example: skipping repositories with basic pattern matching* +```yml +repositories_skipped: my-repo, user/my-repo +``` + +> 💡 Either comma or newlines can be used to separate basic patterns + +### Advanced pattern matching + +To enable advanced pattern matching to skip repositories, include `@use.patterns` at the beginning of the option value. + +Skip repositories by writing file-glob patterns, with any of the supported operation: +- `#` to write comments +- `-` to exclude repositories + - *the `-` is implicit and may be omitted from excluding patterns* +- `+` to include back repositories + +> ℹ️ *metrics* use [isaacs/minimatch](https://github.com/isaacs/minimatch) as its file-glob matcher + +*Example: skipping repositories with basic advanced matching* +```yml +repositories_skipped: | + @use.patterns + + # Skip a specific repository (both patterns are equivalent) + user/repo + -user/repo + + # Skip repositories matching a given pattern + user/repo-* + {user1, user2, user3}/* + + # Include back a previously skipped repository + org/repo + +org/include-this-repo +``` + +> ℹ️ Unlike basic pattern matching, patterns are always tested against the full repository handle (the user will not be implicitly added) + +> ⚠️ As patterns may contain commas, be sure to use newlines rather than commas as separator to ensure patterns are correctly parsed + ## 🪛 Using presets It is possible to reuse the same configuration across different repositories and workflows using configuration presets. diff --git a/source/plugins/core/metadata.yml b/source/plugins/core/metadata.yml index d27330c7..d4e2f88e 100644 --- a/source/plugins/core/metadata.yml +++ b/source/plugins/core/metadata.yml @@ -138,8 +138,7 @@ inputs: Some templates may not support all options type: array default: css, xml - format: - - comma-separated + format: comma-separated values: - css - xml diff --git a/source/plugins/habits/metadata.yml b/source/plugins/habits/metadata.yml index 7f58399b..2b028e19 100644 --- a/source/plugins/habits/metadata.yml +++ b/source/plugins/habits/metadata.yml @@ -33,7 +33,9 @@ inputs: description: | Skipped repositories type: array - format: comma-separated + format: + - newline-separated + - comma-separated default: "" example: my-repo-1, my-repo-2, owner/repo-3, ... inherits: repositories_skipped diff --git a/source/plugins/languages/metadata.yml b/source/plugins/languages/metadata.yml index dc40837f..60e085e0 100644 --- a/source/plugins/languages/metadata.yml +++ b/source/plugins/languages/metadata.yml @@ -34,7 +34,9 @@ inputs: description: | Skipped repositories type: array - format: comma-separated + format: + - newline-separated + - comma-separated default: "" example: my-repo-1, my-repo-2, owner/repo-3, ... inherits: repositories_skipped diff --git a/source/plugins/lines/metadata.yml b/source/plugins/lines/metadata.yml index b1599c3f..1d3a69af 100644 --- a/source/plugins/lines/metadata.yml +++ b/source/plugins/lines/metadata.yml @@ -24,7 +24,9 @@ inputs: description: | Skipped repositories type: array - format: comma-separated + format: + - newline-separated + - comma-separated default: "" example: my-repo-1, my-repo-2, owner/repo-3, ... inherits: repositories_skipped diff --git a/source/plugins/notable/metadata.yml b/source/plugins/notable/metadata.yml index 8d4cc228..f1004fa8 100644 --- a/source/plugins/notable/metadata.yml +++ b/source/plugins/notable/metadata.yml @@ -35,7 +35,9 @@ inputs: description: | Skipped repositories type: array - format: comma-separated + format: + - newline-separated + - comma-separated default: "" example: my-repo-1, my-repo-2, owner/repo-3, ... inherits: repositories_skipped diff --git a/source/plugins/traffic/metadata.yml b/source/plugins/traffic/metadata.yml index 5aa33665..9e7742a2 100644 --- a/source/plugins/traffic/metadata.yml +++ b/source/plugins/traffic/metadata.yml @@ -23,7 +23,9 @@ inputs: description: | Skipped repositories type: array - format: comma-separated + format: + - newline-separated + - comma-separated default: "" example: my-repo-1, my-repo-2, owner/repo-3, ... inherits: repositories_skipped