UNPKG

@immobiliarelabs/backstage-plugin-gitlab

Version:

<p align="center"> <img src="https://avatars.githubusercontent.com/u/10090828?s=200&v=4" width="200px" alt="logo"/> </p> <h1 align="center">Backstage Plugin GitLab</h1>

2,310 lines (2,297 loc) 54.3 kB
import { createApiRef, createRouteRef, createPlugin, createApiFactory, configApiRef, discoveryApiRef, identityApiRef, createRoutableExtension, createComponentExtension, useApi } from '@backstage/core-plugin-api'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import duration from 'dayjs/plugin/duration'; import React, { useState } from 'react'; import { useEntity } from '@backstage/plugin-catalog-react'; import { Progress, InfoCard, Link, StructuredMetadataTable, MarkdownContent } from '@backstage/core-components'; import { Tooltip, Chip, Avatar, Box, Grid, Divider, makeStyles as makeStyles$1, FormControl, Select, MenuItem, FormHelperText, Link as Link$1 } from '@material-ui/core'; import { makeStyles, withStyles } from '@material-ui/core/styles'; import Alert from '@material-ui/lab/Alert'; import { useAsync } from 'react-use'; import '@backstage/integration-react'; import '@backstage/catalog-model'; import ArrowIcon from '@material-ui/icons/ArrowForward'; import '@material-ui/core/Link'; import LocalOfferOutlinedIcon from '@material-ui/icons/LocalOfferOutlined'; import { rcompare, valid, prerelease } from 'semver'; const GitlabCIApiRef = createApiRef({ id: "plugin.gitlabci.service" }); dayjs.extend(relativeTime); dayjs.extend(duration); const getElapsedTime = (start) => { return dayjs(start).fromNow(); }; const getDuration = (start, end) => { if (!end || !start) { return "NA"; } const end_time = dayjs(end); const start_time = dayjs(start); const duration2 = dayjs.duration( end_time.diff(start_time, "seconds"), "seconds" ); const days = duration2.days(); const hours = duration2.hours(); const minutes = duration2.minutes(); const seconds = duration2.seconds(); const output = `${days ? days + "d " : ""}${hours ? hours + "h " : ""}${minutes ? minutes + "m " : ""}${seconds ? seconds + "s" : ""}`; if (!output) return "0s"; return output; }; const parseCodeOwners = (str) => { try { const lines = str.replace(/\r/g, "").split("\n"); const owned = []; for (const line of lines) { if (!line || line.startsWith("#")) { continue; } owned.push(parseCodeOwnerLine(line)); } return owned; } catch (error) { console.log(`failed to load codeowners`, error); throw error; } }; const parseCodeOwnerLine = (rule) => { const parts = rule.split(/\s+/); const path = parts[0]; let teamNames = []; if (parts.length > 1) { teamNames = parts.slice(1, parts.length); for (const name of teamNames) { if (!codeOwnerRegex.test(name)) { throw new Error( `${name} is not a valid owner name in rule ${rule}` ); } } } return { rule, path, owners: teamNames }; }; const codeOwnerRegex = /(^@[a-zA-Z0-9_\-/]*$)|(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/; class GitlabCIClient { constructor({ discoveryApi, identityApi, codeOwnersPath, readmePath, gitlabInstance }) { this.discoveryApi = discoveryApi; this.codeOwnersPath = codeOwnersPath || "CODEOWNERS"; this.readmePath = readmePath || "README.md"; this.gitlabInstance = gitlabInstance; this.identityApi = identityApi; } static setupAPI({ discoveryApi, identityApi, codeOwnersPath, readmePath }) { return { build: (gitlabInstance) => new this({ discoveryApi, identityApi, codeOwnersPath, readmePath, gitlabInstance }) }; } async callApi(path, query) { var _a; const apiUrl = `${await this.discoveryApi.getBaseUrl("gitlab")}/${this.gitlabInstance}`; const token = (await this.identityApi.getCredentials()).token; const options = token ? { headers: { Authorization: `Bearer ${token}` } } : {}; const response = await fetch( `${apiUrl}/${path}?${new URLSearchParams(query).toString()}`, options ); if (response.status === 200) { if ((_a = response.headers.get("content-type")) == null ? void 0 : _a.includes("application/json")) { return await response.json(); } else { return response.text(); } } return null; } async getPipelineSummary(projectID) { const pipelineObjects = await this.callApi( "projects/" + projectID + "/pipelines", {} ); const projectObj = await this.callApi( "projects/" + projectID, {} ); if (pipelineObjects) { pipelineObjects.forEach((element) => { element.project_name = projectObj == null ? void 0 : projectObj.name; }); } return { getPipelinesData: pipelineObjects }; } async getIssuesSummary(projectId) { const issuesObject = await this.callApi( `projects/${projectId}/issues`, {} ); const projectObj = await this.callApi( "projects/" + projectId, {} ); if (issuesObject) { issuesObject.forEach((element) => { element.project_name = projectObj == null ? void 0 : projectObj.name; }); } return { getIssuesData: issuesObject }; } async getProjectName(projectID) { const projectObj = await this.callApi( "projects/" + projectID, {} ); return projectObj == null ? void 0 : projectObj.name; } //TODO: Merge with getUserDetail async getUserProfilesData(contributorsData) { for (let i = 0; contributorsData && i < contributorsData.length; i++) { const userProfile = await this.callApi("users", { search: contributorsData[i].email, without_project_bots: "true" }); if (userProfile) { userProfile.forEach( (userProfileElement) => { if (userProfileElement.name == contributorsData[i].name) { contributorsData[i].avatar_url = userProfileElement == null ? void 0 : userProfileElement.avatar_url; } } ); } } return contributorsData; } async getUserDetail(username) { var _a; if (username.startsWith("@")) { username = username.slice(1); } const userDetail = (_a = await this.callApi("users", { username })) == null ? void 0 : _a[0]; if (!userDetail) throw new Error(`user ${username} does not exist`); return userDetail; } async getGroupDetail(name) { if (name.startsWith("@")) { name = name.slice(1); } const groupDetail = await this.callApi( `groups/${encodeURIComponent(name)}`, { with_projects: "false" } ); if (!groupDetail) throw new Error(`group ${name} does not exist`); return groupDetail; } async getMergeRequestsSummary(projectID) { const mergeRquestsList = await this.callApi( "projects/" + projectID + "/merge_requests", {} ); return { getMergeRequestsData: mergeRquestsList }; } async getMergeRequestsStatusSummary(projectID, count) { const mergeRequestsList = await this.callApi( "projects/" + projectID + "/merge_requests", { per_page: count } ); return { getMergeRequestsStatusData: mergeRequestsList }; } async getContributorsSummary(projectID) { const contributorsData = await this.callApi( "projects/" + projectID + "/repository/contributors", { sort: "desc" } ); const updatedContributorsData = await this.getUserProfilesData( contributorsData ); return { getContributorsData: updatedContributorsData }; } async getLanguagesSummary(projectID) { const languageObjects = await this.callApi( "projects/" + projectID + "/languages", {} ); return { getLanguagesData: languageObjects }; } async getReleasesSummary(projectID) { const releaseObjects = await this.callApi( "projects/" + projectID + "/releases", {} ); return { getReleasesData: releaseObjects }; } async getProjectDetails(projectSlug) { let projectDetails; if (projectSlug) { projectDetails = await this.callApi( "projects/" + encodeURIComponent(projectSlug), {} ); } return projectDetails; } async retryPipelineBuild(projectID, pipelineID) { const retryBuild = await this.callApi( "projects/" + projectID + "/pipelines/" + pipelineID + "/retry", {} ); return retryBuild; } async getCodeOwners(projectID, branch = "HEAD", filePath) { filePath = filePath || this.codeOwnersPath; if (filePath.startsWith("./")) filePath = filePath.slice(2); const codeOwnersStr = await this.callApi( `projects/${projectID}/repository/files/${encodeURI(filePath)}/raw`, { ref: branch } ); if (!codeOwnersStr) { throw Error(`Code owners file not found`); } const codeOwners = parseCodeOwners(codeOwnersStr || ""); const dataOwners = codeOwners; const uniqueOwners = [ ...new Set(dataOwners.flatMap((owner) => owner.owners)) ]; const ownersSettledResult = await Promise.allSettled( uniqueOwners.map(async (owner) => { try { const ownerData = await this.getUserDetail(owner); return ownerData; } catch (error) { const ownerData = await this.getGroupDetail(owner); return ownerData; } }) ); const owners = ownersSettledResult.filter((result) => result.status === "fulfilled").map( (result) => result.value ); return owners; } async getReadme(projectID, branch = "HEAD", filePath) { filePath = filePath || this.readmePath; if (filePath.startsWith("./")) filePath = filePath.slice(2); const readmeStr = await this.callApi( `projects/${projectID}/repository/files/${encodeURI(filePath)}/raw`, { ref: branch } ); if (!readmeStr) { throw Error(`README file not found`); } return readmeStr; } getContributorsLink(projectWebUrl, projectDefaultBranch) { return `${projectWebUrl}/-/graphs/${projectDefaultBranch}`; } getOwnersLink(projectWebUrl, projectDefaultBranch, codeOwnersPath) { return `${projectWebUrl}/-/blob/${projectDefaultBranch}/${codeOwnersPath || this.codeOwnersPath}`; } } const rootRouteRef = createRouteRef({ id: "Gitlab" }); const gitlabPlugin = createPlugin({ id: "Gitlab", apis: [ createApiFactory({ api: GitlabCIApiRef, deps: { configApi: configApiRef, discoveryApi: discoveryApiRef, identityApi: identityApiRef }, factory: ({ configApi, discoveryApi, identityApi }) => GitlabCIClient.setupAPI({ discoveryApi, identityApi, codeOwnersPath: configApi.getOptionalString( "gitlab.defaultCodeOwnersPath" ), readmePath: configApi.getOptionalString( "gitlab.defaultReadmePath" ) }) }) ] }); const EntityGitlabContent = gitlabPlugin.provide( createRoutableExtension({ name: "EntityGitlabContent", component: () => import('./index-f78e0833.esm.js').then((m) => m.GitlabCI), mountPoint: rootRouteRef }) ); const EntityGitlabLanguageCard = gitlabPlugin.provide( createComponentExtension({ name: "EntityGitlabLanguageCard", component: { lazy: () => import('./index-d6520eff.esm.js').then( (m) => m.LanguagesCard ) } }) ); const EntityGitlabPeopleCard = gitlabPlugin.provide( createComponentExtension({ name: "EntityGitlabPeopleCard", component: { lazy: () => import('./index-d6520eff.esm.js').then((m) => m.PeopleCard) } }) ); const EntityGitlabMergeRequestsTable = gitlabPlugin.provide( createComponentExtension({ name: "EntityGitlabMergeRequestsTable", component: { lazy: () => import('./index-d6520eff.esm.js').then( (m) => m.MergeRequestsTable ) } }) ); const EntityGitlabMergeRequestStatsCard = gitlabPlugin.provide( createComponentExtension({ name: "EntityGitlabMergeRequestStatsCard", component: { lazy: () => import('./index-d6520eff.esm.js').then( (m) => m.MergeRequestStats ) } }) ); const EntityGitlabPipelinesTable = gitlabPlugin.provide( createComponentExtension({ name: "EntityGitlabPipelinesTable", component: { lazy: () => import('./index-d6520eff.esm.js').then( (m) => m.PipelinesTable ) } }) ); const EntityGitlabReleasesCard = gitlabPlugin.provide( createComponentExtension({ name: "EntityGitlabReleasesCard", component: { lazy: () => import('./index-d6520eff.esm.js').then( (m) => m.ReleasesCard ) } }) ); const EntityGitlabIssuesTable = gitlabPlugin.provide( createComponentExtension({ name: "EntityGitlabIssuesTable", component: { lazy: () => import('./index-d6520eff.esm.js').then((m) => m.IssuesTable) } }) ); const EntityGitlabReadmeCard = gitlabPlugin.provide( createComponentExtension({ name: "EntityGitlabReadmeCard", component: { lazy: () => import('./index-d6520eff.esm.js').then((m) => m.ReadmeCard) } }) ); const GITLAB_ANNOTATION_PROJECT_ID = "gitlab.com/project-id"; const GITLAB_ANNOTATION_PROJECT_SLUG = "gitlab.com/project-slug"; const GITLAB_ANNOTATION_INSTANCE = "gitlab.com/instance"; const GITLAB_ANNOTATION_CODEOWNERS_PATH = "gitlab.com/codeowners-path"; const GITLAB_ANNOTATION_README_PATH = "gitlab.com/readme-path"; const gitlabProjectId = () => { var _a, _b; const { entity } = useEntity(); const project_id = (_b = (_a = entity.metadata.annotations) == null ? void 0 : _a[GITLAB_ANNOTATION_PROJECT_ID]) != null ? _b : ""; return project_id; }; const gitlabProjectSlug = () => { var _a, _b; const { entity } = useEntity(); const project_slug = (_b = (_a = entity.metadata.annotations) == null ? void 0 : _a[GITLAB_ANNOTATION_PROJECT_SLUG]) != null ? _b : ""; return project_slug; }; const gitlabInstance = () => { var _a, _b; const { entity } = useEntity(); const instance = (_b = (_a = entity.metadata.annotations) == null ? void 0 : _a[GITLAB_ANNOTATION_INSTANCE]) != null ? _b : ""; return instance; }; const gitlabCodeOwnerPath = () => { var _a, _b; const { entity } = useEntity(); const codeowners_path = (_b = (_a = entity.metadata.annotations) == null ? void 0 : _a[GITLAB_ANNOTATION_CODEOWNERS_PATH]) != null ? _b : ""; return codeowners_path; }; const gitlabReadmePath = () => { var _a, _b; const { entity } = useEntity(); const readme_path = (_b = (_a = entity.metadata.annotations) == null ? void 0 : _a[GITLAB_ANNOTATION_README_PATH]) != null ? _b : ""; return readme_path; }; const colors = { "1C Enterprise": { color: "#814CCC" }, "4D": { color: "inherit" }, ABAP: { color: "#E8274B" }, ActionScript: { color: "#882B0F" }, Ada: { color: "#02f88c" }, Agda: { color: "#315665" }, "AGS Script": { color: "#B9D9FF" }, AL: { color: "#3AA2B5" }, Alloy: { color: "#64C800" }, "Alpine Abuild": { color: "inherit" }, AMPL: { color: "#E6EFBB" }, AngelScript: { color: "#C7D7DC" }, ANTLR: { color: "#9DC3FF" }, Apex: { color: "#1797c0" }, "API Blueprint": { color: "#2ACCA8" }, APL: { color: "#5A8164" }, "Apollo Guidance Computer": { color: "#0B3D91" }, AppleScript: { color: "#101F1F" }, Arc: { color: "#aa2afe" }, ASL: { color: "inherit" }, "ASP.NET": { color: "#9400ff" }, AspectJ: { color: "#a957b0" }, Assembly: { color: "#6E4C13" }, Asymptote: { color: "#ff0000" }, ATS: { color: "#1ac620" }, Augeas: { color: "inherit" }, AutoHotkey: { color: "#6594b9" }, AutoIt: { color: "#1C3552" }, Awk: { color: "inherit" }, Ballerina: { color: "#FF5000" }, Batchfile: { color: "#C1F12E" }, Befunge: { color: "inherit" }, Bison: { color: "#6A463F" }, BitBake: { color: "inherit" }, Blade: { color: "#f7523f" }, BlitzBasic: { color: "inherit" }, BlitzMax: { color: "#cd6400" }, Bluespec: { color: "inherit" }, Boo: { color: "#d4bec1" }, Brainfuck: { color: "#2F2530" }, Brightscript: { color: "inherit" }, C: { color: "#555555" }, "C#": { color: "#178600" }, "C++": { color: "#f34b7d" }, "C2hs Haskell": { color: "inherit" }, "Cap'n Proto": { color: "inherit" }, CartoCSS: { color: "inherit" }, Ceylon: { color: "#dfa535" }, Chapel: { color: "#8dc63f" }, Charity: { color: "inherit" }, ChucK: { color: "inherit" }, Cirru: { color: "#ccccff" }, Clarion: { color: "#db901e" }, "Classic ASP": { color: "#6a40fd" }, Clean: { color: "#3F85AF" }, Click: { color: "#E4E6F3" }, CLIPS: { color: "inherit" }, Clojure: { color: "#db5855" }, CMake: { color: "inherit" }, COBOL: { color: "inherit" }, CodeQL: { color: "inherit" }, CoffeeScript: { color: "#244776" }, ColdFusion: { color: "#ed2cd6" }, "ColdFusion CFC": { color: "#ed2cd6" }, "Common Lisp": { color: "#3fb68b" }, "Common Workflow Language": { color: "#B5314C" }, "Component Pascal": { color: "#B0CE4E" }, Cool: { color: "inherit" }, Coq: { color: "inherit" }, Crystal: { color: "#000100" }, CSON: { color: "#244776" }, Csound: { color: "inherit" }, "Csound Document": { color: "inherit" }, "Csound Score": { color: "inherit" }, CSS: { color: "#563d7c" }, Cuda: { color: "#3A4E3A" }, CWeb: { color: "inherit" }, Cycript: { color: "inherit" }, Cython: { color: "inherit" }, D: { color: "#ba595e" }, Dafny: { color: "#FFEC25" }, Dart: { color: "#00B4AB" }, Gnuplot: { color: "#f0a9f0" }, DataWeave: { color: "#003a52" }, Dhall: { color: "#dfafff" }, "DIGITAL Command Language": { color: "inherit" }, DM: { color: "#447265" }, Dockerfile: { color: "#384d54" }, Dogescript: { color: "#cca760" }, DTrace: { color: "inherit" }, Dylan: { color: "#6c616e" }, E: { color: "#ccce35" }, eC: { color: "#913960" }, ECL: { color: "#8a1267" }, ECLiPSe: { color: "inherit" }, Eiffel: { color: "#4d6977" }, EJS: { color: "#a91e50" }, Elixir: { color: "#6e4a7e" }, Elm: { color: "#60B5CC" }, "Emacs Lisp": { color: "#c065db" }, EmberScript: { color: "#FFF4F3" }, EQ: { color: "#a78649" }, Erlang: { color: "#B83998" }, "F#": { color: "#b845fc" }, "F*": { color: "#572e30" }, Factor: { color: "#636746" }, Fancy: { color: "#7b9db4" }, Fantom: { color: "#14253c" }, Faust: { color: "#c37240" }, "Filebench WML": { color: "inherit" }, Filterscript: { color: "inherit" }, fish: { color: "inherit" }, FLUX: { color: "#88ccff" }, Forth: { color: "#341708" }, Fortran: { color: "#4d41b1" }, "Fortran Free Form": { color: "inherit" }, FreeMarker: { color: "#0050b2" }, Frege: { color: "#00cafe" }, Futhark: { color: "#5f021f" }, "G-code": { color: "#D08CF2" }, "Game Maker Language": { color: "#71b417" }, GAML: { color: "#FFC766" }, GAMS: { color: "inherit" }, GAP: { color: "inherit" }, "GCC Machine Description": { color: "inherit" }, GDB: { color: "inherit" }, GDScript: { color: "#355570" }, Genie: { color: "#fb855d" }, Genshi: { color: "inherit" }, "Gentoo Ebuild": { color: "inherit" }, "Gentoo Eclass": { color: "inherit" }, Gherkin: { color: "#5B2063" }, GLSL: { color: "inherit" }, Glyph: { color: "#c1ac7f" }, Go: { color: "#00ADD8" }, Golo: { color: "#88562A" }, Gosu: { color: "#82937f" }, Grace: { color: "inherit" }, "Grammatical Framework": { color: "#ff0000" }, GraphQL: { color: "#e10098" }, Groovy: { color: "#e69f56" }, "Groovy Server Pages": { color: "inherit" }, Hack: { color: "#878787" }, Haml: { color: "#ece2a9" }, Handlebars: { color: "#f7931e" }, Harbour: { color: "#0e60e3" }, Haskell: { color: "#5e5086" }, Haxe: { color: "#df7900" }, HCL: { color: "#00dfd4" }, HiveQL: { color: "#dce200" }, HLSL: { color: "inherit" }, HolyC: { color: "#ffefaf" }, HTML: { color: "#e34c26" }, Hy: { color: "#7790B2" }, HyPhy: { color: "inherit" }, IDL: { color: "#a3522f" }, Idris: { color: "#b30000" }, "IGOR Pro": { color: "#0000cc" }, "Inform 7": { color: "inherit" }, "Inno Setup": { color: "inherit" }, Io: { color: "#a9188d" }, Ioke: { color: "#078193" }, Isabelle: { color: "#FEFE00" }, "Isabelle ROOT": { color: "inherit" }, J: { color: "#9EEDFF" }, Jasmin: { color: "inherit" }, Java: { color: "#b07219" }, "Java Server Pages": { color: "inherit" }, JavaScript: { color: "#f1e05a" }, "JavaScript+ERB": { color: "inherit" }, JFlex: { color: "#DBCA00" }, Jison: { color: "inherit" }, "Jison Lex": { color: "inherit" }, Jolie: { color: "#843179" }, JSONiq: { color: "#40d47e" }, Jsonnet: { color: "#0064bd" }, JSX: { color: "inherit" }, Julia: { color: "#a270ba" }, "Jupyter Notebook": { color: "#DA5B0B" }, "Kaitai Struct": { color: "#773b37" }, Kotlin: { color: "#F18E33" }, KRL: { color: "#28430A" }, LabVIEW: { color: "inherit" }, Lasso: { color: "#999999" }, Latte: { color: "#f2a542" }, Lean: { color: "inherit" }, Less: { color: "#1d365d" }, Lex: { color: "#DBCA00" }, LFE: { color: "#4C3023" }, LilyPond: { color: "inherit" }, Limbo: { color: "inherit" }, "Literate Agda": { color: "inherit" }, "Literate CoffeeScript": { color: "inherit" }, "Literate Haskell": { color: "inherit" }, LiveScript: { color: "#499886" }, LLVM: { color: "#185619" }, Logos: { color: "inherit" }, Logtalk: { color: "inherit" }, LOLCODE: { color: "#cc9900" }, LookML: { color: "#652B81" }, LoomScript: { color: "inherit" }, LSL: { color: "#3d9970" }, Lua: { color: "#000080" }, M: { color: "inherit" }, M4: { color: "inherit" }, M4Sugar: { color: "inherit" }, Macaulay2: { color: "#d8ffff" }, Makefile: { color: "#427819" }, Mako: { color: "inherit" }, Markdown: { color: "#083fa1" }, Marko: { color: "#42bff2" }, Mask: { color: "#f97732" }, Mathematica: { color: "inherit" }, MATLAB: { color: "#e16737" }, Max: { color: "#c4a79c" }, MAXScript: { color: "#00a6a6" }, mcfunction: { color: "#E22837" }, Mercury: { color: "#ff2b2b" }, Meson: { color: "#007800" }, Metal: { color: "#8f14e9" }, MiniD: { color: "inherit" }, Mirah: { color: "#c7a938" }, "mIRC Script": { color: "#3d57c3" }, MLIR: { color: "#5EC8DB" }, Modelica: { color: "inherit" }, "Modula-2": { color: "inherit" }, "Modula-3": { color: "#223388" }, "Module Management System": { color: "inherit" }, Monkey: { color: "inherit" }, Moocode: { color: "inherit" }, MoonScript: { color: "inherit" }, "Motorola 68K Assembly": { color: "inherit" }, MQL4: { color: "#62A8D6" }, MQL5: { color: "#4A76B8" }, MTML: { color: "#b7e1f4" }, MUF: { color: "inherit" }, mupad: { color: "inherit" }, Myghty: { color: "inherit" }, NASL: { color: "inherit" }, NCL: { color: "#28431f" }, Nearley: { color: "#990000" }, Nemerle: { color: "#3d3c6e" }, nesC: { color: "#94B0C7" }, NetLinx: { color: "#0aa0ff" }, "NetLinx+ERB": { color: "#747faa" }, NetLogo: { color: "#ff6375" }, NewLisp: { color: "#87AED7" }, Nextflow: { color: "#3ac486" }, Nim: { color: "#ffc200" }, Nit: { color: "#009917" }, Nix: { color: "#7e7eff" }, NSIS: { color: "inherit" }, Nu: { color: "#c9df40" }, NumPy: { color: "#9C8AF9" }, "Objective-C": { color: "#438eff" }, "Objective-C++": { color: "#6866fb" }, "Objective-J": { color: "#ff0c5a" }, ObjectScript: { color: "#424893" }, OCaml: { color: "#3be133" }, Odin: { color: "#60AFFE" }, Omgrofl: { color: "#cabbff" }, ooc: { color: "#b0b77e" }, Opa: { color: "inherit" }, Opal: { color: "#f7ede0" }, "Open Policy Agent": { color: "inherit" }, OpenCL: { color: "inherit" }, "OpenEdge ABL": { color: "inherit" }, OpenQASM: { color: "#AA70FF" }, "OpenRC runscript": { color: "inherit" }, OpenSCAD: { color: "inherit" }, Ox: { color: "inherit" }, Oxygene: { color: "#cdd0e3" }, Oz: { color: "#fab738" }, P4: { color: "#7055b5" }, Pan: { color: "#cc0000" }, Papyrus: { color: "#6600cc" }, Parrot: { color: "#f3ca0a" }, "Parrot Assembly": { color: "inherit" }, "Parrot Internal Representation": { color: "inherit" }, Pascal: { color: "#E3F171" }, Pawn: { color: "#dbb284" }, Pep8: { color: "#C76F5B" }, Perl: { color: "#0298c3" }, PHP: { color: "#4F5D95" }, PicoLisp: { color: "inherit" }, PigLatin: { color: "#fcd7de" }, Pike: { color: "#005390" }, PLpgSQL: { color: "inherit" }, PLSQL: { color: "#dad8d8" }, PogoScript: { color: "#d80074" }, Pony: { color: "inherit" }, PostScript: { color: "#da291c" }, "POV-Ray SDL": { color: "inherit" }, PowerBuilder: { color: "#8f0f8d" }, PowerShell: { color: "#012456" }, Prisma: { color: "#0c344b" }, Processing: { color: "#0096D8" }, Prolog: { color: "#74283c" }, "Propeller Spin": { color: "#7fa2a7" }, Pug: { color: "#a86454" }, Puppet: { color: "#302B6D" }, PureBasic: { color: "#5a6986" }, PureScript: { color: "#1D222D" }, Python: { color: "#3572A5" }, "Python console": { color: "inherit" }, q: { color: "#0040cd" }, "Q#": { color: "#fed659" }, QMake: { color: "inherit" }, QML: { color: "#44a51c" }, "Qt Script": { color: "#00b841" }, Quake: { color: "#882233" }, R: { color: "#198CE7" }, Racket: { color: "#3c5caa" }, Ragel: { color: "#9d5200" }, Raku: { color: "#0000fb" }, RAML: { color: "#77d9fb" }, Rascal: { color: "#fffaa0" }, REALbasic: { color: "inherit" }, Reason: { color: "#ff5847" }, Rebol: { color: "#358a5b" }, Red: { color: "#f50000" }, Redcode: { color: "inherit" }, "Ren'Py": { color: "#ff7f7f" }, RenderScript: { color: "inherit" }, REXX: { color: "inherit" }, Ring: { color: "#2D54CB" }, Riot: { color: "#A71E49" }, RobotFramework: { color: "inherit" }, Roff: { color: "#ecdebe" }, Rouge: { color: "#cc0088" }, RPC: { color: "inherit" }, Ruby: { color: "#701516" }, RUNOFF: { color: "#665a4e" }, Rust: { color: "#dea584" }, Sage: { color: "inherit" }, SaltStack: { color: "#646464" }, SAS: { color: "#B34936" }, Sass: { color: "#a53b70" }, Scala: { color: "#c22d40" }, Scheme: { color: "#1e4aec" }, Scilab: { color: "inherit" }, SCSS: { color: "#c6538c" }, sed: { color: "#64b970" }, Self: { color: "#0579aa" }, ShaderLab: { color: "inherit" }, Shell: { color: "#89e051" }, ShellSession: { color: "inherit" }, Shen: { color: "#120F14" }, Sieve: { color: "inherit" }, Slash: { color: "#007eff" }, Slice: { color: "#003fa2" }, Slim: { color: "#2b2b2b" }, Smali: { color: "inherit" }, Smalltalk: { color: "#596706" }, Smarty: { color: "#bedf00" }, SmPL: { color: "#c94949" }, SMT: { color: "inherit" }, Solidity: { color: "#AA6746" }, SourcePawn: { color: "#f69e1d" }, SQF: { color: "#3F3F3F" }, SQLPL: { color: "inherit" }, Squirrel: { color: "#800000" }, "SRecode Template": { color: "#348a34" }, Stan: { color: "#b2011d" }, "Standard ML": { color: "#dc566d" }, Starlark: { color: "#76d275" }, Stata: { color: "inherit" }, Stylus: { color: "#ff6347" }, SuperCollider: { color: "#46390b" }, Svelte: { color: "#ff3e00" }, SVG: { color: "#ff9900" }, Swift: { color: "#ffac45" }, SWIG: { color: "inherit" }, SystemVerilog: { color: "#DAE1C2" }, Tcl: { color: "#e4cc98" }, Tcsh: { color: "inherit" }, Terra: { color: "#00004c" }, TeX: { color: "#3D6117" }, Thrift: { color: "inherit" }, "TI Program": { color: "#A0AA87" }, TLA: { color: "inherit" }, TSQL: { color: "inherit" }, TSX: { color: "inherit" }, Turing: { color: "#cf142b" }, Twig: { color: "#c1d026" }, TXL: { color: "inherit" }, TypeScript: { color: "#2b7489" }, "Unified Parallel C": { color: "#4e3617" }, "Unix Assembly": { color: "inherit" }, Uno: { color: "#9933cc" }, UnrealScript: { color: "#a54c4d" }, UrWeb: { color: "inherit" }, V: { color: "#4f87c4" }, Vala: { color: "#fbe5cd" }, VBA: { color: "#867db1" }, VBScript: { color: "#15dcdc" }, VCL: { color: "#148AA8" }, Verilog: { color: "#b2b7f8" }, VHDL: { color: "#adb2cb" }, "Vim script": { color: "#199f4b" }, "Visual Basic .NET": { color: "#945db7" }, Volt: { color: "#1F1F1F" }, Vue: { color: "#2c3e50" }, wdl: { color: "#42f1f4" }, WebAssembly: { color: "#04133b" }, WebIDL: { color: "inherit" }, wisp: { color: "#7582D1" }, Wollok: { color: "#a23738" }, X10: { color: "#4B6BEF" }, xBase: { color: "#403a40" }, XC: { color: "#99DA07" }, Xojo: { color: "inherit" }, XProc: { color: "inherit" }, XQuery: { color: "#5232e7" }, XS: { color: "inherit" }, XSLT: { color: "#EB8CEB" }, Xtend: { color: "inherit" }, Yacc: { color: "#4B6C4B" }, YAML: { color: "#cb171e" }, YARA: { color: "#220000" }, YASnippet: { color: "#32AB90" }, ZAP: { color: "#0d665e" }, Zeek: { color: "inherit" }, ZenScript: { color: "#00BCD1" }, Zephir: { color: "#118f9e" }, Zig: { color: "#ec915c" }, ZIL: { color: "#dc75e5" }, Zimpl: { color: "inherit" } }; const useStyles$6 = makeStyles((theme) => ({ infoCard: { marginBottom: theme.spacing(3), "& + .MuiAlert-root": { marginTop: theme.spacing(3) } }, barContainer: { height: theme.spacing(2), marginBottom: theme.spacing(3), borderRadius: "4px", backgroundColor: "transparent", overflow: "hidden" }, bar: { height: "100%", position: "relative" }, languageDot: { width: "10px", height: "10px", borderRadius: "50%", marginRight: theme.spacing(1), display: "inline-block" }, label: { color: "inherit" } })); const LanguagesCard = ({}) => { const classes = useStyles$6(); let barWidth = 0; let languageTitle = new String(); const project_id = gitlabProjectId(); const project_slug = gitlabProjectSlug(); const gitlab_instance = gitlabInstance(); const GitlabCIAPI = useApi(GitlabCIApiRef).build( gitlab_instance || "gitlab.com" ); const { value, loading, error } = useAsync(async () => { const projectDetails = await GitlabCIAPI.getProjectDetails( project_slug ); const projectId = project_id || (projectDetails == null ? void 0 : projectDetails.id); const gitlabObj = await GitlabCIAPI.getLanguagesSummary(projectId); const data = gitlabObj == null ? void 0 : gitlabObj.getLanguagesData; return data; }); if (loading) { return /* @__PURE__ */ React.createElement(Progress, null); } else if (error) { return /* @__PURE__ */ React.createElement(Alert, { severity: "error", className: classes.infoCard }, error.message); } return value ? /* @__PURE__ */ React.createElement(InfoCard, { title: "Languages" }, /* @__PURE__ */ React.createElement("div", { className: classes.barContainer }, Object.entries(value).map( (language, index) => { var _a; barWidth = barWidth + language[1]; languageTitle = language[0] + " " + language[1] + "%"; return /* @__PURE__ */ React.createElement( Tooltip, { title: languageTitle, placement: "bottom-end", key: language[0] }, /* @__PURE__ */ React.createElement( "div", { className: classes.bar, key: language[0], style: { marginTop: index === 0 ? "0" : `-16px`, zIndex: Object.keys(value).length - index, backgroundColor: ((_a = colors[language[0]]) == null ? void 0 : _a.color) || "#333", width: `${barWidth}%` } } ) ); } )), Object.entries(value).map((language) => { var _a; return /* @__PURE__ */ React.createElement( Chip, { classes: { label: classes.label }, label: /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement( "span", { className: classes.languageDot, style: { backgroundColor: ((_a = colors[language[0]]) == null ? void 0 : _a.color) || "#333" } } ), /* @__PURE__ */ React.createElement("b", null, language[0]), " - ", language[1], "%"), variant: "outlined", key: language[0] } ); })) : /* @__PURE__ */ React.createElement(InfoCard, { title: "Languages" }); }; const LightTooltip = withStyles({ tooltip: { backgroundColor: "white", border: "1px solid lightgrey", color: "#333", minWidth: "320px" } })(Tooltip); const PeopleCardEntity = ({ peopleCardEntity }) => { return /* @__PURE__ */ React.createElement(LightTooltip, { title: peopleCardEntity.name }, /* @__PURE__ */ React.createElement("a", { href: peopleCardEntity.web_url, target: "_blank" }, /* @__PURE__ */ React.createElement( Avatar, { key: peopleCardEntity.name, alt: peopleCardEntity.name, src: peopleCardEntity.avatar_url } ))); }; const useStyles$5 = makeStyles((theme) => ({ link: { color: "inherit", textDecoration: "none", marginRight: theme.spacing(1), marginTop: theme.spacing(0) }, box: { marginTop: theme.spacing(0), marginBottom: theme.spacing(1) }, boxLink: { marginTop: theme.spacing(0) }, title: { marginTop: theme.spacing(0), marginBottom: theme.spacing(0) } })); const PeopleList = ({ title, peopleObj, deepLink }) => { const classes = useStyles$5(); return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement( Box, { className: classes.box, display: "flex", alignItems: "center", justifyContent: "space-between" }, /* @__PURE__ */ React.createElement("h2", { className: classes.title }, title), deepLink && /* @__PURE__ */ React.createElement( Box, { className: classes.boxLink, display: "flex", alignItems: "center" }, /* @__PURE__ */ React.createElement( Link, { className: classes.link, to: deepLink.link, onClick: deepLink.onClick }, deepLink.title ), /* @__PURE__ */ React.createElement(ArrowIcon, { fontSize: "small" }) ) ), /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 1, justifyContent: "flex-start" }, peopleObj == null ? void 0 : peopleObj.map((peopleCardEntity) => /* @__PURE__ */ React.createElement( Grid, { key: peopleCardEntity.email || peopleCardEntity.name, item: true }, /* @__PURE__ */ React.createElement(PeopleCardEntity, { peopleCardEntity }) )))); }; const useStyles$4 = makeStyles((theme) => ({ infoCard: { marginBottom: theme.spacing(3), "& + .MuiAlert-root": { marginTop: theme.spacing(3) } }, subTitle: { marginTop: theme.spacing(0) }, divider: { marginTop: theme.spacing(2), marginBottom: theme.spacing(2) } })); const PeopleCard = ({}) => { const classes = useStyles$4(); const project_id = gitlabProjectId(); const project_slug = gitlabProjectSlug(); const gitlab_instance = gitlabInstance(); const codeowners_path = gitlabCodeOwnerPath(); const GitlabCIAPI = useApi(GitlabCIApiRef).build( gitlab_instance || "gitlab.com" ); const { value, loading, error } = useAsync(async () => { const projectDetails = await GitlabCIAPI.getProjectDetails( project_slug || project_id ); const projectId = project_id || (projectDetails == null ? void 0 : projectDetails.id); const gitlabObj = await GitlabCIAPI.getContributorsSummary(projectId); const contributorData = gitlabObj == null ? void 0 : gitlabObj.getContributorsData; const projectDetailsData = { project_web_url: projectDetails == null ? void 0 : projectDetails.web_url, project_default_branch: projectDetails == null ? void 0 : projectDetails.default_branch }; let codeOwners = []; try { codeOwners = await GitlabCIAPI.getCodeOwners( projectId, projectDetailsData.project_default_branch, codeowners_path ); } catch (error2) { codeOwners = void 0; } return { contributors: contributorData, owners: codeOwners, projectDetails: projectDetailsData }; }, []); const project_web_url = value == null ? void 0 : value.projectDetails.project_web_url; const project_default_branch = value == null ? void 0 : value.projectDetails.project_default_branch; const contributorsLink = GitlabCIAPI.getContributorsLink( project_web_url, project_default_branch ); const ownersLink = GitlabCIAPI.getOwnersLink( project_web_url, project_default_branch, codeowners_path ); const contributorsDeepLink = { link: contributorsLink, title: "go to Contributors", onClick: (e) => { e.preventDefault(); window.open(contributorsLink); } }; const ownersDeepLink = { link: ownersLink, title: "go to Owners File", onClick: (e) => { e.preventDefault(); window.open(ownersLink); } }; if (loading) { return /* @__PURE__ */ React.createElement(Progress, null); } else if (error) { return /* @__PURE__ */ React.createElement(Alert, { severity: "error", className: classes.infoCard }, error.message); } return /* @__PURE__ */ React.createElement(InfoCard, { title: "People", className: classes.infoCard }, (value == null ? void 0 : value.owners) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement( PeopleList, { title: "Owners", peopleObj: value == null ? void 0 : value.owners, deepLink: ownersDeepLink } ), /* @__PURE__ */ React.createElement(Divider, { className: classes.divider })), /* @__PURE__ */ React.createElement( PeopleList, { title: "Contributors", peopleObj: (value == null ? void 0 : value.contributors) || [], deepLink: contributorsDeepLink } )); }; const useStyles$3 = makeStyles$1((theme) => ({ infoCard: { marginBottom: theme.spacing(3), "& + .MuiAlert-root": { marginTop: theme.spacing(3) }, "& .MuiCardContent-root": { padding: theme.spacing(2, 1, 2, 2) }, "& td": { whiteSpace: "normal" } } })); const MergeRequestStats = (props) => { const [count, setCount] = useState(20); const classes = useStyles$3(); const project_id = gitlabProjectId(); const project_slug = gitlabProjectSlug(); const gitlab_instance = gitlabInstance(); const GitlabCIAPI = useApi(GitlabCIApiRef).build( gitlab_instance || "gitlab.com" ); const mergeStat = { avgTimeUntilMerge: 0, closedCount: 0, mergedCount: 0 }; const { value, loading, error } = useAsync(async () => { const projectDetails = await GitlabCIAPI.getProjectDetails( project_slug ); const projectId = project_id || (projectDetails == null ? void 0 : projectDetails.id); const gitlabObj = await GitlabCIAPI.getMergeRequestsStatusSummary( projectId, count ); const data = gitlabObj == null ? void 0 : gitlabObj.getMergeRequestsStatusData; const renderData = { data }; renderData.project_name = await GitlabCIAPI.getProjectName( projectId ); if (renderData.data) { renderData.data.forEach((element) => { mergeStat.avgTimeUntilMerge += element.merged_at ? new Date(element.merged_at).getTime() - new Date(element.created_at).getTime() : 0; mergeStat.mergedCount += element.merged_at ? 1 : 0; mergeStat.closedCount += element.closed_at ? 1 : 0; }); } if (mergeStat.mergedCount === 0) return { avgTimeUntilMerge: "Never", mergedToTotalRatio: "0%" }; const avgTimeUntilMergeDiff = dayjs.duration( mergeStat.avgTimeUntilMerge / mergeStat.mergedCount ); const avgTimeUntilMerge = avgTimeUntilMergeDiff.humanize(); return { avgTimeUntilMerge, mergedToTotalRatio: `${Math.round( mergeStat.mergedCount / count * 100 )}%` }; }, [count]); if (loading) { return /* @__PURE__ */ React.createElement(Progress, null); } else if (error) { return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, error.message); } return value ? /* @__PURE__ */ React.createElement( InfoCard, { title: "Merge requests statistics", className: classes.infoCard, variant: props.variant }, /* @__PURE__ */ React.createElement(Box, { position: "relative" }, /* @__PURE__ */ React.createElement(StructuredMetadataTable, { metadata: value }), /* @__PURE__ */ React.createElement(Box, { display: "flex", justifyContent: "flex-end" }, /* @__PURE__ */ React.createElement(FormControl, null, /* @__PURE__ */ React.createElement( Select, { value: count, onChange: (event) => setCount(Number(event.target.value)) }, /* @__PURE__ */ React.createElement(MenuItem, { value: 10 }, "10"), /* @__PURE__ */ React.createElement(MenuItem, { value: 20 }, "20"), /* @__PURE__ */ React.createElement(MenuItem, { value: 50 }, "50"), /* @__PURE__ */ React.createElement(MenuItem, { value: 100 }, "100") ), /* @__PURE__ */ React.createElement(FormHelperText, null, "Number of MRs")))) ) : /* @__PURE__ */ React.createElement(InfoCard, { title: "Merge Request Statistics" }); }; var MergeRequestStats$1 = MergeRequestStats; const useStyles$2 = makeStyles$1(() => ({ open: { fill: "#22863a" }, closed: { fill: "#cb2431" }, merged: { fill: "#6f42c1" }, draft: { fill: "#6a737d" } })); const StatusOpen = () => { const classes = useStyles$2(); return /* @__PURE__ */ React.createElement( "svg", { width: "16", height: "16", className: classes.open, viewBox: "0 0 16 16" }, /* @__PURE__ */ React.createElement( "path", { fillRule: "evenodd", d: "M7.177 3.073L9.573.677A.25.25 0 0110 .854v4.792a.25.25 0 01-.427.177L7.177 3.427a.25.25 0 010-.354zM3.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122v5.256a2.251 2.251 0 11-1.5 0V5.372A2.25 2.25 0 011.5 3.25zM11 2.5h-1V4h1a1 1 0 011 1v5.628a2.251 2.251 0 101.5 0V5A2.5 2.5 0 0011 2.5zm1 10.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.75 12a.75.75 0 100 1.5.75.75 0 000-1.5z" } ) ); }; const StatusClosed = () => { const classes = useStyles$2(); return /* @__PURE__ */ React.createElement( "svg", { width: "16", height: "16", className: classes.closed, viewBox: "0 0 16 16" }, /* @__PURE__ */ React.createElement( "path", { fillRule: "evenodd", d: "M7.177 3.073L9.573.677A.25.25 0 0110 .854v4.792a.25.25 0 01-.427.177L7.177 3.427a.25.25 0 010-.354zM3.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122v5.256a2.251 2.251 0 11-1.5 0V5.372A2.25 2.25 0 011.5 3.25zM11 2.5h-1V4h1a1 1 0 011 1v5.628a2.251 2.251 0 101.5 0V5A2.5 2.5 0 0011 2.5zm1 10.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.75 12a.75.75 0 100 1.5.75.75 0 000-1.5z" } ) ); }; const StatusMerged = () => { const classes = useStyles$2(); return /* @__PURE__ */ React.createElement( "svg", { width: "16", height: "16", className: classes.merged, viewBox: "0 0 16 16" }, /* @__PURE__ */ React.createElement( "path", { fillRule: "evenodd", d: "M5 3.254V3.25v.005a.75.75 0 110-.005v.004zm.45 1.9a2.25 2.25 0 10-1.95.218v5.256a2.25 2.25 0 101.5 0V7.123A5.735 5.735 0 009.25 9h1.378a2.251 2.251 0 100-1.5H9.25a4.25 4.25 0 01-3.8-2.346zM12.75 9a.75.75 0 100-1.5.75.75 0 000 1.5zm-8.5 4.5a.75.75 0 100-1.5.75.75 0 000 1.5z" } ) ); }; const getStatusIconType = (row) => { switch (true) { case row.state === "opened": return /* @__PURE__ */ React.createElement(Tooltip, { title: "Open" }, /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement(StatusOpen, null))); case row.state === "locked": return /* @__PURE__ */ React.createElement(Tooltip, { title: "Open" }, /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement(StatusOpen, null))); case row.state === "merged": return /* @__PURE__ */ React.createElement(Tooltip, { title: "Merged" }, /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement(StatusMerged, null))); case row.state === "closed": return /* @__PURE__ */ React.createElement(Tooltip, { title: "Closed" }, /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement(StatusClosed, null))); default: return null; } }; const useStyles$1 = makeStyles((theme) => ({ infoCard: { marginBottom: theme.spacing(3), "& + .MuiAlert-root": { marginTop: theme.spacing(3) } }, releaseTitle: { ...theme.typography.h6, margin: 0, marginRight: "0.5rem" }, releaseTagIcon: { verticalAlign: "middle" } })); function makeFilter(show) { switch (show) { case "patch": return (value) => { try { return prerelease(value.tag_name) == null; } catch (error) { return true; } }; case "all": default: return () => true; } } const ReleasesCard = (props) => { const { show = "all", limit = 6 } = props; const classes = useStyles$1(); const project_id = gitlabProjectId(); const project_slug = gitlabProjectSlug(); const gitlab_instance = gitlabInstance(); const GitlabCIAPI = useApi(GitlabCIApiRef).build( gitlab_instance || "gitlab.com" ); const { value, loading, error } = useAsync(async () => { const projectDetails = await GitlabCIAPI.getProjectDetails( project_slug || project_id ); const projectDetailsData = { project_web_url: projectDetails == null ? void 0 : projectDetails.web_url, project_default_branch: projectDetails == null ? void 0 : projectDetails.default_branch }; const projectId = project_id || (projectDetails == null ? void 0 : projectDetails.id); const gitlabObj = await GitlabCIAPI.getReleasesSummary(projectId); const releaseData = gitlabObj == null ? void 0 : gitlabObj.getReleasesData; return { releases: releaseData, projectDetails: projectDetailsData }; }, []); const project_web_url = value == null ? void 0 : value.projectDetails.project_web_url; if (loading) { return /* @__PURE__ */ React.createElement(Progress, null); } else if (error) { return /* @__PURE__ */ React.createElement(Alert, { severity: "error", className: classes.infoCard }, error.message); } let releases = []; if ((value == null ? void 0 : value.releases) != null) { value == null ? void 0 : value.releases.filter(makeFilter(show)).sort((a, b) => { try { return rcompare(a.tag_name, b.tag_name); } catch (error2) { return a.tag_name > b.tag_name ? 1 : -1; } }).forEach((release) => { if (!valid(release.tag_name)) { releases.push(release); return; } const idx = releases.findIndex((value2) => { return release.tag_name.startsWith(value2.tag_name); }); if (idx < 0) releases.push(r