Skip to content

Comments

chore: intake migration#5950

Merged
pushya22 merged 4 commits intopreviewfrom
chore/intake-migration
Nov 5, 2024
Merged

chore: intake migration#5950
pushya22 merged 4 commits intopreviewfrom
chore/intake-migration

Conversation

@NarayanBavisetti
Copy link
Collaborator

@NarayanBavisetti NarayanBavisetti commented Nov 4, 2024

Summary by CodeRabbit

  • New Features

    • Introduced new fields across various models: is_disabled in DeployBoard, extra and source_email in InboxIssue, and bot_type in User.
    • Added new choice "intake" in DeployBoard's type options.
  • Improvements

    • Modified existing fields to allow for more flexible data entry, including nullable and blank options for entity_name in DeployBoard and source in InboxIssue.
    • Enhanced uniqueness constraints for the Label model to improve data integrity.
  • Bug Fixes

    • Adjusted constraints to prevent issues with label uniqueness based on project and deletion status.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2024

Walkthrough

This pull request introduces a migration that modifies the database schema for several models, including label, deployboard, inboxissue, and user. It removes and adds unique constraints on the label model, introduces new fields in the deployboard, inboxissue, and user models, and modifies existing fields to allow for more flexible data handling. The changes aim to refine the relationships and constraints within the data model.

Changes

File Path Change Summary
apiserver/plane/db/migrations/0084_remove_label_label_unique_name_project_when_deleted_at_null_and_more.py - Removed unique constraint on label model based on deleted_at.
- Added unique constraints for label model: unique_name_when_project_null_and_not_deleted and unique_project_name_when_not_deleted.
- Added fields: is_disabled in deployboard, extra and source_email in inboxissue, bot_type in user.
- Modified fields: entity_name and source in respective models.
apiserver/plane/db/models/deploy_board.py - Added choice "intake" in TYPE_CHOICES.
- Updated entity_name to allow null and blank.
- Added field is_disabled (default False).
apiserver/plane/db/models/inbox.py - Updated source from TextField to CharField with default value "IN_APP".
- Added fields: source_email (nullable) and extra (JSONField with default empty dict).
apiserver/plane/db/models/label.py - Updated unique constraints for label model to reflect new logic.
apiserver/plane/db/models/user.py - Added field bot_type (nullable, max length 30).

Possibly related PRs

Suggested reviewers

  • pablohashescobar
  • sriramveeraghanta

🐰 In the garden, changes bloom,
Labels shift, creating room.
Deployboards can now be still,
Inbox issues, new fields fill.
Users welcome bots with cheer,
A brighter model, oh so clear! 🌼


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
Contributor

@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 (6)
apiserver/plane/db/models/deploy_board.py (2)

46-46: Add docstring for is_disabled field

Consider adding a comment to document the purpose and implications of disabling a deploy board.

+    # Indicates whether this deploy board is currently disabled/inactive
     is_disabled = models.BooleanField(default=False)

Line range hint 23-46: Consider backwards compatibility and migration strategy

The changes to entity_name constraints and the addition of disable functionality represent significant architectural changes that might affect:

  1. API consumers expecting entity_name to match TYPE_CHOICES
  2. UI components that rely on non-null entity names
  3. Existing deploy boards in the database

Consider:

  • Documenting these changes in API documentation
  • Adding data migration to handle existing records
  • Updating related services/components to handle nullable entity names
apiserver/plane/db/models/label.py (1)

24-35: Add docstring explaining the label uniqueness rules.

Consider adding a docstring to the Meta class explaining the two types of labels (global vs project-specific) and their uniqueness rules for better maintainability.

     class Meta:
