Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 1 addition & 59 deletions backend/src/services/integrationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
} from '@crowd/common'
import { CommonIntegrationService, getGithubInstallationToken } from '@crowd/common_services'
import { ICreateInsightsProject } from '@crowd/data-access-layer/src/collections'
import { findRepositoriesForSegment } from '@crowd/data-access-layer/src/integrations'
import {
ICreateRepository,
IRepository,
Expand Down Expand Up @@ -193,28 +192,11 @@ export default class IntegrationService {

const { segmentId, id: insightsProjectId } = insightsProject
const { platform } = data
let repositories = []

if (IntegrationService.isCodePlatform(platform)) {
const qx = SequelizeRepository.getQueryExecutor(txOptions)
await CommonIntegrationService.syncGithubRepositoriesToInsights(
qx,
this.options.redis,
integration.id,
)

// Get the updated repositories for git integration
const updatedProject = await collectionService.findInsightsProjectsBySegmentId(segmentId)
repositories = updatedProject[0]?.repositories || []
} else {
repositories = insightsProject.repositories || []
}

await this.updateInsightsProject({
insightsProjectId,
isFirstUpdate: true,
platform,
repositories,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mbani01 just to double check, we don't need to re-update the insightsProject anymore here ? the data is already synced?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No we don't need to re-update repositories, since the enabled is field in public.repositories is by default set to true

segmentId,
transaction,
})
Expand All @@ -241,49 +223,17 @@ export default class IntegrationService {
integration.segmentId,
)

let repositories = []
const { platform } = data

if (insightsProject) {
const { segmentId, id: insightsProjectId } = insightsProject

if (IntegrationService.isCodePlatform(platform)) {
const qx = SequelizeRepository.getQueryExecutor(txOptions)
await CommonIntegrationService.syncGithubRepositoriesToInsights(
qx,
this.options.redis,
integration.id,
)
// Get the updated repositories for git integration
const updatedProject = await collectionService.findInsightsProjectsBySegmentId(segmentId)
repositories = updatedProject[0]?.repositories || []
} else {
repositories = insightsProject.repositories || []
}

await this.updateInsightsProject({
insightsProjectId,
platform,
repositories,
segmentId,
transaction,
})
} else {
const qx = SequelizeRepository.getQueryExecutor(txOptions)
const currentRepositories = await findRepositoriesForSegment(qx, integration.segmentId)
repositories = Object.values(currentRepositories).flatMap((repos) =>
repos.map((repo) => repo.url),
)
}

if (IntegrationService.isCodePlatform(platform) && platform !== PlatformType.GIT) {
await this.gitConnectOrUpdate(
{
remotes: repositories.map((url) => ({ url, forkedFrom: null })),
},
txOptions,
platform,
)
}

return integration
Expand All @@ -301,21 +251,18 @@ export default class IntegrationService {
platform,
segmentId,
transaction,
repositories,
}: {
insightsProjectId: string
isFirstUpdate?: boolean
platform: PlatformType
segmentId: string
transaction: Transaction
repositories: string[]
}) {
const collectionService = new CollectionService({ ...this.options, transaction })

const data: Partial<ICreateInsightsProject> = {}
const { widgets } = await collectionService.findSegmentsWidgetsById(segmentId)
data.widgets = widgets
data.repositories = repositories

if (
(platform === PlatformType.GITHUB || platform === PlatformType.GITHUB_NANGO) &&
Expand Down Expand Up @@ -533,13 +480,8 @@ export default class IntegrationService {
// Note: Repos are soft-deleted in public.repositories via mapUnifiedRepositories above
}

const insightsRepo = insightsProject?.repositories ?? []
const filteredRepos = insightsRepo.filter((repo) => !toRemoveRepo.has(repo))
// remove duplicates
const repositories = [...new Set<string>(filteredRepos)]

if (insightsProject) {
await collectionService.updateInsightsProject(insightsProject.id, { widgets, repositories })
await collectionService.updateInsightsProject(insightsProject.id, { widgets })
}

await SequelizeRepository.commitTransaction(transaction)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,7 @@ export const buildForm = (
keywords: result.keywords || [],
searchKeywords: result.searchKeywords || [],
repositoryGroups: result.repositoryGroups || [],
repositories:
repositories?.map((repository) => ({
...repository,
enabled:
result.repositories?.some((repo: string) => repo === repository.url)
|| false,
})) || [],
repositories: repositories || [],
widgets: Object.fromEntries(
getDefaultWidgets().map((key) => [
key,
Expand All @@ -62,7 +56,7 @@ export const buildForm = (
});

export const buildRepositories = (
res: Record<string, Array<{ url: string; label: string }>>,
res: Record<string, Array<{ url: string; label: string; enabled: boolean }>>,
) => {
const urlMap = new Map<
string,
Expand All @@ -82,12 +76,15 @@ export const buildRepositories = (
// If URL exists, add the platform to its platforms array
const existing = urlMap.get(repo.url)!;
existing.platforms.push(platform);
if (repo.enabled) {
existing.enabled = true;
}
} else {
// If URL is new, create a new entry
urlMap.set(repo.url, {
url: repo.url,
label: repo.label,
enabled: true,
enabled: repo.enabled,
platforms: [platform],
});
}
Expand Down
2 changes: 0 additions & 2 deletions services/apps/nango_worker/src/activities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
removeGithubConnection,
setGithubConnection,
startNangoSync,
syncGithubReposToInsights,
unmapGithubRepo,
updateGitIntegrationWithRepo,
} from './activities/nangoActivities'
Expand All @@ -26,6 +25,5 @@ export {
unmapGithubRepo,
canCreateGithubConnection,
updateGitIntegrationWithRepo,
syncGithubReposToInsights,
logInfo,
}
9 changes: 1 addition & 8 deletions services/apps/nango_worker/src/activities/nangoActivities.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IS_DEV_ENV, IS_STAGING_ENV, singleOrDefault } from '@crowd/common'
import { generateUUIDv4 as uuid } from '@crowd/common'
import { CommonIntegrationService, GithubIntegrationService } from '@crowd/common_services'
import { GithubIntegrationService } from '@crowd/common_services'
import {
addGithubNangoConnection,
addRepoToGitIntegration,
Expand Down Expand Up @@ -501,13 +501,6 @@ function parseGithubUrl(url: string): IGithubRepoData {
throw new Error('Invalid GitHub URL format')
}

export async function syncGithubReposToInsights(integrationId: string): Promise<void> {
svc.log.info({ integrationId }, `Syncing GitHub repositories to insights!`)

const qx = dbStoreQx(svc.postgres.writer)
await CommonIntegrationService.syncGithubRepositoriesToInsights(qx, svc.redis, integrationId)
}

export async function logInfo(message: string, serializedParams?: string): Promise<void> {
svc.log.info(serializedParams ? JSON.parse(serializedParams) : {}, message)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,5 @@ export async function syncGithubIntegration(args: ISyncGithubIntegrationArgument

// start nango sync
await activity.startNangoSync(integrationId, result.providerConfigKey, connectionId)

// sync repositories to segmentRepositories and insightsProjects after processing all repos
await activity.syncGithubReposToInsights(integrationId)
}
}
86 changes: 0 additions & 86 deletions services/libs/common_services/src/services/integration.service.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
import { decryptData } from '@crowd/common'
import {
InsightsProjectField,
queryInsightsProjects,
updateInsightsProject,
} from '@crowd/data-access-layer/src/collections'
import {
fetchIntegrationById,
findNangoRepositoriesToBeRemoved,
findRepositoriesForSegment,
} from '@crowd/data-access-layer/src/integrations'
import { QueryExecutor } from '@crowd/data-access-layer/src/queryExecutor'
import { getRepoUrlsMappedToOtherSegments } from '@crowd/data-access-layer/src/segments'
import { getServiceChildLogger } from '@crowd/logging'
import { RedisClient } from '@crowd/redis'
import { PlatformType } from '@crowd/types'

export class CommonIntegrationService {
Expand Down Expand Up @@ -70,77 +57,4 @@ export class CommonIntegrationService {
return settings
}
}

/**
* Syncs GitHub repositories to insightsProject.repositories field
* @param qx - Query executor for database operations
* @param redis - Redis client for cache invalidation
* @param integrationId - The integration ID to sync repositories for
*/
public static async syncGithubRepositoriesToInsights(
qx: QueryExecutor,
redis: RedisClient,
integrationId: string,
): Promise<void> {
// Fetch integration to get segmentId
const integration = await fetchIntegrationById(qx, integrationId)

if (!integration) {
CommonIntegrationService.log.warn(`Integration ${integrationId} not found`)
return
}

const segmentId = integration.segmentId

// Query insights project for this segment
const insightsProjects = await queryInsightsProjects(qx, {
filter: {
segmentId: { eq: segmentId },
},
fields: [
InsightsProjectField.ID,
InsightsProjectField.SEGMENT_ID,
InsightsProjectField.REPOSITORIES,
],
})

const insightsProject = insightsProjects[0]

if (!insightsProject) {
CommonIntegrationService.log.info(
`The segmentId: ${segmentId} does not have any InsightsProject related`,
)
return
}

const insightsProjectId = insightsProject.id

// Get repositories to be removed
const reposToBeRemoved = await findNangoRepositoriesToBeRemoved(qx, integrationId)

// Get current repositories for segment
const currentRepositories = await findRepositoriesForSegment(qx, segmentId)

const currentUrls = Object.values(currentRepositories).flatMap((repos) =>
repos.map((repo) => repo.url),
)

// Find repos already mapped to other segments (conflicts)
const alreadyMappedRepos = await getRepoUrlsMappedToOtherSegments(qx, currentUrls, segmentId)

// Filter valid repositories (dedupe, remove deleted, remove already mapped to other segments)
const repositories = [...new Set(currentUrls)].filter(
(url) => !reposToBeRemoved.includes(url) && !alreadyMappedRepos.includes(url),
)

// Update insightsProject.repositories field (this also sets updatedAt automatically)
// Note: Writes to public.repositories happen earlier via mapGithubRepoToRepositories()
await updateInsightsProject(qx, insightsProjectId, {
repositories,
})

CommonIntegrationService.log.info(
`Synced ${repositories.length} repositories for integration ${integrationId} to segment ${segmentId}`,
)
}
}
11 changes: 7 additions & 4 deletions services/libs/data-access-layer/src/collections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,22 +299,25 @@ export async function updateInsightsProject(
id: string,
project: Partial<ICreateInsightsProject>,
) {
// Exclude repositories from update; only used to sync public.repositories.enabled
const { repositories, ...projectWithoutRepositories } = project

const updated = await updateTableById(
qx,
'insightsProjects',
id,
Object.values(InsightsProjectField),
prepareProject(project),
prepareProject(projectWithoutRepositories),
)

if (!updated) {
throw new Error(`Update failed or project with id ${id} not found`)
}

// Sync repositories.enabled status when repositories field is updated
// Sync repositories.enabled status when repositories field is provided
// Disables repos not in the new list (new repos are enabled by default on insert)
if (project.repositories !== undefined) {
const enabledUrls = normalizeRepositoriesToUrls(project.repositories)
if (repositories !== undefined) {
const enabledUrls = normalizeRepositoriesToUrls(repositories)
await syncRepositoriesEnabledStatus(qx, id, enabledUrls)
}

Expand Down
15 changes: 8 additions & 7 deletions services/libs/data-access-layer/src/integrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,17 +660,18 @@ export async function findNangoRepositoriesToBeRemoved(
export async function findRepositoriesForSegment(
qx: QueryExecutor,
segmentId: string,
): Promise<Record<string, Array<{ url: string; label: string }>>> {
): Promise<Record<string, Array<{ url: string; label: string; enabled: boolean }>>> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused exported function after refactoring

Low Severity

The normalizeRepoUrl function is exported but no longer used anywhere in the codebase. This PR removed its only usage in findRepositoriesForSegment (which previously called normalizeRepoUrl(url) but now uses repo.url directly), leaving the function as dead code. The function can be safely removed unless it's intended for future use.

Fix in Cursor Fix in Web

// Get all repos grouped by platform (github-nango merged into github)
const reposByPlatform = await getReposBySegmentGroupedByPlatform(qx, segmentId, true)

// Transform to include normalized URLs and labels
const result: Record<string, Array<{ url: string; label: string }>> = {}
// Transform to include URLs, labels, and enabled status
const result: Record<string, Array<{ url: string; label: string; enabled: boolean }>> = {}

for (const [platform, urls] of Object.entries(reposByPlatform)) {
result[platform] = urls.map((url) => ({
url: normalizeRepoUrl(url),
label: extractLabelFromUrl(url),
for (const [platform, repos] of Object.entries(reposByPlatform)) {
result[platform] = repos.map((repo) => ({
url: repo.url,
label: extractLabelFromUrl(repo.url),
enabled: repo.enabled,
}))
}

Expand Down
3 changes: 2 additions & 1 deletion services/libs/data-access-layer/src/repositories/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,8 @@ export async function findSegmentsForRepos(
}

/**
* Syncs repositories.enabled to match insightsProject.repositories list.
* Updates repositories.enabled based on the provided list of enabled URLs.
* Called when user toggles repository enabled status in the UI.
*/
export async function syncRepositoriesEnabledStatus(
qx: QueryExecutor,
Expand Down
Loading