Skip to content

Commit 92eb309

Browse files
simplyme0823simplyme0823
authored andcommitted
ci: add CodSpeed benchmark coverage
1 parent e012ed7 commit 92eb309

25 files changed

Lines changed: 1159 additions & 13 deletions
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Benchmark CLI
2+
3+
on:
4+
workflow_call:
5+
6+
jobs:
7+
benchmark-cli:
8+
name: Run CLI benchmarks
9+
runs-on: ubuntu-22.04
10+
permissions:
11+
contents: read
12+
id-token: write
13+
env:
14+
GOMAXPROCS: 8
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
18+
with:
19+
submodules: true
20+
fetch-depth: 1
21+
22+
- name: Setup Go
23+
uses: ./.github/actions/setup-go
24+
with:
25+
go-version: '1.26.0'
26+
cache-name: benchmark-cli
27+
28+
- name: Setup Node.js
29+
uses: ./.github/actions/setup-node
30+
31+
- name: Build JS package
32+
run: pnpm --filter @rslint/core run build
33+
34+
- name: Run CLI benchmarks
35+
uses: CodSpeedHQ/action@d872884a306dd4853acf0f584f4b706cf0cc72a2
36+
timeout-minutes: 30
37+
env:
38+
RAYON_NUM_THREADS: 1
39+
CODSPEED_EXPERIMENTAL_FAIR_SCHED: true
40+
GH_MATRIX: '${{ toJson(matrix) }}'
41+
GH_STRATEGY: '${{ toJson(strategy) }}'
42+
with:
43+
mode: walltime
44+
run: pnpm run bench:cli
45+
runner-version: 4.13.0
46+
go-runner-version: 1.2.0

.github/workflows/benchmark-go.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Benchmark Go
2+
3+
on:
4+
workflow_call:
5+
6+
jobs:
7+
benchmark-go:
8+
name: Run Go benchmarks
9+
runs-on: ubuntu-22.04
10+
permissions:
11+
contents: read
12+
id-token: write
13+
env:
14+
GOMAXPROCS: 8
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
18+
with:
19+
submodules: true
20+
fetch-depth: 1
21+
22+
- name: Setup Go
23+
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
24+
with:
25+
go-version: '1.26.0'
26+
cache: false
27+
28+
- name: Run benchmarks
29+
uses: CodSpeedHQ/action@d872884a306dd4853acf0f584f4b706cf0cc72a2
30+
with:
31+
mode: walltime
32+
run: go test -bench=. -benchtime=5s ./tests/bench-go/
33+
go-runner-version: 1.2.0

.github/workflows/benchmarks.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Benchmarks
2+
3+
on:
4+
workflow_dispatch:
5+
6+
permissions:
7+
contents: read
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
benchmark-go:
15+
permissions:
16+
contents: read
17+
id-token: write
18+
uses: ./.github/workflows/benchmark-go.yml
19+
20+
benchmark-cli:
21+
permissions:
22+
contents: read
23+
id-token: write
24+
uses: ./.github/workflows/benchmark-cli.yml

.github/workflows/ci.yml

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ name: CI
22

