Multi-platform: support multiple files per version #201

Merged
Oleg-Komarov merged 43 commits from multi-os into main 2024-07-09 16:27:46 +02:00
7 changed files with 77 additions and 9 deletions
Showing only changes of commit 06c939defb - Show all commits

View File

@ -239,7 +239,8 @@ class VersionUploadAPITest(APITestCase):
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual( self.assertEqual(
response.data['message'], response.data['message'],
f'Extension "{other_extension.extension_id}" not maintained by user "{self.user.username}"', f'Extension "{other_extension.extension_id}" not maintained by user '
f'"{self.user.username}"',
) )
def test_version_upload_extension_does_not_exist(self): def test_version_upload_extension_does_not_exist(self):
@ -289,3 +290,59 @@ class VersionUploadAPITest(APITestCase):
self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.token.refresh_from_db() self.token.refresh_from_db()
self.assertIsNotNone(self.token.date_last_access) self.assertIsNotNone(self.token.date_last_access)
def test_multiplatform_upload(self):
extension = create_version(
metadata__id="some_addon",
metadata__version="0.0.1",
user=self.user,
).extension
file_linux = TEST_FILES_DIR / 'addon-with-split-platforms-linux.zip'
file_windows = TEST_FILES_DIR / 'addon-with-split-platforms-windows.zip'
with open(file_linux, 'rb') as version_file:
response = self.client.post(
self._get_upload_url('some_addon'),
{
'version_file': version_file,
'release_notes': 'only linux',
},
format='multipart',
HTTP_AUTHORIZATION=f'Bearer {self.token_key}',
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.json())
extension.refresh_from_db()
self.assertEqual(extension.latest_version.files.count(), 1)
self.assertEqual(extension.latest_version.platforms.count(), 1)
with open(file_windows, 'rb') as version_file:
response = self.client.post(
self._get_upload_url('some_addon'),
{
'version_file': version_file,
'release_notes': 'linux and windows',
},
format='multipart',
HTTP_AUTHORIZATION=f'Bearer {self.token_key}',
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.json())
extension.refresh_from_db()
self.assertEqual(extension.latest_version.release_notes, 'linux and windows')
self.assertEqual(extension.latest_version.files.count(), 2)
self.assertEqual(extension.latest_version.platforms.count(), 2)
with open(file_windows, 'rb') as version_file:
response = self.client.post(
self._get_upload_url('some_addon'),
{
'version_file': version_file,
'release_notes': 'linux and windows',
},
format='multipart',
HTTP_AUTHORIZATION=f'Bearer {self.token_key}',
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.json())
self.assertEqual(
response.data['message']['version_file'],
[f'{extension.latest_version} already has files for windows-x64'],
)

View File

@ -80,7 +80,7 @@ EXPECTED_EXTENSION_DATA = {
'version_str': '0.1.0', 'version_str': '0.1.0',
'slug': 'some-addon', 'slug': 'some-addon',
}, },
'addon-with-split-platforms.zip': { 'addon-with-split-platforms-linux.zip': {
'metadata': { 'metadata': {
'tagline': 'Some add-on tag line', 'tagline': 'Some add-on tag line',
'name': 'Some Add-on', 'name': 'Some Add-on',

View File

@ -210,6 +210,8 @@ class UploadExtensionVersionView(APIView):
form.fields['source'].initial = version_file form.fields['source'].initial = version_file
if not form.is_valid(): if not form.is_valid():
if 'source' in form.errors:
form.errors['version_file'] = form.errors.pop('source')
return Response({'message': form.errors}, status=status.HTTP_400_BAD_REQUEST) return Response({'message': form.errors}, status=status.HTTP_400_BAD_REQUEST)
with transaction.atomic(): with transaction.atomic():
@ -218,7 +220,12 @@ class UploadExtensionVersionView(APIView):
file_instance.user = user file_instance.user = user
file_instance.save() file_instance.save()
# FIXME check if version already exists, then append file and update release_notes manifest_version = file_instance.metadata['version']
if version := extension.versions.filter(version=manifest_version).first():
version.add_file(file_instance)
version.release_notes = release_notes
version.save(update_fields={'release_notes'})
else:
version = extension.create_version_from_file( version = extension.create_version_from_file(
file=file_instance, file=file_instance,
release_notes=release_notes, release_notes=release_notes,

View File

@ -178,7 +178,10 @@ class File(CreatedModifiedMixin, TrackChangesMixin, models.Model):
} }
def platforms(self): def platforms(self):
data = self.metadata return self.parse_platforms_from_manifest(self.metadata)
@classmethod
def parse_platforms_from_manifest(self, data):
build_generated_platforms = None build_generated_platforms = None
if 'build' in data and 'generated' in data['build']: if 'build' in data and 'generated' in data['build']:
build_generated_platforms = data['build']['generated'].get('platforms') build_generated_platforms = data['build']['generated'].get('platforms')

View File

@ -16,6 +16,7 @@ from extensions.models import (
) )
from constants.base import EXTENSION_TYPE_SLUGS_SINGULAR, EXTENSION_TYPE_CHOICES from constants.base import EXTENSION_TYPE_SLUGS_SINGULAR, EXTENSION_TYPE_CHOICES
from files.utils import guess_mimetype_from_ext, guess_mimetype_from_content from files.utils import guess_mimetype_from_ext, guess_mimetype_from_content
import files.models
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -197,7 +198,7 @@ class ExtensionVersionManifestValidator:
# check for platforms # check for platforms
# TODO test coverage # TODO test coverage
available_platforms = version.get_available_platforms() available_platforms = version.get_available_platforms()
if platforms := manifest.get('platforms', None): if platforms := files.models.File.parse_platforms_from_manifest(manifest):
if diff := set(platforms) - available_platforms: if diff := set(platforms) - available_platforms:
raise ValidationError( raise ValidationError(
{ {