[PATCH 4/6] views: Add 'series' parameter to '/mbox' endpoint
Daniel Axtens
dja at axtens.net
Fri Feb 3 08:42:52 AEDT 2017
Hi Stephen,
>> > This allows a user to download dependencies for a patch without
>> > having
>> > to do it manually.
>>
>> I'm not sold on the idea of calling these dependencies and allowing
>> downloads of partial series. It just seems to present the user with
>> an
>> dazzling array of ways to shoot themselves in the foot - for example
>> I
>> can imagine a lot of users clicking at the start of a series or
>> midway
>> into a series and downloading an mbox, not realising that if they
>> want
>> the entire series of patches they need to explicitly find the final
>> patch and download the mbox from there... What was your rationale or
>> inteded use-case for this? (I'm happier to expose it programatically,
>> I
>> guess, it's just more complexity we have to carry around...)
>
> While I have this exposed in the UI in a later patch, this feature is
> mainly intended for use in testing. I'm of the opinion that when
> testing patches, you should test each and every one individually and
> preserve bisectability. This is an approach rooted in my experiences
> with Gerrit, where individual changes are king and are evaluated on
> their own merits. This contrasts with the approach favoured by tools
> such as GitHub, where the individual changes are abstracted in favour
> of an overall "pull request".
>
> I do think "dependencies" is the correct term to use here, and I would
> like to be able to download a patch from the middle of a series with
> all patches below it included for use in testing at least. However,
> this has been a concern for other folks too and there are clear
> benefits to both approaches. Perhaps we could provide a solution to
> both problems by also providing a series mbox download URL? For
> example:
>
> /patch/5/?series=1
> /series/1/mbox/
>
> In this case, the first link will download patch 5 plus any
> dependencies from series 1 (ignoring patch 6+), while the latter will
> download the entirety of series 1. We could expose both in the UI, or
> we could expose just the full series link.
OK, between you and some more testing-oriented co-workers I'm now
convinced. Lets provide an API to get patch + dependencies (and lets go
with that nomenclature), and a separate endpoint to get an entire
series. I suspect from a UI point of view we need only expose the series
download, but we can bikeshed that later on in the series. :)
>
> The one question here is what do we do if a series isn't complete?
> Proceed anyway? Raise an error and fail? Raise an error but provide a
> 'force' parameter to force the mbox download?
Excellent question. (Also one we're going to have to answer for
dependencies!)
I think silently returning a partial series is probably not wise - I can
imagine some tools (and people) getting very confused. I think maybe
raise an error and fail: if people want to download a known-incomplete
series the existing bundle functionality should work nicely.
>
>>
>> > def patch_to_mbox(patch):
>> > + """Get an mbox representation of a single patch.
>> > +
>> > + Arguments:
>> > + patch: The Patch object to convert.
>> > +
>> > + Returns:
>> > + A string for the mbox file.
>> > + """
>>
>> Yay for docstrings, but maybe you should mention them in the
>> commit message, or even put them in a patch with other cleanups?
>
> Yes, this should have been a separate patch. Let's do that for v2.
>
Thanks!
>> > postscript_re = re.compile('\n-{2,3} ?\n')
>> > body = ''
>> >
>> > +
>> > +def series_patch_to_mbox(patch, series_num):
>> > + """Get an mbox representation of a patch with dependencies.
>> > +
>> > + Arguments:
>> > + patch: The Patch object to convert.
>> > + series_num: The series number to retrieve dependencies
>> > from.
>> > +
>> > + Returns:
>> > + A string for the mbox file.
>> > + """
>> > + try:
>> > + series_num = int(series_num)
>> > + except ValueError:
>> > + # TODO(stephenfin): Perhaps we should raise a HTTP code
>> > here?
>>
>> Yes, we should - silently failing is not a great way to go.
>> I think both this case and the series not found should probably both
>> return a 404, preferably with a friendly message of some sort?
>> (see
>> e.g. http://stackoverflow.com/questions/20922543/correct-http-status-
>> code-for-existent-resource-but-non-existent-entity )
>
> Agreed. Let me try this again.
>
Thanks.
>> > + return ''
>> > +
>> > + try:
>> > + series = patch.series.get(id=series_num)
>> > + except Series.DoesNotExist:
>> > + return ''
>> > +
>> > + mbox = []
>> > +
>> > + # get the series-ified patch
>> > + number = series.seriespatch_set.get(patch=patch).number
>> > + for dep in series.seriespatch_set.filter(number__lt=number):
>> > + mbox.append(patch_to_mbox(dep.patch))
>>
>> Are these guaranteed to be ordered even in the event of out of order
>> arrival? I honestly can't remember - I think they are?
>
> Yup, series patches are ordered by number [1] and will appear as such.
>
Excellent!
>> > +
>> > + mbox.append(patch_to_mbox(patch))
>> > +
>> > + return '\n'.join(mbox)
>>
>>
>> > def patch_mbox(request, patch_id):
>> > patch = get_object_or_404(Patch, id=patch_id)
>> > - response = HttpResponse(content_type="text/plain")
>> > - response.write(patch_to_mbox(patch))
>> > + series_num = request.GET.get('series')
>> > +
>> > + response = HttpResponse(content_type='text/plain')
>> > + if series_num:
>> > + response.write(series_patch_to_mbox(patch, series_num))
>> > + else:
>> > + response.write(patch_to_mbox(patch))
>> > response['Content-Disposition'] = 'attachment; filename=' + \
>> > patch.filename.replace(';', '').replace('\n', '')
>>
>> I notice we don't sanitise bundle names the same way we sanitise this
>> filename (see one of your previous patches). Should we? Are the name
>> characters for bundles arbitrary?
>
> I think this is somewhat handled by the BundleForm, which will at least
> prevent anyone creating bundles with slashes [2]. However, it could
> definitely warrant more attention. I've created a bug [3] to track
> investigation here.
Cool, [2] is a good start and thanks for tracking it at [3].
>
> As always, thanks for taking the time to look over this :)
You're welcome - thanks for writing it!
Regards,
Daniel
>
> Stephen
>
> [1] https://github.com/getpatchwork/patchwork/blob/c1d8a0d/patchwork/mo
> dels.py#L668
> [2] https://github.com/getpatchwork/patchwork/blob/c1d8a0d/patchwork/fo
> rms.py#L72-L74
> [3] https://github.com/getpatchwork/patchwork/issues/75
More information about the Patchwork
mailing list