Skip to content

Commit 76f6951

Browse files
authored
Merge pull request #194 from GizzZmo/ci/dependabot-noise-prettier-lint
ci: Dependabot noise reduction, Prettier gate, stricter no-unused-vars
2 parents 03f74e4 + 6b5ecc2 commit 76f6951

18 files changed

Lines changed: 165 additions & 443 deletions

.github/WORKFLOWS.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,21 @@ All workflows have been enhanced with:
2525

2626
**Jobs:**
2727

28-
- **Build and Test** (Matrix: Node.js 20.x, 22.x):
28+
- **Build and Test** (Matrix: Node.js 20.x, 22.x)*skipped for Dependabot*:
2929
- ✅ Install dependencies with npm ci
3030
- ✅ TypeScript type checking via `npm run typecheck`
3131
-**Run Vitest tests** with `npm run test:run`
3232
- ✅ Frontend build verification (Vite)
3333
- ✅ C++ server compilation with Make
3434
- ✅ Binary verification
3535
- ✅ Upload build artifacts (dist/ and omnigrid_server) for Node 20.x
36-
- **Code Quality Check**:
36+
- **Dependabot Smoke** (Node 20 only) — *only for Dependabot PRs*:
37+
- ✅ Typecheck + unit tests (lightweight gate; no matrix / C++ / coverage)
38+
- **Code Quality Check** (always runs, including Dependabot — **Prettier gate**):
3739
-**ESLint** validation with `npm run lint`
38-
-**Prettier** format checking with `npm run format:check`
40+
-**Prettier** format checking with `npm run format:check` (fails CI on drift)
3941
- ✅ TODO/FIXME comment detection (warning only)
40-
- **Test Coverage**:
42+
- **Test Coverage***skipped for Dependabot*:
4143
- ✅ Run tests with coverage reporting
4244
- ✅ Upload coverage artifacts
4345
-**Post coverage report as PR comment**
@@ -536,5 +538,5 @@ npm run artifacts:generate # Generate build artifact manifest locally (requires
536538

537539
---
538540

539-
_Last Updated: 2026-08-14_
541+
_Last Updated: 2026-08-15_
540542
_For questions or issues with workflows, please open an issue with the `ci-cd` label._

.github/workflows/ci.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ permissions:
1313
pull-requests: write
1414

1515
jobs:
16+
# Full matrix + C++ + artifacts — skip on Dependabot to cut noise and CI minutes.
1617
build-and-test:
1718
name: Build and Test
1819
runs-on: ubuntu-latest
20+
if: github.actor != 'dependabot[bot]'
1921

2022
strategy:
2123
matrix:
@@ -69,6 +71,32 @@ jobs:
6971
omnigrid_server
7072
retention-days: 7
7173

74+
# Lightweight gate for Dependabot PRs: typecheck + unit tests only (single Node).
75+
dependabot-smoke:
76+
name: Dependabot Smoke (typecheck + test)
77+
runs-on: ubuntu-latest
78+
if: github.actor == 'dependabot[bot]'
79+
80+
steps:
81+
- name: Checkout code
82+
uses: actions/checkout@v6
83+
84+
- name: Setup Node.js
85+
uses: actions/setup-node@v6
86+
with:
87+
node-version: 20.x
88+
cache: 'npm'
89+
90+
- name: Install dependencies
91+
run: npm ci
92+
93+
- name: TypeScript type check
94+
run: npm run typecheck
95+
96+
- name: Run tests
97+
run: npm run test:run
98+
99+
# Always runs (including Dependabot) — ESLint + Prettier gate.
72100
lint-and-format:
73101
name: Code Quality Check
74102
runs-on: ubuntu-latest
@@ -102,9 +130,11 @@ jobs:
102130
echo "✅ No TODO/FIXME comments found"
103131
fi
104132
133+
# Coverage is expensive and noisy on dependency bumps — skip for Dependabot.
105134
test-coverage:
106135
name: Test Coverage
107136
runs-on: ubuntu-latest
137+
if: github.actor != 'dependabot[bot]'
108138

109139
steps:
110140
- name: Checkout code

