Exemple #1
0
 def test_pending(self):
     """Test for the pending polish signoff"""
     actions = signoff_actions(appversions={"code": "fx1.0"},
                               locales={"code": "pl"})
     actions = list(actions)
     eq_(len(actions), 1)
     so = Signoff.objects.get(action=actions[0][0])
     eq_(so.push.tip.shortrev, "l10n pl 0003")
     eq_(so.locale.code, "pl")
     eq_(so.action_set.count(), 1)
Exemple #2
0
 def test_pending(self):
     """Test for the pending polish signoff"""
     actions = signoff_actions(appversions={"code": "fx1.0"},
                               locales={"code": "pl"})
     actions = list(actions)
     eq_(len(actions), 1)
     so = Signoff.objects.get(action=actions[0][0])
     eq_(so.push.tip.shortrev, "l10n pl 0003")
     eq_(so.locale.code, "pl")
     eq_(so.action_set.count(), 1)
Exemple #3
0
 def test_accepted(self):
     """Test for the german accepted signoff"""
     actions = signoff_actions(appversions={"code": "fx1.0"},
                               locales={"code": "de"})
     actions = list(actions)
     eq_(len(actions), 1)
     so = Signoff.objects.get(action=actions[0][0])
     eq_(so.push.tip.shortrev, "l10n de 0002")
     eq_(so.locale.code, "de")
     eq_(so.action_set.count(), 2)
Exemple #4
0
 def test_accepted(self):
     """Test for the german accepted signoff"""
     actions = signoff_actions(appversions={"code": "fx1.0"},
                               locales={"code": "de"})
     actions = list(actions)
     eq_(len(actions), 1)
     so = Signoff.objects.get(action=actions[0][0])
     eq_(so.push.tip.shortrev, "l10n de 0002")
     eq_(so.locale.code, "de")
     eq_(so.action_set.count(), 2)
Exemple #5
0
 def test_rejected(self):
     """Test for the rejected polish signoff"""
     actions = signoff_actions(appversions={"code": "fx1.0"},
                               locales={"code": "fr"})
     actions = list(actions)
     eq_(len(actions), 1)
     eq_(actions[0][1], Action.REJECTED)
     so = Signoff.objects.get(action=actions[0][0])
     eq_(so.push.tip.shortrev, "l10n fr 0003")
     eq_(so.locale.code, "fr")
     eq_(so.action_set.count(), 2)
Exemple #6
0
 def test_rejected(self):
     """Test for the rejected polish signoff"""
     actions = signoff_actions(appversions={"code": "fx1.0"},
                               locales={"code": "fr"})
     actions = list(actions)
     eq_(len(actions), 1)
     eq_(actions[0][1], Action.REJECTED)
     so = Signoff.objects.get(action=actions[0][0])
     eq_(so.push.tip.shortrev, "l10n fr 0003")
     eq_(so.locale.code, "fr")
     eq_(so.action_set.count(), 2)
Exemple #7
0
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,
                  })
