From 3889335a3b4c63d2624eb18613b82345b85d1ba8 Mon Sep 17 00:00:00 2001 From: Brendan Kellam Date: Tue, 12 May 2026 20:30:09 -0700 Subject: [PATCH 1/2] chore: add lint workflow for PRs Adds a Lint workflow that fans out via a new root `lint` script (mirroring the existing `test` script's foreach pattern) and fixes the existing no-explicit-any errors in the review-agent test files so the workflow lands green. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/lint.yml | 27 +++++++++++++++++++ package.json | 1 + .../review-agent/nodes/githubPrParser.test.ts | 7 ++--- .../nodes/githubPushPrReviews.test.ts | 5 ++-- .../review-agent/nodes/gitlabMrParser.test.ts | 9 ++++--- .../nodes/gitlabPushMrReviews.test.ts | 9 ++++--- 6 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..9fb01bd53 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,27 @@ +name: Lint + +on: + pull_request: + branches: ["main"] + + +jobs: + lint: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: "true" + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Install + run: yarn install --frozen-lockfile + + - name: Lint + run: yarn lint diff --git a/package.json b/package.json index 4ba77e2db..55ea5bfe2 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "build": "cross-env SKIP_ENV_VALIDATION=1 yarn workspaces foreach --all --topological run build", "test": "yarn workspaces foreach --all --topological run test", + "lint": "yarn workspaces foreach --all --topological run lint", "dev": "concurrently --kill-others --names \"zoekt,worker,web,schemas\" 'yarn dev:zoekt' 'yarn dev:backend' 'yarn dev:web' 'yarn watch:schemas'", "with-env": "cross-env PATH=\"$PWD/bin:$PATH\" dotenv -e .env.development -c --", "dev:zoekt": "yarn with-env zoekt-webserver -index .sourcebot/index -rpc", diff --git a/packages/web/src/features/agents/review-agent/nodes/githubPrParser.test.ts b/packages/web/src/features/agents/review-agent/nodes/githubPrParser.test.ts index 66175a03e..d06cdd889 100644 --- a/packages/web/src/features/agents/review-agent/nodes/githubPrParser.test.ts +++ b/packages/web/src/features/agents/review-agent/nodes/githubPrParser.test.ts @@ -1,4 +1,5 @@ import { expect, test, vi, describe } from 'vitest'; +import { Octokit } from 'octokit'; import { githubPrParser } from './githubPrParser'; import { GitHubPullRequest } from '../types'; @@ -50,7 +51,7 @@ function makePullRequest(overrides: Partial<{ function makeMockOctokit(diffText: string) { return { request: vi.fn().mockResolvedValue({ data: diffText }), - } as any; + } as unknown as Octokit; } describe('githubPrParser', () => { @@ -80,7 +81,7 @@ describe('githubPrParser', () => { test('fetches diff using the pull request diff_url', async () => { const mockRequest = vi.fn().mockResolvedValue({ data: '' }); - const octokit = { request: mockRequest } as any; + const octokit = { request: mockRequest } as unknown as Octokit; const pr = makePullRequest({ diff_url: 'https://github.com/my-org/my-repo/pull/7.diff' }); await githubPrParser(octokit, pr); @@ -184,7 +185,7 @@ describe('githubPrParser', () => { test('throws when the diff request fails', async () => { const octokit = { request: vi.fn().mockRejectedValue(new Error('Network error')), - } as any; + } as unknown as Octokit; const pr = makePullRequest(); await expect(githubPrParser(octokit, pr)).rejects.toThrow('Network error'); diff --git a/packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.test.ts b/packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.test.ts index 9e80d31a9..210fffb44 100644 --- a/packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.test.ts +++ b/packages/web/src/features/agents/review-agent/nodes/githubPushPrReviews.test.ts @@ -1,4 +1,5 @@ import { expect, test, vi, describe } from 'vitest'; +import { Octokit } from 'octokit'; import { githubPushPrReviews } from './githubPushPrReviews'; import { sourcebot_pr_payload, sourcebot_file_diff_review } from '../types'; @@ -38,7 +39,7 @@ function makeMockOctokit(createReviewCommentResult: 'resolve' | 'reject' = 'reso : vi.fn().mockRejectedValue(new Error('Unprocessable Entity')), }, }, - } as any; + } as unknown as Octokit; } describe('githubPushPrReviews', () => { @@ -123,7 +124,7 @@ describe('githubPushPrReviews', () => { const mockCreate = vi.fn() .mockRejectedValueOnce(new Error('422')) .mockResolvedValueOnce({}); - const octokit = { rest: { pulls: { createReviewComment: mockCreate } } } as any; + const octokit = { rest: { pulls: { createReviewComment: mockCreate } } } as unknown as Octokit; await githubPushPrReviews(octokit, MOCK_PAYLOAD, twoReviews); diff --git a/packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.test.ts b/packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.test.ts index ba9fd3eae..b4f7d560a 100644 --- a/packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.test.ts +++ b/packages/web/src/features/agents/review-agent/nodes/gitlabMrParser.test.ts @@ -1,7 +1,10 @@ import { expect, test, vi, describe } from 'vitest'; +import { Gitlab } from '@gitbeaker/rest'; import { gitlabMrParser } from './gitlabMrParser'; import { GitLabMergeRequestPayload } from '../types'; +type GitlabClient = InstanceType; + vi.mock('@sourcebot/shared', () => ({ createLogger: () => ({ debug: vi.fn(), @@ -51,7 +54,7 @@ function makeMockGitlabClient(allDiffsResult: unknown, mrOverrides: Partial { @@ -100,7 +103,7 @@ describe('gitlabMrParser', () => { test('calls show and allDiffs with the correct project id and MR iid', async () => { const mockShow = vi.fn().mockResolvedValue(MOCK_MR_API_RESPONSE); const mockAllDiffs = vi.fn().mockResolvedValue([]); - const client = { MergeRequests: { show: mockShow, allDiffs: mockAllDiffs } } as any; + const client = { MergeRequests: { show: mockShow, allDiffs: mockAllDiffs } } as unknown as GitlabClient; await gitlabMrParser(client, MOCK_MR_PAYLOAD, 'gitlab.com'); @@ -244,7 +247,7 @@ describe('gitlabMrParser', () => { show: vi.fn().mockResolvedValue(MOCK_MR_API_RESPONSE), allDiffs: vi.fn().mockRejectedValue(new Error('Network error')), }, - } as any; + } as unknown as GitlabClient; await expect(gitlabMrParser(client, MOCK_MR_PAYLOAD, 'gitlab.com')).rejects.toThrow('Network error'); }); diff --git a/packages/web/src/features/agents/review-agent/nodes/gitlabPushMrReviews.test.ts b/packages/web/src/features/agents/review-agent/nodes/gitlabPushMrReviews.test.ts index b26ecc53b..98caad2d9 100644 --- a/packages/web/src/features/agents/review-agent/nodes/gitlabPushMrReviews.test.ts +++ b/packages/web/src/features/agents/review-agent/nodes/gitlabPushMrReviews.test.ts @@ -1,7 +1,10 @@ import { expect, test, vi, describe } from 'vitest'; +import { Gitlab } from '@gitbeaker/rest'; import { gitlabPushMrReviews } from './gitlabPushMrReviews'; import { sourcebot_pr_payload, sourcebot_file_diff_review } from '../types'; +type GitlabClient = InstanceType; + vi.mock('@sourcebot/shared', () => ({ createLogger: () => ({ debug: vi.fn(), @@ -44,7 +47,7 @@ function makeMockClient(discussionResult: 'resolve' | 'reject' = 'resolve') { MergeRequestNotes: { create: vi.fn().mockResolvedValue({}), }, - } as any; + } as unknown as GitlabClient; } describe('gitlabPushMrReviews', () => { @@ -165,7 +168,7 @@ describe('gitlabPushMrReviews', () => { const client = { MergeRequestDiscussions: { create: mockCreate }, MergeRequestNotes: { create: vi.fn().mockResolvedValue({}) }, - } as any; + } as unknown as GitlabClient; await gitlabPushMrReviews(client, 101, MOCK_PAYLOAD, twoReviews); @@ -178,7 +181,7 @@ describe('gitlabPushMrReviews', () => { const client = { MergeRequestDiscussions: { create: vi.fn().mockRejectedValue(new Error('500')) }, MergeRequestNotes: { create: vi.fn().mockRejectedValue(new Error('500')) }, - } as any; + } as unknown as GitlabClient; await expect( gitlabPushMrReviews(client, 101, MOCK_PAYLOAD, SINGLE_REVIEW), From fd3efeeafa4607e8590f4d454de2dd00fa78cf6d Mon Sep 17 00:00:00 2001 From: Brendan Kellam Date: Tue, 12 May 2026 20:33:58 -0700 Subject: [PATCH 2/2] chore(ci): enable yarn cache in lint workflow Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/lint.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9fb01bd53..3d194eb91 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,6 +19,8 @@ jobs: uses: actions/setup-node@v4 with: node-version: '20.x' + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' - name: Install run: yarn install --frozen-lockfile