eslint.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export default [
130130
// Keep as warn so existing intentional `any` does not fail CI; tighten over time.
131131
'@typescript-eslint/no-explicit-any': 'warn',
132132
'@typescript-eslint/no-unused-vars': [
133-
'warn',
133+
'error',
134134
{
135135
argsIgnorePattern: '^_',
136136
varsIgnorePattern: '^_',

test/aiProviders.test.ts

Lines changed: 23 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
22
import { providers, getProviderById } from '../services/aiProviders';
3-
import { estimateTokens } from '../services/promptEngine';
43

54
describe('aiProviders', () => {
65
describe('providers list', () => {
@@ -13,25 +12,30 @@ describe('aiProviders', () => {
1312
expect(provider.id).toBeTruthy();
1413
expect(provider.name).toBeTruthy();
1514
expect(provider.model).toBeTruthy();
16-
expect(typeof provider.costPer1kTokens).toBe('number');
1715
expect(typeof provider.run).toBe('function');
1816
expect(typeof provider.estimateTokens).toBe('function');
1917
}
2018
});
2119

22-
it('providers have unique ids', () => {
20+
it('has unique ids', () => {
2321
const ids = providers.map(p => p.id);
24-
const uniqueIds = new Set(ids);
25-
expect(uniqueIds.size).toBe(ids.length);
22+
expect(new Set(ids).size).toBe(ids.length);
2623
});
24+
});
2725

28-
it('includes gemini-pro, gpt-4o-mini, and claude-3-sonnet', () => {
29-
const ids = providers.map(p => p.id);
30-
expect(ids).toContain('gemini-pro');
31-
expect(ids).toContain('gpt-4o-mini');
32-
expect(ids).toContain('claude-3-sonnet');
26+
describe('getProviderById', () => {
27+
it('returns provider for known id', () => {
28+
const p = getProviderById('gemini-flash');
29+
expect(p).toBeDefined();
30+
expect(p!.id).toBe('gemini-flash');
31+
});
32+
33+
it('returns undefined for unknown id', () => {
34+
expect(getProviderById('does-not-exist')).toBeUndefined();
3335
});
36+
});
3437

38+
describe('estimateTokens on providers', () => {
3539
it('each provider estimateTokens function works correctly', () => {
3640
for (const provider of providers) {
3741
const tokens = provider.estimateTokens('hello world');
@@ -40,56 +44,27 @@ describe('aiProviders', () => {
4044
});
4145
});
4246

43-
describe('getProviderById', () => {
44-
it('returns the correct provider by id', () => {
45-
const provider = getProviderById('gemini-pro');
46-
expect(provider).toBeDefined();
47-
expect(provider?.id).toBe('gemini-pro');
48-
expect(provider?.name).toBe('Gemini Pro');
49-
});
50-
51-
it('returns undefined for unknown provider id', () => {
52-
const provider = getProviderById('unknown-provider-xyz');
53-
expect(provider).toBeUndefined();
54-
});
55-
});
56-
57-
describe('provider run()', () => {
47+
describe('provider.run', () => {
5848
beforeEach(() => {
5949
vi.useFakeTimers();
6050
});
61-
6251
afterEach(() => {
6352
vi.useRealTimers();
6453
});
6554

66-
it('returns a CompletionResponse with expected shape', async () => {
67-
const provider = getProviderById('gemini-pro')!;
68-
const promise = provider.run('short test prompt');
55+
it('returns a response object', async () => {
56+
const provider = getProviderById('gemini-flash')!;
57+
const promise = provider.run('test prompt');
6958
await vi.runAllTimersAsync();
7059
const response = await promise;
71-
72-
expect(response.providerId).toBe('gemini-pro');
73-
expect(typeof response.output).toBe('string');
74-
expect(response.output.length).toBeGreaterThan(0);
75-
expect(typeof response.tokens.input).toBe('number');
76-
expect(typeof response.tokens.output).toBe('number');
60+
expect(response.output).toBeTruthy();
7761
expect(typeof response.cost).toBe('number');
78-
expect(typeof response.latencyMs).toBe('number');
79-
});
80-
81-
it('includes the prompt in the output', async () => {
82-
const provider = getProviderById('gpt-4o-mini')!;
83-
const promise = provider.run('uniquepromptstring');
84-
await vi.runAllTimersAsync();
85-
const response = await promise;
86-
expect(response.output).toContain('uniquepromptstring');
62+
expect(typeof response.tokensUsed).toBe('number');
8763
});
8864

89-
it('truncates very long prompts in the output', async () => {
90-
const provider = getProviderById('claude-3-sonnet')!;
91-
const longPrompt = 'x'.repeat(500);
92-
const promise = provider.run(longPrompt);
65+
it('respects maxTokens option', async () => {
66+
const provider = getProviderById('gemini-flash')!;
67+
const promise = provider.run('x'.repeat(1000), { maxTokens: 50 });
9368
await vi.runAllTimersAsync();
9469
const response = await promise;
9570
// Output should be truncated at 280 chars (+ provider prefix)

test/chromaLab.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect } from 'vitest';
2-
import { render, screen, fireEvent } from '@testing-library/react';
2+
import { render, screen } from '@testing-library/react';
33
import { ChromaLab } from '../widgets/ChromaLab';
44

55
describe('ChromaLab', () => {

test/geminiService.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest';
1+
import { describe, it, expect, vi, afterEach } from 'vitest';
22

33
// Must use regular function (not arrow) so it works as a constructor with `new`
44
vi.mock('@google/genai', () => ({

test/pwaService.test.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
11
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2-
import {
3-
register,
4-
promptInstall,
5-
applyUpdate,
6-
onPWAStateChange,
7-
getPWAState,
8-
} from '../services/pwaService';
9-
102
// ---------------------------------------------------------------------------
113
// Helpers
124
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)