@code-pushup/core 0.51.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1494,25 +1494,30 @@ import {
1494
1494
  } from "build-md";
1495
1495
  import { posix as pathPosix } from "node:path";
1496
1496
 
1497
- // packages/utils/src/lib/reports/ide-environment.ts
1497
+ // packages/utils/src/lib/reports/types.ts
1498
+ var SUPPORTED_ENVIRONMENTS = [
1499
+ "vscode",
1500
+ "github",
1501
+ "gitlab",
1502
+ "other"
1503
+ ];
1504
+
1505
+ // packages/utils/src/lib/reports/environment-type.ts
1506
+ var environmentChecks = {
1507
+ vscode: () => process.env["TERM_PROGRAM"] === "vscode",
1508
+ github: () => process.env["GITHUB_ACTIONS"] === "true",
1509
+ gitlab: () => process.env["GITLAB_CI"] === "true",
1510
+ other: () => true
1511
+ };
1498
1512
  function getEnvironmentType() {
1499
- if (isVSCode()) {
1500
- return "vscode";
1501
- }
1502
- if (isGitHub()) {
1503
- return "github";
1504
- }
1505
- return "other";
1506
- }
1507
- function isVSCode() {
1508
- return process.env["TERM_PROGRAM"] === "vscode";
1509
- }
1510
- function isGitHub() {
1511
- return process.env["GITHUB_ACTIONS"] === "true";
1513
+ return SUPPORTED_ENVIRONMENTS.find((env) => environmentChecks[env]()) ?? "other";
1512
1514
  }
1513
1515
  function getGitHubBaseUrl() {
1514
1516
  return `${process.env["GITHUB_SERVER_URL"]}/${process.env["GITHUB_REPOSITORY"]}/blob/${process.env["GITHUB_SHA"]}`;
1515
1517
  }
1518
+ function getGitLabBaseUrl() {
1519
+ return `${process.env["CI_SERVER_URL"]}/${process.env["CI_PROJECT_PATH"]}/-/blob/${process.env["CI_COMMIT_SHA"]}`;
1520
+ }
1516
1521
 
1517
1522
  // packages/utils/src/lib/reports/formatting.ts