Exemple #8
0
def data(request):
    app_codes = request.GET.getlist('app')
    if not app_codes:
        raise Http404('List of applications required')
    beta_apps = Application.objects.filter(code__in=app_codes)
    if len(app_codes) != beta_apps.count():
        raise Http404('Some of the given apps were not found')
    try:
        auroradate = datetime.datetime.strptime(request.GET.get('auroradate'),
                                                _dateformat)
    except (ValueError, TypeError):
        raise Http404("missing auroradate, or doesn't match %s" % _dateformat)
    try:
        betadate = datetime.datetime.strptime(request.GET.get('betadate'),
                                              _dateformat)
    except (ValueError, TypeError):
        raise Http404("missing betadate, or doesn't match %s" % _dateformat)

    branches = request.GET.getlist('branch')

    f_aurora = Forest.objects.get(name='releases/l10n/mozilla-aurora')
    f_beta = Forest.objects.get(name='releases/l10n/mozilla-beta')
    forests = []
    if 'aurora' in branches:
        forests.append(f_aurora)
    if 'beta' in branches:
        forests.append(f_beta)
    appvers = (AppVersion.objects.filter(
        app__in=list(beta_apps.values_list('id', flat=True)),
        tree__l10n__in=forests).order_by('code').select_related('app', 'tree'))
    appvers = list(appvers)
    beta_av = dict.fromkeys(av.id for av in appvers
                            if av.tree.l10n_id == f_beta.id)
    name4app = dict(beta_apps.values_list('id', 'name'))
    code4av = dict((av.id, av.code) for av in appvers)
    appname4av = dict((av.id, name4app[av.app_id]) for av in appvers)
    tree4av = dict((av.id, av.tree_id) for av in appvers)
    avq = {'id__in': [av.id for av in appvers]}
    actions = [
        action_id for action_id, flag in signoff_actions(appversions=avq)
        if flag == Action.ACCEPTED
    ]
    old_signoffs = list(
        Signoff.objects.filter(action__in=actions).exclude(
            push__push_date__gte=auroradate).select_related(
                'push__repository'))
    # exclude signoffs on aurora pushes in the previous cycle
    # that are now on beta
    old_signoffs = filter(
        lambda so: not (so.push.repository.forest == f_aurora and so.
                        appversion_id in beta_av and so.push.push_date >=
                        betadate and so.push.push_date < auroradate),
        old_signoffs)
    runqueries = (Q(locale=so.locale_id, tree=tree4av[so.appversion_id])
                  for so in old_signoffs)
    actives = (Run.objects.filter(reduce(
        lambda l, r: l | r, runqueries)).exclude(active__isnull=True))
    missings = dict(((r.tree_id, r.locale_id), r.allmissing) for r in actives)
    matrix = dict()
    for signoff in old_signoffs:
        if signoff.locale_id not in matrix:
            matrix[signoff.locale_id] = [None] * len(appvers)
        for av_i, av in enumerate(appvers):
            if signoff.appversion_id == av.id:
                break
        entry = {
            'push':
            signoff.push.push_date,
            'av':
            code4av[signoff.appversion_id],
            'app':
            appname4av[signoff.appversion_id],
            'missing':
            missings[(tree4av[signoff.appversion_id], signoff.locale_id)]
        }
        matrix[signoff.locale_id][av_i] = entry

    id4loc = dict(
        (Locale.objects.filter(id__in=matrix.keys()).values_list('code',
                                                                 'id')))
    rows = [{
        'loc': loc,
        'entries': matrix[id4loc[loc]]
    } for loc in sorted(id4loc.keys())]

    return render_to_response('shipping/out-data.html', {
        'apps': beta_apps,
        'appvers': appvers,
        'rows': rows,
        'auroradate': auroradate.strftime(_dateformat),
        'betadate': betadate.strftime(_dateformat),
    },
                              context_instance=RequestContext(request))
