Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions core/apps.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
import logging

from django.apps import AppConfig
from django.core.management import call_command
from shared.helpers.cache import RedisBackend

from services.redis_configuration import get_redis_connection
from utils.cache import cache
from utils.config import RUN_ENV

logger = logging.getLogger(__name__)


class CoreConfig(AppConfig):
name = "core"

def ready(self):
import core.signals # noqa: F401

if RUN_ENV == "DEV":
Copy link
Contributor

Choose a reason for hiding this comment

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

Remind me, what's the plan to seed prod then?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

already seeded via Django Admin, and will be kept up to date there as well

try:
# Call your management command here
call_command(
"insert_data_to_db_from_csv",
"core/management/commands/codecovTiers-Jan25.csv",
"--model",
"tiers",
)
call_command(
"insert_data_to_db_from_csv",
"core/management/commands/codecovPlans-Jan25.csv",
"--model",
"plans",
)
except Exception as e:
logger.error(f"Failed to run startup command: {e}")

if RUN_ENV not in ["DEV", "TESTING"]:
cache_backend = RedisBackend(get_redis_connection())
cache.configure(cache_backend)
14 changes: 14 additions & 0 deletions core/management/commands/codecovPlans-Jan25.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"id","created_at","updated_at","base_unit_price","benefits","billing_rate","is_active","marketing_name","max_seats","monthly_uploads_limit","paid_plan","name","tier_id","stripe_id"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Jan 25 corresponds to January 2025

10,2025-01-16 04:40:55.162 -0800,2025-01-24 11:33:46.043 -0800,0,"{""Configurable # of users"",""Unlimited public repositories"",""Unlimited private repositories""}",,true,Developer,,,false,users-trial,6,
9,2025-01-16 04:39:59.759 -0800,2025-01-24 11:34:10.038 -0800,10,"{""Configurable # of users"",""Unlimited public repositories"",""Unlimited private repositories"",""Priority Support""}",annually,true,Enterprise Cloud,,,true,users-enterprisey,4,price_1LmjzwGlVGuVgOrkIwlM46EU
8,2025-01-16 04:39:15.877 -0800,2025-01-24 11:34:31.904 -0800,12,"{""Configurable # of users"",""Unlimited public repositories"",""Unlimited private repositories"",""Priority Support""}",monthly,true,Enterprise Cloud,,,true,users-enterprisem,4,price_1LmjypGlVGuVgOrkzKtNqhwW
7,2025-01-16 04:38:12.544 -0800,2025-01-24 11:34:53.935 -0800,4,"{""Up to 10 users"",""Unlimited repositories"",""2500 private repo uploads"",""Patch coverage analysis""}",annually,true,Team,10,2500,true,users-teamy,2,price_1NrlXiGlVGuVgOrkgMTw5yno
6,2025-01-16 04:37:08.918 -0800,2025-01-24 11:35:15.346 -0800,5,"{""Up to 10 users"",""Unlimited repositories"",""2500 private repo uploads"",""Patch coverage analysis""}",monthly,true,Team,10,2500,true,users-teamm,2,price_1NqPKdGlVGuVgOrkm9OFvtz8
5,2025-01-16 04:35:34.152 -0800,2025-01-24 11:35:42.724 -0800,10,"{""Includes 5 seats"",""$10 per additional seat"",""Unlimited public repositories"",""Unlimited private repositories"",""Priority Support""}",annually,true,Sentry Pro,5,,true,users-sentryy,5,price_1MlYAYGlVGuVgOrke9SdbBUn
4,2025-01-16 04:34:33.867 -0800,2025-01-24 11:35:48.218 -0800,12,"{""Includes 5 seats"",""$10 per additional seat"",""Unlimited public repositories"",""Unlimited private repositories"",""Priority Support""}",monthly,true,Sentry Pro,5,,true,users-sentrym,5,price_1MlY9yGlVGuVgOrkHluurBtJ
Copy link
Contributor

Choose a reason for hiding this comment

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

sentryy unit price should be 10

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I might be missing something, I believe that's the case already :O

But I think you're right about pro plan being off users-pr-inappy having the incorrect price

3,2025-01-16 04:32:44.655 -0800,2025-01-24 11:36:09.660 -0800,12,"{""Configurable # of users"",""Unlimited public repositories"",""Unlimited private repositories"",""Priority Support""}",annually,true,Pro,,,true,users-pr-inappy,3,price_1Gv2COGlVGuVgOrkuOYVLIj7
2,2025-01-16 04:30:42.897 -0800,2025-01-24 11:36:14.651 -0800,12,"{""Configurable # of users"",""Unlimited public repositories"",""Unlimited private repositories"",""Priority Support""}",monthly,true,Pro,,,true,users-pr-inappm,3,price_1Gv2B8GlVGuVgOrkFnLunCgc
13,2025-01-23 14:25:04.793 -0800,2025-01-23 14:25:04.793 -0800,12,"{""Configurable # of users"",""Unlimited public repositories"",""Unlimited private repositories""}",,true,Github Marketplace,,,false,users,3,
12,2025-01-16 04:44:51.064 -0800,2025-01-24 11:33:14.405 -0800,0,"{""Up to 1 user"",""Unlimited public repositories"",""Unlimited private repositories""}",,true,Developer,1,250,false,users-developer,2,
11,2025-01-16 04:44:01.249 -0800,2025-01-24 11:33:28.532 -0800,0,"{""Up to 1 user"",""Unlimited public repositories"",""Unlimited private repositories""}",,true,Developer,1,250,false,users-basic,1,
1,2025-01-16 04:26:44.776 -0800,2025-01-24 11:36:32.387 -0800,0,"{""Up to 1 user"",""Unlimited public repositories"",""Unlimited private repositories""}",,false,Developer,1,,false,users-free,1,
7 changes: 7 additions & 0 deletions core/management/commands/codecovTiers-Jan25.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"id","created_at","updated_at","tier_name","bundle_analysis","test_analytics","flaky_test_detection","project_coverage","private_repo_support"
2,2025-01-16 04:22:06.838 -0800,2025-01-16 04:22:06.838 -0800,team,true,true,false,false,true
3,2025-01-16 04:22:47.221 -0800,2025-01-16 04:22:47.221 -0800,pro,true,true,true,true,true
4,2025-01-16 04:22:59.652 -0800,2025-01-16 04:22:59.652 -0800,enterprise,true,true,true,true,true
5,2025-01-16 04:23:08.585 -0800,2025-01-16 04:23:08.585 -0800,sentry,true,true,true,true,true
1,2025-01-16 04:21:40.374 -0800,2025-01-16 07:34:49.139 -0800,basic,true,true,false,true,true
6,2025-01-23 14:23:21.504 -0800,2025-01-23 14:23:21.504 -0800,trial,true,true,true,true,true
71 changes: 71 additions & 0 deletions core/management/commands/insert_data_to_db_from_csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import csv

