Example #1
0
File: signoff.py Project: gerv/elmo
def signoff(request, locale_code, app_code):
    """View to show recent sign-offs and opportunities to sign off.

    This view is the main entry point to localizers to add sign-offs and to
    review what they're shipping.
    It's also the entry point for drivers to review existing sign-offs.
    """
    appver = get_object_or_404(AppVersion, code=app_code)
    lang = get_object_or_404(Locale, code=locale_code)
    forest = appver.tree.l10n
    repo = get_object_or_404(Repository, locale=lang, forest=forest)
    # which pushes to show
    actions = list(a_id for a_id, flag in \
                   signoff_actions(appversions={'id': appver.id},
                                   locales={'id': lang.id}))
    actions = list(Action.objects.filter(id__in=actions)
                   .select_related('signoff__push', 'author'))

    # get current status of signoffs
    pending, rejected, accepted, initial_diff = signoff_summary(actions)

    pushes, currentpush, suggested_signoff = annotated_pushes(repo, appver,
                                                              lang, actions,
                                                              initial_diff)

    return render(request, 'shipping/signoffs.html', {
                    'appver': appver,
                    'language': lang,
                    'pushes': pushes,
                    'current': currentpush,
                    'pending': pending,
                    'rejected': rejected,
                    'accepted': accepted,
                    'tree': appver.tree.code,
                    'repo': repo,
                    'suggested_signoff': suggested_signoff,
                    'login_form_needs_reload': True,
                    'request': request,
                  })
Example #2
0
def teamsnippet(loc):
    runs = list(loc.run_set.filter(active__isnull=False).select_related('tree')
                .order_by('tree__code'))

    # this locale isn't active in our trees yet
    if not runs:
        return ''

    _application_codes = [(x.code, x) for x in Application.objects.all()]
    # sort their keys so that the longest application codes come first
    # otherwise, suppose we had these keys:
    #   'fe', 'foo', 'fennec' then when matching against a tree code called
    #   'fennec_10x' then, it would "accidentally" match on 'fe' and not
    #   'fennec'.
    _application_codes.sort(lambda x, y: -cmp(len(x[0]), len(y[0])))

    # Create these two based on all appversions attached to a tree so that in
    # the big loop on runs we don't need to make excessive queries for
    # appversions and applications
    _trees_to_appversions = {}
    for appver in (AppVersion.objects
                   .exclude(tree__isnull=True)
                   .select_related('tree')):
        _trees_to_appversions[appver.tree] = appver

    def tree_to_application(tree):
        for key, app in _application_codes:
            if tree.code.startswith(key):
                return app

    def tree_to_appversion(tree):
        return _trees_to_appversions.get(tree)

    # find good revisions to sign-off, latest run needs to be green.
    # keep in sync with api.annotated_pushes
    suggested_runs = filter(lambda r: r.allmissing == 0 and r.errors == 0,
                            runs)
    suggested_rev = dict(Run_Revisions.objects
                         .filter(run__in=suggested_runs,
                                 changeset__repositories__locale=loc)
                         .values_list('run_id', 'changeset__revision'))

    applications = defaultdict(list)
    pushes = set()
    for run_ in runs:
        # copy the Run instance into a fancy dict but only copy those whose
        # key doesn't start with an underscore
        run = Run(dict((k, getattr(run_, k))
                       for k in run_.__dict__
                       if not k.startswith('_')))
        run.allmissing = run_.allmissing  # a @property of the Run model
        run.tree = run_.tree  # foreign key lookup
        application = tree_to_application(run_.tree)
        run.changed_ratio = run.completion
        run.unchanged_ratio = 100 * run.unchanged / run.total
        run.missing_ratio = 100 * run.allmissing / run.total
        # cheat a bit and make sure that the red stripe on the chart is at
        # least 1px wide
        if run.allmissing and run.missing_ratio == 0:
            run.missing_ratio = 1
            for ratio in (run.changed_ratio, run.unchanged_ratio):
                if ratio:
                    ratio -= 1
                    break

        appversion = tree_to_appversion(run.tree)
        # because Django templates (stupidly) swallows lookup errors we
        # have to apply the missing defaults too
        run.pending = run.rejected = run.accepted = \
                      run.suggested_shortrev = run.appversion = None
        if appversion:
            run.appversion = appversion
            actions = [action_id for action_id, flag
                       in signoff_actions(
                          appversions=[run.appversion],
                          locales=[loc.id])
                          ]
            actions = Action.objects.filter(id__in=actions) \
                                    .select_related('signoff__push')
            # get current status of signoffs
            # we really only need the shortrevs, we'll get those below
            run.pending, run.rejected, run.accepted, __ = \
              signoff_summary(actions)
            pushes.update((run.pending, run.rejected, run.accepted))

            # get the suggested signoff. If there are existing actions
            # we'll unset it when we get the shortrevs for those below
            if run_.id in suggested_rev:
                run.suggested_shortrev = suggested_rev[run_.id][:12]

        applications[application].append(run)
    # get the tip shortrevs for all our pushes
    pushes = map(lambda p: p.id, filter(None, pushes))
    tip4push = dict(Push.objects
                    .annotate(tc=Max('changesets'))
                    .filter(id__in=pushes)
                    .values_list('id', 'tc'))
    rev4id = dict(Changeset.objects
                  .filter(id__in=tip4push.values())
                  .values_list('id', 'revision'))
    for runs in applications.itervalues():
        for run in runs:
            for k in ('pending', 'rejected', 'accepted'):
                if run[k] is not None:
                    run[k + '_rev'] = rev4id[tip4push[run[k].id]][:12]
                    # unset the suggestion if there's existing signoff action
                    if run[k + '_rev'] == run.suggested_shortrev:
                        run.suggested_shortrev = None
    applications = ((k, v) for (k, v) in applications.items())

    return render_to_string('shipping/team-snippet.html',
                            {'locale': loc,
                             'applications': applications,
                            })