@@ -4,7 +4,7 @@ import { request } from '@octokit/request'
44import axios , { AxiosRequestConfig , AxiosResponse } from 'axios'
55import lodash from 'lodash'
66import moment from 'moment'
7- import { Transaction } from 'sequelize'
7+ import { QueryTypes , Transaction } from 'sequelize'
88
99import { EDITION , Error400 , Error404 , Error542 , encryptData } from '@crowd/common'
1010import { CommonIntegrationService , getGithubInstallationToken } from '@crowd/common_services'
@@ -1391,6 +1391,38 @@ export default class IntegrationService {
13911391 options ,
13921392 )
13931393
1394+ // Check for repositories already mapped to other integrations
1395+ const seq = SequelizeRepository . getSequelize ( { ...( options || this . options ) , transaction } )
1396+ const urls = remotes . map ( ( r ) => r . url )
1397+
1398+ const existingRows = await seq . query (
1399+ `
1400+ SELECT url, "integrationId" FROM git.repositories
1401+ WHERE url IN (:urls) AND "deletedAt" IS NULL
1402+ ` ,
1403+ {
1404+ replacements : { urls } ,
1405+ type : QueryTypes . SELECT ,
1406+ transaction,
1407+ } ,
1408+ )
1409+
1410+ for ( const row of existingRows as any [ ] ) {
1411+ if ( row . integrationId !== integration . id ) {
1412+ this . options . log . warn (
1413+ `Trying to update git repo ${ row . url } mapping with integrationId ${ integration . id } but it is already mapped to integration ${ row . integrationId } !` ,
1414+ )
1415+
1416+ throw new Error400 (
1417+ ( options || this . options ) . language ,
1418+ 'errors.integrations.repoAlreadyMapped' ,
1419+ row . url ,
1420+ integration . id ,
1421+ row . integrationId ,
1422+ )
1423+ }
1424+ }
1425+
13941426 // upsert repositories to git.repositories in order to be processed by git-integration V2
13951427 const qx = SequelizeRepository . getQueryExecutor ( {
13961428 ...( options || this . options ) ,
@@ -1681,6 +1713,54 @@ export default class IntegrationService {
16811713 host = orgUrl
16821714 }
16831715
1716+ const stripGit = ( url : string ) => {
1717+ if ( url . endsWith ( '.git' ) ) {
1718+ return url . slice ( 0 , - 4 )
1719+ }
1720+ return url
1721+ }
1722+
1723+ // Build full repository URLs from orgURL and repo names
1724+ const remotes = integrationData . remote . repoNames . map ( ( repoName ) => {
1725+ const fullUrl = stripGit ( `${ integrationData . remote . orgURL } /${ repoName } ` )
1726+ return { url : fullUrl , forkedFrom : null }
1727+ } )
1728+
1729+ // Check for conflicts with existing Gerrit integrations
1730+ for ( const remote of remotes ) {
1731+ const existingGerritIntegrations = await this . options . database . sequelize . query (
1732+ `SELECT id, settings FROM integrations
1733+ WHERE platform = 'gerrit' AND "deletedAt" IS NULL` ,
1734+ {
1735+ type : QueryTypes . SELECT ,
1736+ transaction,
1737+ } ,
1738+ )
1739+
1740+ for ( const existingIntegration of existingGerritIntegrations as any [ ] ) {
1741+ const settings = existingIntegration . settings
1742+ if ( settings ?. remote ?. repoNames && settings ?. remote ?. orgURL ) {
1743+ const existingRemotes = settings . remote . repoNames . map ( ( repoName ) =>
1744+ stripGit ( `${ settings . remote . orgURL } /${ repoName } ` ) ,
1745+ )
1746+
1747+ if ( existingRemotes . includes ( remote . url ) ) {
1748+ this . options . log . warn (
1749+ `Trying to map Gerrit repository ${ remote . url } with integrationId ${ integration ?. id || connectionId } but it is already mapped to integration ${ existingIntegration . id } !` ,
1750+ )
1751+
1752+ throw new Error400 (
1753+ this . options . language ,
1754+ 'errors.integrations.repoAlreadyMapped' ,
1755+ remote . url ,
1756+ integration ?. id || connectionId ,
1757+ existingIntegration . id ,
1758+ )
1759+ }
1760+ }
1761+ }
1762+ }
1763+
16841764 const res = await IntegrationService . getGerritServerRepos ( orgUrl )
16851765 if ( integrationData . remote . enableAllRepos ) {
16861766 integrationData . remote . repoNames = res
@@ -1711,13 +1791,6 @@ export default class IntegrationService {
17111791 )
17121792
17131793 if ( integrationData . remote . enableGit ) {
1714- const stripGit = ( url : string ) => {
1715- if ( url . endsWith ( '.git' ) ) {
1716- return url . slice ( 0 , - 4 )
1717- }
1718- return url
1719- }
1720-
17211794 const segmentOptions : IRepositoryOptions = {
17221795 ...this . options ,
17231796 transaction,
@@ -1728,12 +1801,6 @@ export default class IntegrationService {
17281801 ] ,
17291802 }
17301803
1731- // Build full repository URLs from orgURL and repo names
1732- const remotes = integrationData . remote . repoNames . map ( ( repoName ) => {
1733- const fullUrl = stripGit ( `${ integrationData . remote . orgURL } /${ repoName } ` )
1734- return { url : fullUrl , forkedFrom : null }
1735- } )
1736-
17371804 await this . gitConnectOrUpdate (
17381805 {
17391806 remotes,
0 commit comments