The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/.betterer.ts

99 lines
3.6 KiB

import { BettererFileTest } from '@betterer/betterer';
import { promises as fs } from 'fs';
import { ESLint, Linter } from 'eslint';
import path from 'path';
import { glob } from 'glob';
export default {
'better eslint': () =>
countEslintErrors()
.include('**/*.{ts,tsx}')
.exclude(/public\/app\/angular|packages\/grafana-e2e/),
Chore: Upgrade Storybook to v7 (#65943) * chore(grafana-ui): begin migration to storybook7 * refactor(storybook): begin cleanup of storybook and addon configs * chore(storybook): add storybook/blocks to keep yarn berry happy * chore(storybook): rename intro story for storybook 7 * chore(stories): rename internal stories to support SB7 story name mapper * chore(betterer): update glob to support internal story renaming * chore(stories): silence TS errors for subcomponents in SB7 * fix(clickoutsidewrapper): window | document can be undefined not null * chore(storybook): remove patch for 6.5.16 * revert(storybook): put back story globs * docs(storybook): replace removed <Props /> with <ArgsTypes /> in mdx files * docs(storybook): use ArgTypes instead of ArgsTable * chore(storybook): use correct ArgTypes import name in mdx files * chore(storybook): patch blocks to expose Preview component for docs * chore(storybook): rename deprecated ComponentStory and ComponentMeta for v7 * feat(storybook): add STORY env var to customise which stories storybook should load * chore(storybook): bump to 7.0.4 * fix(storybook): set esbuild minify target to fix erroring docs in production builds * fix(toolbarbuttonrow): fix import path to prevent error in storybook doc * docs(storybook): fix up some more stories * chore(storybook): more config updates to match storybook documentation * chore(storybook): bump to 7.0.5 * Apply suggestions from code review Co-authored-by: Joao Silva <100691367+JoaoSilvaGrafana@users.noreply.github.com> * chore(storybook): fix broken merge causing types issues * chore(storybook): mimic broken alphabetical storySort and docs overview ordering * docs(storybook): fix button docs adding p tags due to mdx2 * chore(storybook): bump to 7.0.10 * chore(storybook): apply patch on yarn install * chore(text): update stories for storybook 7 * fix(storybook): make sure globs don't include internal stories in production --------- Co-authored-by: Joao Silva <100691367+JoaoSilvaGrafana@users.noreply.github.com>
2 years ago
'no undocumented stories': () => countUndocumentedStories().include('**/!(*.internal).story.tsx'),
};
function countUndocumentedStories() {
return new BettererFileTest(async (filePaths, fileTestResult) => {
await Promise.all(
filePaths.map(async (filePath) => {
// look for .mdx import in the story file
const regex = new RegExp("^import.*.mdx';$", 'gm');
const fileText = await fs.readFile(filePath, 'utf8');
if (!regex.test(fileText)) {
// In this case the file contents don't matter:
const file = fileTestResult.addFile(filePath, '');
// Add the issue to the first character of the file:
file.addIssue(0, 0, 'No undocumented stories are allowed, please add an .mdx file with some documentation');
}
})
);
});
}
function countEslintErrors() {
return new BettererFileTest(async (filePaths, fileTestResult, resolver) => {
const { baseDirectory } = resolver;
const cli = new ESLint({ cwd: baseDirectory });
const eslintConfigFiles = await glob('**/.eslintrc');
const eslintConfigMainPaths = eslintConfigFiles.map((file) => path.resolve(path.dirname(file)));
const baseRules: Partial<Linter.RulesRecord> = {
'@typescript-eslint/no-explicit-any': 'error',
'@grafana/no-aria-label-selectors': 'error',
};
const nonTestFilesRules: Partial<Linter.RulesRecord> = {
...baseRules,
'@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }],
};
// group files by eslint config file
// this will create two file groups for each eslint config file
// one for test files and one for non-test files
const fileGroups: Record<string, string[]> = {};
for (const filePath of filePaths) {
let configPath = eslintConfigMainPaths.find((configPath) => filePath.startsWith(configPath)) ?? '';
const isTestFile =
filePath.endsWith('.test.tsx') ||
filePath.endsWith('.test.ts') ||
filePath.includes('__mocks__') ||
filePath.includes('public/test/');
if (isTestFile) {
configPath += '-test';
}
if (!fileGroups[configPath]) {
fileGroups[configPath] = [];
}
fileGroups[configPath].push(filePath);
}
for (const configPath of Object.keys(fileGroups)) {
const rules = configPath.endsWith('-test') ? baseRules : nonTestFilesRules;
// this is by far the slowest part of this code. It takes eslint about 2 seconds just to find the config
const linterOptions = (await cli.calculateConfigForFile(fileGroups[configPath][0])) as Linter.Config;
const runner = new ESLint({
baseConfig: {
...linterOptions,
rules: rules,
},
useEslintrc: false,
cwd: baseDirectory,
});
const lintResults = await runner.lintFiles(fileGroups[configPath]);
lintResults
.filter((lintResult) => lintResult.source)
.forEach((lintResult) => {
const { messages } = lintResult;
const filePath = lintResult.filePath;
const file = fileTestResult.addFile(filePath, '');
messages.forEach((message, index) => {
file.addIssue(0, 0, message.message, `${index}`);
});
});
}
});
}