chore: code formatting
This commit is contained in:
@@ -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}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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({
|
||||||
"commits.authoring": argv["commits-authoring"] || login,
|
q: {
|
||||||
}, account: "bypass"})
|
"commits.authoring": argv["commits-authoring"] || login,
|
||||||
|
},
|
||||||
|
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: {
|
||||||
"analysis.timeout": argv["timeout-global"] || "",
|
categories: argv.categories || "",
|
||||||
"analysis.timeout.repositories": argv["timeout-repositories"] || "",
|
"analysis.timeout": argv["timeout-global"] || "",
|
||||||
"recent.load": argv["recent-load"] || "",
|
"analysis.timeout.repositories": argv["timeout-repositories"] || "",
|
||||||
"recent.days": argv["recent-days"] || "",
|
"recent.load": argv["recent-load"] || "",
|
||||||
}, account: "bypass"})
|
"recent.days": argv["recent-days"] || "",
|
||||||
|
},
|
||||||
|
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})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,8 +74,9 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
})()
|
})()
|
||||||
|
|||||||
@@ -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`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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: [],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user