2025-04-25 05:28:13 +00:00
import micromatch from "micromatch" ;
2025-06-02 18:16:01 +00:00
import { createLogger } from "@sourcebot/logger" ;
2025-06-17 21:04:25 +00:00
import { PrismaClient } from "@sourcebot/db" ;
2025-10-29 04:31:28 +00:00
import { getPlan , hasEntitlement , SOURCEBOT_SUPPORT_EMAIL } from "@sourcebot/shared" ;
2025-06-17 21:04:25 +00:00
import { SearchContext } from "@sourcebot/schemas/v3/index.type" ;
2025-06-02 18:16:01 +00:00
const logger = createLogger ( 'sync-search-contexts' ) ;
2025-04-25 05:28:13 +00:00
2025-06-17 21:04:25 +00:00
interface SyncSearchContextsParams {
contexts ? : { [ key : string ] : SearchContext } | undefined ;
orgId : number ;
db : PrismaClient ;
}
export const syncSearchContexts = async ( params : SyncSearchContextsParams ) = > {
const { contexts , orgId , db } = params ;
2025-04-25 05:28:13 +00:00
if ( ! hasEntitlement ( "search-contexts" ) ) {
if ( contexts ) {
const plan = getPlan ( ) ;
2025-06-17 21:04:25 +00:00
logger . warn ( ` Skipping search context sync. Reason: "Search contexts are not supported in your current plan: ${ plan } . If you have a valid enterprise license key, pass it via SOURCEBOT_EE_LICENSE_KEY. For support, contact ${ SOURCEBOT_SUPPORT_EMAIL } ." ` ) ;
2025-04-25 05:28:13 +00:00
}
2025-06-17 21:04:25 +00:00
return false ;
2025-04-25 05:28:13 +00:00
}
if ( contexts ) {
for ( const [ key , newContextConfig ] of Object . entries ( contexts ) ) {
2025-06-17 21:04:25 +00:00
const allRepos = await db . repo . findMany ( {
2025-04-25 05:28:13 +00:00
where : {
2025-06-17 21:04:25 +00:00
orgId ,
2025-04-25 05:28:13 +00:00
} ,
select : {
id : true ,
name : true ,
}
} ) ;
2025-07-27 17:11:58 +00:00
let newReposInContext : { id : number , name : string } [ ] = [ ] ;
if ( newContextConfig . include ) {
newReposInContext = allRepos . filter ( repo = > {
return micromatch . isMatch ( repo . name , newContextConfig . include ! ) ;
} ) ;
}
if ( newContextConfig . includeConnections ) {
const connections = await db . connection . findMany ( {
where : {
orgId ,
name : {
in : newContextConfig . includeConnections ,
}
} ,
include : {
repos : {
select : {
repo : {
select : {
id : true ,
name : true ,
}
}
}
}
}
} ) ;
for ( const connection of connections ) {
newReposInContext = newReposInContext . concat ( connection . repos . map ( repo = > repo . repo ) ) ;
}
}
2025-04-25 05:28:13 +00:00
if ( newContextConfig . exclude ) {
const exclude = newContextConfig . exclude ;
newReposInContext = newReposInContext . filter ( repo = > {
return ! micromatch . isMatch ( repo . name , exclude ) ;
} ) ;
}
2025-07-27 17:11:58 +00:00
if ( newContextConfig . excludeConnections ) {
const connections = await db . connection . findMany ( {
where : {
orgId ,
name : {
in : newContextConfig . excludeConnections ,
}
} ,
include : {
repos : {
select : {
repo : {
select : {
id : true ,
name : true ,
}
}
}
}
}
} ) ;
for ( const connection of connections ) {
newReposInContext = newReposInContext . filter ( repo = > {
return ! connection . repos . map ( r = > r . repo . id ) . includes ( repo . id ) ;
} ) ;
}
}
2025-06-17 21:04:25 +00:00
const currentReposInContext = ( await db . searchContext . findUnique ( {
2025-04-25 05:28:13 +00:00
where : {
name_orgId : {
name : key ,
2025-06-17 21:04:25 +00:00
orgId ,
2025-04-25 05:28:13 +00:00
}
} ,
include : {
repos : true ,
}
} ) ) ? . repos ? ? [ ] ;
2025-06-17 21:04:25 +00:00
await db . searchContext . upsert ( {
2025-04-25 05:28:13 +00:00
where : {
name_orgId : {
name : key ,
2025-06-17 21:04:25 +00:00
orgId ,
2025-04-25 05:28:13 +00:00
}
} ,
update : {
repos : {
connect : newReposInContext.map ( repo = > ( {
id : repo.id ,
} ) ) ,
disconnect : currentReposInContext
. filter ( repo = > ! newReposInContext . map ( r = > r . id ) . includes ( repo . id ) )
. map ( repo = > ( {
id : repo.id ,
} ) ) ,
} ,
description : newContextConfig.description ,
} ,
create : {
name : key ,
description : newContextConfig.description ,
org : {
connect : {
2025-06-17 21:04:25 +00:00
id : orgId ,
2025-04-25 05:28:13 +00:00
}
} ,
repos : {
connect : newReposInContext.map ( repo = > ( {
id : repo.id ,
} ) ) ,
}
}
} ) ;
}
}
2025-06-17 21:04:25 +00:00
const deletedContexts = await db . searchContext . findMany ( {
2025-04-25 05:28:13 +00:00
where : {
name : {
notIn : Object.keys ( contexts ? ? { } ) ,
} ,
2025-06-17 21:04:25 +00:00
orgId ,
2025-04-25 05:28:13 +00:00
}
} ) ;
for ( const context of deletedContexts ) {
2025-06-02 18:16:01 +00:00
logger . info ( ` Deleting search context with name ' ${ context . name } '. ID: ${ context . id } ` ) ;
2025-06-17 21:04:25 +00:00
await db . searchContext . delete ( {
2025-04-25 05:28:13 +00:00
where : {
id : context.id ,
}
} )
}
2025-06-17 21:04:25 +00:00
return true ;
2025-04-25 05:28:13 +00:00
}