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

✨ Link schemas in the repository and continuously update the ERD #941

Merged
merged 8 commits into from
Mar 21, 2025

Conversation

NoritakaIkeda
Copy link
Member

@NoritakaIkeda NoritakaIkeda commented Mar 19, 2025 β€’

Issue

  • resolve:

Why is this change needed?

2025-03-21.18.28.58.mov

What would you like reviewers to focus on?

Testing Verification

What was done

πŸ€– Generated by PR Agent at 4f12f89

  • Introduced ERD (Entity-Relationship Diagram) rendering for GitHub repositories.
    • Added ERDViewer component for rendering database structures.
    • Integrated GitHub API to fetch repository and file content.
  • Refactored GitHub API utilities for better caching and error handling.
    • Replaced getFileContent with a cached version.
    • Added getRepository utility for repository metadata retrieval.
  • Enhanced migration detail page with ERD links.
    • Dynamically generated links to ERD diagrams for matched schema files.
    • Updated styles and layout for better user experience.
  • Fixed metadata generation errors by avoiding notFound calls.

Detailed Changes

Relevant files
Enhancement
api.server.ts
Refactor GitHub API utilities with caching                             

frontend/apps/app/libs/github/api.server.ts

  • Added getRepository and cached getFileContent functions.
  • Refactored getFileContent for better error handling and caching.
  • Removed the old getFileContent implementation.
  • +53/-32 
    processSavePullRequest.ts
    Update `processSavePullRequest` to use cached API               

    frontend/apps/app/src/functions/processSavePullRequest.ts

  • Updated getFileContent usage to use the new cached version.
  • Adjusted parameters for getFileContent calls.
  • +3/-5     
    MigrationDetailPage.module.css
    Add styles for ERD links                                                                 

    frontend/apps/app/features/migrations/pages/MigrationDetailPage/MigrationDetailPage.module.css

  • Added styles for ERD link elements.
  • Enhanced hover effects for ERD links.
  • +12/-0   
    erdViewer.tsx
    Add `ERDViewer` component for database visualization         

    frontend/apps/app/app/(app)/app/projects/[projectId]/erd/[branchOrCommit]/[...slug]/erdViewer.tsx

  • Added ERDViewer component for rendering database structures.
  • Integrated ERDRenderer and cookie consent functionality.
  • +61/-0   
    page.tsx
    Implement ERD page with GitHub integration                             

    frontend/apps/app/app/(app)/app/projects/[projectId]/erd/[branchOrCommit]/[...slug]/page.tsx

  • Implemented ERD page for rendering database structures.
  • Integrated GitHub API for fetching repository and file content.
  • Added error handling for missing files and unsupported formats.
  • +216/-0 
    MigrationDetailPage.tsx
    Add ERD links to migration detail page                                     

    frontend/apps/app/features/migrations/pages/MigrationDetailPage/MigrationDetailPage.tsx

  • Added ERD links to migration detail page.
  • Integrated GitHub API for pull request details and file matching.
  • Enhanced migration content fetching with schema file patterns.
  • +58/-1   

    Additional Notes


    Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • Copy link

    changeset-bot bot commented Mar 19, 2025 β€’

    ⚠️ No Changeset found

    Latest commit: b875be4

    Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

    This PR includes no changesets

    When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

    Click here to learn what changesets are, and how to add one.

    Click here if you're a maintainer who wants to add a changeset to this PR

    Copy link

    vercel bot commented Mar 19, 2025 β€’

    The latest updates on your projects. Learn more about Vercel for Git β†—οΈŽ

    Name Status Preview Comments Updated (UTC)
    liam-app βœ… Ready (Inspect) Visit Preview πŸ’¬ Add feedback Mar 21, 2025 11:43am
    liam-erd-sample βœ… Ready (Inspect) Visit Preview πŸ’¬ Add feedback Mar 21, 2025 11:43am
    4 Skipped Deployments
    Name Status Preview Comments Updated (UTC)
    liam-docs ⬜️ Ignored (Inspect) Visit Preview Mar 21, 2025 11:43am
    test-liam-app ⬜️ Ignored (Inspect) Mar 21, 2025 11:43am
    test-liam-docs ⬜️ Ignored (Inspect) Mar 21, 2025 11:43am
    test-liam-erd-sample ⬜️ Ignored (Inspect) Mar 21, 2025 11:43am

    Copy link

    supabase bot commented Mar 19, 2025 β€’

    Updates to Preview Branch (migration-erd) β†—οΈŽ

    Deployments Status Updated
    Database βœ… Fri, 21 Mar 2025 11:40:05 UTC
    Services βœ… Fri, 21 Mar 2025 11:40:05 UTC
    APIs βœ… Fri, 21 Mar 2025 11:40:05 UTC

    Tasks are run on every commit but only new migration files are pushed.
    Close and reopen this PR if you want to apply changes from existing seed or migration files.

    Tasks Status Updated
    Configurations βœ… Fri, 21 Mar 2025 11:40:06 UTC
    Migrations βœ… Fri, 21 Mar 2025 11:40:06 UTC
    Seeding βœ… Fri, 21 Mar 2025 11:40:06 UTC
    Edge Functions βœ… Fri, 21 Mar 2025 11:40:06 UTC

    View logs for this Workflow Run β†—οΈŽ.
    Learn more about Supabase for Git β†—οΈŽ.

    Comment on lines 120 to 151
    export const getFileContent = async (
    installationId: number,
    owner: string,
    repo: string,
    path: string,
    ref?: string,
    ): Promise<string> => {
    const octokit = await createOctokit(installationId)

    try {
    const response = await octokit.repos.getContent({
    owner,
    repo,
    path,
    ref,
    })

    // The GitHub API returns the file content encoded in Base64
    if ('content' in response.data && !Array.isArray(response.data)) {
    const content = Buffer.from(response.data.content, 'base64').toString(
    'utf-8',
    )
    return content
    }

    throw new Error('Not a file or file content not available')
    } catch (error) {
    console.error(`Error fetching file content for ${path}:`, error)
    throw error
    }
    }

    Copy link
    Member Author

    Choose a reason for hiding this comment

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

    Merged the parallel implementations of getRepository that were developed concurrently.

    Comment on lines 98 to +106
    const content = await getFileContent(
    Number(repository.installationId),
    repository.owner,
    repository.name,
    `${repository.owner}/${repository.name}`,
    file.filename,
    prDetails.head.ref,
    Number(repository.installationId),
    )

    return {
    filename: file.filename,
    content,
    content: content ?? '',
    Copy link
    Member Author

    Choose a reason for hiding this comment

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

    As a result of merging the parallel implementations of getRepository that were developed concurrently, I also updated the usage accordingly.

    Copy link
    Member Author

    Choose a reason for hiding this comment

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

    Based on the implementation in this file, I updated the code to fetch file data from the GitHub API instead.

    Copy link
    Member Author

    Choose a reason for hiding this comment

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

    The implementation is almost the same as in erdViewer.tsx.

    @NoritakaIkeda NoritakaIkeda marked this pull request as ready for review March 21, 2025 09:49
    @NoritakaIkeda NoritakaIkeda requested a review from a team as a code owner March 21, 2025 09:49
    @NoritakaIkeda NoritakaIkeda requested review from hoshinotsuyoshi, FunamaYukina, junkisai, MH4GF and sasamuku and removed request for a team March 21, 2025 09:49
    Copy link
    Contributor

    PR Reviewer Guide πŸ”

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 3 πŸ”΅πŸ”΅πŸ”΅βšͺβšͺ
    πŸ§ͺ No relevant tests
    πŸ”’ No security concerns identified
    ⚑ Recommended focus areas for review

    Error Handling

    The new getFileContent function returns null on error instead of throwing exceptions. This changes error handling behavior which might affect dependent code that expects exceptions.

    export const getFileContent = cache(
      async (
        repositoryFullName: string,
        filePath: string,
        ref: string,
        installationId: number,
      ): Promise<string | null> => {
        const [owner, repo] = repositoryFullName.split('/')
    
        if (!owner || !repo) {
          console.error('Invalid repository format:', repositoryFullName)
          return null
        }
    
        const octokit = await createOctokit(installationId)
    
        try {
          const { data } = await octokit.repos.getContent({
            owner,
            repo,
            path: filePath,
            ref,
          })
    
          if ('type' in data && data.type === 'file' && 'content' in data) {
            return Buffer.from(data.content, 'base64').toString('utf-8')
          }
    
          console.warn('Not a file:', filePath)
          return null
        } catch (error) {
          console.error(`Error fetching file content for ${filePath}:`, error)
          return null
        }
      },
    Potential Error

    The code sets prism.wasm path using path.resolve with process.cwd(), which might not work correctly in production environments where the working directory could be different.

    setPrismWasmUrl(path.resolve(process.cwd(), 'prism.wasm'))
    
    Error Suppression

    The catch block at the end of the Page component catches all errors with a generic _error variable but doesn't log the actual error, making debugging difficult.

    } catch (_error) {
      return (
        <ERDViewer
          dbStructure={blankDbStructure}
          defaultSidebarOpen={false}
          errorObjects={[
            {
              name: 'GitHubError',
              message: 'Failed to fetch file content from GitHub',
              instruction:
                'Please check your repository permissions and try again.',
            },
          ]}
        />
      )
    }
    

    Copy link
    Contributor

    qodo-merge-pro-for-open-source bot commented Mar 21, 2025 β€’

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Fix path resolution issue

    The path.resolve(process.cwd(), 'prism.wasm') will likely fail in production
    environments where the current working directory might differ from what's
    expected. Consider using a path relative to the application's root or a public
    URL.

    frontend/apps/app/app/(app)/app/projects/[projectId]/erd/[branchOrCommit]/[...slug]/page.tsx [142]

    -setPrismWasmUrl(path.resolve(process.cwd(), 'prism.wasm'))
    +setPrismWasmUrl('/prism.wasm') // Use a path relative to the public directory
    • Apply this suggestion
    Suggestion importance[1-10]: 9

    __

    Why: The suggestion addresses a critical path resolution issue that would likely cause the application to fail in production environments. Using an absolute path with process.cwd() is unreliable as the working directory can vary between environments.

    High
    General
    Improve error reporting

    Sending every parsing error to Sentry could potentially flood your error
    tracking system. Consider adding context to the errors or implementing rate
    limiting for these errors.

    frontend/apps/app/app/(app)/app/projects/[projectId]/erd/[branchOrCommit]/[...slug]/page.tsx [171-174]

     const { value: dbStructure, errors } = await parse(content, format)
    -for (const error of errors) {
    -  Sentry.captureException(error)
    +if (errors.length > 0) {
    +  Sentry.withScope((scope) => {
    +    scope.setContext('parsing', { 
    +      filePath, 
    +      format, 
    +      errorCount: errors.length 
    +    });
    +    Sentry.captureException(new Error(`Schema parsing errors in ${filePath}`));
    +  });
     }
    • Apply this suggestion
    Suggestion importance[1-10]: 7

    __

    Why: The suggestion significantly improves error reporting by adding context to Sentry errors and preventing potential flooding of the error tracking system. This enhances debugging capabilities while maintaining system performance.

    Medium
    • Update

    Copy link
    Member

    @MH4GF MH4GF left a comment

    Choose a reason for hiding this comment

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

    LGTM πŸ‘πŸ»

    errorObjects={errorObjects}
    />
    </VersionProvider>
    {isShowCookieConsent && <CookieConsent />}
    Copy link
    Member

    Choose a reason for hiding this comment

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

    This CookieConsent should be enabled on all pages, so it should be moved to layout.tsx.

    Comment on lines +40 to +47
    const versionData = {
    version: '0.1.0', // NOTE: no maintained version for ERD Web
    gitHash: process.env.NEXT_PUBLIC_GIT_HASH,
    envName: process.env.NEXT_PUBLIC_ENV_NAME,
    date: process.env.NEXT_PUBLIC_RELEASE_DATE,
    displayedOn: 'web',
    }
    const version = v.parse(versionSchema, versionData)
    Copy link
    Member

    Choose a reason for hiding this comment

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

    I would like to commonize with Liam ERD side.

    key={path}
    href={path}
    className={styles.erdLink}
    aria-label={`View ERD diagram for ${filename}`}
    Copy link
    Member

    Choose a reason for hiding this comment

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

    Is this necessary?

    Copy link
    Member Author

    Choose a reason for hiding this comment

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

    Not needed here, so I removed it πŸ™†

    @NoritakaIkeda NoritakaIkeda added this pull request to the merge queue Mar 21, 2025
    Merged via the queue into main with commit bb45e51 Mar 21, 2025
    20 checks passed
    @NoritakaIkeda NoritakaIkeda deleted the migration-erd branch March 21, 2025 11:51
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    2 participants