from django.core.management.base import BaseCommand
from shared.django_apps.codecov_auth.models import Plan, Tier


class Command(BaseCommand):
help = "Insert data from a CSV file into the database for either plans or tiers"

def add_arguments(self, parser):
parser.add_argument("csv_file", type=str, help="The path to the CSV file")
parser.add_argument(
"--model",
type=str,
choices=["plans", "tiers"],
required=True,
help="Specify the model to insert data into: plans or tiers",
)

def handle(self, *args, **kwargs):
csv_file_path = kwargs["csv_file"]
model_choice = kwargs["model"]

# Determine which model to use
if model_choice == "plans":
Model = Plan
elif model_choice == "tiers":
Model = Tier
else:
self.stdout.write(self.style.ERROR("Invalid model choice"))
return

with open(csv_file_path, newline="") as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
model_data = {
field: self.convert_value(value)
for field, value in row.items()
if field in [f.name for f in Model._meta.fields]
}

# Handle ForeignKey for tier
if "tier_id" in row and model_choice == "plans":
try:
model_data["tier"] = Tier.objects.get(id=row["tier_id"])
except Tier.DoesNotExist:
self.stdout.write(
self.style.ERROR(
f"Tier with id {row['tier_id']} does not exist. Skipping row."
)
)
continue

Model.objects.create(**model_data)
self.stdout.write(self.style.SUCCESS(f"Inserted row: {row}"))

self.stdout.write(
self.style.SUCCESS(
f"Successfully inserted all data into {model_choice} from CSV"
)
)

def convert_value(self, value):
"""Convert CSV string values to appropriate Python types."""
if value == "":
return None
if value.lower() == "true":
return True
if value.lower() == "false":
return False
return value
61 changes: 61 additions & 0 deletions core/tests/test_management_commands.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import csv
import os
import tempfile
import unittest.mock as mock
from io import StringIO

import pytest
from django.core.management import call_command
from shared.config import ConfigHelper
from shared.django_apps.codecov_auth.models import Plan, Tier
from shared.django_apps.core.tests.factories import OwnerFactory, RepositoryFactory

from services.redis_configuration import get_redis_connection
Expand Down Expand Up @@ -121,3 +125,60 @@ def test_delete_rate_limit_keys_ip_option():
# Get rid of lingering keys
redis.delete("rl-user:1")
redis.delete("rl-ip:2")


@pytest.mark.django_db
def test_insert_data_to_db_from_csv_for_plans():
# Create a temporary CSV file
with tempfile.NamedTemporaryFile(mode="w", delete=False, newline="") as temp_csv:
writer = csv.writer(temp_csv)
writer.writerow(
["name", "marketing_name", "base_unit_price", "tier_id", "is_active"]
)
writer.writerow(["Plan A", "Marketing A", "100", "1", "true"])
writer.writerow(["Plan B", "Marketing B", "200", "2", "false"])
csv_path = temp_csv.name

Tier.objects.create(tier_name="Tier 1")
Tier.objects.create(tier_name="Tier 2")

out = StringIO()
call_command("insert_data_to_db_from_csv", csv_path, "--model", "plans", stdout=out)

# Check the output
assert "Successfully inserted all data into plans from CSV" in out.getvalue()

# Verify the data was inserted correctly
assert Plan.objects.filter(
name="Plan A",
).exists()
assert Plan.objects.filter(
name="Plan B",
).exists()

# Clean up the temporary file
os.remove(csv_path)


@pytest.mark.django_db
def test_insert_data_to_db_from_csv_for_tiers():
# Create a temporary CSV file
with tempfile.NamedTemporaryFile(mode="w", delete=False, newline="") as temp_csv:
writer = csv.writer(temp_csv)
writer.writerow(["tier_name"])
writer.writerow(["Tier 1"])
writer.writerow(["Tier 2"])
csv_path = temp_csv.name

out = StringIO()
call_command("insert_data_to_db_from_csv", csv_path, "--model", "tiers", stdout=out)

# Check the output
assert "Successfully inserted all data into tiers from CSV" in out.getvalue()

# Verify the data was inserted correctly
assert Tier.objects.filter(tier_name="Tier 1").exists()
assert Tier.objects.filter(tier_name="Tier 2").exists()

# Clean up the temporary file
os.remove(csv_path)
Loading