>
> [0]
>
> 1249 lines. Please have mercy on us poor reviewers ;). I know Javascript is verbose and you've done a lot of refactoring but still, I'm sure you would have had a volunteer reviewer for this branch sooner if you had split it into 2 or 3. Also, the problem with enormous branches is that the odds of getting a conflict goes way up.
>
Yeah, the core work was < 800 lines but then the yui tests pushed it
over. Normally I would go and split it but the core work would still
have produced a large diff.
>> 3. Bug found
>> There were conflicting implementations of userCanEditImportance() found. One was essentially:
>> bugtask.userCanEditImportance(self.user) and not bugtask.bugwatch
>
> For instance you could have fixed this in another pipe (I don't know if you already use the bzr pipeline plugin but in case you don't, please check it out: http://wiki.bazaar.canonical.com/BzrPipeline).
>
In fact, this mp itself is the 2nd in a pipeline so I know how to use
such things :-P
The first branch adds the non-ajax ui for deleting bugtasks.
This mp would have been broken without the bug fix; if I were to have
introduced a new pipe before this one, it would only have saved a few lines.
> [2]
>
> 312 + def check_bugtask_data(bugtask, can_delete):
> 313 + self.assertIn(bugtask.id, all_bugtask_data)
>
> Don't you think it would be easier to read if you moved this method outside of the test method?
>
I like the use of an inner method here. The code is not relevant outside
the test method it is in and nicely packages the common checks together
to eliminate duplication.
> [3]
>
> 361 + self.assertEqual(
> 362 + view.request.response.getHeader('content-type'),
> 363 + 'application/json')
>
> 'application/json' should be the first argument, otherwise a failure will be difficult to interpret.
>
Of course. Typo. Thanks for spotting that.
> [4]
>
> 334 + bug = self.factory.makeBug()
> 335 + bugtask = self.factory.makeBugTask(bug=bug)
> 336 + target_name = bugtask.bugtargetdisplayname
> 337 + bugtask_url = canonical_url(bugtask, rootsite='bugs')
>
> And
>
> 370 + bug = self.factory.makeBug()
> 371 + bugtask = self.factory.makeBugTask(bug=bug)
> 372 + target_name = bugtask.bugtargetdisplayname
> 373 + default_bugtask_url = canonical_url(
> 374 + bug.default_bugtask, rootsite='bugs')
>
> Would you mind refactoring that code into a common setup method?
>
Sure. I didn't bother because it was only a few lines but I'll add the
method.
Old habits. I prefer the above formatting and used it for the past 15
years so am still adjusting to the requirement to put the braces in the
"wrong" place :-/
> [6]
>
> 591 + var delete_text = [
> 592 + '<p class="large-warning" style="padding:2px 2px 0 36px;">',
> 593 + 'You are about to mark bug "',
> 594 + conf.bug_title,
> 595 + '"<br>as no longer affecting ',
> 596 + conf.targetname,
> 597 + '.<br><br><strong>Please confirm you really want to do this.',
> 598 + '</strong></p>'
> 599 + ].join('');
>
> Well, I do that all the times so I won't blame you but you will admit this is not very readable and someone editing this code might easily introduce a bug…
>
> a) multi-line js string
> I have no solution for the multi-line string… I hear an alternative solution is to use:
> var template='\
> line1 \
> line2';
> … but that is rather ugly too.
>
Yes, and this is not preferred AFAIK.
> b) string interpolation
> For the string interpolation part maybe you could start using Mustache.js which was integrated recently in lp by abentley?
> e.g:
> var view = {
> title: "Joe",
> calc: function() {
> return 2 + 4;
> }
> }
> var template = "{{title}} spends {{calc}}";
> var html = Mustache.to_html(template, view);
>
I normally use Y.Lang.substitute(). I'll see if I can tweak it to make
it more readable.
> [7]
>
> 638 + return;
> 639 + }
> 640 + // We have received HTML, so we replace the current bugtask table with a
>
> I think the possible code paths would be better expressed with an if then else instead of the 'return;' statement in the middle of the method.
>
I used the return to avoid indentation. I'll look at changing.
> [9]
>
> 663 + namespace._hideDeleteSpinner(delete_link);
> [...]
> 674 + start:
> 675 + function() {
> 676 + namespace._showDeleteSpinner(delete_link);
> 677 + },
>
> I suppose you did not use 'end' here because the spinner will get removed anyway if the XHR is a success (?)… but maybe you could consider using it anyway for readability/security:
> start: Y.bind(namespace._showDeleteSpinner, namespace, delete_link),
> end: Y.bind(namespace._hideDeleteSpinner, namespace, delete_link),
>
Correct. It is not required since the html is replaced. I think it would
be confusing to have code that is never executed?
>
> [11]
>
> 862 + '<table id="affected-software">',
> 863 + '<tbody>',
> 864 + '<tr id="tasksummary49">',
> 865 + '<td>',
> 866 + '<div>',
>
> To avoid having this in js tests files, Henning suggested a little trick that I find really nice: you can simply put that string in the test html file with a bogus type="text/x-template". You can see an example of this in the two following files:
> lib/lp/app/javascript/confirmationoverlay/tests/test_confirmationoverlay.html →<script type="text/x-template" id="form-template">
> lib/lp/app/javascript/confirmationoverlay/tests/test_confirmationoverlay.js → Y.one('#form-template').getContent();
>
Hi Raphaël
Thanks for the great review!
>
> [0]
>
> 1249 lines. Please have mercy on us poor reviewers ;). I know Javascript is verbose and you've done a lot of refactoring but still, I'm sure you would have had a volunteer reviewer for this branch sooner if you had split it into 2 or 3. Also, the problem with enormous branches is that the odds of getting a conflict goes way up.
>
Yeah, the core work was < 800 lines but then the yui tests pushed it
over. Normally I would go and split it but the core work would still
have produced a large diff.
>> 3. Bug found rtance( ) found. One was essentially: userCanEditImpo rtance( self.user) and not bugtask.bugwatch wiki.bazaar. canonical. com/BzrPipeline).
>> There were conflicting implementations of userCanEditImpo
>> bugtask.
>
> For instance you could have fixed this in another pipe (I don't know if you already use the bzr pipeline plugin but in case you don't, please check it out: http://
>
In fact, this mp itself is the 2nd in a pipeline so I know how to use
such things :-P
The first branch adds the non-ajax ui for deleting bugtasks.
This mp would have been broken without the bug fix; if I were to have
introduced a new pipe before this one, it would only have saved a few lines.
> [2] data(bugtask, can_delete): bugtask. id, all_bugtask_data)
>
> 312 + def check_bugtask_
> 313 + self.assertIn(
>
> Don't you think it would be easier to read if you moved this method outside of the test method?
>
I like the use of an inner method here. The code is not relevant outside
the test method it is in and nicely packages the common checks together
to eliminate duplication.
> [3] response. getHeader( 'content- type'),
>
> 361 + self.assertEqual(
> 362 + view.request.
> 363 + 'application/json')
>
> 'application/json' should be the first argument, otherwise a failure will be difficult to interpret.
>
Of course. Typo. Thanks for spotting that.
> [4] makeBug( ) makeBugTask( bug=bug) bugtargetdispla yname url(bugtask, rootsite='bugs') makeBug( ) makeBugTask( bug=bug) bugtargetdispla yname bugtask, rootsite='bugs')
>
> 334 + bug = self.factory.
> 335 + bugtask = self.factory.
> 336 + target_name = bugtask.
> 337 + bugtask_url = canonical_
>
> And
>
> 370 + bug = self.factory.
> 371 + bugtask = self.factory.
> 372 + target_name = bugtask.
> 373 + default_bugtask_url = canonical_url(
> 374 + bug.default_
>
> Would you mind refactoring that code into a common setup method?
>
Sure. I didn't bother because it was only a few lines but I'll add the
method.
> [5] data.hasOwnProp erty(id) ) { data.hasOwnProp erty(id) ) { → if (bugtask_ data.hasOwnProp erty(id) ) { 'js-action' ) ) { isFunction( connect_ func)) {
>
> 517 + if( bugtask_
>
> small typos: if( bugtask_
>
> Same here:
>
> 532 + if( link.hasClass(
> 537 + if( Y.Lang.
> 629 + if( content_type === 'application/json' ) {
>
Old habits. I prefer the above formatting and used it for the past 15
years so am still adjusting to the requirement to put the braces in the
"wrong" place :-/
> [6] large-warning" style="padding:2px 2px 0 36px;">', br><strong> Please confirm you really want to do this.',
>
> 591 + var delete_text = [
> 592 + '<p class="
> 593 + 'You are about to mark bug "',
> 594 + conf.bug_title,
> 595 + '"<br>as no longer affecting ',
> 596 + conf.targetname,
> 597 + '.<br><
> 598 + '</strong></p>'
> 599 + ].join('');
>
> Well, I do that all the times so I won't blame you but you will admit this is not very readable and someone editing this code might easily introduce a bug…
>
> a) multi-line js string
> I have no solution for the multi-line string… I hear an alternative solution is to use:
> var template='\
> line1 \
> line2';
> … but that is rather ugly too.
>
Yes, and this is not preferred AFAIK.
> b) string interpolation to_html( template, view);
> For the string interpolation part maybe you could start using Mustache.js which was integrated recently in lp by abentley?
> e.g:
> var view = {
> title: "Joe",
> calc: function() {
> return 2 + 4;
> }
> }
> var template = "{{title}} spends {{calc}}";
> var html = Mustache.
>
I normally use Y.Lang. substitute( ). I'll see if I can tweak it to make
it more readable.
> [7]
>
> 638 + return;
> 639 + }
> 640 + // We have received HTML, so we replace the current bugtask table with a
>
> I think the possible code paths would be better expressed with an if then else instead of the 'return;' statement in the middle of the method.
>
I used the return to avoid indentation. I'll look at changing.
> [9] _hideDeleteSpin ner(delete_ link); _showDeleteSpin ner(delete_ link); security: namespace. _showDeleteSpin ner, namespace, delete_link), namespace. _hideDeleteSpin ner, namespace, delete_link),
>
> 663 + namespace.
> [...]
> 674 + start:
> 675 + function() {
> 676 + namespace.
> 677 + },
>
> I suppose you did not use 'end' here because the spinner will get removed anyway if the XHR is a success (?)… but maybe you could consider using it anyway for readability/
> start: Y.bind(
> end: Y.bind(
>
Correct. It is not required since the html is replaced. I think it would
be confusing to have code that is never executed?
> software" >', 49">', x-template" . You can see an example of this in the two following files: app/javascript/ confirmationove rlay/tests/ test_confirmati onoverlay. html →<script type="text/ x-template" id="form-template"> app/javascript/ confirmationove rlay/tests/ test_confirmati onoverlay. js → Y.one(' #form-template' ).getContent( );
> [11]
>
> 862 + '<table id="affected-
> 863 + '<tbody>',
> 864 + '<tr id="tasksummary
> 865 + '<td>',
> 866 + '<div>',
>
> To avoid having this in js tests files, Henning suggested a little trick that I find really nice: you can simply put that string in the test html file with a bogus type="text/
> lib/lp/
> lib/lp/
>
Ah, I had forgotten about that. Thanks.