1518
1523
  function tableSection(tableData, options) {
@@ -1578,6 +1583,15 @@ function formatGitHubLink(file, position) {
1578
1583
  const lineRange = end && start !== end ? `${start}-${end}` : start;
1579
1584
  return `${baseUrl}/${file}#${lineRange}`;
1580
1585
  }
1586
+ function formatGitLabLink(file, position) {
1587
+ const baseUrl = getGitLabBaseUrl();
1588
+ if (!position) {
1589
+ return `${baseUrl}/${file}`;
1590
+ }
1591
+ const { startLine, endLine } = position;
1592
+ const lineRange = endLine && startLine !== endLine ? `${startLine}-${endLine}` : startLine;
1593
+ return `${baseUrl}/${file}#L${lineRange}`;
1594
+ }
1581
1595
  function formatFileLink(file, position, outputDir) {
1582
1596
  const relativePath = pathPosix.relative(outputDir, file);
1583
1597
  const env = getEnvironmentType();
@@ -1586,6 +1600,8 @@ function formatFileLink(file, position, outputDir) {
1586
1600
  return position ? `${relativePath}#L${position.startLine}` : relativePath;
1587
1601
  case "github":
1588
1602
  return formatGitHubLink(file, position);
1603
+ case "gitlab":
1604
+ return formatGitLabLink(file, position);
1589
1605
  default:
1590
1606
  return relativePath;
1591
1607
  }
@@ -2231,11 +2247,11 @@ import { bold as bold4, cyan, cyanBright, green as green2, red } from "ansis";
2231
2247
  function log(msg = "") {
2232
2248
  ui().logger.log(msg);
2233
2249
  }
2234
- function logStdoutSummary(report) {
2250
+ function logStdoutSummary(report, verbose = false) {
2235
2251
  const printCategories = report.categories.length > 0;
2236
2252
  log(reportToHeaderSection(report));
2237
2253
  log();
2238
- logPlugins(report);
2254
+ logPlugins(report.plugins, verbose);
2239
2255
  if (printCategories) {
2240
2256
  logCategories(report);
2241
2257
  }
@@ -2246,36 +2262,49 @@ function reportToHeaderSection(report) {
2246
2262
  const { packageName, version: version2 } = report;
2247
2263
  return `${bold4(REPORT_HEADLINE_TEXT)} - ${packageName}@${version2}`;
2248
2264
  }
2249
- function logPlugins(report) {
2250
- const { plugins } = report;
2265
+ function logPlugins(plugins, verbose) {
2251
2266
  plugins.forEach((plugin) => {
2252
2267
  const { title, audits } = plugin;
2268
+ const filteredAudits = verbose ? audits : audits.filter(({ score }) => score !== 1);
2269
+ const diff = audits.length - filteredAudits.length;
2270
+ logAudits(title, filteredAudits);
2271
+ if (diff > 0) {
2272
+ const notice = filteredAudits.length === 0 ? `... All ${diff} audits have perfect scores ...` : `... ${diff} audits with perfect scores omitted for brevity ...`;
2273
+ logRow(1, notice);
2274
+ }
2253
2275
  log();
2254
- log(bold4.magentaBright(`${title} audits`));
2255
- log();
2256
- audits.forEach((audit) => {
2257
- ui().row([
2258
- {
2259
- text: applyScoreColor({ score: audit.score, text: "\u25CF" }),
2260
- width: 2,
2261
- padding: [0, 1, 0, 0]
2262
- },
2263
- {
2264
- text: audit.title,
2265
- // eslint-disable-next-line no-magic-numbers
2266
- padding: [0, 3, 0, 0]
2267
- },
2268
- {
2269
- text: cyanBright(audit.displayValue || `${audit.value}`),
2270
- // eslint-disable-next-line no-magic-numbers
2271
- width: 20,
2272
- padding: [0, 0, 0, 0]
2273
- }
2274
- ]);
2275
- });
2276
- log();
2277
2276
  });
2278
2277
  }
2278
+ function logAudits(pluginTitle, audits) {
2279
+ log();
2280
+ log(bold4.magentaBright(`${pluginTitle} audits`));
2281
+ log();
2282
+ audits.forEach(({ score, title, displayValue, value }) => {
2283
+ logRow(score, title, displayValue || `${value}`);
2284
+ });
2285
+ }
2286
+ function logRow(score, title, value) {
2287
+ ui().row([
2288
+ {
2289
+ text: applyScoreColor({ score, text: "\u25CF" }),
2290
+ width: 2,
2291
+ padding: [0, 1, 0, 0]
2292
+ },
2293
+ {
2294
+ text: title,
2295
+ // eslint-disable-next-line no-magic-numbers
2296
+ padding: [0, 3, 0, 0]
2297
+ },
2298
+ ...value ? [
2299
+ {
2300
+ text: cyanBright(value),
2301
+ // eslint-disable-next-line no-magic-numbers
2302
+ width: 20,
2303
+ padding: [0, 0, 0, 0]
2304
+ }
2305
+ ] : []
2306
+ ]);
2307
+ }
2279
2308
  function logCategories({ categories, plugins }) {
2280
2309
  const hAlign = (idx) => idx === 0 ? "left" : "right";
2281
2310
  const rows = categories.map(({ title, score, refs, isBinary }) => [
@@ -2421,7 +2450,7 @@ var verboseUtils = (verbose = false) => ({
2421
2450
 
2422
2451
  // packages/core/package.json
2423
2452
  var name = "@code-pushup/core";
2424
- var version = "0.51.0";
2453
+ var version = "0.53.0";
2425
2454
 
2426
2455
  // packages/core/src/lib/implementation/execute-plugin.ts
2427
2456
  import { bold as bold5 } from "ansis";
@@ -2616,10 +2645,8 @@ var PersistError = class extends Error {
2616
2645
  super(`fileName: ${reportPath} could not be saved.`);
2617
2646
  }
2618
2647
  };
2619
- async function persistReport(report, options) {
2648
+ async function persistReport(report, sortedScoredReport, options) {
2620
2649
  const { outputDir, filename, format } = options;
2621
- const sortedScoredReport = sortReport(scoreReport(report));
2622
- logStdoutSummary(sortedScoredReport);
2623
2650
  const results = format.map((reportType) => {
2624
2651
  switch (reportType) {
2625
2652
  case "json":
@@ -2665,7 +2692,13 @@ function logPersistedResults(persistResults) {
2665
2692
  async function collectAndPersistReports(options) {
2666
2693
  const { exec } = verboseUtils(options.verbose);
2667
2694
  const report = await collect(options);
2668
- const persistResults = await persistReport(report, options.persist);
2695
+ const sortedScoredReport = sortReport(scoreReport(report));
2696
+ const persistResults = await persistReport(
2697
+ report,
2698
+ sortedScoredReport,
2699
+ options.persist
2700
+ );
2701
+ logStdoutSummary(sortedScoredReport, options.verbose);
2669
2702
  exec(() => {
2670
2703
  logPersistedResults(persistResults);
2671
2704
  });
@@ -2677,10 +2710,6 @@ async function collectAndPersistReports(options) {
2677
2710
  // packages/core/src/lib/compare.ts
2678
2711
  import { writeFile as writeFile2 } from "node:fs/promises";
2679
2712
  import { join as join5 } from "node:path";
2680
- import {
2681
- PortalOperationError,
2682
- getPortalComparisonLink
2683
- } from "@code-pushup/portal-client";
2684
2713
 
2685
2714
  // packages/core/src/lib/implementation/compare-scorables.ts
2686
2715
  function compareCategories(reports) {
@@ -2816,6 +2845,18 @@ function selectMeta(meta) {
2816
2845
  };
2817
2846
  }
2818
2847
 
2848
+ // packages/core/src/lib/load-portal-client.ts
2849
+ async function loadPortalClient() {
2850
+ try {
2851
+ return await import("@code-pushup/portal-client");
2852
+ } catch {
2853
+ ui().logger.error(
2854
+ "Optional peer dependency @code-pushup/portal-client is not available. Make sure it is installed to enable upload functionality."
2855
+ );
2856
+ return null;
2857
+ }
2858
+ }
2859
+
2819
2860
  // packages/core/src/lib/compare.ts
2820
2861
  async function compareReportFiles(inputPaths, persistConfig, uploadConfig, label) {
2821
2862
  const { outputDir, filename, format } = persistConfig;
@@ -2880,6 +2921,11 @@ function reportsDiffToFileContent(reportsDiff, format) {
2880
2921
  }
2881
2922
  async function fetchPortalComparisonLink(uploadConfig, commits) {
2882
2923
  const { server, apiKey, organization, project } = uploadConfig;
2924
+ const portalClient = await loadPortalClient();
2925
+ if (!portalClient) {
2926
+ return;
2927
+ }
2928
+ const { PortalOperationError, getPortalComparisonLink } = portalClient;
2883
2929
  try {
2884
2930
  return await getPortalComparisonLink({
2885
2931
  server,
@@ -2902,18 +2948,7 @@ async function fetchPortalComparisonLink(uploadConfig, commits) {
2902
2948
  }
2903
2949
  }
2904
2950
 
2905
- // packages/core/src/lib/upload.ts
2906
- import {
2907
- uploadToPortal
2908
- } from "@code-pushup/portal-client";
2909
-
2910
2951
  // packages/core/src/lib/implementation/report-to-gql.ts
2911
- import {
2912
- CategoryConfigRefType as PortalCategoryRefType,
2913
- IssueSeverity as PortalIssueSeverity,
2914
- IssueSourceType as PortalIssueSourceType,
2915
- TableAlignment as PortalTableAlignment
2916
- } from "@code-pushup/portal-client";
2917
2952
  function reportToGQL(report) {
2918
2953
  return {
2919
2954
  packageName: report.packageName,
@@ -2980,7 +3015,7 @@ function issueToGQL(issue) {
2980
3015
  message: issue.message,
2981
3016
  severity: issueSeverityToGQL(issue.severity),
2982
3017
  ...issue.source?.file && {
2983
- sourceType: PortalIssueSourceType.SourceCode,
3018
+ sourceType: safeEnum("SourceCode"),
2984
3019
  sourceFilePath: issue.source.file,
2985
3020
  sourceStartLine: issue.source.position?.startLine,
2986
3021
  sourceStartColumn: issue.source.position?.startColumn,
@@ -3026,37 +3061,45 @@ function categoryToGQL(category) {
3026
3061
  function categoryRefTypeToGQL(type) {
3027
3062
  switch (type) {
3028
3063
  case "audit":
3029
- return PortalCategoryRefType.Audit;
3064
+ return safeEnum("Audit");
3030
3065
  case "group":
3031
- return PortalCategoryRefType.Group;
3066
+ return safeEnum("Group");
3032
3067
  }
3033
3068
  }
3034
3069
  function issueSeverityToGQL(severity) {
3035
3070
  switch (severity) {
3036
3071
  case "info":
3037
- return PortalIssueSeverity.Info;
3072
+ return safeEnum("Info");
3038
3073
  case "error":
3039
- return PortalIssueSeverity.Error;
3074
+ return safeEnum("Error");
3040
3075
  case "warning":
3041
- return PortalIssueSeverity.Warning;
3076
+ return safeEnum("Warning");
3042
3077
  }
3043
3078
  }
3044
3079
  function tableAlignmentToGQL(alignment) {
3045
3080
  switch (alignment) {
3046
3081
  case "left":
3047
- return PortalTableAlignment.Left;
3082
+ return safeEnum("Left");
3048
3083
  case "center":
3049
- return PortalTableAlignment.Center;
3084
+ return safeEnum("Center");
3050
3085
  case "right":
3051
- return PortalTableAlignment.Right;
3086
+ return safeEnum("Right");
3052
3087
  }
3053
3088
  }
3089
+ function safeEnum(value) {
3090
+ return value;
3091
+ }
3054
3092
 
3055
3093
  // packages/core/src/lib/upload.ts
3056
- async function upload(options, uploadFn = uploadToPortal) {
3094
+ async function upload(options) {
3057
3095
  if (options.upload == null) {
3058
3096
  throw new Error("Upload configuration is not set.");
3059
3097
  }
3098
+ const portalClient = await loadPortalClient();
3099
+ if (!portalClient) {
3100
+ return;
3101
+ }
3102
+ const { uploadToPortal } = portalClient;
3060
3103
  const { apiKey, server, organization, project, timeout } = options.upload;
3061
3104
  const report = await loadReport({
3062
3105
  ...options.persist,
@@ -3071,7 +3114,7 @@ async function upload(options, uploadFn = uploadToPortal) {
3071
3114
  commit: report.commit.hash,
3072
3115
  ...reportToGQL(report)
3073
3116
  };
3074
- return uploadFn({ apiKey, server, data, timeout });
3117
+ return uploadToPortal({ apiKey, server, data, timeout });
3075
3118
  }
3076
3119
 
3077
3120
  // packages/core/src/lib/history.ts
package/package.json CHANGED
@@ -1,14 +1,21 @@
1
1
  {
2
2
  "name": "@code-pushup/core",
3
- "version": "0.51.0",
3
+ "version": "0.53.0",
4
4
  "license": "MIT",
5
5
  "description": "Core business logic for the used by the Code PushUp CLI",
6
6
  "dependencies": {
7
- "@code-pushup/models": "0.51.0",
8
- "@code-pushup/utils": "0.51.0",
9
- "@code-pushup/portal-client": "^0.9.0",
7
+ "@code-pushup/models": "0.53.0",
8
+ "@code-pushup/utils": "0.53.0",
10
9
  "ansis": "^3.3.0"
11
10
  },
11
+ "peerDependencies": {
12
+ "@code-pushup/portal-client": "^0.9.0"
13
+ },
14
+ "peerDependenciesMeta": {
15
+ "@code-pushup/portal-client": {
16
+ "optional": true
17
+ }
18
+ },
12
19
  "homepage": "https://github.com/code-pushup/cli/tree/main/packages/core#readme",
13
20
  "bugs": {
14
21
  "url": "https://github.com/code-pushup/cli/issues"
@@ -18,6 +25,9 @@
18
25
  "url": "git+https://github.com/code-pushup/cli.git",
19
26
  "directory": "packages/core"
20
27
  },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
21
31
  "type": "module",
22
32
  "main": "./index.js",
23
33
  "types": "./src/index.d.ts"
@@ -1,10 +1,10 @@
1
1
  import type { PersistConfig, Report } from '@code-pushup/models';
2
- import { type MultipleFileResults } from '@code-pushup/utils';
2
+ import { type MultipleFileResults, type ScoredReport } from '@code-pushup/utils';
3
3
  export declare class PersistDirError extends Error {
4
4
  constructor(outputDir: string);
5
5
  }
6
6
  export declare class PersistError extends Error {
7
7
  constructor(reportPath: string);
8
8
  }
9
- export declare function persistReport(report: Report, options: Required<PersistConfig>): Promise<MultipleFileResults>;
9
+ export declare function persistReport(report: Report, sortedScoredReport: ScoredReport, options: Required<PersistConfig>): Promise<MultipleFileResults>;
10
10
  export declare function logPersistedResults(persistResults: MultipleFileResults): void;
@@ -1,4 +1,4 @@
1
- import { type AuditReportIssue as PortalIssue, type AuditReportTable as PortalTable, type SaveReportMutationVariables } from '@code-pushup/portal-client';
1
+ import type { AuditReportIssue as PortalIssue, AuditReportTable as PortalTable, SaveReportMutationVariables } from '@code-pushup/portal-client';
2
2
  import type { Issue, Report, Table } from '@code-pushup/models';
3
3
  export declare function reportToGQL(report: Report): Omit<SaveReportMutationVariables, 'organization' | 'project' | 'commit'>;
4
4
  export declare function issueToGQL(issue: Issue): PortalIssue;
@@ -0,0 +1 @@
1
+ export declare function loadPortalClient(): Promise<typeof import('@code-pushup/portal-client') | null>;
@@ -1,4 +1,3 @@
1
- import { uploadToPortal } from '@code-pushup/portal-client';
2
1
  import type { PersistConfig, UploadConfig } from '@code-pushup/models';
3
2
  import type { GlobalOptions } from './types';
4
3
  export type UploadOptions = {
@@ -11,4 +10,4 @@ export type UploadOptions = {
11
10
  * @param options
12
11
  * @param uploadFn
13
12
  */
14
- export declare function upload(options: UploadOptions, uploadFn?: typeof uploadToPortal): Promise<import("@code-pushup/portal-client").ReportFragment>;
13
+ export declare function upload(options: UploadOptions): Promise<import("@code-pushup/portal-client").ReportFragment | undefined>;