Exemple #9
0
def data(request):
    app_codes = request.GET.getlist('app')
    if not app_codes:
        raise Http404('List of applications required')
    beta_apps = Application.objects.filter(code__in=app_codes)
    if len(app_codes) != beta_apps.count():
        raise Http404('Some of the given apps were not found')
    try:
        auroradate = datetime.datetime.strptime(request.GET.get('auroradate'),
                                                _dateformat)
    except (ValueError, TypeError):
        raise Http404("missing auroradate, or doesn't match %s" % _dateformat)
    try:
        betadate = datetime.datetime.strptime(request.GET.get('betadate'),
                                              _dateformat)
    except (ValueError, TypeError):
        raise Http404("missing betadate, or doesn't match %s" % _dateformat)

    branches = request.GET.getlist('branch')

    f_aurora = Forest.objects.get(name='releases/l10n/mozilla-aurora')
    f_beta = Forest.objects.get(name='releases/l10n/mozilla-beta')
    forests = []
    if 'aurora' in branches:
        forests.append(f_aurora)
    if 'beta' in branches:
        forests.append(f_beta)
    appvers = (AppVersion.objects.
               filter(app__in=list(beta_apps.values_list('id', flat=True)),
                      tree__l10n__in=forests)
               .order_by('code')
               .select_related('app', 'tree'))
    appvers = list(appvers)
    beta_av = dict.fromkeys(av.id for av in appvers
                            if av.tree.l10n_id == f_beta.id)
    name4app = dict(beta_apps.values_list('id', 'name'))
    code4av = dict((av.id, av.code) for av in appvers)
    appname4av = dict((av.id, name4app[av.app_id]) for av in appvers)
    tree4av = dict((av.id, av.tree_id) for av in appvers)
    avq = {'id__in': [av.id for av in appvers]}
    actions = [action_id
               for action_id, flag in signoff_actions(appversions=avq)
               if flag == Action.ACCEPTED]
    old_signoffs = list(Signoff.objects
                       .filter(action__in=actions)
                       .exclude(push__push_date__gte=auroradate)
                       .select_related('push__repository'))
    # exclude signoffs on aurora pushes in the previous cycle
    # that are now on beta
    old_signoffs = filter(lambda so:
                          not (so.push.repository.forest == f_aurora and
                               so.appversion_id in beta_av and
                               so.push.push_date >= betadate and
                               so.push.push_date < auroradate),
                          old_signoffs)
    runqueries = (Q(locale=so.locale_id, tree=tree4av[so.appversion_id])
                  for so in old_signoffs)
    actives = (Run.objects
               .filter(reduce(lambda l, r: l | r, runqueries))
               .exclude(active__isnull=True))
    missings = dict(((r.tree_id, r.locale_id), r.allmissing)
                    for r in actives)
    matrix = dict()
    for signoff in old_signoffs:
        if signoff.locale_id not in matrix:
            matrix[signoff.locale_id] = [None] * len(appvers)
        for av_i, av in enumerate(appvers):
            if signoff.appversion_id == av.id:
                break
        entry = {'push': signoff.push.push_date,
                 'av': code4av[signoff.appversion_id],
                 'app': appname4av[signoff.appversion_id],
                 'missing': missings[(tree4av[signoff.appversion_id],
                                      signoff.locale_id)]}
        matrix[signoff.locale_id][av_i] = entry

    id4loc = dict((Locale.objects
                   .filter(id__in=matrix.keys())
                   .values_list('code', 'id')))
    rows = [{'loc':loc, 'entries': matrix[id4loc[loc]]}
            for loc in sorted(id4loc.keys())]

    return render_to_response('shipping/out-data.html',
                              {'apps': beta_apps,
                               'appvers': appvers,
                               'rows': rows,
                               'auroradate': auroradate.strftime(_dateformat),
                               'betadate': betadate.strftime(_dateformat),
                               },
                              context_instance=RequestContext(request))
Exemple #10
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,
                            })
Exemple #11
0
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
    pushes_q = Push.objects.order_by('-push_date').filter(
        changesets__branch__id=1)
    pushes_q = pushes_q.filter(repository=repo)
    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'))
    current_so = currentpush = None
    actions4push = defaultdict(list)
    for action in actions:
        if action.flag == Action.ACCEPTED:
            current_so = action.signoff
            currentpush = current_so.push_id
        actions4push[action.signoff.push_id].append(action)
    if current_so is not None:
        pushes_q = pushes_q.filter(
            push_date__gte=current_so.push.push_date).distinct()
    else:
        pushes_q = pushes_q.distinct()[:10]

    # get pushes, changesets and signoffs/actions
    _p = list(pushes_q.values_list('id', flat=True))
    pcs = Push_Changesets.objects.filter(push__in=_p).order_by(
        '-push__push_date', '-changeset__id')

    pushes = _RowCollector(pcs, actions4push).pushes

    # get current status of signoffs
    pending = rejected = accepted = None
    all_actions = sorted(actions, key=lambda _a: -_a.signoff.id)
    initial_diff = []
    for action in all_actions:
        flag = action.flag
        _so = action.signoff
        if flag == Action.PENDING:  # keep if there's no pending or rejected
            if pending is None and rejected is None:
                pending = _so.push
                if len(initial_diff) < 2: initial_diff.append(_so.id)
            continue
        elif flag == Action.ACCEPTED:  # store and don't look any further
            accepted = _so.push
            if len(initial_diff) < 2: initial_diff.append(_so.id)
            break
        elif flag == Action.REJECTED:  # keep, if there's no rejected
            if rejected is None:
                rejected = _so.push
                if len(initial_diff) < 2: initial_diff.append(_so.id)
            continue
        elif flag == Action.OBSOLETED:  # obsoleted, stop looking
            break
        else:
            # flag == Action.CANCELED, ignore, keep looking
            pass

    # get latest runs for our changesets
    csl = list(pcs.values_list('changeset__id', flat=True))
    rrs = Run_Revisions.objects.filter(run__tree=appver.tree_id,
                                       run__locale=lang,
                                       changeset__in=csl)
    rrs = rrs.order_by('changeset', 'run')
    c2r = dict(rrs.values_list('changeset', 'run'))
    r2r = dict((r.id, r) for r in (Run.objects.filter(
        id__in=c2r.values()).select_related('build')))

    # merge data back into pushes list
    suggested_signoff = None
    # initial_diff and runs
    if len(initial_diff) < 2 and pushes:
        pushes[0]['changes'][0].diffbases = [None] * (2 - len(initial_diff))
    for p in pushes:
        # initial_diff
        for sod in p['signoffs']:
            if sod['signoff'].id in initial_diff:
                sod['diffbases'] = 1
        # runs
        for c in p['changes']:
            if c.id in c2r and c2r[c.id] is not None:
                # we stored a run for a changeset in this push
                _r = r2r[c2r[c.id]]
                p['run'] = _r
                # should we suggest this?
                if suggested_signoff is None:
                    if p['signoffs']:
                        # last good push is signed off, don't suggest anything
                        suggested_signoff = False
                    elif _r.allmissing == 0 and _r.errors == 0:
                        # source checks are good, suggest
                        suggested_signoff = p['id']

    return render_to_response('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,
    },
                              context_instance=RequestContext(request))
