def test_multi_line(self): self.create_events() e = utils.create_event(user=self.owner, commit1='456', branch1=self.branch, branch2=self.branch, cause=models.Event.PUSH) e.description = "some description" e.save() event_q = EventsStatus.get_default_events_query()[:30] info = EventsStatus.multiline_events_info(event_q, max_jobs_per_line=100) self.assertEqual(len(info), 3) self.assertEqual(len(info[0]["jobs"]), 6) info = EventsStatus.multiline_events_info(event_q, max_jobs_per_line=1) self.assertEqual(len(info), 18)
def view_user(request, username): """ Render the user page based on username Input: request[django.http.HttpRequest] username[str]: Name of the user """ users = models.GitUser.objects.filter(name=username) if users.count() == 0: raise Http404('Bad username') repos = RepositoryStatus.get_user_repos_with_open_prs_status(username) pr_ids = [] for r in repos: for pr in r["prs"]: pr_ids.append(pr["id"]) event_list = EventsStatus.get_single_event_for_open_prs(pr_ids) evs_info = EventsStatus.multiline_events_info(event_list) data = { 'username': username, 'repos': repos, 'events': evs_info, "update_interval": settings.EVENT_PAGE_UPDATE_INTERVAL, } return render(request, 'ci/user.html', data)
def repo_update(request): """ Get the updates for the repo page. """ if 'last_request' not in request.GET or 'limit' not in request.GET or 'repo_id' not in request.GET: return HttpResponseBadRequest('Missing parameters') this_request = TimeUtils.get_local_timestamp() repo_id = int(request.GET['repo_id']) limit = int(request.GET['limit']) last_request = int(float(request.GET['last_request'])) # in case it has decimals dt = timezone.localtime(timezone.make_aware(datetime.datetime.utcfromtimestamp(last_request))) repo = get_object_or_404(models.Repository, pk=repo_id) repos_status = RepositoryStatus.filter_repos_status([repo.pk], last_modified=dt) event_q = EventsStatus.get_default_events_query() event_q = event_q.filter(base__branch__repository=repo)[:limit] events_info = EventsStatus.multiline_events_info(event_q, last_modified=dt) # we also need to check if a PR closed recently closed = [] for pr in models.PullRequest.objects.filter(repository=repo, closed=True, last_modified__gte=dt).values('id').all(): closed.append({'id': pr['id']}) return JsonResponse({'repo_status': repos_status, 'closed': closed, 'last_request': this_request, 'events': events_info, 'limit': limit, })
def do_branch_page(request, branch): """ Render the branch page given a branch object Input: request[django.http.HttpRequest] branch[models.Branch] """ if request.method != "GET": return HttpResponseNotAllowed(['GET']) causes = [] if request.GET.get("do_filter", "0") == "0": causes = [models.Event.PUSH, models.Event.MANUAL, models.Event.RELEASE] form = forms.BranchEventsForm(initial={"filter_events": causes}) else: form = forms.BranchEventsForm(request.GET) if form.is_valid(): causes = [int(c) for c in form.cleaned_data["filter_events"]] event_list = EventsStatus.get_default_events_query().filter( base__branch=branch, cause__in=causes) events = get_paginated(request, event_list) evs_info = EventsStatus.multiline_events_info(events) return render(request, 'ci/branch.html', { "form": form, 'branch': branch, 'events': evs_info, 'pages': events })
def recipe_crons(request, recipe_id): recipe = get_object_or_404(models.Recipe, pk=recipe_id) event_list = (EventsStatus.get_default_events_query().filter( jobs__recipe__filename=recipe.filename, jobs__recipe__cause=recipe.cause, jobs__recipe__scheduler__isnull=False).exclude( jobs__recipe__scheduler='')) total = 0 count = 0 qs = models.Job.objects.filter(recipe__filename=recipe.filename) for job in qs.all(): total += job.seconds.total_seconds( ) if job.status == models.JobStatus.SUCCESS else 0 count += 1 if job.status == models.JobStatus.SUCCESS else 0 if count: total /= count events = get_paginated(request, event_list) evs_info = EventsStatus.multiline_events_info(events) avg = timedelta(seconds=total) data = { 'recipe': recipe, 'events': evs_info, 'average_time': avg, 'pages': events, } return render(request, 'ci/recipe_events.html', data)
def cronjobs(request): # TODO: make this check for permission to view cron stuff instead allowed = Permissions.is_allowed_to_see_clients(request.session) if not allowed: return render(request, 'ci/cronjobs.html', { 'recipes': None, 'allowed': False }) recipe_list = models.Recipe.objects.filter( active=True, current=True, scheduler__isnull=False, branch__isnull=False).exclude(scheduler="") local_tz = pytz.timezone('US/Mountain') for r in recipe_list: event_list = (EventsStatus.get_default_events_query().filter( jobs__recipe__filename=r.filename, jobs__recipe__cause=r.cause)) events = get_paginated(request, event_list) evs_info = EventsStatus.multiline_events_info(events) r.most_recent_event = evs_info[0]['id'] if len(evs_info) > 0 else None c = croniter(r.scheduler, start_time=r.last_scheduled.astimezone(local_tz)) r.next_run_time = c.get_next(datetime) # TODO: augment recipes objects with fields that html template will need. data = { 'recipes': recipe_list, 'allowed': True, 'update_interval': settings.HOME_PAGE_UPDATE_INTERVAL, } return render(request, 'ci/cronjobs.html', data)
def sha_events(request, owner, repo, sha): repo = get_object_or_404(models.Repository.objects, name=repo, user__name=owner) event_q = models.Event.objects.filter(head__branch__repository=repo, head__sha__startswith=sha) event_list = EventsStatus.get_default_events_query(event_q) events = get_paginated(request, event_list) evs_info = EventsStatus.multiline_events_info(events) return render(request, 'ci/events.html', {'events': evs_info, 'pages': events, 'sha': sha, 'repo': repo})
def scheduled_events(request): """ List schedule events """ event_list = EventsStatus.get_default_events_query().filter(cause=models.Event.MANUAL) events = get_paginated(request, event_list) evs_info = EventsStatus.multiline_events_info(events) return render(request, 'ci/scheduled.html', {'events': evs_info, 'pages': events})
def event_list(request): event_list = EventsStatus.get_default_events_query() events = get_paginated(request, event_list) evs_info = EventsStatus.multiline_events_info(events) return render(request, 'ci/events.html', { 'events': evs_info, 'pages': events })
def event_update(request, event_id): ev = get_object_or_404(models.Event, pk=event_id) ev_data = {'id': ev.pk, 'complete': ev.complete, 'last_modified': TimeUtils.display_time_str(ev.last_modified), 'created': TimeUtils.display_time_str(ev.created), 'status': ev.status_slug(), } ev_data['events'] = EventsStatus.multiline_events_info([ev]) return JsonResponse(ev_data)
def pr_update(request, pr_id): pr = get_object_or_404(models.PullRequest, pk=pr_id) closed = 'Open' if pr.closed: closed = 'Closed' pr_data = {'id': pr.pk, 'closed': closed, 'last_modified': TimeUtils.display_time_str(pr.last_modified), 'created': TimeUtils.display_time_str(pr.created), 'status': pr.status_slug(), } pr_data['events'] = EventsStatus.multiline_events_info(pr.events.all(), events_url=True) return JsonResponse(pr_data)
def user_open_prs(request, username): """ Get the updates for the main page. """ users = models.GitUser.objects.filter(name=username) if users.count() == 0: return HttpResponseBadRequest('Bad username') if 'last_request' not in request.GET: return HttpResponseBadRequest('Missing parameters') this_request = TimeUtils.get_local_timestamp() last_request = int(float(request.GET['last_request'])) # in case it has decimals dt = timezone.localtime(timezone.make_aware(datetime.datetime.utcfromtimestamp(last_request))) repos = RepositoryStatus.get_user_repos_with_open_prs_status(username) repo_ids = [] pr_ids = [] for r in repos: repo_ids.append(r["id"]) for pr in r["prs"]: pr_ids.append(pr["id"]) event_list = EventsStatus.get_single_event_for_open_prs(pr_ids) evs_info = EventsStatus.multiline_events_info(event_list) ev_ids = [] for e in evs_info: ev_ids.append(e["id"]) # Now get the changed ones repos = RepositoryStatus.get_user_repos_with_open_prs_status(username, dt) evs_info = EventsStatus.multiline_events_info(event_list, dt) data = {'repos': repo_ids, 'prs': pr_ids, 'events': ev_ids, 'repo_status': repos, 'closed': [], 'last_request': this_request, 'changed_events': evs_info, } return JsonResponse(data)
def view_event(request, event_id): """ Show the details of an Event """ ev = get_object_or_404(EventsStatus.events_with_head(), pk=event_id) evs_info = EventsStatus.multiline_events_info([ev]) allowed = Permissions.is_collaborator(request.session, ev.build_user, ev.base.repo()) has_unactivated = ev.jobs.filter(active=False).count() != 0 context = {'event': ev, 'events': evs_info, 'allowed_to_cancel': allowed, "update_interval": settings.EVENT_PAGE_UPDATE_INTERVAL, "has_unactivated": has_unactivated, } return render(request, 'ci/event.html', context)
def view_pr(request, pr_id): """ Show the details of a PR Input: request: django.http.HttpRequest pr_id: pk of models.PullRequest Return: django.http.HttpResponse based object """ pr = get_object_or_404(models.PullRequest.objects.select_related('repository__user'), pk=pr_id) ev = pr.events.select_related('build_user', 'base__branch__repository__user__server').latest() allowed = Permissions.is_collaborator(request.session, ev.build_user, ev.base.repo()) current_alt = [] alt_choices = [] default_choices = [] if allowed: alt_recipes = (models.Recipe.objects .filter(repository=pr.repository, build_user=ev.build_user, current=True, active=True, cause=models.Recipe.CAUSE_PULL_REQUEST_ALT,) .order_by("display_name")) default_recipes = (models.Recipe.objects .filter(repository=pr.repository, build_user=ev.build_user, current=True, active=True, cause=models.Recipe.CAUSE_PULL_REQUEST,) .order_by("display_name")) push_recipes = (models.Recipe.objects .filter(repository=pr.repository, build_user=ev.build_user, current=True, active=True, cause=models.Recipe.CAUSE_PUSH,) .order_by("display_name")) default_recipes = [r for r in default_recipes.all()] current_alt = [ r.pk for r in pr.alternate_recipes.all() ] current_default = [j.recipe.filename for j in pr.events.latest("created").jobs.all() ] push_map = {r.filename: r.branch for r in push_recipes.all()} alt_choices = [] for r in alt_recipes: alt_choices.append({"recipe": r, "selected": r.pk in current_alt, "push_branch": push_map.get(r.filename), }) default_choices = [] for r in default_recipes: default_choices.append({"recipe": r, "pk": r.pk, "disabled": r.filename in current_default, "push_branch": push_map.get(r.filename), }) if alt_choices and request.method == "POST": form_choices = [ (r.pk, r.display_name) for r in alt_recipes ] form = forms.AlternateRecipesForm(request.POST) form.fields["recipes"].choices = form_choices form_default_choices = [] for r in default_choices: if not r["disabled"]: form_default_choices.append((r["pk"], r["recipe"].display_name)) form.fields["default_recipes"].choices = form_default_choices if form.is_valid(): pr.alternate_recipes.clear() for pk in form.cleaned_data["recipes"]: alt = models.Recipe.objects.get(pk=pk) pr.alternate_recipes.add(alt) # do some saves to update the timestamp so that the javascript updater gets activated pr.save() pr.events.latest('created').save() messages.info(request, "Success") pr_event = PullRequestEvent.PullRequestEvent() selected_default_recipes = [] if form.cleaned_data["default_recipes"]: q = models.Recipe.objects.filter(pk__in=form.cleaned_data["default_recipes"]) selected_default_recipes = [r for r in q] pr_event.create_pr_alternates(pr, default_recipes=selected_default_recipes) # update the choices so the new form is correct current_alt = [ r.pk for r in pr.alternate_recipes.all() ] alt_choices = [ {"recipe": r, "selected": r.pk in current_alt} for r in alt_recipes ] else: messages.warning(request, "Invalid form") logger.warning("Invalid form") for field, errors in form.errors.items(): logger.warning("Form error in field: %s: %s" % (field, errors)) events = EventsStatus.events_with_head(pr.events) evs_info = EventsStatus.multiline_events_info(events, events_url=True) context = { "pr": pr, "events": evs_info, "allowed": allowed, "update_interval": settings.EVENT_PAGE_UPDATE_INTERVAL, "alt_choices": alt_choices, "default_choices": default_choices, } return render(request, 'ci/pr.html', context)