33
on:
44
push:
5-
branches: [main]
5+
branches:
6+
- main
7+
- 'chore/release-*'
68
pull_request:
79
types: [opened, synchronize]
810
workflow_dispatch:
@@ -319,6 +321,21 @@ jobs:
319321
320322
- name: Run tests
321323
run: cargo test --verbose
324+
325+
benchmark-go:
326+
if: ${{ startsWith(github.ref_name, 'chore/release-') || startsWith(github.head_ref, 'chore/release-') }}
327+
permissions:
328+
contents: read
329+
id-token: write
330+
uses: ./.github/workflows/benchmark-go.yml
331+
332+
benchmark-cli:
333+
if: ${{ startsWith(github.ref_name, 'chore/release-') || startsWith(github.head_ref, 'chore/release-') }}
334+
permissions:
335+
contents: read
336+
id-token: write
337+
uses: ./.github/workflows/benchmark-cli.yml
338+
322339
done:
323340
needs:
324341
- test-go
@@ -328,9 +345,44 @@ jobs:
328345
- lint
329346
- test-wasm
330347
- test-rust
348+
- benchmark-go
349+
- benchmark-cli
331350
if: always()
332351
runs-on: ubuntu-latest
333352
name: CI Done
334353
steps:
335-
- run: exit 1
336-
if: ${{ always() && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'skipped') || contains(needs.*.result, 'cancelled')) }}
354+
- name: Verify required jobs completed
355+
env:
356+
IS_RELEASE_BRANCH: ${{ startsWith(github.ref_name, 'chore/release-') || startsWith(github.head_ref, 'chore/release-') }}
357+
TEST_GO_RESULT: ${{ needs.test-go.result }}
358+
TEST_GO_WINDOWS_RESULT: ${{ needs.test-go-windows.result }}
359+
TEST_NODE_RESULT: ${{ needs.test-node.result }}
360+
TEST_NODE_WINDOWS_RESULT: ${{ needs.test-node-windows.result }}
361+
LINT_RESULT: ${{ needs.lint.result }}
362+
TEST_WASM_RESULT: ${{ needs.test-wasm.result }}
363+
TEST_RUST_RESULT: ${{ needs.test-rust.result }}
364+
BENCHMARK_GO_RESULT: ${{ needs.benchmark-go.result }}
365+
BENCHMARK_CLI_RESULT: ${{ needs.benchmark-cli.result }}
366+
run: |
367+
required_results=(
368+
"$TEST_GO_RESULT"
369+
"$TEST_GO_WINDOWS_RESULT"
370+
"$TEST_NODE_RESULT"
371+
"$TEST_NODE_WINDOWS_RESULT"
372+
"$LINT_RESULT"
373+
"$TEST_WASM_RESULT"
374+
"$TEST_RUST_RESULT"
375+
)
376+
377+
if [ "$IS_RELEASE_BRANCH" = "true" ]; then
378+
required_results+=(
379+
"$BENCHMARK_GO_RESULT"
380+
"$BENCHMARK_CLI_RESULT"
381+
)
382+
fi
383+
384+
for result in "${required_results[@]}"; do
385+
if [ "$result" != "success" ]; then
386+
exit 1
387+
fi
388+
done

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,12 @@ npm/tsgo/*/local
156156
## vscode settings
157157
.vscode/settings.json
158158

159+
159160
# go cache
160161
packages/rslint/pkg/
161162

162163
# rust
163164
target/
164165

165166
# generated rule manifest
166-
website/generated/
167+
website/generated/

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<a href="https://npmjs.com/package/@rslint/core?activeTab=readme"><img src="https://img.shields.io/npm/v/@rslint/core?style=flat-square&colorA=564341&colorB=EDED91" alt="npm version" /></a>
1010
<a href="https://npmcharts.com/compare/@rslint/core?minimal=true"><img src="https://img.shields.io/npm/dm/@rslint/core.svg?style=flat-square&colorA=564341&colorB=EDED91" alt="downloads" /></a>
1111
<a href="https://github.com/web-infra-dev/rslint/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square&colorA=564341&colorB=EDED91" alt="license" /></a>
12+
<a href="https://codspeed.io/web-infra-dev/rslint?utm_source=badge"><img src="https://img.shields.io/endpoint?url=https://codspeed.io/badge.json" alt="CodSpeed"/></a>
1213
</p>
1314

1415
> [!NOTE]

cmd/rslint/api.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"errors"
77
"fmt"
88
"os"
9+
"path/filepath"
910
"sort"
1011
"sync"
1112

@@ -63,13 +64,34 @@ func (h *IPCHandler) HandleLint(req api.LintRequest) (*api.LintResponse, error)
6364
// Create filesystem
6465
fs := bundled.WrapFS(cachedvfs.From(osvfs.FS()))
6566
allowedFiles := []string{}
67+
allowedFileSet := map[string]struct{}{}
68+
69+
// Respect explicit file targeting from the JS API so benchmark and API
70+
// callers can avoid relying on config glob traversal order.
71+
for _, file := range req.Files {
72+
absPath, err := filepath.Abs(file)
73+
if err != nil {
74+
return nil, fmt.Errorf("failed to resolve lint file %s: %w", file, err)
75+
}
76+
normalizedPath := tspath.NormalizePath(absPath)
77+
if _, ok := allowedFileSet[normalizedPath]; ok {
78+
continue
79+
}
80+
allowedFiles = append(allowedFiles, normalizedPath)
81+
allowedFileSet[normalizedPath] = struct{}{}
82+
}
83+
6684
// Apply file contents if provided
6785
if len(req.FileContents) > 0 {
6886
fileContents := make(map[string]string, len(req.FileContents))
6987
for k, v := range req.FileContents {
7088
normalizePath := tspath.NormalizePath(k)
7189
fileContents[normalizePath] = v
90+
if _, ok := allowedFileSet[normalizePath]; ok {
91+
continue
92+
}
7293
allowedFiles = append(allowedFiles, normalizePath)
94+
allowedFileSet[normalizePath] = struct{}{}
7395
}
7496
fs = utils.NewOverlayVFS(fs, fileContents)
7597

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
"build": "pnpm -r --filter=!@typescript/api --filter=!@typescript/ast --filter=@rslint/test-tools... --filter=rslint... build",
1717
"build:npm": "zx scripts/build-npm.mjs",
1818
"build:website": "pnpm --filter @rslint/core run build:js && pnpm --filter=!@typescript/api --filter=!@typescript/ast --filter=!@rslint/core --filter @rslint/website... -r build",
19+
"bench:cli": "pnpm --filter rslint-bench-cli run bench",
20+
"bench:go": "go test -bench=. -benchtime=5s ./tests/bench-go/",
1921
"check-spell": "pnpx cspell lint --no-progress --show-context",
2022
"version": "zx scripts/version.mjs",
2123
"release": "pnpm publish -r --no-git-checks",
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"editor.codeActionsOnSave": {}
3+
}

packages/rslint/tests/api.test.mjs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,25 @@ describe('lint api', async (t) => {
3939
});
4040
expect(diags).toMatchSnapshot();
4141
});
42+
43+
test('explicit files filter limits lint scope', async () => {
44+
const config = path.resolve(import.meta.dirname, '../fixtures/rslint.json');
45+
const targetFile = path.resolve(cwd, 'src/index.ts');
46+
const diags = await lint({
47+
config,
48+
files: [targetFile],
49+
ruleOptions: {
50+
'@typescript-eslint/no-unsafe-member-access': 'error',
51+
},
52+
workingDirectory: cwd,
53+
});
54+
55+
expect(diags.fileCount).toBe(1);
56+
expect(diags.diagnostics.length).toBeGreaterThan(0);
57+
expect(new Set(diags.diagnostics.map((diag) => diag.filePath))).toEqual(
58+
new Set(['src/index.ts']),
59+
);
60+
});
4261
});
4362

4463
describe('applyFixes api', async (t) => {

0 commit comments

Comments
 (0)