Exemple #12
0
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
    pushes_q = Push.objects.order_by('-push_date').filter(changesets__branch__id=1)
    pushes_q = pushes_q.filter(repository=repo)
    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'))
    current_so = currentpush = None
    actions4push = defaultdict(list)
    for action in actions:
        if action.flag == Action.ACCEPTED:
            current_so = action.signoff
            currentpush = current_so.push_id
        actions4push[action.signoff.push_id].append(action)
    if current_so is not None:
        pushes_q = pushes_q.filter(push_date__gte=current_so.push.push_date).distinct()
    else:
        pushes_q = pushes_q.distinct()[:10]

    # get pushes, changesets and signoffs/actions
    _p = list(pushes_q.values_list('id',flat=True))
    pcs = Push_Changesets.objects.filter(push__in=_p).order_by('-push__push_date','-changeset__id')

    pushes = _RowCollector(pcs, actions4push).pushes

    # get current status of signoffs
    pending = rejected = accepted = None
    all_actions = sorted(actions, key=lambda _a: -_a.signoff.id)
    initial_diff = []
    for action in all_actions:
        flag = action.flag
        _so = action.signoff
        if flag == Action.PENDING: # keep if there's no pending or rejected
            if pending is None and rejected is None:
                pending = _so.push
                if len(initial_diff) < 2:initial_diff.append(_so.id)
            continue
        elif flag == Action.ACCEPTED: # store and don't look any further
            accepted = _so.push
            if len(initial_diff) < 2:initial_diff.append(_so.id)
            break
        elif flag == Action.REJECTED: # keep, if there's no rejected
            if rejected is None:
                rejected = _so.push
                if len(initial_diff) < 2:initial_diff.append(_so.id)
            continue
        elif flag == Action.OBSOLETED: # obsoleted, stop looking
            break
        else:
            # flag == Action.CANCELED, ignore, keep looking
            pass

    # get latest runs for our changesets
    csl = list(pcs.values_list('changeset__id', flat=True))
    rrs = Run_Revisions.objects.filter(run__tree=appver.tree_id,
                                       run__locale=lang,
                                       changeset__in=csl)
    rrs = rrs.order_by('changeset', 'run')
    c2r = dict(rrs.values_list('changeset', 'run'))
    r2r = dict((r.id, r) for r in (Run.objects
                                   .filter(id__in=c2r.values())
                                   .select_related('build')))

    # merge data back into pushes list
    suggested_signoff = None
    # initial_diff and runs
    if len(initial_diff) < 2 and pushes:
        pushes[0]['changes'][0].diffbases = [None] * (2 - len(initial_diff))
    for p in pushes:
        # initial_diff
        for sod in p['signoffs']:
            if sod['signoff'].id in initial_diff:
                sod['diffbases'] = 1
        # runs
        for c in p['changes']:
            if c.id in c2r and c2r[c.id] is not None:
                # we stored a run for a changeset in this push
                _r = r2r[c2r[c.id]]
                p['run'] = _r
                # should we suggest this?
                if suggested_signoff is None:
                    if p['signoffs']:
                        # last good push is signed off, don't suggest anything
                        suggested_signoff = False
                    elif _r.allmissing == 0 and _r.errors == 0:
                        # source checks are good, suggest
                        suggested_signoff = p['id']

    return render_to_response('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,
                               },
                              context_instance=RequestContext(request))