@diplodoc/lint 1.12.0 → 1.13.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/README.md
CHANGED
|
@@ -85,6 +85,7 @@ Initializes linting in a package:
|
|
|
85
85
|
Updates configuration files to the latest versions:
|
|
86
86
|
|
|
87
87
|
- Updates `.eslintrc.js`, `.prettierrc.js`, `.stylelintrc.js`
|
|
88
|
+
- Updates/copies GitHub Actions workflows (including `sonarcloud.yml`, `coverage.yml`) and `sonar-project.properties` (with `{{PACKAGE_NAME}}` substitution)
|
|
88
89
|
- Updates ignore files with new patterns
|
|
89
90
|
- **Does not** re-initialize Husky
|
|
90
91
|
- **Does not** modify existing scripts in `package.json`
|
|
@@ -224,6 +225,20 @@ build({
|
|
|
224
225
|
- **Import**: Use `@diplodoc/lint/esbuild` — it re-exports the full esbuild API (ESM and CJS).
|
|
225
226
|
- **Why**: Aligns esbuild version and avoids duplicate native bindings; add `@diplodoc/lint` as a devDependency and use this export instead of installing `esbuild` directly in the package.
|
|
226
227
|
|
|
228
|
+
### SonarCloud
|
|
229
|
+
|
|
230
|
+
Scaffolding provides optional SonarCloud integration for code quality and coverage:
|
|
231
|
+
|
|
232
|
+
- **`sonar-project.properties`** — copied to the package root; the placeholder `{{PACKAGE_NAME}}` is replaced with the package name **without scope** (e.g. `@diplodoc/foo` → `foo`) so each repo has a unique SonarCloud project key.
|
|
233
|
+
- **`.github/workflows/sonarcloud.yml`** — runs SonarCloud analysis on push/PR to `master`/`main`. The scan runs only when the package has a `test:coverage` script and coverage was generated; otherwise the job skips the scan.
|
|
234
|
+
- **`.github/workflows/coverage.yml`** — optional workflow that runs `test:coverage` when the script exists (see above); does not block merging.
|
|
235
|
+
|
|
236
|
+
To enable SonarCloud for a repository:
|
|
237
|
+
|
|
238
|
+
1. Add the repository in [SonarCloud](https://sonarcloud.io) (organization `diplodoc-platform`).
|
|
239
|
+
2. Add the **SONAR_TOKEN** secret in the GitHub repo settings.
|
|
240
|
+
3. Optionally add a `test:coverage` script (e.g. `vitest run --coverage`) so the SonarCloud workflow can upload coverage.
|
|
241
|
+
|
|
227
242
|
## Metapackage vs Standalone Usage
|
|
228
243
|
|
|
229
244
|
The package works in two modes:
|
package/package.json
CHANGED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# ⚠️ IMPORTANT: This workflow is a template from diplodoc/lint/scaffolding
|
|
2
|
+
# Do not edit this file in other packages - it is automatically copied from here.
|
|
3
|
+
# To modify this workflow, edit it in diplodoc/devops/lint/scaffolding/.github/workflows/
|
|
4
|
+
# and then run the scaffolding update process.
|
|
5
|
+
#
|
|
6
|
+
# This workflow is optional: it does not block merging even if it fails (continue-on-error).
|
|
7
|
+
|
|
8
|
+
name: Coverage
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches:
|
|
13
|
+
- master
|
|
14
|
+
- main
|
|
15
|
+
pull_request:
|
|
16
|
+
branches:
|
|
17
|
+
- master
|
|
18
|
+
- main
|
|
19
|
+
workflow_dispatch:
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
coverage:
|
|
23
|
+
name: Test coverage
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
continue-on-error: true
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout repository
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
with:
|
|
30
|
+
fetch-depth: 0
|
|
31
|
+
|
|
32
|
+
- name: Setup Node.js
|
|
33
|
+
uses: actions/setup-node@v4
|
|
34
|
+
with:
|
|
35
|
+
node-version: 22
|
|
36
|
+
cache: 'npm'
|
|
37
|
+
|
|
38
|
+
- name: Install latest npm (>= 11.5.1)
|
|
39
|
+
run: |
|
|
40
|
+
[ "$(printf '%s\n' "11.5.1" "$(npm -v)" | sort -V | head -n1)" = "11.5.1" ] || npm install -g npm@latest
|
|
41
|
+
shell: bash
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: npm ci
|
|
45
|
+
|
|
46
|
+
- name: Run tests with coverage
|
|
47
|
+
id: coverage-run
|
|
48
|
+
run: |
|
|
49
|
+
if node -e "const s=require('./package.json').scripts; process.exit(s && s['test:coverage'] ? 0 : 1)"; then
|
|
50
|
+
npm run test:coverage
|
|
51
|
+
echo "ran=true" >> "$GITHUB_OUTPUT"
|
|
52
|
+
else
|
|
53
|
+
echo "test:coverage script not found, skipping."
|
|
54
|
+
echo "ran=false" >> "$GITHUB_OUTPUT"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
- name: Upload coverage artifact
|
|
58
|
+
if: success() && steps.coverage-run.outputs.ran == 'true'
|
|
59
|
+
uses: actions/upload-artifact@v4
|
|
60
|
+
with:
|
|
61
|
+
name: coverage
|
|
62
|
+
path: coverage/
|
|
63
|
+
retention-days: 7
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: SonarCloud Analysis
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master, main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master, main]
|
|
8
|
+
types: [opened, synchronize, reopened]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
sonarcloud:
|
|
12
|
+
name: SonarCloud Analysis
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout code
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0 # Shallow clones should be disabled for better analysis
|
|
19
|
+
|
|
20
|
+
- name: Setup Node.js
|
|
21
|
+
uses: actions/setup-node@v4
|
|
22
|
+
with:
|
|
23
|
+
node-version: 22.x
|
|
24
|
+
cache: 'npm'
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: npm ci
|
|
28
|
+
|
|
29
|
+
- name: Run tests with coverage
|
|
30
|
+
id: coverage-run
|
|
31
|
+
run: |
|
|
32
|
+
if node -e "const s=require('./package.json').scripts; process.exit(s && s['test:coverage'] ? 0 : 1)"; then
|
|
33
|
+
npm run test:coverage
|
|
34
|
+
echo "ran=true" >> "$GITHUB_OUTPUT"
|
|
35
|
+
else
|
|
36
|
+
echo "test:coverage script not found, skipping."
|
|
37
|
+
echo "ran=false" >> "$GITHUB_OUTPUT"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
- name: SonarCloud Scan
|
|
41
|
+
if: success() && steps.coverage-run.outputs.ran == 'true'
|
|
42
|
+
uses: SonarSource/sonarqube-scan-action@v7.0.0
|
|
43
|
+
env:
|
|
44
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
45
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# SonarCloud project configuration
|
|
2
|
+
# This file will be generated/updated by SonarCloud when you connect your repository
|
|
3
|
+
|
|
4
|
+
# Project identification
|
|
5
|
+
# Note: sonar.organization can also be set via environment variable SONAR_ORGANIZATION
|
|
6
|
+
# or via GitHub Actions workflow. If not set here, it must be provided in the workflow.
|
|
7
|
+
sonar.organization=diplodoc-platform
|
|
8
|
+
sonar.projectKey=diplodoc-platform_{{package}}
|
|
9
|
+
sonar.projectName={{package}}
|
|
10
|
+
|
|
11
|
+
# Source code location
|
|
12
|
+
sonar.sources=src
|
|
13
|
+
sonar.exclusions=**/*.spec.ts,**/*.test.ts,**/__tests__/**
|
|
14
|
+
|
|
15
|
+
# Test code location
|
|
16
|
+
sonar.tests=src
|
|
17
|
+
sonar.test.inclusions=**/*.spec.ts,**/*.test.ts,**/__tests__/**
|
|
18
|
+
|
|
19
|
+
# Coverage reports
|
|
20
|
+
sonar.javascript.lcov.reportPaths=coverage/lcov.info
|
|
21
|
+
sonar.typescript.lcov.reportPaths=coverage/lcov.info
|
|
22
|
+
|
|
23
|
+
# TypeScript configuration
|
|
24
|
+
sonar.typescript.tsconfigPath=tsconfig.json
|
|
25
|
+
|
|
26
|
+
# Encoding
|
|
27
|
+
sonar.sourceEncoding=UTF-8
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const {join, relative, dirname} = require('node:path');
|
|
2
|
-
const {readdirSync, copyFileSync, mkdirSync, existsSync, realpathSync} = require('node:fs');
|
|
2
|
+
const {readdirSync, readFileSync, writeFileSync, copyFileSync, mkdirSync, existsSync, realpathSync} = require('node:fs');
|
|
3
3
|
|
|
4
4
|
// Determine package root directory
|
|
5
5
|
// Try multiple strategies to find the package root
|
|
@@ -32,6 +32,41 @@ if (!existsSync(srcDir)) {
|
|
|
32
32
|
|
|
33
33
|
const targetDir = process.cwd();
|
|
34
34
|
|
|
35
|
+
/** @type {{ PACKAGE_NAME: string }} Variables for scaffolding template substitution */
|
|
36
|
+
let scaffoldVars = {PACKAGE_NAME: 'package'};
|
|
37
|
+
const packageJsonPath = join(targetDir, 'package.json');
|
|
38
|
+
if (existsSync(packageJsonPath)) {
|
|
39
|
+
try {
|
|
40
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
41
|
+
const name = pkg.name && typeof pkg.name === 'string' ? pkg.name : '';
|
|
42
|
+
scaffoldVars.PACKAGE_NAME = name.replace(/^@[^/]+\//, '') || 'package';
|
|
43
|
+
} catch {
|
|
44
|
+
// leave default
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function applyTemplate(content) {
|
|
49
|
+
if (typeof content !== 'string' || !content.includes('{{')) {
|
|
50
|
+
return content;
|
|
51
|
+
}
|
|
52
|
+
return content.replace(/\{\{PACKAGE_NAME\}\}/g, scaffoldVars.PACKAGE_NAME);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function copyFileWithSubstitution(srcPath, targetPath) {
|
|
56
|
+
let content;
|
|
57
|
+
try {
|
|
58
|
+
content = readFileSync(srcPath, 'utf8');
|
|
59
|
+
} catch {
|
|
60
|
+
copyFileSync(srcPath, targetPath);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (content.includes('{{PACKAGE_NAME}}')) {
|
|
64
|
+
writeFileSync(targetPath, applyTemplate(content), 'utf8');
|
|
65
|
+
} else {
|
|
66
|
+
writeFileSync(targetPath, content, 'utf8');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
35
70
|
// Verify scaffolding directory exists
|
|
36
71
|
if (!existsSync(srcDir)) {
|
|
37
72
|
console.error(`[@diplodoc/lint] Error: scaffolding directory not found at ${srcDir}`);
|
|
@@ -74,9 +109,9 @@ function copyScaffoldingFiles(excludePatterns = []) {
|
|
|
74
109
|
if (!existsSync(targetParent)) {
|
|
75
110
|
mkdirSync(targetParent, {recursive: true});
|
|
76
111
|
}
|
|
77
|
-
// Force overwrite existing files
|
|
112
|
+
// Force overwrite existing files (with optional {{PACKAGE_NAME}} substitution)
|
|
78
113
|
try {
|
|
79
|
-
|
|
114
|
+
copyFileWithSubstitution(srcPath, targetPath);
|
|
80
115
|
} catch (error) {
|
|
81
116
|
console.error(`[@diplodoc/lint] Error copying ${srcPath} to ${targetPath}:`, error.message);
|
|
82
117
|
throw error;
|
|
@@ -105,7 +140,7 @@ function copyWorkflows() {
|
|
|
105
140
|
if (entry.isFile()) {
|
|
106
141
|
const srcPath = join(workflowsSrc, entry.name);
|
|
107
142
|
const targetPath = join(workflowsTarget, entry.name);
|
|
108
|
-
|
|
143
|
+
copyFileWithSubstitution(srcPath, targetPath);
|
|
109
144
|
}
|
|
110
145
|
}
|
|
111
146
|
}
|