Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Github archive #2691

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open

Github archive #2691

wants to merge 29 commits into from

Conversation

gaspergrom
Copy link
Contributor

@gaspergrom gaspergrom commented Nov 18, 2024

Changes proposed ✍️

What

copilot:summary

copilot:poem

Why

How

copilot:walkthrough

Checklist ✅

  • Label appropriately with Feature, Improvement, or Bug.
  • Add screenshots to the PR description for relevant FE changes
  • New backend functionality has been unit-tested.
  • API documentation has been updated (if necessary) (see docs on API documentation).
  • Quality standards are met.

Summary by CodeRabbit

  • New Features

    • Introduced new API endpoints for searching GitHub organizations and repositories.
    • Added functionality for managing GitHub repository settings through a new modal interface.
    • Implemented a new SnowflakeClient and GithubSnowflakeClient for database interactions.
    • Added environment variables for Snowflake configuration.
    • Introduced new TypeScript interfaces for handling GitHub-related data.
  • Bug Fixes

    • Enhanced error handling and response mechanisms for GitHub integration functionalities.
  • Refactor

    • Restructured GitHub integration logic for improved clarity and maintainability.
    • Updated the configuration for GitHub integration, replacing old components with new structures.
  • Chores

    • Added new dependencies for Snowflake integration and updated configuration files for better management.

@gaspergrom gaspergrom self-assigned this Nov 18, 2024
Copy link

coderabbitai bot commented Nov 18, 2024

Walkthrough

This pull request introduces significant changes to both the backend and frontend components of the application. Key modifications include the addition of Snowflake configuration settings in the backend, new API endpoints for GitHub organization and repository management, and the introduction of new Vue components for GitHub integration in the frontend. Additionally, several existing GitHub-related components have been removed or refactored. The changes also involve the establishment of a new Snowflake client and associated types, enhancing the application's ability to manage integrations with GitHub and Snowflake.

Changes

File Path Change Summary
backend/config/custom-environment-variables.json Added a new "snowflake" section with keys for Snowflake configuration.
backend/package.json Added dependency @crowd/snowflake with version workspace:*.
backend/src/api/integration/helpers/githubOrgRepos.ts Added a new async function to handle GitHub organization repositories.
backend/src/api/integration/helpers/githubSearchOrgs.ts Added a new async function for searching GitHub organizations.
backend/src/api/integration/helpers/githubSearchRepos.ts Added a new async function for searching GitHub repositories.
backend/src/api/integration/index.ts Introduced new GET routes for GitHub organization and repository searches.
backend/src/conf/configTypes.ts Added a new interface SnowflakeConfiguration for Snowflake settings.
backend/src/conf/index.ts Added export for SNOWFLAKE_CONFIG using the SnowflakeConfiguration type.
backend/src/services/githubIntegrationService.ts Introduced the GithubIntegrationService class with methods for GitHub interactions.
frontend/src/config/integrations/github/components/connect/github-connect-finishing-modal.vue Removed the GitHub finishing modal component.
frontend/src/config/integrations/github/components/connect/github-connect-modal.vue Removed the GitHub connection modal component.
frontend/src/config/integrations/github/components/connect/github-connect.vue Removed the main GitHub connect component.
frontend/src/config/integrations/github/components/github-action.vue Removed the GitHub action component.
frontend/src/config/integrations/github/components/github-connect.vue Added a new GitHub connect component.
frontend/src/config/integrations/github/components/github-dropdown.vue Added a new GitHub dropdown component.
frontend/src/config/integrations/github/components/github-status.vue Removed the GitHub status component.
frontend/src/config/integrations/github/components/settings/github-settings-add-repository-modal.vue Added a modal for adding GitHub repositories.
frontend/src/config/integrations/github/components/settings/github-settings-drawer.vue Refactored the settings drawer component for GitHub integrations.
frontend/src/config/integrations/github/components/settings/github-settings-empty.vue Added a new empty state component for GitHub settings.
frontend/src/config/integrations/github/components/settings/github-settings-mapping.vue Added a component for managing GitHub repository settings.
frontend/src/config/integrations/github/components/settings/github-settings-org-item.vue Added a component for managing GitHub organization settings.
frontend/src/config/integrations/github/components/settings/github-settings-repo-item.vue Added a component for managing GitHub repository settings.
frontend/src/config/integrations/github/components/settings/github-settings-repositories-bulk-select.vue Refactored bulk select component for GitHub settings.
frontend/src/config/integrations/github/config.ts Updated GitHub integration configuration to include a dropdown component.
frontend/src/config/integrations/github/services/github.api.service.ts Introduced the GithubApiService class for interacting with GitHub's API.
frontend/src/config/integrations/github/types/GithubSettings.ts Added several new TypeScript interfaces for GitHub settings.
frontend/src/modules/admin/modules/integration/types/Integration.ts Added a new generic Integration interface.
frontend/src/modules/integration/integration-service.js Updated methods in IntegrationService to handle data more flexibly.
frontend/src/ui-kit/drawer/Drawer.vue Introduced a new drawer component for UI.
services/libs/snowflake/package.json Created a new package for the @crowd/snowflake library with necessary scripts and dependencies.
services/libs/snowflake/src/client.ts Added SnowflakeClient class for connecting to Snowflake.
services/libs/snowflake/src/github.ts Introduced GithubSnowflakeClient class for GitHub events management.
services/libs/snowflake/src/types.ts Added multiple new interfaces for handling responses related to GitHub activities.

Possibly related PRs

  • Remove some logs and handle rate limits for groupsio #2666: This PR focuses on enhancing error handling and logging for GitHub webhook events, which may relate to the overall integration and configuration changes involving Snowflake, as both involve managing external integrations and their configurations. However, it does not directly modify the same files or functionalities as the main PR.

🐰 In the code we hop and play,
New features bloom, bright as day.
Snowflake's here, GitHub too,
Integration magic, all brand new!
With every change, we leap and cheer,
A brighter future, oh so near! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

🛑 Comments failed to post (80)
backend/src/services/githubIntegrationService.ts (5)

14-14: ⚠️ Potential issue

Correct the perPage parameter to comply with GitHub API limits

The perPage parameter is set to 10000, but the GitHub API's maximum allowed per_page value is 100. Setting it to a value higher than 100 will not fetch more results in a single request. To retrieve all repositories, you need to implement pagination.

Here's a suggested modification to handle pagination:

public async getGithubRepositories(org: string) {
  const client = SnowflakeClient.fromEnv()
  this.options.log.info(`Getting GitHub repositories for org: ${org}`)
  const githubClient = new GithubSnowflakeClient(client)

  let allRepos = []
  let page = 1
  const perPage = 100
  let repos = []

  do {
    repos = await githubClient.getOrgRepositories({ org, perPage, page })
    allRepos = allRepos.concat(repos)
    page++
  } while (repos.length === perPage)

  return allRepos
}

This modification retrieves repositories in batches of 100 until all repositories are fetched.


25-28: ⚠️ Potential issue

Add error handling for the second API request

The second request in Promise.all lacks error handling. If it fails, it will cause the promise to reject, potentially crashing the application. To enhance robustness, add error handling similar to the first request.

Here's how you can add error handling:

const [orgRepos, repos] = await Promise.all([
  request('GET /search/repositories', {
    q: `owner:${query}`,
  }).catch((err) => {
    console.error(`Error getting GitHub repositories for owner: ${query}`, err)
    return { data: { items: [] } }
  }),
  request('GET /search/repositories', {
    q: query,
  }).catch((err) => {
    console.error(`Error searching repositories with query: ${query}`, err)
    return { data: { items: [] } }
  }),
])

43-52: ⚠️ Potential issue

Add error handling for GitHub API request

The findOrgs method does not handle potential errors from the GitHub API. If the request fails, it could lead to unhandled exceptions.

Consider adding a try-catch block:

public static async findOrgs(query: string) {
  let response
  try {
    response = await request('GET /search/users', {
      q: query,
    })
  } catch (err) {
    console.error(`Error searching GitHub organizations with query: ${query}`, err)
    return []
  }
  return response.data.items.map((item) => ({
    name: item.login,
    url: item.html_url,
    logo: item.avatar_url,
  }))
}

54-62: ⚠️ Potential issue

Implement error handling for fetching organization repositories

Similar to findOrgs, the getOrgRepos method lacks error handling. An API failure could result in an unhandled exception.

Add error handling as follows:

public static async getOrgRepos(org: string) {
  let response
  try {
    response = await request('GET /orgs/{org}/repos', {
      org,
    })
  } catch (err) {
    console.error(`Error fetching repositories for org: ${org}`, err)
    return []
  }
  return response.data.map((repo) => ({
    name: repo.name,
    url: repo.html_url,
  }))
}

22-22: ⚠️ Potential issue

Fix usage of this in static method

In the static method findGithubRepos, this.options is referenced, but this is not accessible in a static context. This will cause a runtime error.

You can fix this by removing the dependency on this:

-       this.options.log.error(`Error getting GitHub repositories for org: ${query}`, err)
+       console.error(`Error getting GitHub repositories for org: ${query}`, err)

Alternatively, consider making findGithubRepos an instance method if access to instance properties is required.

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Biome

[error] 22-22: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

services/libs/snowflake/src/client.ts (2)

76-87: 🛠️ Refactor suggestion

Simplify the run method by removing unnecessary Promise wrapping

The run method currently wraps the asynchronous operation in a new Promise, which is unnecessary since this.pool.use returns a Promise. Simplifying the code enhances readability and reduces complexity.

Here is the suggested refactor:

- public async run<T>(query: string, binds?: any[]): Promise<T[]> {
-   return new Promise((resolve, reject) => {
-     this.pool.use(async (connection) => {
-       try {
-         const results = await this.executeQuery(connection, query, binds)
-         resolve(results)
-       } catch (err) {
-         reject(err)
-       }
-     })
-   })
- }
+ public async run<T>(query: string, binds?: any[]): Promise<T[]> {
+   return this.pool.use(async (connection) => {
+     return this.executeQuery<T>(connection, query, binds)
+   })
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  public async run<T>(query: string, binds?: any[]): Promise<T[]> {
    return this.pool.use(async (connection) => {
      return this.executeQuery<T>(connection, query, binds)
    })
  }

89-100: ⚠️ Potential issue

Validate environment variables in fromEnv method to prevent runtime errors

Currently, missing environment variables could lead to undefined behavior or runtime exceptions. It's essential to validate the presence of required environment variables and provide meaningful error messages.

Here's a suggested approach:

  public static fromEnv(extraConfig: any = {}) {
+   const {
+     CROWD_SNOWFLAKE_PRIVATE_KEY,
+     CROWD_SNOWFLAKE_ACCOUNT,
+     CROWD_SNOWFLAKE_USERNAME,
+     CROWD_SNOWFLAKE_DATABASE,
+     CROWD_SNOWFLAKE_WAREHOUSE,
+     CROWD_SNOWFLAKE_ROLE,
+   } = process.env
+
+   if (
+     !CROWD_SNOWFLAKE_PRIVATE_KEY ||
+     !CROWD_SNOWFLAKE_ACCOUNT ||
+     !CROWD_SNOWFLAKE_USERNAME ||
+     !CROWD_SNOWFLAKE_DATABASE ||
+     !CROWD_SNOWFLAKE_WAREHOUSE
+   ) {
+     throw new Error('Missing required Snowflake environment variables.')
+   }
+
    return new SnowflakeClient({
-     privateKeyString: process.env.CROWD_SNOWFLAKE_PRIVATE_KEY,
-     account: process.env.CROWD_SNOWFLAKE_ACCOUNT,
-     username: process.env.CROWD_SNOWFLAKE_USERNAME,
-     database: process.env.CROWD_SNOWFLAKE_DATABASE,
-     warehouse: process.env.CROWD_SNOWFLAKE_WAREHOUSE,
-     role: process.env.CROWD_SNOWFLAKE_ROLE,
+     privateKeyString: CROWD_SNOWFLAKE_PRIVATE_KEY,
+     account: CROWD_SNOWFLAKE_ACCOUNT,
+     username: CROWD_SNOWFLAKE_USERNAME,
+     database: CROWD_SNOWFLAKE_DATABASE,
+     warehouse: CROWD_SNOWFLAKE_WAREHOUSE,
+     role: CROWD_SNOWFLAKE_ROLE,
      maxConnections: 1,
      ...extraConfig,
    })
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  public static fromEnv(extraConfig: any = {}) {
    const {
      CROWD_SNOWFLAKE_PRIVATE_KEY,
      CROWD_SNOWFLAKE_ACCOUNT,
      CROWD_SNOWFLAKE_USERNAME,
      CROWD_SNOWFLAKE_DATABASE,
      CROWD_SNOWFLAKE_WAREHOUSE,
      CROWD_SNOWFLAKE_ROLE,
    } = process.env

    if (
      !CROWD_SNOWFLAKE_PRIVATE_KEY ||
      !CROWD_SNOWFLAKE_ACCOUNT ||
      !CROWD_SNOWFLAKE_USERNAME ||
      !CROWD_SNOWFLAKE_DATABASE ||
      !CROWD_SNOWFLAKE_WAREHOUSE
    ) {
      throw new Error('Missing required Snowflake environment variables.')
    }

    return new SnowflakeClient({
      privateKeyString: CROWD_SNOWFLAKE_PRIVATE_KEY,
      account: CROWD_SNOWFLAKE_ACCOUNT,
      username: CROWD_SNOWFLAKE_USERNAME,
      database: CROWD_SNOWFLAKE_DATABASE,
      warehouse: CROWD_SNOWFLAKE_WAREHOUSE,
      role: CROWD_SNOWFLAKE_ROLE,
      maxConnections: 1,
      ...extraConfig,
    })
  }
services/libs/integrations/src/integrations/github-old/generateStreams.ts (1)

76-81: ⚠️ Potential issue

Handle undefined repository to prevent runtime errors

The repo variable may be undefined if a repository with the given repoUrl is not found in manualSettings.repos. Accessing repo.name without checking can lead to a runtime error. Add a check to handle the case when repo is undefined.

Apply this diff to add the necessary check:

 const repo = manualSettings.repos.find((r) => r.url === repoUrl)
+if (!repo) {
+  ctx.abortRunWithError(`Repository not found for URL: ${repoUrl}`)
+}
 await ctx.publishStream<GithubBasicStream>(
   `${endpoint}:${repo.name}:firstPage`,
   {
     repo,
     page: '',
   },
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

          const repo = manualSettings.repos.find((r) => r.url === repoUrl)
          if (!repo) {
            ctx.abortRunWithError(`Repository not found for URL: ${repoUrl}`)
          }
          await ctx.publishStream<GithubBasicStream>(`${endpoint}:${repo.name}:firstPage`, {
            repo,
            page: '',
          })
        }
frontend/src/config/integrations/github/components/settings/github-settings-drawer.vue (4)

120-124: ⚠️ Potential issue

Add error handling in fetchSubProjects function

The fetchSubProjects function lacks error handling, which means that if LfService.findSegment fails, the error will go unhandled. This could lead to unexpected behavior or application crashes.

Apply this diff to handle potential errors:

const fetchSubProjects = () => {
  LfService.findSegment(route.params.grandparentId)
    .then((segment) => {
      subprojects.value = segment.projects.map((p) => p.subprojects).flat();
    })
+   .catch((error) => {
+     console.error('Failed to fetch subprojects:', error);
+     Message.error('Unable to fetch subprojects. Please try again later.');
+   });
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const fetchSubProjects = () => {
  LfService.findSegment(route.params.grandparentId)
    .then((segment) => {
      subprojects.value = segment.projects.map((p) => p.subprojects).flat();
    })
    .catch((error) => {
      console.error('Failed to fetch subprojects:', error);
      Message.error('Unable to fetch subprojects. Please try again later.');
    });

193-212: ⚠️ Potential issue

Handle potential undefined values in watch callback

In the watch callback for props.integration, accessing value.settings.orgs without null checking could result in a runtime error if settings or orgs are undefined.

Apply this diff to add null checks:

watch(() => props.integration, (value?: Integration<GitHubSettings>) => {
  if (value) {
-   const { orgs } = value.settings;
+   const orgs = value.settings?.orgs || [];
    organizations.value = orgs
      .filter((o) => o.fullSync)
      .map((o) => ({
        name: o.name,
        logo: o.logo,
        url: o.url,
        updatedAt: o.updatedAt,
      }));
    repositories.value = orgs.reduce((acc: GitHubSettingsRepository[], o) => [...acc, ...o.repos.map((r) => ({
      ...r,
      org: {
        name: o.name,
        logo: o.logo,
        url: o.url,
        updatedAt: o.updatedAt,
      },
    }))], []);
  }
}, { immediate: true });

This prevents potential runtime errors if settings or orgs are undefined.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  if (value) {
    const orgs = value.settings?.orgs || [];
    organizations.value = orgs
      .filter((o) => o.fullSync)
      .map((o) => ({
        name: o.name,
        logo: o.logo,
        url: o.url,
        updatedAt: o.updatedAt,
      }));
    repositories.value = orgs.reduce((acc: GitHubSettingsRepository[], o) => [...acc, ...o.repos.map((r) => ({
      ...r,
      org: {
        name: o.name,
        logo: o.logo,
        url: o.url,
        updatedAt: o.updatedAt,
      },
    }))], []);
  }

155-163: ⚠️ Potential issue

Ensure proper promise chaining in connect method

In the connect function, the promise returned by IntegrationService.githubMapRepos is not being chained correctly. As a result, subsequent operations may execute before githubMapRepos completes, potentially causing race conditions or unexpected behavior.

Apply this diff to fix the promise chain:

const connect = () => {
  let integration: any = null;
  const settings: GitHubSettings = buildSettings();
  (props.integration?.id
    ? IntegrationService.update(props.integration.id, { settings })
    : IntegrationService.create({ settings, platform: 'github', status: 'in-progress' }))
    .then((res) => {
      integration = res;
-     IntegrationService.githubMapRepos(res.id, repoMappings.value, [res.segmentId]);
+     return IntegrationService.githubMapRepos(res.id, repoMappings.value, [res.segmentId]);
    })
    .then(() => {
      doFetch([integration.segmentId]);
      // Rest of the code
    })
    .catch(() => {
      // Error handling
    });
};

This ensures that doFetch is called only after githubMapRepos has successfully completed.

Committable suggestion skipped: line range outside the PR's diff.


168-173: 💡 Codebase verification

Based on the gathered information, I can now provide the final response:

Property name inconsistency in event tracking

The event tracking in github-settings-drawer.vue uses integration: Platform.GITHUB while all other integration components consistently use platform as the property name. This inconsistency should be fixed to maintain uniform analytics data.

  • Change integration: Platform.GITHUB to platform: Platform.GITHUB in frontend/src/config/integrations/github/components/settings/github-settings-drawer.vue
🔗 Analysis chain

Ensure correct event tracking properties

In the trackEvent call, verify that all required properties are correctly set and that the event conforms to the analytics schema.

Run the following script to check for required properties in event tracking:

This ensures that analytics events are properly recorded.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the 'CONNECT_INTEGRATION' event has all necessary properties.

# Expected properties: key, type, properties.integration

# Search for 'trackEvent' invocations with 'CONNECT_INTEGRATION' key
rg "trackEvent\(\s*{\s*key:\s*FeatureEventKey\.CONNECT_INTEGRATION"

# Check if 'integration' property is set to 'github'
# The output should show 'integration: Platform.GITHUB'

Length of output: 230


Script:

#!/bin/bash
# Let's try a simpler search pattern first to find event tracking usage
rg -A 5 "FeatureEventKey.CONNECT_INTEGRATION"

# Also search for the event key definition
rg "CONNECT_INTEGRATION.*=.*"

# Check analytics schema or type definitions
fd "analytics|event" --type f

Length of output: 10317


Script:

#!/bin/bash
# Let's check the event type definitions and schema
cat frontend/src/shared/modules/monitoring/types/event.ts

# Also check if there's any standardization of property names across integrations
rg -B2 -A2 "properties:\s*{.*platform:" 
rg -B2 -A2 "properties:\s*{.*integration:"

Length of output: 6486

services/libs/integrations/src/integrations/github/processStream.ts (1)

291-294: ⚠️ Potential issue

Potential mismatch in function call in processPullCommitsStream.

The processPullCommitsStream function calls gh.getRepoPushes, which retrieves repository pushes. However, the function aims to process pull request commits. Consider using gh.getPullRequestCommits to fetch commits associated with pull requests.

Apply this diff to correct the function call:

-const result = await gh.getRepoPushes({
+const result = await gh.getPullRequestCommits({
   repo: data.repo.url,
   page: data.page,
 })

Committable suggestion skipped: line range outside the PR's diff.

frontend/src/config/integrations/github/components/settings/github-settings-add-repository-modal.vue (2)

101-101: ⚠️ Potential issue

Correct v-for syntax: Use in instead of of

Replace org of resultOrganizations with org in resultOrganizations in the v-for directive.

Apply this diff:

-<article v-for="org of resultOrganizations" :key="org.url" class="flex justify-between items-center">
+<article v-for="org in resultOrganizations" :key="org.url" class="flex justify-between items-center">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

              <article v-for="org in resultOrganizations" :key="org.url" class="flex justify-between items-center">

205-214: ⚠️ Potential issue

Add error handling for API call in addOrganizations function

The API call to getOrganizationRepositories may fail, leading to unhandled errors. Consider adding error handling to manage failed API requests.

Apply this diff to add error handling:

const addOrganizations = (org: GitHubOrganization) => {
  organizations.value.push({ ...org, updatedAt: dayjs().toISOString() });
  GithubApiService.getOrganizationRepositories(org.name)
    .then((res) => {
      const newRepositories = (res as GitHubSettingsRepository[])
        .filter((r: GitHubSettingsRepository) => !repositories.value.some((repo: GitHubSettingsRepository) => repo.url === r.url))
        .map((r: GitHubSettingsRepository) => ({ ...r, org, updatedAt: dayjs().toISOString() }));
      repositories.value = [...repositories.value, ...newRepositories];
    })
+   .catch(() => {
+     Message.error('Failed to fetch organization repositories.');
+   });
};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const addOrganizations = (org: GitHubOrganization) => {
  organizations.value.push({ ...org, updatedAt: dayjs().toISOString() });
  GithubApiService.getOrganizationRepositories(org.name)
    .then((res) => {
      const newRepositories = (res as GitHubSettingsRepository[])
        .filter((r: GitHubSettingsRepository) => !repositories.value.some((repo: GitHubSettingsRepository) => repo.url === r.url))
        .map((r: GitHubSettingsRepository) => ({ ...r, org, updatedAt: dayjs().toISOString() }));
      repositories.value = [...repositories.value, ...newRepositories];
    })
    .catch(() => {
      Message.error('Failed to fetch organization repositories.');
    });
};
services/libs/snowflake/src/github.ts (3)

28-29: ⚠️ Potential issue

Possible Typo in SQL Query Table Alias

In the getOrgRepositories method, the FROM clause in your SQL query seems to have a typo or redundant alias:

FROM github_events_ingest.cybersyn.github_repos _ingest.cybersyn.github_repos

The alias _ingest.cybersyn.github_repos appears incorrect. It might be intended as either:

FROM github_events_ingest.cybersyn.github_repos

or

FROM github_events_ingest.cybersyn.github_repos AS some_alias

Please verify and correct the table alias to ensure the query executes properly.


70-70: 🛠️ Refactor suggestion

Potential SQL Injection Risk with Dynamic Query Fragments

In your SQL queries, you're conditionally appending the date filter using template literals:

${since_days_ago ? 'AND CREATED_AT_TIMESTAMP >= DATEADD(day, -?, CURRENT_TIMESTAMP())' : ''}

While the parameter value since_days_ago is safely passed as a query parameter, constructing SQL queries using template literals can introduce risks if not carefully managed.

Consider refactoring to avoid template literals for SQL fragments. One approach is to build the query string and parameters separately:

let dateFilter = '';
const params = [repo];

if (since_days_ago) {
  dateFilter = 'AND CREATED_AT_TIMESTAMP >= DATEADD(day, -?, CURRENT_TIMESTAMP())';
  params.push(since_days_ago);
}

const result = await this.client.run<IGetResponseType>(
  `SELECT ...
   FROM github_events_ingest.cybersyn.github_repos
   WHERE repo_name = ?
   AND type = 'EventType'
   ${dateFilter}
   ORDER BY CREATED_AT_TIMESTAMP DESC
   LIMIT ?
   OFFSET ?`,
  [...params, perPage, (page - 1) * perPage],
);

This approach enhances readability and reduces the risk of SQL injection vulnerabilities.

Also applies to: 114-114, 159-159, 204-204, 249-249, 292-292, 336-336, 380-380


354-395: 🛠️ Refactor suggestion

Ensure Correct Pagination Logic in Return Statements

In the getRepoIssueComments method, verify that the hasNextPage calculation accurately reflects the availability of additional pages:

hasNextPage: result.length === perPage,

If the total number of records is a multiple of perPage, hasNextPage might incorrectly return true even when there are no more records.

Consider fetching one extra record to determine if there is a next page:

LIMIT ? + 1

And then adjust the hasNextPage logic accordingly:

const hasNextPage = result.length > perPage;
if (hasNextPage) {
  result.pop(); // Remove the extra record used for checking
}

This approach ensures hasNextPage accurately indicates the presence of additional data.

services/libs/integrations/src/integrations/github/processData.ts (5)

197-210: ⚠️ Potential issue

Ensure 'member.organizations' is defined in 'IMemberData'

When assigning to member.organizations, verify that the IMemberData interface includes the organizations property. This prevents potential TypeScript errors due to missing interface definitions.

Consider verifying the interface:

#!/bin/bash
# Description: Check if 'organizations' is defined in 'IMemberData' interface

# Search for the 'IMemberData' interface and look for 'organizations' property
rg -A 10 'interface IMemberData' --glob '**/*.ts' | rg 'organizations'

If the property is missing, update the IMemberData interface accordingly.


348-348: ⚠️ Potential issue

Add null checks for 'data.payload.forkee.node_id'

In the parseFork function, ensure that data.payload.forkee and data.payload.forkee.node_id are defined before accessing them. Accessing undefined properties can lead to runtime errors.

Apply this diff to add null checks:

 const activity: IActivityData = {
   type: GithubActivityType.FORK,
-  sourceId: data.payload.forkee.node_id,
+  sourceId: data.payload.forkee?.node_id || '',
   sourceParentId: '',
   timestamp: new Date(data.timestamp).toISOString(),
   channel: apiData.repo.url,
   member,
   score: GITHUB_GRID.fork.score,
   isContribution: GITHUB_GRID.fork.isContribution,
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    sourceId: data.payload.forkee?.node_id || '',

449-450: ⚠️ Potential issue

Handle potential undefined properties in 'sourceId'

In the parsePullRequestClosed function, sourceId concatenates several properties, including data.payload.pull_request.node_id and memberData.memberFromApi.login. Ensure these properties are defined to avoid runtime errors.

Consider updating the code:

 sourceId: `gen-CE_${data.payload.pull_request?.node_id || ''}_${memberData.memberFromApi?.login || 'unknown'}_${new Date(
   data.timestamp,
 ).toISOString()}`,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    sourceId: `gen-CE_${data.payload.pull_request?.node_id || ''}_${memberData.memberFromApi?.login || 'unknown'}_${new Date(
      data.timestamp,

416-416: ⚠️ Potential issue

Ensure 'data.payload.pull_request.node_id' is defined

In the parsePullRequestOpened function, sourceId uses data.payload.pull_request.node_id. Verify that data.payload.pull_request and data.payload.pull_request.node_id are defined to prevent potential runtime errors.

Consider adding null checks:

 const activity: IActivityData = {
   type: GithubActivityType.PULL_REQUEST_OPENED,
-  sourceId: data.payload.pull_request.node_id,
+  sourceId: data.payload.pull_request?.node_id || '',
   sourceParentId: '',
   timestamp: new Date(data.timestamp).toISOString(),
   body: data.payload.pull_request.body,
   url: data.payload.pull_request._links.html.href,
   channel: apiData.repo.url,
   title: data.payload.pull_request.title,
   attributes: {
     state: data.payload.pull_request.state.toLowerCase(),
     // ...
   },
   member,
   score: GITHUB_GRID[GithubActivityType.PULL_REQUEST_OPENED].score,
   isContribution: GITHUB_GRID[GithubActivityType.PULL_REQUEST_OPENED].isContribution,
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    sourceId: data.payload.pull_request?.node_id || '',

654-670: 🛠️ Refactor suggestion

⚠️ Potential issue

Validate commit data before processing

In the parseAuthoredCommit function, ensure that data.payload.commits is an array and that each commit has the required properties. This prevents runtime errors when processing commits.

Apply this diff to add validation:

+if (Array.isArray(data.payload.commits)) {
   for (const commit of data.payload.commits) {
+    if (commit && commit.sha && commit.message) {
       const activity: IActivityData = {
         channel: apiData.repo.url,
         url: `${apiData.repo.url}/commit/${commit.sha}`,
         body: commit.message,
         type: 'authored-commit',
         sourceId: commit.sha,
         sourceParentId: '',
         timestamp: new Date(data.timestamp).toISOString(),
         attributes: {
-          insertions: 'additions' in data.commit ? data.commit.additions : 0,
-          deletions: 'deletions' in data.commit ? data.commit.deletions : 0,
-          lines:
-            'additions' in data.commit && 'deletions' in data.commit
-              ? data.commit.additions - data.commit.deletions
-              : 0,
+          insertions: 'additions' in data.commit ? data.commit.additions : 0,
+          deletions: 'deletions' in data.commit ? data.commit.deletions : 0,
+          lines: ('additions' in data.commit && 'deletions' in data.commit)
+            ? data.commit.additions - data.commit.deletions
+            : 0,
           isMerge: data.commit.parents.totalCount > 1,
         },
         member,
         score: GITHUB_GRID[GithubActivityType.AUTHORED_COMMIT].score,
         isContribution: GITHUB_GRID[GithubActivityType.AUTHORED_COMMIT].isContribution,
       }
       await ctx.publishActivity(activity)
+    }
   }
+} else {
+  // Handle the case where commits are not an array
+  await ctx.abortWithError('Expected commits to be an array')
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  if (Array.isArray(data.payload.commits)) {
    for (const commit of data.payload.commits) {
      if (commit && commit.sha && commit.message) {
        const activity: IActivityData = {
          channel: apiData.repo.url,
          url: `${apiData.repo.url}/commit/${commit.sha}`,
          body: commit.message,
          type: 'authored-commit',
          sourceId: commit.sha,
          sourceParentId: '',
          timestamp: new Date(data.timestamp).toISOString(),
          attributes: {
            insertions: 'additions' in data.commit ? data.commit.additions : 0,
            deletions: 'deletions' in data.commit ? data.commit.deletions : 0,
            lines: ('additions' in data.commit && 'deletions' in data.commit)
              ? data.commit.additions - data.commit.deletions
              : 0,
            isMerge: data.commit.parents.totalCount > 1,
          },
          member,
          score: GITHUB_GRID[GithubActivityType.AUTHORED_COMMIT].score,
          isContribution: GITHUB_GRID[GithubActivityType.AUTHORED_COMMIT].isContribution,
        }
        await ctx.publishActivity(activity)
      }
    }
  } else {
    // Handle the case where commits are not an array
    await ctx.abortWithError('Expected commits to be an array')
  }
services/libs/snowflake/src/types.ts (4)

226-233: 🛠️ Refactor suggestion

Define a Specific Interface for Pull Request Review Payload

The payload in IGetRepoPullRequestReviewsResult is currently typed as Record<string, unknown>, which lacks detail. Define a specific interface to represent the payload structure for better type checking.

Create an interface for the payload:

export interface IPullRequestReviewPayload {
  action: string;
  review: {
    id: number;
    body: string;
    state: string;
    // additional relevant properties
  };
  pull_request: {
    number: number;
    // additional relevant properties
  };
}

Update the payload type:

 export interface IGetRepoPullRequestReviewsResult extends IBasicResponse {
   sfId: number
   state: string
   pullRequestNumber: number
   timestamp: string
-  payload: Record<string, unknown>
+  payload: IPullRequestReviewPayload
 }

234-726: 🛠️ Refactor suggestion

Consider Simplifying Deeply Nested Structures

The interfaces for pull request review comments (IGetRepoPullRequestReviewCommentsResult) contain deeply nested objects with many properties. This can make maintenance challenging. Assess which fields are essential and simplify the interfaces accordingly.

Identify essential fields and adjust the interfaces to include only those fields. For example:

export interface IPullRequestReviewCommentPayload {
  action: string;
  comment: {
    id: number;
    body: string;
    user: {
      login: string;
      id: number;
      avatar_url: string;
    };
    created_at: string;
    updated_at: string;
    // additional essential properties
  };
  pull_request: {
    number: number;
    title: string;
    // additional essential properties
  };
}

export interface IGetRepoPullRequestReviewCommentsResult extends IBasicResponse {
  sfId: number
  action: string
  pullRequestNumber: number
  timestamp: string
  payload: IPullRequestReviewCommentPayload
}

This refactoring enhances readability and focuses on the most relevant data.


822-1034: 🛠️ Refactor suggestion

Simplify the Issue Comment Interfaces

The IGetRepoIssueCommentsResult interface contains extensive nested structures. Consider narrowing down to essential fields to reduce complexity.

Modify the interfaces to focus on key properties:

export interface IIssueCommentPayload {
  action: string;
  comment: {
    id: number;
    body: string;
    user: {
      login: string;
      id: number;
      avatar_url: string;
    };
    created_at: string;
    updated_at: string;
    // additional essential properties
  };
  issue: {
    number: number;
    title: string;
    // additional essential properties
  };
}

export interface IGetRepoIssueCommentsResult extends IBasicResponse {
  sfId: number
  action: string
  issueNumber: number
  timestamp: string
  payload: IIssueCommentPayload
}

This refactoring will make the code easier to work with and maintain.


29-138: 🛠️ Refactor suggestion

Simplify and Reduce the Payload Size in IGetRepoForksResult

The payload.forkee object contains an extensive list of properties, many of which may not be necessary. Consider selecting only the relevant fields to include in the interface to improve performance and maintainability.

Apply this diff to streamline the forkee structure:

 export interface IGetRepoForksResult extends IBasicResponse {
   sfId: number
   fork: string
   forkId: number
   timestamp: string
   payload: {
     forkee: {
-      // Extensive list of properties
+      id: number
+      name: string
+      full_name: string
+      owner: {
+        login: string
+        id: number
+        avatar_url: string
+      }
+      html_url: string
+      description: string | null
+      created_at: string
+      updated_at: string
+      pushed_at: string
+      stargazers_count: number
+      watchers_count: number
+      forks_count: number
+      language: string | null
+      default_branch: string
     }
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

export interface IGetRepoForksResult extends IBasicResponse {
  sfId: number
  fork: string
  forkId: number
  timestamp: string
  payload: {
    forkee: {
      id: number
      name: string
      full_name: string
      owner: {
        login: string
        id: number
        avatar_url: string
      }
      html_url: string
      description: string | null
      created_at: string
      updated_at: string
      pushed_at: string
      stargazers_count: number
      watchers_count: number
      forks_count: number
      language: string | null
      default_branch: string
    }
  }
}
services/libs/integrations/src/integrations/github-old/processStream.ts (4)

93-109: ⚠️ Potential issue

Ensure Token Rotator Initialization

If personal access tokens are not configured, getTokenRotator returns undefined, which may cause issues in functions that expect a valid token rotator.

Consider handling the absence of personal access tokens by throwing an error or providing a fallback mechanism to prevent unexpected behavior.


905-926: 🛠️ Refactor suggestion

Handle Specific Errors When Fetching Pull Request Commits

Catching all errors broadly may mask underlying issues. It's better to catch specific errors and handle them appropriately.

Adjust the error handling to catch specific exceptions related to the GitHub API limitations.

try {
  // Existing code
} catch (err) {
  if (isGraphQLError(err) && isAdditionLimitError(err)) {
    // Handle the specific error
  } else {
    // Re-throw unexpected errors
    throw err
  }
}

Replace isGraphQLError and isAdditionLimitError with appropriate checks for your context.


54-54: 🛠️ Refactor suggestion

Use Regular Expression Literal Instead of RegExp Constructor

Using a regular expression literal is more concise and avoids unnecessary escaping, improving readability and performance.

Apply this diff to replace the RegExp constructor with a regular expression literal:

-  const hrefRegex = new RegExp('href\\s*=\\s*["\'][^"\']*["\']', 'i')
+  const hrefRegex = /href\s*=\s*["'][^"']*["']/i
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  const hrefRegex = /href\s*=\s*["'][^"']*["']/i
🧰 Tools
🪛 Biome

[error] 54-54: Use a regular expression literal instead of the RegExp constructor.

Regular expression literals avoid some escaping required in a string literal, and are easier to analyze statically.
Safe fix: Use a literal notation instead.

(lint/complexity/useRegexLiterals)


86-86: ⚠️ Potential issue

Inconsistency Between Comment and Code for Concurrent Requests Limit

The comment indicates a maximum of 2 concurrent requests, but the code sets the limit to 50. This discrepancy could lead to unintended performance issues.

Please verify the intended maximum number of concurrent requests and update either the code or the comment accordingly.

If the limit should be 2:

-      50, // max 2 concurrent requests
+      2,  // max 2 concurrent requests

If the limit should be 50, update the comment:

-      50, // max 2 concurrent requests
+      50, // max 50 concurrent requests

Committable suggestion skipped: line range outside the PR's diff.

services/libs/integrations/src/integrations/github-old/processData.ts (4)

95-236: 🛠️ Refactor suggestion

Refactor parseMember Function for Improved Readability and Maintainability

The parseMember function is quite lengthy and handles multiple responsibilities, including parsing regular members, bots, and deleted users. Consider refactoring it to separate these concerns into smaller, more focused functions. This will enhance readability and make the code easier to maintain and test.

Apply this diff to refactor the parseMember function:

-const parseMember = (memberData: GithubPrepareMemberOutput): IMemberData => {
-  // existing code
-}
+const parseMember = (memberData: GithubPrepareMemberOutput): IMemberData => {
+  const { memberFromApi } = memberData;
+
+  if (memberFromApi.isBot) {
+    return parseBotMember(memberData);
+  }
+
+  if (memberFromApi.isDeleted) {
+    return parseDeletedMember(memberData);
+  }
+
+  return parseRegularMember(memberData);
+};
+
+const parseRegularMember = (memberData: GithubPrepareMemberOutput): IMemberData => {
+  // code to parse regular members
+};

Committable suggestion skipped: line range outside the PR's diff.


836-865: ⚠️ Potential issue

Potential Type Misassignment in parseAuthoredCommit

The type property is assigned the string 'authored-commit' instead of using the GithubActivityType.AUTHORED_COMMIT enum value. This could lead to inconsistencies and harder-to-maintain code.

Apply this diff to correct the type property assignment:

-  type: 'authored-commit',
+  type: GithubActivityType.AUTHORED_COMMIT,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  const data = apiData.data
  const memberData = apiData.member

  const member = parseMember(memberData)
  const sourceParentId = apiData.sourceParentId // this is a pull request id

  const activity: IActivityData = {
    channel: apiData.repo.url,
    url: `${apiData.repo.url}/commit/${data.commit.oid}`,
    body: data.commit.message,
    type: GithubActivityType.AUTHORED_COMMIT,
    sourceId: data.commit.oid,
    sourceParentId: `${sourceParentId}`,
    timestamp: new Date(data.commit.authoredDate).toISOString(),
    attributes: {
      insertions: 'additions' in data.commit ? data.commit.additions : 0,
      deletions: 'deletions' in data.commit ? data.commit.deletions : 0,
      lines:
        'additions' in data.commit && 'deletions' in data.commit
          ? data.commit.additions - data.commit.deletions
          : 0,
      isMerge: data.commit.parents.totalCount > 1,
    },
    member,
    score: GITHUB_GRID[GithubActivityType.AUTHORED_COMMIT].score,
    isContribution: GITHUB_GRID[GithubActivityType.AUTHORED_COMMIT].isContribution,
  }

  await ctx.publishActivity(activity)
}

425-455: ⚠️ Potential issue

Possible Missing Attributes in parsePullRequestOpened

The parsePullRequestOpened function constructs an IActivityData object but may be missing important attributes such as url and title when they are undefined. Ensure that these attributes are always provided or handled appropriately to prevent issues when accessing them later.

Apply this diff to handle undefined url and title:

-  url: data.url ? data.url : '',
-  title: data.title,
+  url: data.url || '',
+  title: data.title || '',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const parsePullRequestOpened: ProcessDataHandler = async (ctx) => {
  const apiData = ctx.data as GithubApiData
  const data = apiData.data as GithubPullRequest
  const memberData = apiData.member

  const member = parseMember(memberData)

  const activity: IActivityData = {
    type: GithubActivityType.PULL_REQUEST_OPENED,
    sourceId: data.id,
    sourceParentId: '',
    timestamp: new Date(data.createdAt).toISOString(),
    body: data.bodyText,
    url: data.url || '',
    channel: apiData.repo.url,
    title: data.title || '',
    attributes: {
      state: data.state.toLowerCase(),
      additions: data.additions,
      deletions: data.deletions,
      changedFiles: data.changedFiles,
      authorAssociation: data.authorAssociation,
      labels: data.labels?.nodes.map((l) => l.name),
    },
    member,
    score: GITHUB_GRID[GithubActivityType.PULL_REQUEST_OPENED].score,
    isContribution: GITHUB_GRID[GithubActivityType.PULL_REQUEST_OPENED].isContribution,
  }

  await ctx.publishActivity(activity)
}

1491-1520: ⚠️ Potential issue

Inconsistent Spelling of GithubWehookEvent

The enum GithubWehookEvent appears to have a typo in its name (Wehook instead of Webhook). Correcting this will improve code readability and prevent confusion.

Apply this diff to correct the typo:

-export enum GithubWehookEvent {
+export enum GithubWebhookEvent {

Also, update all usages of GithubWehookEvent in the codebase accordingly.

Committable suggestion skipped: line range outside the PR's diff.

backend/src/api/integration/helpers/githubSearchOrgs.ts (1)

5-10: ⚠️ Potential issue

Add error handling and input validation.

The current implementation lacks proper error handling and input validation, which could lead to unhandled errors and potential security issues.

Consider applying these improvements:

-export default async (req, res) => {
+export default async (req: Request, res: Response) => {
+  try {
+    if (!req.query.query || typeof req.query.query !== 'string') {
+      throw new Error('Invalid or missing query parameter')
+    }
+
     new PermissionChecker(req).validateHas(Permissions.values.integrationEdit)
 
     const payload = await GithubIntegrationService.findOrgs(req.query.query)
     await req.responseHandler.success(req, res, payload)
+  } catch (error) {
+    await req.responseHandler.error(req, res, error)
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

export default async (req: Request, res: Response) => {
  try {
    if (!req.query.query || typeof req.query.query !== 'string') {
      throw new Error('Invalid or missing query parameter')
    }

    new PermissionChecker(req).validateHas(Permissions.values.integrationEdit)

    const payload = await GithubIntegrationService.findOrgs(req.query.query)
    await req.responseHandler.success(req, res, payload)
  } catch (error) {
    await req.responseHandler.error(req, res, error)
  }
}
backend/src/api/integration/helpers/githubOrgRepos.ts (3)

5-5: 🛠️ Refactor suggestion

Add TypeScript type definitions for request/response parameters.

The function parameters should be properly typed for better type safety and developer experience.

-export default async (req, res) => {
+import { Request, Response } from 'express'
+
+export default async (req: Request, res: Response) => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

import { Request, Response } from 'express'

export default async (req: Request, res: Response) => {

6-6: ⚠️ Potential issue

Add error handling for permission validation.

The permission check could throw an error, but it's not being handled. This could result in unhandled promise rejections.

-  new PermissionChecker(req).validateHas(Permissions.values.integrationEdit)
+  try {
+    new PermissionChecker(req).validateHas(Permissions.values.integrationEdit)
+  } catch (error) {
+    return req.responseHandler.error(req, res, error)
+  }

Committable suggestion skipped: line range outside the PR's diff.


8-9: ⚠️ Potential issue

Add input validation and error handling for the GitHub API call.

The function needs to:

  1. Validate the org parameter
  2. Handle potential GitHub API errors
  3. Consider rate limiting
-  const payload = await GithubIntegrationService.getOrgRepos(req.params.org)
-  await req.responseHandler.success(req, res, payload)
+  try {
+    if (!req.params.org || typeof req.params.org !== 'string') {
+      throw new Error('Invalid organization parameter')
+    }
+
+    const payload = await GithubIntegrationService.getOrgRepos(req.params.org)
+    await req.responseHandler.success(req, res, payload)
+  } catch (error) {
+    if (error.status === 403 && error.headers?.['x-ratelimit-remaining'] === '0') {
+      return req.responseHandler.error(
+        req,
+        res,
+        new Error('GitHub API rate limit exceeded'),
+        429
+      )
+    }
+    return req.responseHandler.error(req, res, error)
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  try {
    if (!req.params.org || typeof req.params.org !== 'string') {
      throw new Error('Invalid organization parameter')
    }

    const payload = await GithubIntegrationService.getOrgRepos(req.params.org)
    await req.responseHandler.success(req, res, payload)
  } catch (error) {
    if (error.status === 403 && error.headers?.['x-ratelimit-remaining'] === '0') {
      return req.responseHandler.error(
        req,
        res,
        new Error('GitHub API rate limit exceeded'),
        429
      )
    }
    return req.responseHandler.error(req, res, error)
  }
backend/src/api/integration/helpers/githubSearchRepos.ts (4)

8-8: 💡 Codebase verification

Error handling needs improvement in GitHub repository search

The verification reveals that error handling is incomplete in the GitHub integration:

  • The first API call (org repos) has error handling that logs and returns empty results
  • The second API call (general repos) lacks error handling completely
  • The controller method doesn't have any try-catch block to handle service-level errors
🔗 Analysis chain

Verify GitHub API integration error handling

Let's verify how the GithubIntegrationService.findGithubRepos method handles GitHub API errors.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for error handling in the GitHub integration service
ast-grep --pattern 'class GithubIntegrationService {
  $$$
  async findGithubRepos($_) {
    $$$
  }
  $$$
}'

# Look for error handling patterns in the service
rg -A 10 "findGithubRepos" 

Length of output: 1406


8-8: ⚠️ Potential issue

Add input validation for the query parameter

The query parameter is passed directly to the service without validation. This could lead to potential security issues or unexpected behavior.

+  if (!req.query.query || typeof req.query.query !== 'string') {
+    throw new Error400('Query parameter is required and must be a string');
+  }
+  const sanitizedQuery = req.query.query.trim();
-  const payload = await GithubIntegrationService.findGithubRepos(req.query.query)
+  const payload = await GithubIntegrationService.findGithubRepos(sanitizedQuery)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  if (!req.query.query || typeof req.query.query !== 'string') {
    throw new Error400('Query parameter is required and must be a string');
  }
  const sanitizedQuery = req.query.query.trim();
  const payload = await GithubIntegrationService.findGithubRepos(sanitizedQuery)

5-10: 🛠️ Refactor suggestion

Add TypeScript type definitions

The function parameters and return type should be properly typed for better maintainability and type safety.

-export default async (req, res) => {
+export default async (req: Request, res: Response): Promise<void> => {

Committable suggestion skipped: line range outside the PR's diff.


5-10: ⚠️ Potential issue

Implement proper error handling

The current implementation lacks proper error handling for potential failures in the GitHub API call.

 export default async (req, res) => {
-  new PermissionChecker(req).validateHas(Permissions.values.integrationEdit)
+  try {
+    new PermissionChecker(req).validateHas(Permissions.values.integrationEdit)
 
-  const payload = await GithubIntegrationService.findGithubRepos(req.query.query)
-  await req.responseHandler.success(req, res, payload)
+    if (!req.query.query || typeof req.query.query !== 'string') {
+      throw new Error400('Query parameter is required and must be a string');
+    }
+    const sanitizedQuery = req.query.query.trim();
+    
+    const payload = await GithubIntegrationService.findGithubRepos(sanitizedQuery)
+    await req.responseHandler.success(req, res, payload)
+  } catch (error) {
+    if (error instanceof Error400) {
+      await req.responseHandler.error(req, res, error)
+    } else {
+      await req.responseHandler.error(req, res, new Error500('Failed to search GitHub repositories'))
+    }
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

export default async (req, res) => {
  try {
    new PermissionChecker(req).validateHas(Permissions.values.integrationEdit)

    if (!req.query.query || typeof req.query.query !== 'string') {
      throw new Error400('Query parameter is required and must be a string');
    }
    const sanitizedQuery = req.query.query.trim();
    
    const payload = await GithubIntegrationService.findGithubRepos(sanitizedQuery)
    await req.responseHandler.success(req, res, payload)
  } catch (error) {
    if (error instanceof Error400) {
      await req.responseHandler.error(req, res, error)
    } else {
      await req.responseHandler.error(req, res, new Error500('Failed to search GitHub repositories'))
    }
  }
}
frontend/src/config/integrations/github/types/GithubSettings.ts (1)

1-12: 🛠️ Refactor suggestion

Add essential fields and type constraints to base interfaces

The base interfaces could be enhanced for better type safety and data integrity:

Consider applying these improvements:

+// ISO 8601 timestamp type for consistency
+type ISOTimestamp = string;

 export interface GitHubOrganization {
+  id: string;  // GitHub organization ID
   logo: string;
   name: string;
-  url: string;
+  url: URL;    // Using URL type for validation
-  updatedAt?: string;
+  updatedAt?: ISOTimestamp;
 }

 export interface GitHubRepository {
+  id: string;  // GitHub repository ID
   name: string;
-  url: string;
+  url: URL;    // Using URL type for validation
   org?: GitHubOrganization;
 }

Committable suggestion skipped: line range outside the PR's diff.

frontend/src/config/integrations/github/config.ts (1)

12-12: 💡 Codebase verification

Functionality preserved but with reduced visibility

The new dropdown implementation has preserved the core functionality of opening the GitHub settings drawer, but it has made the "Map repositories" action less prominent by moving it behind a dropdown menu. This could impact user experience during the repository mapping phase.

  • The original github-action.vue showed a dedicated "Map repositories" button when status was "mapping"
  • The new github-dropdown.vue only shows a generic "Settings" option in the dropdown
  • The settings drawer integration is preserved but with reduced context-awareness

Consider:

  • Adding a status-aware label in the dropdown item when integration status is "mapping"
  • Or keeping a separate prominent action button for the mapping state while using the dropdown for other actions
🔗 Analysis chain

Architectural change: Consolidating UI components

The replacement of separate status and action components with a unified dropdown component represents a good architectural improvement:

  • Reduces component fragmentation
  • Simplifies the UI/UX by consolidating GitHub-related actions
  • Follows modern UI patterns for integration management

However, please ensure that all functionality from the previous components has been preserved in the new dropdown implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Analyze the new dropdown component to verify feature parity

# Check the implementation of the new dropdown component
echo "Analyzing GithubDropdown implementation..."
ast-grep --pattern 'template {
  $$$
}' frontend/src/config/integrations/github/components/github-dropdown.vue

# Look for potential missing features by checking the old components in git history
git log -p --full-history -- '**/github-status*' '**/github-action*'

Length of output: 4954


Script:

#!/bin/bash
# Let's check the implementation of the new GithubDropdown component

# First, verify if the file exists
fd -t f "github-dropdown.vue" frontend/src/config/integrations/github/components/

# If it exists, check its contents
rg -U "template|script" -A 10 frontend/src/config/integrations/github/components/github-dropdown.vue

# Also check for any settings drawer references to ensure the mapping functionality is preserved
rg -U "github-settings-drawer" frontend/src/config/integrations/github/components/

Length of output: 1796

services/libs/snowflake/src/test.ts (3)

19-22: 🛠️ Refactor suggestion

Improve test structure and error handling

The current implementation uses setImmediate and lacks proper error handling for the API call. Consider restructuring this as a proper test suite.

Consider refactoring to use a testing framework like Jest:

-setImmediate(async () => {
-  const res = await gh.getOrgRepositories({ org: 'CrowdDotDev' })
-  console.log(res)
-})
+describe('GithubSnowflakeClient', () => {
+  it('should fetch organization repositories', async () => {
+    try {
+      const res = await gh.getOrgRepositories({ org: 'CrowdDotDev' });
+      expect(res).toBeDefined();
+      // Add more specific assertions based on expected response structure
+    } catch (error) {
+      console.error('Failed to fetch repositories:', error);
+      throw error;
+    }
+  });
+});

Committable suggestion skipped: line range outside the PR's diff.


8-15: ⚠️ Potential issue

Security concern: Hardcoded credentials in source code

The Snowflake client configuration contains hardcoded credentials and configuration values. This is a security risk and makes the code less maintainable.

Consider using environment variables for sensitive configuration:

 const sf = new SnowflakeClient({
-  account: 'xmb01974',
-  username: 'DEV_IKOTUA',
-  database: 'GITHUB_EVENTS_INGEST',
-  warehouse: 'DBT_DEV',
-  role: 'DBT_TRANSFORM_DEV',
+  account: process.env.SNOWFLAKE_ACCOUNT,
+  username: process.env.SNOWFLAKE_USERNAME,
+  database: process.env.SNOWFLAKE_DATABASE,
+  warehouse: process.env.SNOWFLAKE_WAREHOUSE,
+  role: process.env.SNOWFLAKE_ROLE,
   privateKeyString: privateKeyString,
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const sf = new SnowflakeClient({
  account: process.env.SNOWFLAKE_ACCOUNT,
  username: process.env.SNOWFLAKE_USERNAME,
  database: process.env.SNOWFLAKE_DATABASE,
  warehouse: process.env.SNOWFLAKE_WAREHOUSE,
  role: process.env.SNOWFLAKE_ROLE,
  privateKeyString: privateKeyString,
})

1-6: ⚠️ Potential issue

Improve error handling for file operations

The file reading operation lacks error handling and could fail if the private key file doesn't exist or is inaccessible.

Apply this diff to add proper error handling:

 import fs from 'fs'
 import { SnowflakeClient } from './client'
 import { GithubSnowflakeClient } from './github'

-const privateKeyString = fs.readFileSync(process.env.HOME + '/.sf/rsa_key.p8', 'utf8')
+let privateKeyString: string;
+try {
+  privateKeyString = fs.readFileSync(process.env.HOME + '/.sf/rsa_key.p8', 'utf8');
+} catch (error) {
+  console.error('Failed to read Snowflake private key:', error);
+  process.exit(1);
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

import fs from 'fs'

import { SnowflakeClient } from './client'
import { GithubSnowflakeClient } from './github'

let privateKeyString: string;
try {
  privateKeyString = fs.readFileSync(process.env.HOME + '/.sf/rsa_key.p8', 'utf8');
} catch (error) {
  console.error('Failed to read Snowflake private key:', error);
  process.exit(1);
}
services/libs/integrations/src/integrations/github-old/index.ts (1)

19-22: 🛠️ Refactor suggestion

Improve type safety in postProcess function

The function uses any type and lacks proper type definitions, which bypasses TypeScript's type checking benefits.

Consider implementing proper types:

-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  postProcess: (settings: any) => {
+  postProcess: (settings: IntegrationSettings) => {

Also, the function simply returns the input without any processing. If no post-processing is needed, consider documenting why this pass-through exists.

Committable suggestion skipped: line range outside the PR's diff.

frontend/src/config/integrations/github/components/github-dropdown.vue (1)

19-21: 🛠️ Refactor suggestion

Add proper typing for the integration prop

Using any type reduces type safety. Consider creating and using a proper interface for the integration prop.

+interface GitHubIntegration {
+  // Add relevant properties based on the integration object structure
+  id: string;
+  type: string;
+  // ... other properties
+}

 const props = defineProps<{
-  integration: any,
+  integration: GitHubIntegration,
 }>();

Committable suggestion skipped: line range outside the PR's diff.

frontend/src/ui-kit/drawer/Drawer.stories.ts (1)

8-26: 🛠️ Refactor suggestion

Fix props configuration issues.

Several improvements needed in the props configuration:

  1. The modelValue prop's defaultValue should be a boolean, not a string
  2. The width prop should validate CSS units
  3. The closeFunction prop needs clearer documentation

Apply these changes:

    modelValue: {
      description: 'Is drawer open',
-     defaultValue: 'false',
+     defaultValue: false,
      control: 'boolean',
    },

    width: {
-     description: 'Specifies drawer width',
+     description: 'Specifies drawer width (e.g., "37.5rem", "500px")',
      defaultValue: '37.5rem',
      control: 'text',
    },

    closeFunction: {
-     description: 'Function that prevents drawer from closing',
+     description: 'Function that returns boolean to prevent drawer from closing when true',
      control: {
        type: null,
      },
    },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    // Props
    modelValue: {
      description: 'Is drawer open',
      defaultValue: false,
      control: 'boolean',
    },

    width: {
      description: 'Specifies drawer width (e.g., "37.5rem", "500px")',
      defaultValue: '37.5rem',
      control: 'text',
    },

    closeFunction: {
      description: 'Function that returns boolean to prevent drawer from closing when true',
      control: {
        type: null,
      },
    },
frontend/src/config/integrations/github/components/settings/github-settings-empty.vue (1)

1-17: 🛠️ Refactor suggestion

Enhance accessibility and maintainability of the template.

Several improvements can be made to the template:

  1. Use semantic HTML elements for better accessibility
  2. Add ARIA attributes
  3. Externalize text content for internationalization
  4. Standardize icon component usage

Consider applying these changes:

 <template>
   <div class="flex justify-center">
-    <div class="pt-16 flex flex-col items-center w-full max-w-100">
-      <lf-icon-old name="git-repository-line" :size="64" class="text-gray-300 mb-6" />
-      <h6 class="text-center pb-3">
+    <section class="pt-16 flex flex-col items-center w-full max-w-100" role="region" aria-labelledby="github-settings-title">
+      <lf-icon name="git-repository-line" :size="64" class="text-gray-300 mb-6" aria-hidden="true" />
+      <h2 id="github-settings-title" class="text-center pb-3 text-h6">
         Sync and map GitHub repositories
-      </h6>
+      </h2>
       <p class="text-center text-small text-gray-500 pb-6">
         Choose which repositories you want to track, and map them with the corresponding project.
       </p>
-      <lf-button type="primary-ghost" @click="emit('add')">
+      <lf-button 
+        type="primary-ghost" 
+        @click="emit('add')"
+        aria-label="Add GitHub repositories">
         <lf-icon name="arrows-rotate" type="regular" />
         Add repositories
       </lf-button>
-    </div>
+    </section>
   </div>
 </template>

Also, consider adding these changes in a separate file:

// i18n/github-settings.ts
export default {
  title: 'Sync and map GitHub repositories',
  description: 'Choose which repositories you want to track, and map them with the corresponding project.',
  addButton: 'Add repositories'
}
frontend/src/ui-kit/search/Search.vue (1)

27-27: ⚠️ Potential issue

Fix type mismatch between props and ref

The modelValue prop accepts string | number, but valueProxy is typed as string. This could cause type errors when a number value is provided.

Apply this fix:

-const valueProxy = ref<string>(props.modelValue);
+const valueProxy = ref<string | number>(props.modelValue);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const valueProxy = ref<string | number>(props.modelValue);
frontend/src/config/integrations/github/services/github.api.service.ts (3)

21-44: 🛠️ Refactor suggestion

⚠️ Potential issue

Address code duplication and secure URL parameters

Both methods share similar patterns and would benefit from shared error handling. Additionally, the organization name in the URL path needs to be properly encoded.

Consider extracting common functionality and securing the URL:

// Add this helper function
async function makeGithubRequest<T>(
  path: string,
  params?: Record<string, string>
): Promise<T> {
  const tenantId = AuthService.getTenantId();
  if (!tenantId) {
    throw new Error('Tenant ID is required');
  }

  try {
    const response = await authAxios.get(
      `/tenant/${tenantId}/integration/github/${path}`,
      params ? { params } : undefined
    );
    return response.data;
  } catch (error) {
    throw new Error(`GitHub API request failed: ${error.message}`);
  }
}

// Then refactor the methods to use it:
static async searchOrganizations(query: string): Promise<GitHubOrganization[]> {
  if (!query?.trim()) {
    throw new Error('Search query cannot be empty');
  }
  return makeGithubRequest('search/orgs', { query: query.trim() });
}

static async getOrganizationRepositories(name: string): Promise<GitHubRepository[]> {
  if (!name?.trim()) {
    throw new Error('Organization name cannot be empty');
  }
  return makeGithubRequest(`orgs/${encodeURIComponent(name.trim())}/repos`);
}

1-5: 🛠️ Refactor suggestion

Consider refactoring the class to standalone functions

The class currently only contains static methods, which suggests it's being used as a namespace. In TypeScript, it's more idiomatic to use either a namespace or standalone functions.

Consider refactoring like this:

-export class GithubApiService {
-  static async searchRepositories
+export async function searchGithubRepositories

Committable suggestion skipped: line range outside the PR's diff.


6-19: ⚠️ Potential issue

Add input validation and error handling

The method should validate the query parameter and implement proper error handling for failed requests.

Consider implementing these improvements:

-  static async searchRepositories(query: string): Promise<GitHubRepository[]> {
+  static async searchRepositories(query: string): Promise<GitHubRepository[]> {
+    if (!query?.trim()) {
+      throw new Error('Search query cannot be empty');
+    }
+
     const tenantId = AuthService.getTenantId();
+    if (!tenantId) {
+      throw new Error('Tenant ID is required');
+    }
 
-    const response = await authAxios.get(
-      `/tenant/${tenantId}/integration/github/search/repos`,
-      {
-        params: {
-          query,
-        },
-      },
-    );
+    try {
+      const response = await authAxios.get(
+        `/tenant/${tenantId}/integration/github/search/repos`,
+        {
+          params: {
+            query: query.trim(),
+          },
+        },
+      );
 
-    return response.data;
+      return response.data;
+    } catch (error) {
+      throw new Error(`Failed to search repositories: ${error.message}`);
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  static async searchRepositories(query: string): Promise<GitHubRepository[]> {
    if (!query?.trim()) {
      throw new Error('Search query cannot be empty');
    }

    const tenantId = AuthService.getTenantId();
    if (!tenantId) {
      throw new Error('Tenant ID is required');
    }

    try {
      const response = await authAxios.get(
        `/tenant/${tenantId}/integration/github/search/repos`,
        {
          params: {
            query: query.trim(),
          },
        },
      );

      return response.data;
    } catch (error) {
      throw new Error(`Failed to search repositories: ${error.message}`);
    }
  }
frontend/src/ui-kit/drawer/Drawer.vue (2)

40-45: ⚠️ Potential issue

Handle async closeFunction and add error handling

The clickOutsideClose function needs to handle async closeFunction and potential errors:

-const clickOutsideClose = () => {
-  const canClose = props.closeFunction();
+const clickOutsideClose = async () => {
+  try {
+    const canClose = await Promise.resolve(props.closeFunction());
   if (canClose) {
     close();
   }
+  } catch (error) {
+    console.error('Error in closeFunction:', error);
+  }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const clickOutsideClose = async () => {
  try {
    const canClose = await Promise.resolve(props.closeFunction());
    if (canClose) {
      close();
    }
  } catch (error) {
    console.error('Error in closeFunction:', error);
  }
};

47-59: ⚠️ Potential issue

Improve event handling and prevent memory leaks

Several improvements needed for the event handling:

  1. Use event.key instead of deprecated event.which
  2. Add proper TypeScript types
  3. Clean up event listener on component unmount
-const onEscapeKeyUp = (event: any) => {
-  if (event.which === 27) {
+const onEscapeKeyUp = (event: KeyboardEvent) => {
+  if (event.key === 'Escape') {
     clickOutsideClose();
   }
 };

+onBeforeUnmount(() => {
+  window.removeEventListener('keyup', onEscapeKeyUp);
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const onEscapeKeyUp = (event: KeyboardEvent) => {
  if (event.key === 'Escape') {
    clickOutsideClose();
  }
};

watch(() => isDrawerOpened.value, (show: boolean) => {
  if (!show) {
    window.removeEventListener('keyup', onEscapeKeyUp);
  } else {
    window.addEventListener('keyup', onEscapeKeyUp);
  }
}, { immediate: true });

onBeforeUnmount(() => {
  window.removeEventListener('keyup', onEscapeKeyUp);
});
services/apps/integration_stream_worker/config/custom-environment-variables.json (1)

44-51: 💡 Codebase verification

⚠️ Potential issue

Incorrect namespace for Snowflake configuration - Action Required

The review comment is correct. The configuration section named "github" in services/apps/integration_stream_worker/config/custom-environment-variables.json contains Snowflake credentials but is incorrectly namespaced. This is evidenced by:

  1. The presence of Snowflake client initialization in the codebase that uses these exact environment variables (CROWD_SNOWFLAKE_*)
  2. The proper namespacing of these variables under "snowflake" in another config file (backend/config/custom-environment-variables.json)
  3. The default configuration shows no GitHub-related settings in this section

The configuration should be renamed from "github" to "snowflake" to maintain consistency with the rest of the codebase and accurately reflect its purpose.

🔗 Analysis chain

Incorrect namespace for Snowflake configuration.

The configuration section is named "github" but contains Snowflake-related settings. This creates confusion and violates the principle of least surprise.

Consider these improvements:

  1. Rename the section to match its purpose:
-  "github": {
+  "snowflake": {
     "privateKey": "CROWD_SNOWFLAKE_PRIVATE_KEY",
     "account": "CROWD_SNOWFLAKE_ACCOUNT",
     "username": "CROWD_SNOWFLAKE_USERNAME",
     "database": "CROWD_SNOWFLAKE_DATABASE",
     "warehouse": "CROWD_SNOWFLAKE_WAREHOUSE",
     "role": "CROWD_SNOWFLAKE_ROLE"
   },
  1. Verify the impact of this configuration change:
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any hardcoded references to config.github that should be updated to config.snowflake

# Search for config.github references
echo "Searching for potential hardcoded config.github references that need updating:"
rg -l "config\.github\." --type ts --type js

# Search for environment variable usage
echo "Checking environment variable usage:"
rg "CROWD_SNOWFLAKE_" --type dockerfile --type sh

Length of output: 381


Script:

#!/bin/bash
# Let's try a broader search approach

# 1. Search for any references to github configuration in TypeScript/JavaScript files
echo "Searching for 'github' configuration references:"
rg "github['\"]?\s*:\s*{" --type ts --type js -C 2

# 2. Search for Snowflake environment variables in all files
echo -e "\nSearching for Snowflake environment variables:"
rg "CROWD_SNOWFLAKE_" -C 2

# 3. Look for config files that might use this configuration
echo -e "\nSearching for config files:"
fd -e json -e js -e ts "config" --type f

Length of output: 13410


Script:

#!/bin/bash
# Let's check how this configuration is being used in the codebase

# 1. Search for references to config.github in the integration_stream_worker
echo "Searching for config.github usage in integration_stream_worker:"
rg "config\.github" services/apps/integration_stream_worker -C 3

# 2. Check the default configuration to understand the intended structure
echo -e "\nChecking default configuration:"
cat services/apps/integration_stream_worker/config/default.json

# 3. Let's also check if there are any Snowflake client initializations
echo -e "\nChecking Snowflake client usage:"
rg "new SnowflakeClient|SnowflakeClient\.fromEnv" -C 3

Length of output: 3213

services/libs/integrations/src/integrations/github-old/grid.ts (1)

70-73: 🛠️ Refactor suggestion

Reconsider commit scoring weight

The current scoring gives commits (2 points) significantly less weight than PR comments (6 points) or issue comments (6 points). Since commits represent actual code contributions, consider increasing their score to better reflect their value to the project.

frontend/src/config/integrations/github/components/settings/github-settings-repo-item.vue (3)

65-65: 🛠️ Refactor suggestion

Replace 'any' type with a proper interface

Using any type reduces type safety and IDE support.

Consider creating a proper interface for subprojects:

interface Subproject {
  id: string;
  name: string;
  // Add other relevant properties
}

Then update the prop type:

-  subprojects: any[];
+  subprojects: Subproject[];

96-100: ⚠️ Potential issue

Add guard clause for empty subprojects array

The watcher assumes that subprojects array has at least one item, which could cause runtime errors if the array is empty.

 watch(() => model.value, (value) => {
   if (!value) {
+    if (!props.subprojects.length) return;
     model.value = props.subprojects[0].id;
   }
 }, { immediate: true });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

watch(() => model.value, (value) => {
  if (!value) {
    if (!props.subprojects.length) return;
    model.value = props.subprojects[0].id;
  }
}, { immediate: true });

23-38: 🛠️ Refactor suggestion

Add ARIA label for better accessibility

The select component lacks an aria-label which could impact accessibility for screen readers.

   <el-select
     v-model="model"
     placeholder="Select sub-project"
+    aria-label="Select sub-project for repository"
     class="w-full"
     placement="bottom-end"
     filterable
     @blur="$v.model.$touch"
     @change="$v.model.$touch"
   >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

          <el-select
            v-model="model"
            placeholder="Select sub-project"
            aria-label="Select sub-project for repository"
            class="w-full"
            placement="bottom-end"
            filterable
            @blur="$v.model.$touch"
            @change="$v.model.$touch"
          >
            <el-option
              v-for="subproject of props.subprojects"
              :key="subproject.id"
              :value="subproject.id"
              :label="subproject.name"
            />
          </el-select>
frontend/src/config/integrations/github/components/settings/github-settings-mapping.vue (2)

84-84: 🛠️ Refactor suggestion

Replace any[] with a proper type definition

Using any[] reduces type safety and makes the code more prone to runtime errors.

Consider creating a proper interface for subprojects:

interface Subproject {
  id: string;
  name: string;
  // Add other relevant properties
}

Then update the prop type:

-subprojects: any[];
+subprojects: Subproject[];

113-125: 🛠️ Refactor suggestion

Improve type safety and simplify organization processing

The current implementation has several issues:

  1. Uses non-null assertions without proper checks
  2. Uses any type
  3. Complex reduce logic could be simplified

Consider this safer implementation:

-const allOrganizations = computed<any[]>(() => {
+interface ProcessedOrganization extends GitHubOrganization {
+  repositories: GitHubSettingsRepository[];
+}
+
+const allOrganizations = computed<ProcessedOrganization[]>(() => {
   const owners = new Set();
   return filteredRepos.value.reduce((acc: any[], r) => {
-    if (!owners.has(r.org!.name)) {
-      owners.add(r.org!.name);
+    const org = r.org;
+    if (!org) return acc;
+    
+    if (!owners.has(org.name)) {
+      owners.add(org.name);
       acc.push({
-        ...(r.org!),
-        repositories: props.repositories.filter((repo) => repo.org!.url === r.org!.url),
+        ...org,
+        repositories: props.repositories.filter((repo) => repo.org?.url === org.url),
       });
     }
     return acc;
-  }, []);
+  }, [] as ProcessedOrganization[]);
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

interface ProcessedOrganization extends GitHubOrganization {
  repositories: GitHubSettingsRepository[];
}

const allOrganizations = computed<ProcessedOrganization[]>(() => {
  const owners = new Set();
  return filteredRepos.value.reduce((acc: any[], r) => {
    const org = r.org;
    if (!org) return acc;
    
    if (!owners.has(org.name)) {
      owners.add(org.name);
      acc.push({
        ...org,
        repositories: props.repositories.filter((repo) => repo.org?.url === org.url),
      });
    }
    return acc;
  }, [] as ProcessedOrganization[]);
});
frontend/src/config/integrations/github/components/settings/github-settings-org-item.vue (4)

55-58: ⚠️ Potential issue

Add confirmation dialog for destructive action.

The remove organization action is destructive and affects all repositories. It should have a confirmation dialog to prevent accidental clicks.

Consider implementing a confirmation dialog before executing the remove action. I can help implement this if needed.


25-27: 🛠️ Refactor suggestion

Add aria-label to icon-only button for accessibility.

The icon-only button needs an accessible label for screen readers.

-            <lf-button type="secondary-ghost" icon-only>
+            <lf-button type="secondary-ghost" icon-only aria-label="Organization settings">
               <lf-icon name="ellipsis" />
             </lf-button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

            <lf-button type="secondary-ghost" icon-only aria-label="Organization settings">
              <lf-icon name="ellipsis" />
            </lf-button>

119-122: ⚠️ Potential issue

Handle potential undefined org property safely.

The remove function uses a non-null assertion (org!.url) which could cause runtime errors if org is undefined.

 const remove = () => {
   unsync();
-  repos.value = repos.value.filter((repo) => repo.org!.url !== props.organization.url);
+  repos.value = repos.value.filter((repo) => repo.org?.url === props.organization.url);
 };

Committable suggestion skipped: line range outside the PR's diff.


104-113: ⚠️ Potential issue

Add error handling and loading state for API call.

The sync function makes an API call but doesn't handle errors or show loading state to users.

Consider implementing error handling and loading state:

+const isLoading = ref(false);
+const error = ref<Error | null>(null);

 const sync = async () => {
+  isLoading.value = true;
+  error.value = null;
   orgs.value.push({ ...props.organization, updatedAt: dayjs().toISOString() });
-  GithubApiService.getOrganizationRepositories(props.organization.name)
-    .then((res) => {
+  try {
+    const res = await GithubApiService.getOrganizationRepositories(props.organization.name);
       const newRepositories = (res as GitHubSettingsRepository[])
         .filter((r: GitHubSettingsRepository) => !repos.value.some((repo: GitHubSettingsRepository) => repo.url === r.url))
         .map((r: GitHubSettingsRepository) => ({ ...r, org: props.organization, updatedAt: dayjs().toISOString() }));
       repos.value = [...repos.value, ...newRepositories];
-    });
+  } catch (e) {
+    error.value = e as Error;
+    // Rollback the organization addition on error
+    orgs.value = orgs.value.filter(org => org.url !== props.organization.url);
+  } finally {
+    isLoading.value = false;
+  }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

const isLoading = ref(false);
const error = ref<Error | null>(null);

const sync = async () => {
  isLoading.value = true;
  error.value = null;
  orgs.value.push({ ...props.organization, updatedAt: dayjs().toISOString() });
  try {
    const res = await GithubApiService.getOrganizationRepositories(props.organization.name);
    const newRepositories = (res as GitHubSettingsRepository[])
      .filter((r: GitHubSettingsRepository) => !repos.value.some((repo: GitHubSettingsRepository) => repo.url === r.url))
      .map((r: GitHubSettingsRepository) => ({ ...r, org: props.organization, updatedAt: dayjs().toISOString() }));
    repos.value = [...repos.value, ...newRepositories];
  } catch (e) {
    error.value = e as Error;
    // Rollback the organization addition on error
    orgs.value = orgs.value.filter(org => org.url !== props.organization.url);
  } finally {
    isLoading.value = false;
  }
};
services/libs/integrations/src/integrations/github-old/types.ts (9)

1-1: 🛠️ Refactor suggestion

Consider removing the ESLint disable comment.

The blanket disable of @typescript-eslint/no-explicit-any reduces type safety. Consider explicitly typing the any occurrences throughout the file.


85-85: ⚠️ Potential issue

Fix typo in enum name GithubWehookEvent.

The enum name contains a typo: "Wehook" should be "Webhook".

-export enum GithubWehookEvent {
+export enum GithubWebhookEvent {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

export enum GithubWebhookEvent {

234-240: 🛠️ Refactor suggestion

Standardize property naming in GithubBotMember.

The interface mixes camelCase (avatarUrl) and snake_case (avatar_url) naming conventions.

 export interface GithubBotMember {
   login: string;
   avatarUrl: string;
-  avatar_url?: string;  // Remove duplicate snake_case property
   id: string;
   url: string;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

export interface GithubBotMember {
  login: string
  avatarUrl: string
  id: string
  url: string
}

66-71: 🛠️ Refactor suggestion

Replace any types with proper interfaces in webhook payload.

The webhook payload uses any type for both event and data properties.

+interface GithubWebhookEvent {
+  type: string;
+  payload: Record<string, unknown>;
+}
+
 export interface GithubWebhookPayload {
   signature: string;
-  event: any;
-  data: any;
+  event: GithubWebhookEvent;
+  data: Record<string, unknown>;
   date?: string;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

interface GithubWebhookEvent {
  type: string;
  payload: Record<string, unknown>;
}

export interface GithubWebhookPayload {
  signature: string;
  event: GithubWebhookEvent;
  data: Record<string, unknown>;
  date?: string;
}

161-171: 🛠️ Refactor suggestion

Use boolean type for isCommitDataEnabled.

The isCommitDataEnabled property is using string type but should be boolean based on its name.

 export interface GithubPlatformSettings {
   appId: string;
   clientId: string;
   clientSecret: string;
   privateKey: string;
   webhookSecret: string;
-  isCommitDataEnabled: string;
+  isCommitDataEnabled: boolean;
   globalLimit?: number;
   callbackUrl: string;
   personalAccessTokens: string;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

export interface GithubPlatformSettings {
  appId: string
  clientId: string
  clientSecret: string
  privateKey: string
  webhookSecret: string
  isCommitDataEnabled: boolean
  globalLimit?: number
  callbackUrl: string
  personalAccessTokens: string
}

48-64: 🛠️ Refactor suggestion

Replace any types with proper interfaces in timeline items.

Both timeline interfaces use any type which reduces type safety.

+interface GithubActor {
+  id: string;
+  login: string;
+  avatarUrl: string;
+  url: string;
+}
+
 export interface GithubPullRequestTimelineItem {
   __typename: string;
   id: string;
-  actor: any;
+  actor: GithubActor;
   createdAt: string;
-  assignee?: any;
+  assignee?: GithubActor;
   // ...
 }

 export interface GithubIssueTimelineItem {
   __typename: string;
   id: string;
-  actor?: any;
+  actor?: GithubActor;
   // ...
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

interface GithubActor {
  id: string;
  login: string;
  avatarUrl: string;
  url: string;
}

export interface GithubPullRequestTimelineItem {
  __typename: string
  id: string
  actor: GithubActor
  createdAt: string
  assignee?: GithubActor
  submittedAt?: string
  body?: string
  state?: string
}

export interface GithubIssueTimelineItem {
  __typename: string
  id: string
  actor?: GithubActor
  createdAt: string
}

33-35: 🛠️ Refactor suggestion

Replace any[] with a properly typed label interface.

The labels.nodes property uses any[] which reduces type safety.

+interface GithubLabel {
+  id: string;
+  name: string;
+  color: string;
+  description?: string;
+}
+
 export interface GithubPullRequest {
   // ...
   labels?: {
-    nodes?: any[]
+    nodes?: GithubLabel[]
   }
   // ...
 }

Committable suggestion skipped: line range outside the PR's diff.


124-146: 🛠️ Refactor suggestion

Improve type safety and consider consolidating similar interfaces.

Both GithubApiData and GithubWebhookData interfaces:

  1. Use any types extensively
  2. Share similar structure
+interface BaseGithubData {
+  data: Record<string, unknown>[] | Record<string, unknown>;
+  relatedData?: Record<string, unknown> | Record<string, unknown>[];
+  member?: GithubPrepareMemberOutput;
+  orgMember?: GithubPrepareOrgMemberOutput;
+  objectMember?: GithubPrepareMemberOutput;
+  sourceParentId?: string;
+}
+
-export interface GithubApiData {
+export interface GithubApiData extends BaseGithubData {
   type: GithubActivityType;
   subType?: string;
-  data: any[] | any;
-  relatedData?: any | any[];
-  member?: GithubPrepareMemberOutput;
-  orgMember?: GithubPrepareOrgMemberOutput;
-  objectMember?: GithubPrepareMemberOutput;
-  sourceParentId?: string;
   repo: Repo;
 }

-export interface GithubWebhookData {
+export interface GithubWebhookData extends BaseGithubData {
   webhookType: GithubWebhookEvent;
   subType?: string;
-  data: any[] | any;
-  relatedData?: any | any[];
-  member?: GithubPrepareMemberOutput;
-  orgMember?: GithubPrepareOrgMemberOutput;
-  objectMember?: GithubPrepareMemberOutput;
-  sourceParentId?: string;
   date?: string;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

interface BaseGithubData {
  data: Record<string, unknown>[] | Record<string, unknown>;
  relatedData?: Record<string, unknown> | Record<string, unknown>[];
  member?: GithubPrepareMemberOutput;
  orgMember?: GithubPrepareOrgMemberOutput;
  objectMember?: GithubPrepareMemberOutput;
  sourceParentId?: string;
}

export interface GithubApiData extends BaseGithubData {
  type: GithubActivityType;
  subType?: string;
  repo: Repo;
}

export interface GithubWebhookData extends BaseGithubData {
  webhookType: GithubWebhookEvent;
  subType?: string;
  date?: string;
}

228-233: 🛠️ Refactor suggestion

Replace any types in GithubPrepareMemberOutput.

The interface uses any type for multiple fields which reduces type safety.

+interface GithubOrg {
+  id: string;
+  login: string;
+  url: string;
+}
+
+interface GithubMemberApi {
+  id: string;
+  login: string;
+  avatarUrl: string;
+  url: string;
+  email?: string;
+}
+
 export interface GithubPrepareMemberOutput {
   email: string;
-  orgs: any;
-  memberFromApi: any;
+  orgs: GithubOrg[];
+  memberFromApi: GithubMemberApi;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

interface GithubOrg {
  id: string;
  login: string;
  url: string;
}

interface GithubMemberApi {
  id: string;
  login: string;
  avatarUrl: string;
  url: string;
  email?: string;
}

export interface GithubPrepareMemberOutput {
  email: string;
  orgs: GithubOrg[];
  memberFromApi: GithubMemberApi;
}
backend/src/api/integration/index.ts (2)

47-58: ⚠️ Potential issue

Add authentication middleware to protect GitHub endpoints

The new GitHub endpoints are missing the authMiddleware that's present on other sensitive endpoints in this file. This could expose GitHub organization and repository data to unauthorized users.

Add the authentication middleware to each endpoint:

 app.get(
   `/tenant/:tenantId/integration/github/search/orgs`,
+  authMiddleware,
   safeWrap(require('./helpers/githubSearchOrgs').default),
 )
 app.get(
   `/tenant/:tenantId/integration/github/search/repos`,
+  authMiddleware,
   safeWrap(require('./helpers/githubSearchRepos').default),
 )
 app.get(
   `/tenant/:tenantId/integration/github/orgs/:org/repos`,
+  authMiddleware,
   safeWrap(require('./helpers/githubOrgRepos').default),
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  app.get(
    `/tenant/:tenantId/integration/github/search/orgs`,
    authMiddleware,
    safeWrap(require('./helpers/githubSearchOrgs').default),
  )
  app.get(
    `/tenant/:tenantId/integration/github/search/repos`,
    authMiddleware,
    safeWrap(require('./helpers/githubSearchRepos').default),
  )
  app.get(
    `/tenant/:tenantId/integration/github/orgs/:org/repos`,
    authMiddleware,
    safeWrap(require('./helpers/githubOrgRepos').default),
  )

47-58: 💡 Codebase verification

GitHub API integration needs improvements for error handling and pagination

The implementation has several issues that need to be addressed:

  • Error handling is inconsistent - only implemented in findGithubRepos for org repos query but missing in other methods
  • No rate limit handling across all GitHub API calls
  • Pagination is only properly handled in getGithubRepositories method (using perPage: 10000), but missing in other methods that use the GitHub API directly
  • No retry mechanism for failed requests

Key locations requiring updates:

  • findOrgs: Add error handling and pagination
  • getOrgRepos: Add error handling and pagination
  • findGithubRepos: Add pagination for both queries
  • All methods: Add rate limit handling
🔗 Analysis chain

Verify the implementation of GitHub helper functions

Let's verify that the helper functions properly handle GitHub API rate limits, pagination, and error cases.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check implementation of GitHub helper functions

# Check for rate limiting and pagination handling
echo "Checking for rate limit handling..."
rg -A 5 "rate.*limit" "./backend/src/api/integration/helpers/github*.ts"

echo "Checking for pagination handling..."
rg -A 5 "page|per_page" "./backend/src/api/integration/helpers/github*.ts"

# Check error handling
echo "Checking error handling..."
rg -A 5 "catch|throw|error" "./backend/src/api/integration/helpers/github*.ts"

Length of output: 724


Script:

#!/bin/bash
# Let's first find the correct paths for the GitHub helper files
echo "Finding GitHub helper files..."
fd "githubSearchOrgs|githubSearchRepos|githubOrgRepos" backend/src/api/integration/helpers/

# Once we find the files, let's check their implementation
echo -e "\nChecking rate limit handling..."
rg -A 5 "rate.*limit" backend/src/api/integration/helpers/

echo -e "\nChecking pagination handling..."
rg -A 5 "page|per_page" backend/src/api/integration/helpers/

echo -e "\nChecking error handling..."
rg -A 5 "catch|throw|error" backend/src/api/integration/helpers/

Length of output: 8701


Script:

#!/bin/bash
# Let's examine the content of the GitHub helper files directly
echo "Content of githubSearchOrgs.ts:"
cat backend/src/api/integration/helpers/githubSearchOrgs.ts

echo -e "\nContent of githubSearchRepos.ts:"
cat backend/src/api/integration/helpers/githubSearchRepos.ts

echo -e "\nContent of githubOrgRepos.ts:"
cat backend/src/api/integration/helpers/githubOrgRepos.ts

Length of output: 1736


Script:

#!/bin/bash
# Let's examine the GithubIntegrationService implementation
echo "Searching for GithubIntegrationService implementation..."
fd "githubIntegrationService" backend/src/services/

echo -e "\nChecking content of GithubIntegrationService..."
cat backend/src/services/githubIntegrationService.ts

Length of output: 2227

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (7)
frontend/src/config/integrations/github/components/settings/github-settings-mapping.vue (3)

36-45: Enhance table accessibility.

The table header lacks proper ARIA attributes for better screen reader support.

 <thead>
-  <tr>
+  <tr role="row">
-    <th class="w-5/12">
+    <th class="w-5/12" role="columnheader" scope="col">
       Repository
     </th>
-    <th class="w-7/12">
+    <th class="w-7/12" role="columnheader" scope="col">
       Mapped with
     </th>
   </tr>
 </thead>

65-65: Consider optimizing bulk mapping update.

Using the spread operator for bulk updates might cause unnecessary re-renders. Consider using Object.assign or a more targeted update approach.

-@apply="repoMappings = { ...repoMappings, ...$event }"
+@apply="Object.assign(repoMappings, $event)"

117-118: Optimize filteredRepos computed property.

The current implementation creates new strings on each computation. Consider moving toLowerCase() calls outside the filter.

-const filteredRepos = computed(() => repos.value.filter((r) => r.name.toLowerCase().includes(search.value.toLowerCase())
-    || (r.org?.name || '').toLowerCase().includes(search.value.toLowerCase())));
+const filteredRepos = computed(() => {
+  const searchTerm = search.value.toLowerCase();
+  return repos.value.filter((r) => {
+    const repoName = r.name.toLowerCase();
+    const orgName = (r.org?.name || '').toLowerCase();
+    return repoName.includes(searchTerm) || orgName.includes(searchTerm);
+  });
+});
frontend/src/config/integrations/github/components/settings/github-settings-repo-item.vue (4)

65-65: Specify the type for 'subprojects' prop instead of using 'any[]'

Using any[] for the subprojects prop undermines type safety. Defining a specific interface improves code readability and maintainability.

Define an interface for Subproject and update the prop type:

+ interface Subproject {
+   id: string;
+   name: string;
+ }

 const props = defineProps<{
   repositories: GitHubRepository[];
   repository: GitHubRepository;
-  subprojects: any[];
+  subprojects: Subproject[];
   modelValue: string;
   orgSyncing: boolean;
 }>();

70-71: Refine 'defineEmits' for better TypeScript compatibility

The current defineEmits usage with an object type is less optimal. Using the function syntax enhances type inference and code clarity.

Update defineEmits as follows:

 const emit = defineEmits<{
-  (e: 'update:repositories', value: GitHubRepository[]): void,
-  (e: 'update:modelValue', value: string): void
+  'update:repositories': (value: GitHubRepository[]) => void;
+  'update:modelValue': (value: string) => void;
 }>();

104-108: Consolidate multiple <script> blocks into one

Having two <script> blocks can cause confusion and is not recommended. Merge them into a single block for better organization.

Remove the second <script> block and set the component name using defineOptions:

- </script>

- <script lang="ts">
- export default {
-   name: 'LfGithubSettingsRepoItem',
- };
+ defineOptions({
+   name: 'LfGithubSettingsRepoItem',
+ });
 </script>

24-38: Enhance accessibility of the select component

Adding an aria-label or associating the select with a label improves accessibility for users relying on assistive technologies.

Apply this diff to include an accessible label:

 <el-select
   v-model="model"
   placeholder="Select sub-project"
+  aria-label="Sub-project"
   class="w-full"
   placement="bottom-end"
   filterable
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 45eae0f and c0b1616.

📒 Files selected for processing (2)
  • frontend/src/config/integrations/github/components/settings/github-settings-mapping.vue (1 hunks)
  • frontend/src/config/integrations/github/components/settings/github-settings-repo-item.vue (1 hunks)
🔇 Additional comments (2)
frontend/src/config/integrations/github/components/settings/github-settings-mapping.vue (2)

135-139: LGTM!

The component definition follows Vue.js best practices.


48-49: ⚠️ Potential issue

Add type safety check for organization property.

The v-for binding assumes repository objects always have an organization, but the type GitHubSettingsRepository might allow null/undefined organizations. Consider adding a filter or type guard.

-v-for="(repo) of o.repositories"
+v-for="(repo) of o.repositories.filter(r => r.org)"

Likely invalid or redundant comment.

repositories: GitHubSettingsRepository[];
organizations: GitHubOrganization[];
mappings: Record<string, string>;
subprojects: any[];
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace 'any' type with a proper interface.

Using 'any' type reduces type safety. Consider creating a proper interface for subprojects.

-subprojects: any[];
+interface Subproject {
+  id: string;
+  name: string;
+  // Add other required properties
+}
+
+subprojects: Subproject[];

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +120 to +132
const allOrganizations = computed<any[]>(() => {
const owners = new Set();
return filteredRepos.value.reduce((acc: any[], r) => {
if (!owners.has(r.org!.name)) {
owners.add(r.org!.name);
acc.push({
...(r.org!),
repositories: props.repositories.filter((repo) => repo.org!.url === r.org!.url),
});
}
return acc;
}, []);
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve type safety and performance in allOrganizations computed property.

The current implementation has several issues:

  1. Uses 'any' type in reduce accumulator
  2. Uses non-null assertions without proper type guards
  3. Performs unnecessary filtering on each computation
-const allOrganizations = computed<any[]>(() => {
+interface OrganizationWithRepos extends GitHubOrganization {
+  repositories: GitHubSettingsRepository[];
+}
+
+const allOrganizations = computed<OrganizationWithRepos[]>(() => {
   const owners = new Set();
-  return filteredRepos.value.reduce((acc: any[], r) => {
-    if (!owners.has(r.org!.name)) {
-      owners.add(r.org!.name);
+  return filteredRepos.value.reduce((acc: OrganizationWithRepos[], r) => {
+    if (!r.org?.name || owners.has(r.org.name)) {
+      return acc;
+    }
+    owners.add(r.org.name);
       acc.push({
-        ...(r.org!),
-        repositories: props.repositories.filter((repo) => repo.org!.url === r.org!.url),
+        ...r.org,
+        repositories: props.repositories.filter((repo) => repo.org?.url === r.org.url),
       });
-    }
     return acc;
   }, []);
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const allOrganizations = computed<any[]>(() => {
const owners = new Set();
return filteredRepos.value.reduce((acc: any[], r) => {
if (!owners.has(r.org!.name)) {
owners.add(r.org!.name);
acc.push({
...(r.org!),
repositories: props.repositories.filter((repo) => repo.org!.url === r.org!.url),
});
}
return acc;
}, []);
});
interface OrganizationWithRepos extends GitHubOrganization {
repositories: GitHubSettingsRepository[];
}
const allOrganizations = computed<OrganizationWithRepos[]>(() => {
const owners = new Set();
return filteredRepos.value.reduce((acc: OrganizationWithRepos[], r) => {
if (!r.org?.name || owners.has(r.org.name)) {
return acc;
}
owners.add(r.org.name);
acc.push({
...r.org,
repositories: props.repositories.filter((repo) => repo.org?.url === r.org.url),
});
return acc;
}, []);
});

Comment on lines +99 to +100
model.value = props.subprojects[0].id;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Check for empty 'subprojects' array before accessing elements

Accessing props.subprojects[0] without verifying the array's length can lead to runtime errors if the array is empty.

Apply this diff to add a safety check:

 watch(() => model.value, (value) => {
   if (!value) {
-    model.value = props.subprojects[0].id;
+    if (props.subprojects.length > 0) {
+      model.value = props.subprojects[0].id;
+    } else {
+      model.value = '';
+    }
   }
 }, { immediate: true });

Committable suggestion skipped: line range outside the PR's diff.

@@ -0,0 +1,108 @@
<template>
<tr class="!border-0">
<td class="!pb-2.5" :class="ri > 0 ? '!pt-2.5' : '!pt-5'">
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Undefined variable 'ri' in template

The variable ri used in the template is not defined within the component, which will lead to a runtime error.

Apply this diff to correct the issue by defining the variable or using the correct reference:

- <td class="!pb-2.5" :class="ri > 0 ? '!pt-2.5' : '!pt-5'">
+ <td class="!pb-2.5" :class="index > 0 ? '!pt-2.5' : '!pt-5'">

Ensure that index is properly defined and passed to the component.

Committable suggestion skipped: line range outside the PR's diff.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (5)
frontend/src/config/integrations/github/components/settings/github-settings-drawer.vue (5)

40-40: Move inline styles to CSS class

The box-shadow styling should be moved to a CSS class for better maintainability and consistency.

-<div class="border-t border-gray-100 py-5 px-6 flex justify-end gap-4" style="box-shadow: 0 -4px 4px 0 rgba(0, 0, 0, 0.05)">
+<div class="border-t border-gray-100 py-5 px-6 flex justify-end gap-4 drawer-footer-shadow">

Add to your stylesheet:

.drawer-footer-shadow {
  box-shadow: 0 -4px 4px 0 rgba(0, 0, 0, 0.05);
}

44-50: Enhance button disabled state validation

The current disabled state only checks for form validation and repositories length. Consider adding loading state handling during the connection process to prevent multiple submissions.

 <lf-button
   type="primary"
-  :disabled="$v.$invalid || !repositories.length"
+  :disabled="$v.$invalid || !repositories.length || isConnecting"
   @click="connect()"
 >
   {{ props.integration ? 'Update settings' : 'Connect' }}
 </lf-button>

Add isConnecting ref to the setup script:

const isConnecting = ref(false);

76-80: Consider using more specific types for GitHub entities

The GitHub-related types could be more specific to improve type safety and maintainability.

-  GitHubSettings, GitHubSettingsOrganization, GitHubSettingsRepository,
+  GitHubSettings,
+  GitHubSettingsOrganization,
+  GitHubSettingsRepository,
+  GitHubApiResponse, // Add this if not exists

Consider creating an interface for API responses:

interface GitHubApiResponse {
  id: string;
  segmentId: string;
  status: 'in-progress' | 'connected' | 'failed';
  // Add other relevant fields
}

105-108: Initialize state with proper typing and default values

The state initialization could be more robust with proper typing and default values.

-const subprojects = ref([]);
-const organizations = ref<GitHubOrganization[]>([]);
-const repositories = ref<GitHubSettingsRepository[]>([]);
-const repoMappings = ref<Record<string, string>>({});
+const subprojects = ref<Array<{ id: string; name: string }>>([]);
+const organizations = ref<GitHubOrganization[]>([]);
+const repositories = ref<GitHubSettingsRepository[]>([]);
+const repoMappings = ref<Record<string, string>>({});

227-229: Add error handling to mounted hook

The fetchSubProjects call in onMounted should include error handling.

 onMounted(() => {
-  fetchSubProjects();
+  fetchSubProjects().catch((error) => {
+    console.error('Error fetching subprojects:', error);
+    Message.error('Failed to load subprojects');
+  });
 });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c0b1616 and 3b1276e.

📒 Files selected for processing (1)
  • frontend/src/config/integrations/github/components/settings/github-settings-drawer.vue (2 hunks)

Comment on lines 154 to 189
const connect = () => {
const data = { ...form.value };
ConfirmDialog({
type: 'warning',
title: 'Are you sure you want to proceed?',
message:
'Repository mapping is not reversible. Once GitHub is connected, you wont be able to update these settings.\n\n'
+ 'Reconnecting a different organization and/or repositories won’t remove past activities. '
+ 'In order to clean up existing data please reach out to our support team.',
confirmButtonText: 'Connect GitHub',
cancelButtonText: 'Cancel',
icon: 'ri-alert-fill',
} as any)
let integration: any = null;
const settings: GitHubSettings = buildSettings();
(props.integration?.id
? IntegrationService.update(props.integration.id, { settings })
: IntegrationService.create({ settings, platform: 'github', status: 'in-progress' }))
.then((res) => {
integration = res;
return IntegrationService.githubMapRepos(res.id, repoMappings.value, [res.segmentId]);
})
.then(() => {
IntegrationService.githubMapRepos(props.integration.id, data, [props.integration.segmentId])
.then(() => {
isDrawerVisible.value = false;

doFetch([props.integration.segmentId]);

trackEvent({
key: FeatureEventKey.CONNECT_INTEGRATION,
type: EventType.FEATURE,
properties: {
integration: Platform.GITHUB,
},
});

showIntegrationProgressNotification('github', props.integration.segmentId);

router.push({
name: 'integration',
params: {
id: props.integration.segmentId,
},
});
})
.catch(() => {
Message.error(
'There was an error mapping github repos',
);
});
doFetch([integration.segmentId]);

trackEvent({
key: FeatureEventKey.CONNECT_INTEGRATION,
type: EventType.FEATURE,
properties: {
integration: Platform.GITHUB,
},
});

if (integration.status === 'in-progress') {
showIntegrationProgressNotification('github', integration.segmentId);
} else {
Message.success(props.integration?.id
? 'Settings have been updated'
: 'GitHub has been connected successfully');
}

isDrawerVisible.value = false;
})
.catch(() => {
Message.error(props.integration?.id
? 'There was error updating settings'
: 'There was error connecting GitHub');
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve error handling and type safety in connect method

The connect method could benefit from better error handling and type safety:

  1. The integration variable is typed as any
  2. Error handling is generic and could be more specific
  3. Loading state is not managed
+interface ConnectResponse {
+  id: string;
+  segmentId: string;
+  status: 'in-progress' | 'connected' | 'failed';
+}

 const connect = () => {
-  let integration: any = null;
+  let integration: ConnectResponse | null = null;
+  isConnecting.value = true;

   const settings: GitHubSettings = buildSettings();
   (props.integration?.id
     ? IntegrationService.update(props.integration.id, { settings })
     : IntegrationService.create({ settings, platform: 'github', status: 'in-progress' }))
     .then((res) => {
       integration = res;
       return IntegrationService.githubMapRepos(res.id, repoMappings.value, [res.segmentId]);
     })
     .then(() => {
       doFetch([integration!.segmentId]);
       // ... rest of success handling
     })
-    .catch(() => {
+    .catch((error: Error) => {
+      console.error('GitHub connection error:', error);
       Message.error(props.integration?.id
-        ? 'There was error updating settings'
-        ? 'There was error connecting GitHub');
+        ? `Error updating settings: ${error.message}`
+        : `Error connecting GitHub: ${error.message}`);
+    })
+    .finally(() => {
+      isConnecting.value = false;
     });
 };

Committable suggestion skipped: line range outside the PR's diff.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (4)
services/libs/integrations/src/integrations/github/processData.ts (4)

197-212: Consider extracting company name parsing logic

The company name parsing logic could be extracted into a separate helper function for better maintainability and reusability.

+const parseCompanyName = (company: string): string => {
+  return company.replace('@', '').trim()
+}

 if (org && company.length > 0) {
-  const company = memberData.company.replace('@', '').trim()
+  const parsedCompany = parseCompanyName(memberData.company)
   const organizationPayload: IOrganization = {
     displayName: org.login,
     // ... rest of the payload
   }

310-317: Remove commented-out code

If this code is no longer needed, it should be removed. If it's intended for future use, please add a TODO comment explaining why it's kept.


Line range hint 682-727: Consider using a map for event handlers

The switch statement could be replaced with a map of event types to their handlers, making it more maintainable and easier to extend.

+const eventHandlers = new Map<GithubActivityType, ProcessDataHandler>([
+  [GithubActivityType.STAR, parseStar],
+  [GithubActivityType.FORK, parseFork],
+  // ... other handlers
+]);

 const handler: ProcessDataHandler = async (ctx) => {
   const data = ctx.data as any
   const event = data?.type as GithubActivityType

   if (event) {
-    switch (event) {
-      case GithubActivityType.STAR:
-        await parseStar(ctx)
-        break
-      // ... other cases
-    }
+    const eventHandler = eventHandlers.get(event);
+    if (eventHandler) {
+      await eventHandler(ctx);
+    } else {
+      await ctx.abortWithError(`Event not supported '${event}'!`);
+    }
   } else {
     await ctx.abortWithError('No event type found in data!')
   }
 }

654-677: Consider batch processing commits for better performance

The current implementation processes commits sequentially. Consider batch processing commits to improve performance when handling large push events.

-for (const commit of data.payload.commits) {
-  const activity: IActivityData = {
-    // ... activity construction
-  }
-  await ctx.publishActivity(activity)
-}
+const activities = data.payload.commits.map(commit => ({
+  channel: apiData.repo.url,
+  // ... rest of activity construction
+}));
+await Promise.all(activities.map(activity => ctx.publishActivity(activity)));
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3b1276e and 8ed8aac.

📒 Files selected for processing (1)
  • services/libs/integrations/src/integrations/github/processData.ts (15 hunks)
🔇 Additional comments (2)
services/libs/integrations/src/integrations/github/processData.ts (2)

4-12: LGTM! Enhanced type safety with Snowflake types

The addition of proper type definitions from the Snowflake package improves type safety and makes the code more maintainable.


663-671: Verify if commit attributes are still needed

The commented-out attributes contain valuable metadata about the commit (insertions, deletions, lines changed). Please verify if these attributes are still required for the application's functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants