chore: code formatting

This commit is contained in:
github-actions[bot]
2022-10-16 18:44:18 +00:00
parent e863269d79
commit a8f95ebe5e
7 changed files with 92 additions and 89 deletions

View File

@@ -3,13 +3,12 @@ import fs from "fs/promises"
import os from "os" import os from "os"
import paths from "path" import paths from "path"
import git from "simple-git" import git from "simple-git"
import {filters} from "../../../app/metrics/utils.mjs" import { filters } from "../../../app/metrics/utils.mjs"
/**Analyzer */ /**Analyzer */
export class Analyzer { export class Analyzer {
/**Constructor */ /**Constructor */
constructor(login, {account = "bypass", authoring = [], uid = Math.random(), shell, rest = null, context = {mode:"user"}, skipped = [], categories = ["programming", "markup"], timeout = {global:NaN, repositories:NaN}}) { constructor(login, {account = "bypass", authoring = [], uid = Math.random(), shell, rest = null, context = {mode: "user"}, skipped = [], categories = ["programming", "markup"], timeout = {global: NaN, repositories: NaN}}) {
//User informations //User informations
this.login = login this.login = login
this.account = account this.account = account
@@ -22,9 +21,9 @@ export class Analyzer {
this.rest = rest this.rest = rest
this.context = context this.context = context
this.markers = { this.markers = {
hash:/\b[0-9a-f]{40}\b/, hash: /\b[0-9a-f]{40}\b/,
file:/^[+]{3}\sb[/](?<file>[\s\S]+)$/, file: /^[+]{3}\sb[/](?<file>[\s\S]+)$/,
line:/^(?<op>[-+])\s*(?<content>[\s\S]+)$/, line: /^(?<op>[-+])\s*(?<content>[\s\S]+)$/,
} }
this.parser = /^(?<login>[\s\S]+?)\/(?<name>[\s\S]+?)(?:@(?<branch>[\s\S]+?)(?::(?<ref>[\s\S]+))?)?$/ this.parser = /^(?<login>[\s\S]+?)\/(?<name>[\s\S]+?)(?:@(?<branch>[\s\S]+?)(?::(?<ref>[\s\S]+))?)?$/
this.consumed = false this.consumed = false
@@ -35,7 +34,7 @@ export class Analyzer {
this.timeout = timeout this.timeout = timeout
//Results //Results
this.results = {partial: {global:false, repositories:false}, total: 0, lines: {}, stats: {}, colors: {}, commits: 0, files: 0, missed: {lines: 0, bytes: 0, commits: 0}, elapsed:0} this.results = {partial: {global: false, repositories: false}, total: 0, lines: {}, stats: {}, colors: {}, commits: 0, files: 0, missed: {lines: 0, bytes: 0, commits: 0}, elapsed: 0}
this.debug(`instantiated a new ${this.constructor.name}`) this.debug(`instantiated a new ${this.constructor.name}`)
} }
@@ -65,7 +64,7 @@ export class Analyzer {
completed = true completed = true
solve(this.results) solve(this.results)
}) })
results.partial = (results.partial.global)||(results.partial.repositories) results.partial = (results.partial.global) || (results.partial.repositories)
return results return results
} }
@@ -76,7 +75,7 @@ export class Analyzer {
if (!this.parser.test(repository)) if (!this.parser.test(repository))
throw new TypeError(`"${repository}" pattern is not supported`) throw new TypeError(`"${repository}" pattern is not supported`)
const {login, name, ...groups} = repository.match(this.parser)?.groups ?? {} const {login, name, ...groups} = repository.match(this.parser)?.groups ?? {}
repository = {owner:{login}, name} repository = {owner: {login}, name}
branch = groups.branch ?? null branch = groups.branch ?? null
ref = groups.ref ?? null ref = groups.ref ?? null
} }
@@ -110,14 +109,14 @@ export class Analyzer {
/**Analyze a repository */ /**Analyze a repository */
async analyze(path, {commits = []} = {}) { async analyze(path, {commits = []} = {}) {
const cache = {files:{}, languages:{}} const cache = {files: {}, languages: {}}
const start = Date.now() const start = Date.now()
let elapsed = 0, processed = 0 let elapsed = 0, processed = 0
if (this.timeout.repositories) if (this.timeout.repositories)
this.debug(`timeout for repository analysis set to ${this.timeout.repositories}m`) this.debug(`timeout for repository analysis set to ${this.timeout.repositories}m`)
for (const commit of commits) { for (const commit of commits) {
elapsed = (Date.now() - start)/1000/60 elapsed = (Date.now() - start) / 1000 / 60
if ((this.timeout.repositories)&&(elapsed > this.timeout.repositories)) { if ((this.timeout.repositories) && (elapsed > this.timeout.repositories)) {
this.results.partial.repositories = true this.results.partial.repositories = true
this.debug(`reached maximum execution time of ${this.timeout.repositories}m for repository analysis (${elapsed}m elapsed)`) this.debug(`reached maximum execution time of ${this.timeout.repositories}m for repository analysis (${elapsed}m elapsed)`)
break break
@@ -145,8 +144,8 @@ export class Analyzer {
finally { finally {
this.results.elapsed += elapsed this.results.elapsed += elapsed
processed++ processed++
if ((processed%50 === 0)||(processed === commits.length)) if ((processed % 50 === 0) || (processed === commits.length))
this.debug(`at commit ${processed}/${commits.length} (${(100*processed/commits.length).toFixed(2)}%, ${elapsed.toFixed(2)}m elapsed)`) this.debug(`at commit ${processed}/${commits.length} (${(100 * processed / commits.length).toFixed(2)}%, ${elapsed.toFixed(2)}m elapsed)`)
} }
} }
this.results.colors = Object.fromEntries(Object.entries(cache.languages).map(([lang, {color}]) => [lang, color])) this.results.colors = Object.fromEntries(Object.entries(cache.languages).map(([lang, {color}]) => [lang, color]))
@@ -178,5 +177,4 @@ export class Analyzer {
debug(message) { debug(message) {
return console.debug(`metrics/compute/${this.login}/plugins > languages > ${this.constructor.name.replace(/([a-z])([A-Z])/, (_, a, b) => `${a} ${b.toLocaleLowerCase()}`).toLocaleLowerCase()} > ${message}`) return console.debug(`metrics/compute/${this.login}/plugins > languages > ${this.constructor.name.replace(/([a-z])([A-Z])/, (_, a, b) => `${a} ${b.toLocaleLowerCase()}`).toLocaleLowerCase()} > ${message}`)
} }
} }

View File

@@ -1,8 +1,8 @@
//Imports //Imports
import { IndepthAnalyzer } from "./indepth.mjs"
import { RecentAnalyzer } from "./recent.mjs"
import OctokitRest from "@octokit/rest" import OctokitRest from "@octokit/rest"
import yargsparser from "yargs-parser" import yargsparser from "yargs-parser"
import { IndepthAnalyzer } from "./indepth.mjs"
import { RecentAnalyzer } from "./recent.mjs"
const help = ` const help = `
@@ -19,25 +19,31 @@ export async function cli() {
} }
const {default: setup} = await import("../../../app/metrics/setup.mjs") const {default: setup} = await import("../../../app/metrics/setup.mjs")
const {conf: {metadata}} = await setup({log: false}) const {conf: {metadata}} = await setup({log: false})
const {login, _:repositories, mode = "indepth"} = argv const {login, _: repositories, mode = "indepth"} = argv
const { const {
"commits.authoring": authoring, "commits.authoring": authoring,
} = await metadata.plugins.base.inputs({q:{ } = await metadata.plugins.base.inputs({
q: {
"commits.authoring": argv["commits-authoring"] || login, "commits.authoring": argv["commits-authoring"] || login,
}, account: "bypass"}) },
account: "bypass",
})
const { const {
categories, categories,
"analysis.timeout":_timeout_global, "analysis.timeout": _timeout_global,
"analysis.timeout.repositories":_timeout_repositories, "analysis.timeout.repositories": _timeout_repositories,
"recent.load":_recent_load, "recent.load": _recent_load,
"recent.days":_recent_days, "recent.days": _recent_days,
} = await metadata.plugins.languages.inputs({q: { } = await metadata.plugins.languages.inputs({
categories:argv.categories || "", q: {
categories: argv.categories || "",
"analysis.timeout": argv["timeout-global"] || "", "analysis.timeout": argv["timeout-global"] || "",
"analysis.timeout.repositories": argv["timeout-repositories"] || "", "analysis.timeout.repositories": argv["timeout-repositories"] || "",
"recent.load": argv["recent-load"] || "", "recent.load": argv["recent-load"] || "",
"recent.days": argv["recent-days"] || "", "recent.days": argv["recent-days"] || "",
}, account: "bypass"}) },
account: "bypass",
})
//Prepare call //Prepare call
const imports = await import("../../../app/metrics/utils.mjs") const imports = await import("../../../app/metrics/utils.mjs")
@@ -50,14 +56,14 @@ export async function cli() {
console.log(`commits authoring | ${authoring}`) console.log(`commits authoring | ${authoring}`)
console.log(`analysis timeout (global) | ${_timeout_global}`) console.log(`analysis timeout (global) | ${_timeout_global}`)
switch (mode) { switch (mode) {
case "recent":{ case "recent": {
console.log(`events to load | ${_recent_load}`) console.log(`events to load | ${_recent_load}`)
console.log(`events maximum age | ${_recent_days}`) console.log(`events maximum age | ${_recent_days}`)
return new RecentAnalyzer(login, {rest, shell:imports, authoring, categories, timeout:{global:_timeout_global, repositories:_timeout_repositories}, load:_recent_load, days:_recent_days}).run({}) return new RecentAnalyzer(login, {rest, shell: imports, authoring, categories, timeout: {global: _timeout_global, repositories: _timeout_repositories}, load: _recent_load, days: _recent_days}).run({})
} }
case "indepth":{ case "indepth": {
console.log(`repositories | ${repositories}`) console.log(`repositories | ${repositories}`)
return new IndepthAnalyzer(login, {rest, shell:imports, authoring, categories, timeout:{global:_timeout_global, repositories:_timeout_repositories}}).run({repositories}) return new IndepthAnalyzer(login, {rest, shell: imports, authoring, categories, timeout: {global: _timeout_global, repositories: _timeout_repositories}}).run({repositories})
} }
} }
} }

View File

@@ -1,16 +1,16 @@
//Imports //Imports
import { Analyzer } from "./analyzer.mjs"
import fs from "fs/promises" import fs from "fs/promises"
import linguist from "linguist-js"
import os from "os" import os from "os"
import paths from "path" import paths from "path"
import linguist from "linguist-js" import { Analyzer } from "./analyzer.mjs"
/**Indepth analyzer */ /**Indepth analyzer */
export class IndepthAnalyzer extends Analyzer { export class IndepthAnalyzer extends Analyzer {
/**Constructor */ /**Constructor */
constructor() { constructor() {
super(...arguments) super(...arguments)
this.manual = {repositories:[]} this.manual = {repositories: []}
Object.assign(this.results, {verified: {signature: 0}}) Object.assign(this.results, {verified: {signature: 0}})
} }
@@ -74,9 +74,10 @@ export class IndepthAnalyzer extends Analyzer {
this.debug(`importing gpg ${id}`) this.debug(`importing gpg ${id}`)
await this.shell.run(`gpg --import ${path}`) await this.shell.run(`gpg --import ${path}`)
} }
else else {
this.debug("skipping import of gpg keys as we are not in GitHub Actions environment") this.debug("skipping import of gpg keys as we are not in GitHub Actions environment")
} }
}
catch (error) { catch (error) {
this.debug(`an error occurred while importing gpg ${id}, skipping...`) this.debug(`an error occurred while importing gpg ${id}, skipping...`)
} }
@@ -95,14 +96,14 @@ export class IndepthAnalyzer extends Analyzer {
for (const author of this.authoring) { for (const author of this.authoring) {
//Search by --author //Search by --author
{ {
const output = await this.shell.run(`git log --author='${author}' --pretty=format:"%H" --regexp-ignore-case --no-merges`, {cwd:path, env: {LANG: "en_GB"}}, {log:false, debug:false, prefixed: false}) const output = await this.shell.run(`git log --author='${author}' --pretty=format:"%H" --regexp-ignore-case --no-merges`, {cwd: path, env: {LANG: "en_GB"}}, {log: false, debug: false, prefixed: false})
const hashes = output.split("\n").map(line => line.trim()).filter(line => this.markers.hash.test(line)) const hashes = output.split("\n").map(line => line.trim()).filter(line => this.markers.hash.test(line))
hashes.forEach(hash => commits.add(hash)) hashes.forEach(hash => commits.add(hash))
this.debug(`found ${hashes.length} for ${author} (using --author)`) this.debug(`found ${hashes.length} for ${author} (using --author)`)
} }
//Search by --grep //Search by --grep
{ {
const output = await this.shell.run(`git log --grep='${author}' --pretty=format:"%H" --regexp-ignore-case --no-merges`, {cwd:path, env: {LANG: "en_GB"}}, {log:false, debug:false, prefixed: false}) const output = await this.shell.run(`git log --grep='${author}' --pretty=format:"%H" --regexp-ignore-case --no-merges`, {cwd: path, env: {LANG: "en_GB"}}, {log: false, debug: false, prefixed: false})
const hashes = output.split("\n").map(line => line.trim()).filter(line => this.markers.hash.test(line)) const hashes = output.split("\n").map(line => line.trim()).filter(line => this.markers.hash.test(line))
hashes.forEach(hash => commits.add(hash)) hashes.forEach(hash => commits.add(hash))
this.debug(`found ${hashes.length} for ${author} (using --grep)`) this.debug(`found ${hashes.length} for ${author} (using --grep)`)
@@ -111,7 +112,7 @@ export class IndepthAnalyzer extends Analyzer {
//Apply ref range if specified //Apply ref range if specified
if (ref) { if (ref) {
this.debug(`filtering commits referenced by ${ref} in ${path}`) this.debug(`filtering commits referenced by ${ref} in ${path}`)
const output = await this.shell.run(`git rev-list --boundary ${ref}`, {cwd:path, env: {LANG: "en_GB"}}, {log:false, debug:false, prefixed: false}) const output = await this.shell.run(`git rev-list --boundary ${ref}`, {cwd: path, env: {LANG: "en_GB"}}, {log: false, debug: false, prefixed: false})
const hashes = output.split("\n").map(line => line.trim()).filter(line => this.markers.hash.test(line)) const hashes = output.split("\n").map(line => line.trim()).filter(line => this.markers.hash.test(line))
commits.forEach(commit => !hashes.includes(commit) ? commits.delete(commit) : null) commits.forEach(commit => !hashes.includes(commit) ? commits.delete(commit) : null)
} }
@@ -131,8 +132,8 @@ export class IndepthAnalyzer extends Analyzer {
try { try {
commits.push({ commits.push({
sha, sha,
name: await this.shell.run(`git log ${sha} --format="%s (authored by %an on %cI)" --max-count=1`, {cwd: path, env: {LANG: "en_GB"}}, {log: false, debug:false, prefixed: false}), name: await this.shell.run(`git log ${sha} --format="%s (authored by %an on %cI)" --max-count=1`, {cwd: path, env: {LANG: "en_GB"}}, {log: false, debug: false, prefixed: false}),
verified: ("verified" in this.results) ? await this.shell.run(`git verify-commit ${sha}`, {cwd: path, env: {LANG: "en_GB"}}, {log: false, debug:false, prefixed: false}).then(() => true).catch(() => null) : null, verified: ("verified" in this.results) ? await this.shell.run(`git verify-commit ${sha}`, {cwd: path, env: {LANG: "en_GB"}}, {log: false, debug: false, prefixed: false}).then(() => true).catch(() => null) : null,
editions: await this.editions(path, {sha}), editions: await this.editions(path, {sha}),
}) })
} }
@@ -149,8 +150,8 @@ export class IndepthAnalyzer extends Analyzer {
let edition = null let edition = null
let cursor = 0 let cursor = 0
await this.shell.spawn("git", ["log", sha, "--format=''", "--max-count=1", "--patch"], {cwd: path, env: {LANG: "en_GB"}}, { await this.shell.spawn("git", ["log", sha, "--format=''", "--max-count=1", "--patch"], {cwd: path, env: {LANG: "en_GB"}}, {
debug:false, debug: false,
stdout:line => { stdout: line => {
try { try {
//Ignore empty lines or unneeded lines //Ignore empty lines or unneeded lines
cursor++ cursor++
@@ -161,26 +162,26 @@ export class IndepthAnalyzer extends Analyzer {
if (this.markers.file.test(line)) { if (this.markers.file.test(line)) {
edition = { edition = {
path: `${path}/${line.match(this.markers.file)?.groups?.file}`.replace(/\\/g, "/"), path: `${path}/${line.match(this.markers.file)?.groups?.file}`.replace(/\\/g, "/"),
added: {lines:0, bytes:0}, added: {lines: 0, bytes: 0},
deleted: {lines:0, bytes:0}, deleted: {lines: 0, bytes: 0},
} }
editions.push(edition) editions.push(edition)
return return
} }
//Line markers //Line markers
if ((edition)&&(this.markers.line.test(line))) { if ((edition) && (this.markers.line.test(line))) {
const {op = "+", content = ""} = line.match(this.markers.line)?.groups ?? {} const {op = "+", content = ""} = line.match(this.markers.line)?.groups ?? {}
const size = Buffer.byteLength(content, "utf-8") const size = Buffer.byteLength(content, "utf-8")
edition[{"+":"added", "-":"deleted"}[op]].bytes += size edition[{"+": "added", "-": "deleted"}[op]].bytes += size
edition[{"+":"added", "-":"deleted"}[op]].lines++ edition[{"+": "added", "-": "deleted"}[op]].lines++
return return
} }
} }
catch (error) { catch (error) {
this.debug(`skipping line ${sha}#${cursor} (${error})`) this.debug(`skipping line ${sha}#${cursor} (${error})`)
} }
} },
}) })
return editions return editions
} }
@@ -193,16 +194,16 @@ export class IndepthAnalyzer extends Analyzer {
/**Run linguist against a commit and compute edited lines and bytes*/ /**Run linguist against a commit and compute edited lines and bytes*/
async linguist(path, {commit, cache}) { async linguist(path, {commit, cache}) {
const result = {total:0, files:0, missed:{lines:0, bytes:0}, lines:{}, stats:{}} const result = {total: 0, files: 0, missed: {lines: 0, bytes: 0}, lines: {}, stats: {}}
const edited = new Set() const edited = new Set()
const seen = new Set() const seen = new Set()
for (const edition of commit.editions) { for (const edition of commit.editions) {
edited.add(edition.path) edited.add(edition.path)
//Guess file language with linguist (only run it once per sha) //Guess file language with linguist (only run it once per sha)
if ((!(edition.path in cache.files))&&(!seen.has(commit.sha))) { if ((!(edition.path in cache.files)) && (!seen.has(commit.sha))) {
this.debug(`language for file ${edition.path} is not in cache, running linguist at ${commit.sha}`) this.debug(`language for file ${edition.path} is not in cache, running linguist at ${commit.sha}`)
await this.shell.run(`git checkout ${commit.sha}`, {cwd: path, env: {LANG: "en_GB"}}, {log: false, debug:false, prefixed: false}) await this.shell.run(`git checkout ${commit.sha}`, {cwd: path, env: {LANG: "en_GB"}}, {log: false, debug: false, prefixed: false})
const {files: {results: files}, languages: {results: languages}} = await linguist(path) const {files: {results: files}, languages: {results: languages}} = await linguist(path)
Object.assign(cache.files, files) Object.assign(cache.files, files)
Object.assign(cache.languages, languages) Object.assign(cache.languages, languages)
@@ -227,6 +228,4 @@ export class IndepthAnalyzer extends Analyzer {
result.files = edited.size result.files = edited.size
return result return result
} }
} }

View File

@@ -1,7 +1,7 @@
//Imports //Imports
import { Analyzer } from "./analyzer.mjs"
import {filters} from "../../../app/metrics/utils.mjs"
import linguist from "linguist-js" import linguist from "linguist-js"
import { filters } from "../../../app/metrics/utils.mjs"
import { Analyzer } from "./analyzer.mjs"
/**Recent analyzer */ /**Recent analyzer */
export class RecentAnalyzer extends Analyzer { export class RecentAnalyzer extends Analyzer {
@@ -10,7 +10,7 @@ export class RecentAnalyzer extends Analyzer {
super(...arguments) super(...arguments)
this.days = arguments[1]?.days ?? 0 this.days = arguments[1]?.days ?? 0
this.load = arguments[1]?.load ?? 0 this.load = arguments[1]?.load ?? 0
Object.assign(this.results, {days:this.days}) Object.assign(this.results, {days: this.days})
} }
/**Run analyzer */ /**Run analyzer */
@@ -23,7 +23,7 @@ export class RecentAnalyzer extends Analyzer {
/**Analyze a repository */ /**Analyze a repository */
async analyze(path) { async analyze(path) {
const patches = await this.patches() const patches = await this.patches()
return super.analyze(path, {commits:patches}) return super.analyze(path, {commits: patches})
} }
/**Fetch patches */ /**Fetch patches */
@@ -33,7 +33,7 @@ export class RecentAnalyzer extends Analyzer {
const commits = [], pages = Math.ceil((this.load || Infinity) / 100) const commits = [], pages = Math.ceil((this.load || Infinity) / 100)
if (this.context.mode === "repository") { if (this.context.mode === "repository") {
try { try {
const {data:{default_branch:branch}} = await this.rest.repos.get(this.context) const {data: {default_branch: branch}} = await this.rest.repos.get(this.context)
this.context.branch = branch this.context.branch = branch
this.results.branch = branch this.results.branch = branch
this.debug(`default branch for ${this.context.owner}/${this.context.repo} is ${branch}`) this.debug(`default branch for ${this.context.owner}/${this.context.repo} is ${branch}`)
@@ -47,10 +47,10 @@ export class RecentAnalyzer extends Analyzer {
this.debug(`fetching events page ${page}`) this.debug(`fetching events page ${page}`)
commits.push( commits.push(
...(await (this.context.mode === "repository" ? this.rest.activity.listRepoEvents(this.context) : this.rest.activity.listEventsForAuthenticatedUser({username: this.login, per_page: 100, page}))).data ...(await (this.context.mode === "repository" ? this.rest.activity.listRepoEvents(this.context) : this.rest.activity.listEventsForAuthenticatedUser({username: this.login, per_page: 100, page}))).data
.filter(({type, payload}) => (type === "PushEvent")&&((this.context.mode !== "repository")||((this.context.mode === "repository")&&(payload?.ref?.includes?.(`refs/heads/${this.context.branch}`))))) .filter(({type, payload}) => (type === "PushEvent") && ((this.context.mode !== "repository") || ((this.context.mode === "repository") && (payload?.ref?.includes?.(`refs/heads/${this.context.branch}`)))))
.filter(({actor}) => (this.account === "organization")||(this.context.mode === "repository") ? true : !filters.text(actor.login, [this.login], {debug:false})) .filter(({actor}) => (this.account === "organization") || (this.context.mode === "repository") ? true : !filters.text(actor.login, [this.login], {debug: false}))
.filter(({repo: {name: repo}}) => !this.ignore(repo)) .filter(({repo: {name: repo}}) => !this.ignore(repo))
.filter(({created_at}) => ((!this.days)||(new Date(created_at) > new Date(Date.now() - this.days * 24 * 60 * 60 * 1000)))), .filter(({created_at}) => ((!this.days) || (new Date(created_at) > new Date(Date.now() - this.days * 24 * 60 * 60 * 1000)))),
) )
} }
} }
@@ -67,7 +67,7 @@ export class RecentAnalyzer extends Analyzer {
...await Promise.allSettled( ...await Promise.allSettled(
commits commits
.flatMap(({payload}) => payload.commits) .flatMap(({payload}) => payload.commits)
.filter(({committer}) => filters.text(committer?.email, this.authoring, {debug:false})) .filter(({committer}) => filters.text(committer?.email, this.authoring, {debug: false}))
.map(commit => commit.url) .map(commit => commit.url)
.map(async commit => (await this.rest.request(commit)).data), .map(async commit => (await this.rest.request(commit)).data),
), ),
@@ -75,15 +75,15 @@ export class RecentAnalyzer extends Analyzer {
.filter(({status}) => status === "fulfilled") .filter(({status}) => status === "fulfilled")
.map(({value}) => value) .map(({value}) => value)
.filter(({parents}) => parents.length <= 1) .filter(({parents}) => parents.length <= 1)
.map(({sha, commit:{message, committer}, verification, files}) => ({ .map(({sha, commit: {message, committer}, verification, files}) => ({
sha, sha,
name:`${message} (authored by ${committer.name} on ${committer.date})`, name: `${message} (authored by ${committer.name} on ${committer.date})`,
verified:verification?.verified ?? null, verified: verification?.verified ?? null,
editions:files.map(({filename, patch = ""}) => { editions: files.map(({filename, patch = ""}) => {
const edition = { const edition = {
path: filename, path: filename,
added: {lines:0, bytes:0}, added: {lines: 0, bytes: 0},
deleted: {lines:0, bytes:0}, deleted: {lines: 0, bytes: 0},
patch, patch,
} }
for (const line of patch.split("\n")) { for (const line of patch.split("\n")) {
@@ -92,27 +92,27 @@ export class RecentAnalyzer extends Analyzer {
if (this.markers.line.test(line)) { if (this.markers.line.test(line)) {
const {op = "+", content = ""} = line.match(this.markers.line)?.groups ?? {} const {op = "+", content = ""} = line.match(this.markers.line)?.groups ?? {}
const size = Buffer.byteLength(content, "utf-8") const size = Buffer.byteLength(content, "utf-8")
edition[{"+":"added", "-":"deleted"}[op]].bytes += size edition[{"+": "added", "-": "deleted"}[op]].bytes += size
edition[{"+":"added", "-":"deleted"}[op]].lines++ edition[{"+": "added", "-": "deleted"}[op]].lines++
continue continue
} }
} }
return edition return edition
}) }),
})) }))
return patches return patches
} }
/**Run linguist against a commit and compute edited lines and bytes*/ /**Run linguist against a commit and compute edited lines and bytes*/
async linguist(_, {commit, cache:{languages}}) { async linguist(_, {commit, cache: {languages}}) {
const cache = {files:{}, languages} const cache = {files: {}, languages}
const result = {total:0, files:0, missed:{lines:0, bytes:0}, lines:{}, stats:{}, languages:{}} const result = {total: 0, files: 0, missed: {lines: 0, bytes: 0}, lines: {}, stats: {}, languages: {}}
const edited = new Set() const edited = new Set()
for (const edition of commit.editions) { for (const edition of commit.editions) {
edited.add(edition.path) edited.add(edition.path)
//Guess file language with linguist //Guess file language with linguist
const {files: {results: files}, languages: {results: languages}, unknown} = await linguist(edition.path, {fileContent:edition.patch}) const {files: {results: files}, languages: {results: languages}, unknown} = await linguist(edition.path, {fileContent: edition.patch})
Object.assign(cache.files, files) Object.assign(cache.files, files)
Object.assign(cache.languages, languages) Object.assign(cache.languages, languages)
if (!(edition.path in cache.files)) if (!(edition.path in cache.files))
@@ -140,5 +140,4 @@ export class RecentAnalyzer extends Analyzer {
result.languages = cache.languages result.languages = cache.languages
return result return result
} }
} }

View File

@@ -1,21 +1,21 @@
//Imports //Imports
import { cli } from "./analyzer/cli.mjs"
import { IndepthAnalyzer } from "./analyzer/indepth.mjs" import { IndepthAnalyzer } from "./analyzer/indepth.mjs"
import { RecentAnalyzer } from "./analyzer/recent.mjs" import { RecentAnalyzer } from "./analyzer/recent.mjs"
import { cli } from "./analyzer/cli.mjs"
/**Indepth analyzer */ /**Indepth analyzer */
export async function indepth({login, data, imports, rest, context, repositories}, {skipped, categories, timeout}) { export async function indepth({login, data, imports, rest, context, repositories}, {skipped, categories, timeout}) {
return new IndepthAnalyzer(login, {shell:imports, uid:data.user.databaseId, skipped, authoring:data.shared["commits.authoring"], timeout, rest, context, categories}).run({repositories}) return new IndepthAnalyzer(login, {shell: imports, uid: data.user.databaseId, skipped, authoring: data.shared["commits.authoring"], timeout, rest, context, categories}).run({repositories})
} }
/**Recent languages activity */ /**Recent languages activity */
export async function recent({login, data, imports, rest, context, account}, {skipped = [], categories, days = 0, load = 0, timeout}) { export async function recent({login, data, imports, rest, context, account}, {skipped = [], categories, days = 0, load = 0, timeout}) {
return new RecentAnalyzer(login, {shell:imports, uid:data.user.databaseId, skipped, authoring:data.shared["commits.authoring"], timeout, account, rest, context, days, categories, load}).run() return new RecentAnalyzer(login, {shell: imports, uid: data.user.databaseId, skipped, authoring: data.shared["commits.authoring"], timeout, account, rest, context, days, categories, load}).run()
} }
//import.meta.main //import.meta.main
if (/languages.analyzers.mjs$/.test(process.argv[1])) { if (/languages.analyzers.mjs$/.test(process.argv[1])) {
(async () => { ;(async () => {
console.log(await cli()) console.log(await cli())
process.exit(0) process.exit(0)
})() })()

View File

@@ -18,13 +18,14 @@ export default async function({login, data, imports, q, rest, account}, {enabled
} }
//Load inputs //Load inputs
let {ignored, skipped, other, colors, aliases, details, threshold, limit, indepth, "indepth.custom":_indepth_custom, "analysis.timeout": _timeout_global, "analysis.timeout.repositories": _timeout_repositories, sections, categories, "recent.categories": _recent_categories, "recent.load": _recent_load, "recent.days": _recent_days} = imports.metadata.plugins.languages let {ignored, skipped, other, colors, aliases, details, threshold, limit, indepth, "indepth.custom": _indepth_custom, "analysis.timeout": _timeout_global, "analysis.timeout.repositories": _timeout_repositories, sections, categories, "recent.categories": _recent_categories, "recent.load": _recent_load, "recent.days": _recent_days} = imports.metadata
.plugins.languages
.inputs({ .inputs({
data, data,
account, account,
q, q,
}) })
const timeout = {global:_timeout_global, repositories:_timeout_repositories} const timeout = {global: _timeout_global, repositories: _timeout_repositories}
threshold = (Number(threshold.replace(/%$/, "")) || 0) / 100 threshold = (Number(threshold.replace(/%$/, "")) || 0) / 100
skipped.push(...data.shared["repositories.skipped"]) skipped.push(...data.shared["repositories.skipped"])
if (!limit) if (!limit)
@@ -80,7 +81,7 @@ export default async function({login, data, imports, q, rest, account}, {enabled
try { try {
console.debug(`metrics/compute/${login}/plugins > languages > switching to indepth mode (this may take some time)`) console.debug(`metrics/compute/${login}/plugins > languages > switching to indepth mode (this may take some time)`)
const existingColors = languages.colors const existingColors = languages.colors
Object.assign(languages, await indepth_analyzer({login, data, imports, rest, context, repositories:repositories.concat(_indepth_custom)}, {skipped, categories, timeout})) Object.assign(languages, await indepth_analyzer({login, data, imports, rest, context, repositories: repositories.concat(_indepth_custom)}, {skipped, categories, timeout}))
Object.assign(languages.colors, existingColors) Object.assign(languages.colors, existingColors)
console.debug(`metrics/compute/${login}/plugins > languages > indepth analysis processed successfully ${languages.commits} and missed ${languages.missed.commits} commits in ${languages.elapsed.toFixed(2)}m`) console.debug(`metrics/compute/${login}/plugins > languages > indepth analysis processed successfully ${languages.commits} and missed ${languages.missed.commits} commits in ${languages.elapsed.toFixed(2)}m`)
} }

View File

@@ -52,7 +52,7 @@ export default async function({faker}, target, that, args) {
patch: '@@ -0,0 +1,5 @@\n+//Imports\n+ import app from "./src/app.mjs"\n+\n+//Start app\n+ await app()\n\\ No newline at end of file', patch: '@@ -0,0 +1,5 @@\n+//Imports\n+ import app from "./src/app.mjs"\n+\n+//Start app\n+ await app()\n\\ No newline at end of file',
}, },
], ],
parents: [] parents: [],
}, },
}) })
} }