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" ;
import { getPlan , hasEntitlement } from "../entitlements.js" ;
import { SOURCEBOT_SUPPORT_EMAIL } from "../constants.js" ;
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 ,
}
} ) ;
let newReposInContext = allRepos . filter ( repo = > {
return micromatch . isMatch ( repo . name , newContextConfig . include ) ;
} ) ;
if ( newContextConfig . exclude ) {
const exclude = newContextConfig . exclude ;
newReposInContext = newReposInContext . filter ( repo = > {
return ! micromatch . isMatch ( repo . name , exclude ) ;
} ) ;
}
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
}