Merge pull request #105 from revsys/version-library-m2m

Add a ManyToMany on Library to Version
This commit is contained in:
Frank Wiles
2023-02-03 11:07:07 -06:00
committed by GitHub
7 changed files with 215 additions and 1 deletions

View File

@@ -104,6 +104,22 @@ For production, execute:
$ yarn build
```
## Generating Fake Data
### Versions and LibraryVersions
First, make sure your `GITHUB_TOKEN` is set in you `.env` file and run `./manage.py update_libraries`. This takes a long time. See below.
Run `./manage.py generate_fake_versions`. This will create 50 active Versions, and associate Libraries to them.
The data created is realistic-looking in that each Library will contain a M2M relationship to every Version newer than the oldest one it's included in. (So if a Library's earliest LibraryVersion is 1.56.0, then there will be a LibraryVersion object for that Library for each Version since 1.56.0 was released.)
This does not add VersionFile objects to the Versions.
### Libraries, Pull Requests, and Issues
There is not currently a way to generate fake Libraries, Issues, or Pull Requests. To generate those, use your GitHub token and run `./manage.py update_libraries` locally to pull in live GitHub data. This command takes a long time to run; you might consider editing `libraries/github.py` to add counters and breaks to shorten the runtime.
## Deploying
TDB

View File

@@ -1,6 +1,6 @@
from django.contrib import admin
from .models import Category, Issue, Library, PullRequest
from .models import Category, Issue, Library, LibraryVersion, PullRequest
@admin.register(Category)
@@ -26,6 +26,13 @@ class LibraryAdmin(admin.ModelAdmin):
return obj.active_development
@admin.register(LibraryVersion)
class LibraryVersionAdmin(admin.ModelAdmin):
list_display = ["library", "version"]
list_filter = ["library", "version"]
search_fields = ["library__name", "version__name"]
@admin.register(Issue)
class IssueAdmin(admin.ModelAdmin):
list_display = ["title", "number", "is_open", "closed"]

View File

@@ -0,0 +1,55 @@
import djclick as click
import random
from datetime import timedelta
from django.utils import timezone
from faker import Faker
from libraries.models import Library, LibraryVersion
from versions.models import Version
fake = Faker()
@click.command()
def command():
"""
Create Version objects and attach libraries to them.
"""
# Create versions
release_date = timezone.now() - timedelta(days=3650)
for i in range(30, 80):
version, created = Version.objects.get_or_create(
name=f"1.{i}.0",
defaults={
"release_date": release_date,
"description": fake.paragraph(nb_sentences=2),
"active": True,
},
)
if created:
click.secho(f"Version {version.name} created succcessfully", fg="green")
else:
click.secho(f"Version {version.name} already exists.")
delta = random.choice(range(20, 50))
release_date += timedelta(delta)
for library in Library.objects.all():
# Select the starting version randomly
start_version = Version.objects.order_by("?").first()
# Add a LibraryVersion for each Version newer than the starting version
for version in Version.objects.filter(
release_date__gt=start_version.release_date
):
lib_version, created = LibraryVersion.objects.get_or_create(
library=library, version=version
)
if created:
click.secho(f"---{lib_version} created succcessfully", fg="green")
else:
click.secho(f"LibraryVersion {lib_version} already exists.")
click.secho("All done!", fg="green")

View File

@@ -0,0 +1,56 @@
# Generated by Django 3.2.2 on 2023-01-30 18:30
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("versions", "0005_version_active"),
("libraries", "0003_library_slug"),
]
operations = [
migrations.CreateModel(
name="LibraryVersion",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"library",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="library_version",
to="libraries.library",
),
),
(
"version",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="library_version",
to="versions.version",
),
),
],
),
migrations.AddField(
model_name="library",
name="versions",
field=models.ManyToManyField(
related_name="libraries",
through="libraries.LibraryVersion",
to="versions.Version",
),
),
]

View File

@@ -43,6 +43,9 @@ class Library(models.Model):
blank=True,
null=True,
)
versions = models.ManyToManyField(
"versions.Version", through="libraries.LibraryVersion", related_name="libraries"
)
cpp_standard_minimum = models.CharField(max_length=50, blank=True, null=True)
active_development = models.BooleanField(default=True, db_index=True)
@@ -89,6 +92,24 @@ class Library(models.Model):
return self.github_properties()["repo"]
class LibraryVersion(models.Model):
version = models.ForeignKey(
"versions.Version",
related_name="library_version",
on_delete=models.SET_NULL,
null=True,
)
library = models.ForeignKey(
"libraries.Library",
related_name="library_version",
on_delete=models.SET_NULL,
null=True,
)
def __str__(self):
return f"{self.library.name} ({self.version.name})"
class Issue(models.Model):
"""
Model that tracks Library repository issues in Github

View File

@@ -18,6 +18,21 @@ def library(db):
)
@pytest.fixture
def library_version(library, version):
return baker.make("libraries.LibraryVersion", library=library, version=version)
@pytest.fixture
def issue(library):
return baker.make("libraries.Issue", library=library)
@pytest.fixture
def pull_request(library):
return baker.make("libraries.PullRequest", library=library)
@pytest.fixture(autouse=True)
def github_api_get_ref_response(db):
"""Returns a JSON example of GhApi().api.git.get_ref(owner=owner, repo=repo, ref=ref)"""

View File

@@ -1,3 +1,6 @@
from model_bakery import baker
def test_github_properties(library):
properties = library.github_properties()
assert properties["owner"] == "boostorg"
@@ -10,3 +13,44 @@ def test_github_owner(library):
def test_github_repo(library):
assert library.github_repo == "multi_array"
def test_category_creation(category):
assert category.name is not None
def test_library_creation(library):
assert library.versions.count() == 0
def test_issue_creation(issue, library):
assert issue.library == library
def test_pull_request_creation(pull_request, library):
assert pull_request.library == library
def test_library_version_creation(library_version, library, version):
assert library_version.library == library
assert library_version.version == version
def test_library_version_str(library_version, library, version):
assert str(library_version) == f"{library.name} ({version.name})"
def test_library_version_multiple_versions(library, library_version):
assert library.versions.count() == 1
assert library.versions.filter(
library_version__version=library_version.version
).exists()
other_version = baker.make("versions.Version")
new_library_version = baker.make(
"libraries.LibraryVersion", library=library, version=other_version
)
assert library.versions.count() == 2
assert library.versions.filter(
library_version__version=library_version.version
).exists()
assert library.versions.filter(library_version__version=other_version).exists()