Multi-platform: support multiple files per version #201
BIN
extensions/tests/files/addon-with-split-platforms-windows.zip
Normal file
BIN
extensions/tests/files/addon-with-split-platforms-windows.zip
Normal file
Binary file not shown.
@ -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'],
|
||||||
|
)
|
||||||
|
@ -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',
|
||||||
|
@ -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,11 +220,16 @@ 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']
|
||||||
version = extension.create_version_from_file(
|
if version := extension.versions.filter(version=manifest_version).first():
|
||||||
file=file_instance,
|
version.add_file(file_instance)
|
||||||
release_notes=release_notes,
|
version.release_notes = release_notes
|
||||||
)
|
version.save(update_fields={'release_notes'})
|
||||||
|
else:
|
||||||
|
version = extension.create_version_from_file(
|
||||||
|
file=file_instance,
|
||||||
|
release_notes=release_notes,
|
||||||
|
)
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
{
|
{
|
||||||
|
@ -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')
|
||||||
|
@ -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(
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user