- Notifications
You must be signed in to change notification settings - Fork 15
Plugin interface draft
Michael Hladky edited this page Aug 16, 2023 · 2 revisions
exporttypeCoreConfig={/** list of plugins to be used (built-in, 3rd party, or custom) */plugins: PluginConfig[];/** portal configuration for uploading results */upload?: UploadConfig;/** categorization of individual audits */categories: CategoryConfig[];/** budget rules for assertion */budgets?: Budget[];};typeUploadConfig={/** URL of deployed portal API */server: string;// required if self-hosting (could default to our public cloud URL later)/** API key with write access to portal */apiKey: string;// should use environment variable};typeCategoryConfig={/** human-readable unique ID */slug: string;/** display name */title: string;/** description (Markdown) */description?: string;/** weighted references to plugin-specific audits/categories */metrics: {/** reference to a plugin's audit (e.g. 'eslint#max-lines') or category (e.g. 'categories:lhci#performance') */ref: string;/** coefficient for given score (use weight 0 if only for display) */weight: number;}[];};typeBudget={/** reference to audit ('eslint#max-lines') or category ('categories:performance') */ref: string;/** fail assertion if score too low */minScore?: number;/** fail assertion if too many warnings */maxWarnings?: number;/** fail assertion if value too high */maxValue?: number;};constconfig: CoreConfig={upload: {server: 'https://192.168.123.132/api/graphql',apiKey: process.env.SECRET_API_KEY!,},plugins: [eslintPlugin({config: 'eslint.config.js'}),lhciPlugin({config: '.lighthouserc.json'}),// ...],categories: [{slug: 'performance',title: 'Performance',metrics: [{ref: 'groups:lhci#performance',weight: 3,},{ref: 'bundle-size#main',weight: 1,},{ref: 'eslint#@angular-eslint/template/no-call-expression',weight: 0,},],},// ...],budgets: [{ref: 'categories:performance',minScore: 0.6},{ref: 'bundle-size#main',maxValue: 2_000_000},],};exportdefaultconfig;exporttypePluginConfig={/** plugin metadata */meta: PluginMetadata;/** how to execute runner */runner: RunnerConfig;/** list of scorable metrics for given plugin */audits: AuditMetadata[];/** list of groups */groups?: Group[];};typePluginMetadata={/** unique ID (human-readable, URL-safe) */slug: string;/** display name */name: string;/** plugin categorization */type: PluginType;/** icon from VSCode Material Icons extension */icon?: MaterialIcon;// see: https://github.com/flowup/quality-metrics/tree/main/libs/material-icons#readme/** plugin documentation site */docsUrl?: string;};typePluginType=|'static-analysis'// eslint, stylelint, tsc, jscpd, ...|'performance-measurements'// lhci collect, user-flow, ...|'test-coverage'// jest --coverage, ...|'dependency-audit';// npm audit, ...typeRunnerConfig={/** shell command to execute */command: string;/** path to runner artefact */outputPath: string};typeAuditMetadata={/** ID (unique within plugin) */slug: string;/** abbreviated name */label: string;// e.g. 'LCP', 'no-explicit-any' 'main.js'/** descriptive name */title: string;// e.g. 'Largest Contentful Paint', 'Disallow the `any` type', 'Size of main bundle'/** description (Markdown) */description?: string;/** link to documentation (rule rationale) */docsUrl?: string;};typeGroup={/** human-readable unique ID */slug: string;/** display name */title: string;/** description (Markdown) */description?: string;/** weighted references to plugin-specific audits/categories */audits: {/** reference to a audit within plugin (e.g. 'max-lines') */ref: string;/** coefficient for given score (use weight 0 if only for display) */weight: number;}[];};/* ESLint plugin */typeESLintPluginOptions={config: string|import('eslint').Linter.Config;};exportfunctioneslintPlugin(options: ESLintPluginOptions): PluginConfig{// ... load configuration, etc. ...return{meta: {slug: 'eslint',name: 'ESLint',type: 'static-analysis',icon: 'eslint',docsUrl: 'https://pushup.github.io/code-pushup/plugins/eslint',},runner: {// inputs via environment variables (e.g. process.env.CPU_AFFECTED_FILES)command: 'node node_modules/@cpu/eslint-plugin/bin/main.js',},audits: [{slug: '@typescript-eslint/no-explicit-any',label: 'no-explicit-any',title: 'Disallow the `any` type',docsUrl: 'https://typescript-eslint.io/rules/no-explicit-any/',},{slug: 'max-lines-200',// options part of ID (accurate comparisons)label: 'max-lines',title: 'Enforce a maximum number of lines per file',docsUrl: 'https://eslint.org/docs/latest/rules/max-lines',},// ...],};}/* Lighthouse CI plugin */typeLHCIPluginOptions={config: string;};exportfunctionlhciPlugin(options: LHCIPluginOptions): PluginConfig{// ... load configuration, etc. ...return{meta: {slug: 'lhci',name: 'Lighthouse CI',type: 'performance-measurements',icon: 'lighthouse',docsUrl: 'https://pushup.github.io/code-pushup/plugins/lhci'},runner: {outputPath: './dist/cpu/runner-outputs/lhci-plugin.json',command: 'npx lhci autorun',},audits: [{slug: 'largest-contentful-paint',label: 'LCP',title: 'Largest Contentful Paint',docsUrl: 'https://developer.chrome.com/docs/lighthouse/performance/lighthouse-largest-contentful-paint/',},// ...],groups: [{slug: 'performance',title: 'Lighthouse Performance',audits: [{ref: 'largest-contentful-paint',weight: 3},// ...],},],};}To .... we need:
- outPath - name of /dist/plugin-a/runner-output.json
- format -
JSON === RunnerOutput
// JSON formatted output emitted by runnerexporttypeRunnerOutput={audits: Audit[];};typeAudit={/** references audit metadata */slug: string;/** formatted value (e.g. '0.9 s', '2.1 MB') */displayValue?: string;/** raw numeric value (defaults to score ?? details.warnings.length) */value?: number;/** value between 0 and 1 (defaults to Number(details.warnings.length === 0)) */score?: number;/** detailed information */details?: {/** list of findings */issues: Issue[];};};typeIssue={/** descriptive error message */message: string;/** severity level */severity: IssueSeverity;/** reference to source code */source?: SourceFileLocation;// if applicable (linter, unit test)// TODO: other context data};typeIssueSeverity='info'|'warning'|'error';typeSourceFileLocation={/** relative path to source file in Git repo */file: string;/** location in file */position?: {startLine: number;startColumn?: number;endLine?: number;endColumn?: number;};};consteslintOutput: RunnerOutput={audits: [{slug: '@typescript-eslint/no-explicit-any',score: 0,value: 2,details: {issues: [{message: 'Unexpected any. Specify a different type.',severity: 'warning',source: {file: 'src/utils.ts',position: {startLine: 5,startColumn: 10,endLine: 5,endColumn: 13,},},},{message: 'Unexpected any. Specify a different type.',severity: 'warning',source: {file: 'src/utils.ts',position: {startLine: 34,startColumn: 8,endLine: 34,endColumn: 11,},},},],},},// ...],};constlhciOutput: RunnerOutput={audits: [{slug: 'largest-contentful-paint',value: 1100,score: 0.9,details: {issues: [{message: 'Avoid chaining critical requests',severity: 'info'},],},},// ...],};