Skip to content

Commit 22d548e

Browse files
fix(search-contexts): Fix issue where a repository would not appear in a search context if it was created after the search context was created (#354)
## Problem If a repository is added **after** a search context (e.g., a new repository is synced from the code host), then it will never be added to the context even if it should be included. The workaround is to restart the instance. ## Solution This PR adds a call to re-sync all search contexts whenever a connection is successfully synced. This PR adds the `@sourcebot/shared` package that contains `syncSearchContexts.ts` (previously in web) and it's dependencies (namely the entitlements system). ## Why another package? Because the `syncSearchContexts` call is now called from: 1. `initialize.ts` in **web** - handles syncing search contexts on startup and whenever the config is modified in watch mode. This is the same as before. 2. `connectionManager.ts` in **backend** - syncs the search contexts whenever a connection is successfully synced. ## Follow-up devex work Two things: 1. We have several very thin shared packages (i.e., `crypto`, `error`, and `logger`) that we can probably fold into this "general" shared package. `schemas` and `db` _feels_ like they should remain separate (mostly because they are "code-gen" packages). 2. When running `yarn dev`, any changes made to the shared package will only get picked if you `ctrl+c` and restart the instance. Would be nice if we have watch mode work across package dependencies in the monorepo.
1 parent c0caa5a commit 22d548e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+321
-172
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Fixed
1111
- Delete account join request when redeeming an invite. [#352](https://github.com/sourcebot-dev/sourcebot/pull/352)
12+
- Fix issue where a repository would not be included in a search context if the context was created before the repository. [#354](https://github.com/sourcebot-dev/sourcebot/pull/354)
1213

1314
## [4.3.0] - 2025-06-11
1415

Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@ COPY ./packages/schemas ./packages/schemas
4343
COPY ./packages/crypto ./packages/crypto
4444
COPY ./packages/error ./packages/error
4545
COPY ./packages/logger ./packages/logger
46+
COPY ./packages/shared ./packages/shared
4647

4748
RUN yarn workspace @sourcebot/db install
4849
RUN yarn workspace @sourcebot/schemas install
4950
RUN yarn workspace @sourcebot/crypto install
5051
RUN yarn workspace @sourcebot/error install
5152
RUN yarn workspace @sourcebot/logger install
53+
RUN yarn workspace @sourcebot/shared install
5254
# ------------------------------------
5355

5456
# ------ Build Web ------
@@ -92,6 +94,7 @@ COPY --from=shared-libs-builder /app/packages/schemas ./packages/schemas
9294
COPY --from=shared-libs-builder /app/packages/crypto ./packages/crypto
9395
COPY --from=shared-libs-builder /app/packages/error ./packages/error
9496
COPY --from=shared-libs-builder /app/packages/logger ./packages/logger
97+
COPY --from=shared-libs-builder /app/packages/shared ./packages/shared
9598

9699
# Fixes arm64 timeouts
97100
RUN yarn workspace @sourcebot/web install
@@ -132,6 +135,7 @@ COPY --from=shared-libs-builder /app/packages/schemas ./packages/schemas
132135
COPY --from=shared-libs-builder /app/packages/crypto ./packages/crypto
133136
COPY --from=shared-libs-builder /app/packages/error ./packages/error
134137
COPY --from=shared-libs-builder /app/packages/logger ./packages/logger
138+
COPY --from=shared-libs-builder /app/packages/shared ./packages/shared
135139
RUN yarn workspace @sourcebot/backend install
136140
RUN yarn workspace @sourcebot/backend build
137141

@@ -215,6 +219,7 @@ COPY --from=shared-libs-builder /app/packages/schemas ./packages/schemas
215219
COPY --from=shared-libs-builder /app/packages/crypto ./packages/crypto
216220
COPY --from=shared-libs-builder /app/packages/error ./packages/error
217221
COPY --from=shared-libs-builder /app/packages/logger ./packages/logger
222+
COPY --from=shared-libs-builder /app/packages/shared ./packages/shared
218223

219224
# Configure dependencies
220225
RUN apk add --no-cache git ca-certificates bind-tools tini jansson wget supervisor uuidgen curl perl jq redis postgresql postgresql-contrib openssl util-linux unzip

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Copyright (c) 2025 Taqla Inc.
22

33
Portions of this software are licensed as follows:
44

5-
- All content that resides under the "ee/" and "packages/web/src/ee/" directories of this repository, if these directories exist, is licensed under the license defined in "ee/LICENSE".
5+
- All content that resides under the "ee/", "packages/web/src/ee/", and "packages/shared/src/ee/" directories of this repository, if these directories exist, is licensed under the license defined in "ee/LICENSE".
66
- All third party components incorporated into the Sourcebot Software are licensed under the original license provided by the owner of the applicable component.
77
- Content outside of the above mentioned directories or restrictions above is available under the "MIT Expat" license as defined below.
88

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ clean:
3434
packages/error/dist \
3535
packages/mcp/node_modules \
3636
packages/mcp/dist \
37+
packages/shared/node_modules \
38+
packages/shared/dist \
3739
.sourcebot
3840

3941
soft-reset:

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"dev:prisma:migrate:dev": "yarn with-env yarn workspace @sourcebot/db prisma:migrate:dev",
1717
"dev:prisma:studio": "yarn with-env yarn workspace @sourcebot/db prisma:studio",
1818
"dev:prisma:migrate:reset": "yarn with-env yarn workspace @sourcebot/db prisma:migrate:reset",
19-
"build:deps": "yarn workspaces foreach -R --from '{@sourcebot/schemas,@sourcebot/error,@sourcebot/crypto,@sourcebot/db}' run build"
19+
"build:deps": "yarn workspaces foreach -R --from '{@sourcebot/schemas,@sourcebot/error,@sourcebot/crypto,@sourcebot/db,@sourcebot/shared}' run build"
2020
},
2121
"devDependencies": {
2222
"cross-env": "^7.0.3",

packages/backend/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@
3333
"@sourcebot/error": "workspace:*",
3434
"@sourcebot/logger": "workspace:*",
3535
"@sourcebot/schemas": "workspace:*",
36+
"@sourcebot/shared": "workspace:*",
3637
"@t3-oss/env-core": "^0.12.0",
3738
"@types/express": "^5.0.0",
38-
"ajv": "^8.17.1",
3939
"argparse": "^2.0.1",
4040
"bullmq": "^5.34.10",
4141
"cross-fetch": "^4.0.0",
@@ -50,7 +50,6 @@
5050
"posthog-node": "^4.2.1",
5151
"prom-client": "^15.1.3",
5252
"simple-git": "^3.27.0",
53-
"strip-json-comments": "^5.0.1",
5453
"zod": "^3.24.3"
5554
}
5655
}

packages/backend/src/connectionManager.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { BackendError, BackendException } from "@sourcebot/error";
99
import { captureEvent } from "./posthog.js";
1010
import { env } from "./env.js";
1111
import * as Sentry from "@sentry/node";
12+
import { loadConfig, syncSearchContexts } from "@sourcebot/shared";
1213

1314
interface IConnectionManager {
1415
scheduleConnectionSync: (connection: Connection) => Promise<void>;
@@ -264,7 +265,7 @@ export class ConnectionManager implements IConnectionManager {
264265

265266
private async onSyncJobCompleted(job: Job<JobPayload>, result: JobResult) {
266267
this.logger.info(`Connection sync job for connection ${job.data.connectionName} (id: ${job.data.connectionId}, jobId: ${job.id}) completed`);
267-
const { connectionId } = job.data;
268+
const { connectionId, orgId } = job.data;
268269

269270
let syncStatusMetadata: Record<string, unknown> = (await this.db.connection.findUnique({
270271
where: { id: connectionId },
@@ -289,7 +290,25 @@ export class ConnectionManager implements IConnectionManager {
289290
notFound.repos.length > 0 ? ConnectionSyncStatus.SYNCED_WITH_WARNINGS : ConnectionSyncStatus.SYNCED,
290291
syncedAt: new Date()
291292
}
292-
})
293+
});
294+
295+
// After a connection has synced, we need to re-sync the org's search contexts as
296+
// there may be new repos that match the search context's include/exclude patterns.
297+
if (env.CONFIG_PATH) {
298+
try {
299+
const config = await loadConfig(env.CONFIG_PATH);
300+
301+
await syncSearchContexts({
302+
db: this.db,
303+
orgId,
304+
contexts: config.contexts,
305+
});
306+
} catch (err) {
307+
this.logger.error(`Failed to sync search contexts for connection ${connectionId}: ${err}`);
308+
Sentry.captureException(err);
309+
}
310+
}
311+
293312

294313
captureEvent('backend_connection_sync_job_completed', {
295314
connectionId: connectionId,

packages/backend/src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ export const DEFAULT_SETTINGS: Settings = {
1616
repoGarbageCollectionGracePeriodMs: 10 * 1000, // 10 seconds
1717
repoIndexTimeoutMs: 1000 * 60 * 60 * 2, // 2 hours
1818
enablePublicAccess: false,
19-
}
19+
}

packages/backend/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import { PrismaClient } from "@sourcebot/db";
1010
import { env } from "./env.js";
1111
import { createLogger } from "@sourcebot/logger";
1212

13-
const logger = createLogger('index');
13+
const logger = createLogger('backend-entrypoint');
14+
1415

1516
// Register handler for normal exit
1617
process.on('exit', (code) => {
@@ -72,3 +73,4 @@ main(prisma, context)
7273
.finally(() => {
7374
logger.info("Shutting down...");
7475
});
76+

packages/backend/src/main.ts

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,16 @@ import { ConnectionManager } from './connectionManager.js';
77
import { RepoManager } from './repoManager.js';
88
import { env } from './env.js';
99
import { PromClient } from './promClient.js';
10-
import { isRemotePath } from './utils.js';
11-
import { readFile } from 'fs/promises';
12-
import stripJsonComments from 'strip-json-comments';
13-
import { SourcebotConfig } from '@sourcebot/schemas/v3/index.type';
14-
import { indexSchema } from '@sourcebot/schemas/v3/index.schema';
15-
import { Ajv } from "ajv";
10+
import { loadConfig } from '@sourcebot/shared';
1611

1712
const logger = createLogger('backend-main');
18-
const ajv = new Ajv({
19-
validateFormats: false,
20-
});
2113

2214
const getSettings = async (configPath?: string) => {
2315
if (!configPath) {
2416
return DEFAULT_SETTINGS;
2517
}
2618

27-
const configContent = await (async () => {
28-
if (isRemotePath(configPath)) {
29-
const response = await fetch(configPath);
30-
if (!response.ok) {
31-
throw new Error(`Failed to fetch config file ${configPath}: ${response.statusText}`);
32-
}
33-
return response.text();
34-
} else {
35-
return readFile(configPath, { encoding: 'utf-8' });
36-
}
37-
})();
38-
39-
const config = JSON.parse(stripJsonComments(configContent)) as SourcebotConfig;
40-
const isValidConfig = ajv.validate(indexSchema, config);
41-
if (!isValidConfig) {
42-
throw new Error(`Config file '${configPath}' is invalid: ${ajv.errorsText(ajv.errors)}`);
43-
}
19+
const config = await loadConfig(configPath);
4420

4521
return {
4622
...DEFAULT_SETTINGS,

0 commit comments

Comments
 (0)