Skip to content

Commit 1f882b4

Browse files
committed
Add a new table to hold project URLs
1 parent af4f0b6 commit 1f882b4

File tree

4 files changed

+94
-0
lines changed

4 files changed

+94
-0
lines changed

tests/unit/forklift/test_legacy.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3091,6 +3091,7 @@ def test_upload_succeeds_creates_release(
30913091
]
30923092
assert set(release.requires_dist) == {"foo", "bar (>1.0)"}
30933093
assert set(release.project_urls) == {"Test, https://example.com/"}
3094+
assert release.project_urls_new == {"Test": "https://example.com/"}
30943095
assert set(release.requires_external) == {"Cheese (>1.0)"}
30953096
assert set(release.provides) == {"testing"}
30963097
assert release.version == expected_version

warehouse/forklift/legacy.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,12 @@ def file_upload(request):
11231123
request.db.add(missing_classifier)
11241124
release_classifiers.append(missing_classifier)
11251125

1126+
# Parse the Project URLs structure into a key/value dict
1127+
project_urls = {
1128+
name.strip(): url.strip()
1129+
for name, url in (us.split(",", 1) for us in form.project_urls.data)
1130+
}
1131+
11261132
release = Release(
11271133
project=project,
11281134
_classifiers=release_classifiers,
@@ -1151,6 +1157,7 @@ def file_upload(request):
11511157
html=rendered or "",
11521158
rendered_by=readme.renderer_version(),
11531159
),
1160+
project_urls_new=project_urls,
11541161
**{
11551162
k: getattr(form, k).data
11561163
for k in {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
"""
13+
add ReleaseURL
14+
15+
Revision ID: 7a8c380cefa4
16+
Revises: d1c00b634ac8
17+
Create Date: 2022-06-10 22:02:49.522320
18+
"""
19+
20+
import sqlalchemy as sa
21+
22+
from alembic import op
23+
from sqlalchemy.dialects import postgresql
24+
25+
revision = "7a8c380cefa4"
26+
down_revision = "d1c00b634ac8"
27+
28+
29+
def upgrade():
30+
op.create_table(
31+
"release_urls",
32+
sa.Column(
33+
"id",
34+
postgresql.UUID(as_uuid=True),
35+
server_default=sa.text("gen_random_uuid()"),
36+
nullable=False,
37+
),
38+
sa.Column("release_id", postgresql.UUID(as_uuid=True), nullable=False),
39+
sa.Column("name", sa.String(length=32), nullable=False),
40+
sa.Column("url", sa.Text(), nullable=False),
41+
sa.ForeignKeyConstraint(
42+
["release_id"], ["releases.id"], onupdate="CASCADE", ondelete="CASCADE"
43+
),
44+
sa.PrimaryKeyConstraint("id"),
45+
sa.UniqueConstraint("release_id", "name"),
46+
)
47+
op.create_index(
48+
op.f("ix_release_urls_release_id"), "release_urls", ["release_id"], unique=False
49+
)
50+
51+
52+
def downgrade():
53+
op.drop_index(op.f("ix_release_urls_release_id"), table_name="release_urls")
54+
op.drop_table("release_urls")

warehouse/packaging/models.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
ForeignKey,
3232
Index,
3333
Integer,
34+
String,
3435
Table,
3536
Text,
3637
UniqueConstraint,
@@ -43,6 +44,7 @@
4344
from sqlalchemy.ext.declarative import declared_attr # type: ignore
4445
from sqlalchemy.ext.hybrid import hybrid_property
4546
from sqlalchemy.orm import validates
47+
from sqlalchemy.orm.collections import attribute_mapped_collection
4648
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
4749
from sqlalchemy.sql import expression
4850
from trove_classifiers import sorted_classifiers
@@ -323,6 +325,22 @@ class Description(db.Model):
323325
rendered_by = Column(Text, nullable=False)
324326

325327

328+
class ReleaseURL(db.Model):
329+
330+
__tablename__ = "release_urls"
331+
__table_args__ = (UniqueConstraint("release_id", "name", name="uix_1"),)
332+
__repr__ = make_repr("name", "url")
333+
334+
release_id = Column(
335+
ForeignKey("releases.id", onupdate="CASCADE", ondelete="CASCADE"),
336+
nullable=False,
337+
index=True,
338+
)
339+
340+
name = Column(String(32), nullable=False)
341+
url = Column(Text, nullable=False)
342+
343+
326344
class Release(db.Model):
327345

328346
__tablename__ = "releases"
@@ -396,6 +414,20 @@ def __table_args__(cls): # noqa
396414
)
397415
classifiers = association_proxy("_classifiers", "classifier")
398416

417+
_project_urls_new = orm.relationship(
418+
ReleaseURL,
419+
backref="release",
420+
collection_class=attribute_mapped_collection("name"),
421+
cascade="all, delete-orphan",
422+
order_by=lambda: ReleaseURL.name.asc(),
423+
passive_deletes=True,
424+
)
425+
project_urls_new = association_proxy(
426+
"_project_urls_new",
427+
"url",
428+
creator=lambda k, v: ReleaseURL(name=k, url=v), # type: ignore
429+
)
430+
399431
files = orm.relationship(
400432
"File",
401433
backref="release",

0 commit comments

Comments
 (0)