+        """
+        Label uniqueness rules:
+        1. Global labels (project=NULL): Must have unique names across workspace
+        2. Project labels: Must have unique names within their project
+        Note: Soft-deleted labels (deleted_at not NULL) don't count towards uniqueness
+        """
         constraints = [
apiserver/plane/db/migrations/0084_remove_label_label_unique_name_project_when_deleted_at_null_and_more.py (2)

21-25: Document the purpose of is_disabled field.

The addition of is_disabled to the Deployboard model needs clarification:

  • What triggers a board to be disabled?
  • What functionality is affected when disabled?
  • Is this for soft deletion or feature flagging?

Consider adding these details to the model's docstring.

Also applies to: 43-47


36-42: Enhance bot_type field implementation.

Consider the following improvements for the bot_type field:

  1. Add choices to validate bot types
  2. Add an index if this field will be frequently queried
  3. Document the purpose and possible values

Example implementation:

BOT_TYPE_CHOICES = [
    ("GITHUB", "GitHub Bot"),
    ("SLACK", "Slack Bot"),
    # add other bot types
]

bot_type = models.CharField(
    "Bot Type",
    max_length=30,
    choices=BOT_TYPE_CHOICES,
    blank=True,
    null=True,
    db_index=True  # if frequently queried
)
apiserver/plane/db/models/user.py (1)

110-115: Consider adding validation and documentation for bot types.

To ensure data consistency and improve maintainability:

  1. Define choices for valid bot types
  2. Add validation to ensure bot_type is only set when is_bot=True
  3. Document the supported bot types and their purposes

Example implementation:

+    BOT_TYPE_CHOICES = (
+        ('github', 'GitHub Bot'),
+        ('gitlab', 'GitLab Bot'),
+        ('custom', 'Custom Bot'),
+    )
+
     bot_type = models.CharField(
         max_length=30,
         verbose_name="Bot Type",
         blank=True,
         null=True,
+        choices=BOT_TYPE_CHOICES,
+        help_text="Type of bot (only applicable when is_bot=True)"
     )

+    def clean(self):
+        super().clean()
+        if self.bot_type and not self.is_bot:
+            raise ValidationError({'bot_type': 'Bot type can only be set for bot users'})
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f205d72 and 8e3bc83.

📒 Files selected for processing (5)
  • apiserver/plane/db/migrations/0084_remove_label_label_unique_name_project_when_deleted_at_null_and_more.py (1 hunks)
  • apiserver/plane/db/models/deploy_board.py (2 hunks)
  • apiserver/plane/db/models/inbox.py (1 hunks)
  • apiserver/plane/db/models/label.py (1 hunks)
  • apiserver/plane/db/models/user.py (1 hunks)
🔇 Additional comments (5)
apiserver/plane/db/models/deploy_board.py (1)

23-23: LGTM: New intake type follows existing pattern

The addition of the "intake" type follows the established naming convention and integrates well with existing types.

apiserver/plane/db/models/label.py (1)

24-35: LGTM! Verify data compliance with new constraints.

The new constraints properly handle both global labels and project-specific labels while maintaining soft-delete functionality. This is a good improvement in data modeling.

Let's verify existing data compliance:

✅ Verification successful

Let me generate new scripts to better verify the changes since the previous attempt used ast-grep incorrectly for SQL queries.


Let me check for migrations related to these constraint changes with a more specific search.


Let me check the specific migration that handles these label constraints.


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

✓ Label constraint changes are properly implemented with migration

The changes to the Label model's unique constraints are well-structured and properly implemented:

  1. The migration file (0084) correctly:

    • Removes the old constraint
    • Adds two new constraints with proper conditions
    • Handles the transition cleanly
  2. The API views handle labels appropriately:

    • WorkspaceLabelsEndpoint for workspace-level operations
    • LabelViewSet with proper project-based permissions
    • BulkCreateIssueLabelsEndpoint with admin-only access

The split between global and project-specific label constraints is a valid improvement in data modeling.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential constraint violations in existing data
# Note: This helps identify any data that needs cleanup before applying migration

# Test 1: Check for duplicate global label names (where project is NULL)
echo "Checking for duplicate global label names..."
ast-grep --pattern 'SELECT name, COUNT(*) as count
FROM labels 
WHERE project_id IS NULL 
  AND deleted_at IS NULL 
GROUP BY name 
HAVING COUNT(*) > 1;'

# Test 2: Check for duplicate names within same project
echo "Checking for duplicate names within projects..."
ast-grep --pattern 'SELECT project_id, name, COUNT(*) as count
FROM labels 
WHERE project_id IS NOT NULL 
  AND deleted_at IS NULL 
GROUP BY project_id, name 
HAVING COUNT(*) > 1;'

Length of output: 541


Script:

#!/bin/bash
# Let's analyze the codebase to understand the label model and its usage

# Check the complete label model definition
echo "=== Label Model Definition ==="
rg -A 20 "class Label" apiserver/plane/db/models/label.py

# Check for any migrations related to these constraint changes
echo -e "\n=== Related Migrations ==="
fd -e py -x grep -l "Label" {} apiserver/plane/db/migrations/

# Check for any tests related to label uniqueness
echo -e "\n=== Label Tests ==="
fd -e py -x grep -l "Label.*unique" {} tests/

# Check for API endpoints handling label creation/updates
echo -e "\n=== Label API Usage ==="
rg "Label\." apiserver/plane/api/views/

Length of output: 46256


Script:

#!/bin/bash
# Let's find and examine recent migrations that might contain these constraint changes
echo "=== Recent Migrations ==="
fd -e py -x grep -l "UniqueConstraint.*name.*project" {} apiserver/plane/db/migrations/

# Check for any existing constraints in the migrations
echo -e "\n=== Constraint Details in Migrations ==="
rg -A 5 "UniqueConstraint.*name.*project" apiserver/plane/db/migrations/

# Check for any related migration operations
echo -e "\n=== Migration Operations ==="
rg "RemoveConstraint|AddConstraint" apiserver/plane/db/migrations/

Length of output: 30205


Script:

#!/bin/bash
# Check the content of the migration file that modifies label constraints
echo "=== Label Constraint Migration ==="
cat apiserver/plane/db/migrations/0084_remove_label_label_unique_name_project_when_deleted_at_null_and_more.py

# Check for any label-related views that might handle label creation/updates
echo -e "\n=== Label Views ==="
rg -A 10 "class.*Label" apiserver/plane/app/views/

Length of output: 5296

apiserver/plane/db/models/inbox.py (1)

60-65: Verify data compatibility with new CharField constraints.

The change from TextField to CharField(max_length=255) is a good practice for fixed-length strings. However, we should verify that existing data complies with the new length constraint.

✅ Verification successful

Change from TextField to CharField(max_length=255) is safe to proceed

Based on the evidence found:

  • The source field is primarily used with "IN_APP" as the default value
  • The only direct usage found in views sets the source as "in-app" (in inbox.py)
  • Migration file 0084 shows this change was already properly migrated with the same constraints
  • No instances of source values exceeding 255 characters were found in the codebase

The change is well-structured and maintains backward compatibility while improving data constraints.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any existing source values that might exceed the new 255 character limit
echo "Checking for source values exceeding 255 characters..."
ast-grep --pattern 'class InboxIssue($$$)' | rg -A 2 'source.*TextField'

# Look for any hardcoded source values in the codebase that might not match "IN_APP"
echo "Checking for hardcoded source values..."
rg -g '*.py' 'source.*=.*(?!IN_APP)["\''][^\'"]+["\']' 

Length of output: 376


Script:

#!/bin/bash
# Let's try a different approach to find source field usage and values

# Check for the original model definition
echo "Original model definition:"
rg -A 10 "class InboxIssue" apiserver/plane/db/models/inbox.py

# Look for any source field assignments or filters in views/APIs
echo -e "\nSource field usage in views and APIs:"
rg -g '*.py' -B 2 -A 2 'source.*=.*["\''][^\'"]+["\']' apiserver/plane

# Check for any migrations related to InboxIssue
echo -e "\nRelated migrations:"
fd -g '*migrations*.py' -x rg -l "InboxIssue" {}

# Look for any tests setting the source field
echo -e "\nSource field in tests:"
fd -g '*test*.py' -x rg -l "source.*=.*[\"'][^\"']+[\"']" {}

Length of output: 680


Script:

#!/bin/bash
# Let's try one final approach with simpler commands

# Check for migrations containing source field
echo "Checking migrations:"
rg -g '*migrations*.py' 'source.*=.*models\.' apiserver/plane/db/migrations/

# Look for source field usage in views
echo -e "\nChecking views for source field usage:"
rg -g '*.py' 'source' apiserver/plane/api/views/

# Check for any API filters or queries using source
echo -e "\nChecking API filters and queries:"
rg -g '*.py' 'source' apiserver/plane/api/filters/
rg -g '*.py' 'source' apiserver/plane/api/serializers/

# Look for any default values or constraints
echo -e "\nChecking for source field constraints:"
rg -g '*.py' '"IN_APP"' apiserver/plane/

Length of output: 7551

apiserver/plane/db/migrations/0084_remove_label_label_unique_name_project_when_deleted_at_null_and_more.py (1)

13-20: Verify data integrity before applying label constraint changes.

The modification of label uniqueness constraints is a breaking change. The new constraints enforce:

  1. Unique names for global labels (when project is null)
  2. Unique names within each project

Please ensure existing data complies with these new constraints before applying the migration.

Also applies to: 55-74

✅ Verification successful

Based on the examination of migration 0084, I can now provide a definitive response about the label constraint changes:

The constraint changes are safe to apply

The migration makes the following changes to label constraints:

  1. Removes the old constraint label_unique_name_project_when_deleted_at_null
  2. Clears the unique_together constraint
  3. Adds two new conditional unique constraints:
    • Global labels (project=null): unique name when not deleted
    • Project labels: unique name within project when not deleted

These changes maintain the same uniqueness rules but implement them more explicitly using Django's conditional constraints. There are no data migrations that could affect label data integrity, and the constraints are equivalent to the previous ones.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential constraint violations in existing data

# Find duplicate label names where project is null and not deleted
echo "Checking for duplicate global labels..."
psql -c "
SELECT name, COUNT(*) 
FROM db_label 
WHERE project_id IS NULL 
AND deleted_at IS NULL 
GROUP BY name 
HAVING COUNT(*) > 1;"

# Find duplicate label names within same project where not deleted
echo "Checking for duplicate project labels..."
psql -c "
SELECT project_id, name, COUNT(*) 
FROM db_label 
WHERE project_id IS NOT NULL 
AND deleted_at IS NULL 
GROUP BY project_id, name 
HAVING COUNT(*) > 1;"

Length of output: 626


Script:

#!/bin/bash
# Let's analyze the migration history and model definitions to understand the context better

# Check the previous migration to understand the old constraints
echo "Previous migration (0083):"
fd "0083.*\.py" apiserver/plane/db/migrations/ --exec cat {}

# Check the Label model definition
echo -e "\nLabel model definition:"
rg -A 10 "^class Label\(" apiserver/plane/db/migrations/

# Look for any existing unique constraints on Label model
echo -e "\nExisting unique constraints:"
rg "unique_together.*=.*\{.*'label'.*\}" apiserver/plane/db/migrations/
rg "UniqueConstraint.*model='label'" apiserver/plane/db/migrations/

Length of output: 44495


Script:

#!/bin/bash
# Let's check the Label model definition and constraints in the models.py file
echo "Label model definition in models.py:"
rg -A 15 "^class Label\(" apiserver/plane/db/models.py

# Check for any existing data migrations related to Label model
echo -e "\nLabel-related migrations:"
fd ".*\.py" apiserver/plane/db/migrations/ --exec grep -l "Label" {}

# Look for any SQL operations or data migrations
echo -e "\nSQL operations in migrations:"
rg "migrations\.RunSQL|migrations\.RunPython" apiserver/plane/db/migrations/

Length of output: 6815


Script:

#!/bin/bash
# Let's examine the specific migrations that define Label constraints
echo "Checking migration 0001_initial.py for Label model:"
rg -A 10 "name='Label'," apiserver/plane/db/migrations/0001_initial.py

echo -e "\nChecking migration 0084 for complete changes:"
cat apiserver/plane/db/migrations/0084_remove_label_label_unique_name_project_when_deleted_at_null_and_more.py

# Check if there are any data migrations between these that modify Label data
echo -e "\nChecking for Label data modifications in migrations:"
for file in $(fd ".*\.py" apiserver/plane/db/migrations/); do
  if grep -l "Label" "$file" > /dev/null; then
    echo "=== $file ==="
    rg "RunPython.*Label" "$file" || true
  fi
done

Length of output: 16271

apiserver/plane/db/models/user.py (1)

110-115: LGTM! The field addition looks good.

The bot_type field is properly defined with appropriate nullable constraints, making it a safe migration.

Comment on lines +29 to +30
null=True,
blank=True,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Restore type safety for entity_name field

The removal of choices=TYPE_CHOICES while adding null=True, blank=True introduces several concerns:

  1. Loss of type safety - values are no longer validated against TYPE_CHOICES
  2. Potential conflict with unique constraints when null values are introduced
  3. No validation mechanism to ensure values align with defined types

Consider one of these solutions:

entity_name = models.CharField(
    max_length=30,
-   null=True,
-   blank=True,
+   choices=TYPE_CHOICES,
+   null=True,  # if null values are really needed
+   blank=True, # if blank values are really needed
)

Or if flexible values are required, add a validator:

+from django.core.validators import RegexValidator
+
entity_name = models.CharField(
    max_length=30,
    null=True,
    blank=True,
+   validators=[RegexValidator(
+       regex='^(project|issue|module|cycle|page|view|intake)$',
+       message='entity_name must match one of the defined types',
+   )]
)

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

null=True,
blank=True,
)
source_email = models.TextField(blank=True, null=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider JSONField default value implementation.

While the new fields are well-structured, using a mutable default (dict) for JSONField can lead to unexpected behavior. Consider using a callable default instead.

-    extra = models.JSONField(default=dict)
+    extra = models.JSONField(default=dict)
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        if self.extra is None:
+            self.extra = {}

Also, consider adding validation for the source_email field if it's intended to store email addresses:

+    def clean(self):
+        super().clean()
+        if self.source_email:
+            from django.core.validators import validate_email
+            validate_email(self.source_email)

Also applies to: 69-69

Comment on lines +48 to +54
migrations.AlterField(
model_name="inboxissue",
name="source",
field=models.CharField(
blank=True, default="IN_APP", max_length=255, null=True
),
),
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add choices for source field.

The source field should have predefined choices to maintain data consistency, especially since "IN_APP" is a default value.

Consider adding choices like:

SOURCE_CHOICES = [
    ("IN_APP", "In App"),
    ("EMAIL", "Email"),
    # add other sources
]

Comment on lines +27 to +30
model_name="inboxissue",
name="extra",
field=models.JSONField(default=dict),
),
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix mutable default in JSONField.

Using default=dict for JSONField is dangerous as it creates a mutable default that's shared between instances.

Replace with:

-field=models.JSONField(default=dict),
+field=models.JSONField(default=dict()),

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚙️backend 🔄migrations Contains Migration changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants