Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create build logs webapge #251

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .coafile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[all]
files = **.py, **.js, **.sh
ignore = .git/**, **/__pycache__/**, gci/client.py, */migrations/**, private/*, openhub/**, **/leaflet_dist/**
ignore = .git/**, **/__pycache__/**, gci/client.py, */migrations/**, private/*, openhub/**, **/leaflet_dist/**, .idea/**
max_line_length = 80
use_spaces = True
preferred_quotation = '
2 changes: 1 addition & 1 deletion .moban.yaml
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ packages:
- gci
- gsoc
- gamification
- log
- ci_build
- meta_review
- model
- unassigned_issues
2 changes: 1 addition & 1 deletion .nocover.yaml
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ nocover_file_globs:
- community/git.py
- gci/*.py
- gsoc/*.py
- log/*.py
- ci_build/*.py
- meta_review/handler.py
- model/*.py
- openhub/*.py
133 changes: 133 additions & 0 deletions ci_build/view_log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import re
import json
import os
import sys

from django.views.generic import TemplateView

from community.views import get_header_and_footer
from community.git import (
get_org_name,
get_owner,
get_deploy_url,
get_upstream_deploy_url
)


class BuildLogsView(TemplateView):
template_name = 'build_logs.html'

def copy_build_logs_json(self, ci_build_jsons):
"""
KVGarg marked this conversation as resolved.
Show resolved Hide resolved
Copy the build logs detailed JSON file from ./_site directory to
./static and ./public directories
:param ci_build_jsons: A dict of directories path
:return: A boolean, whether the build file is copied
"""
if os.path.isfile(ci_build_jsons['public_path']):
if sys.platform == 'linux':
os.popen('cp {} {}'.format(
ci_build_jsons['site_path'],
ci_build_jsons['public_path']))
os.popen('cp {} {}'.format(
ci_build_jsons['site_path'],
ci_build_jsons['static_path']))
else:
os.popen('copy {} {}'.format(
ci_build_jsons['site_path'],
ci_build_jsons['public_path']))
os.popen('copy {} {}'.format(
ci_build_jsons['site_path'],
ci_build_jsons['static_path']))
return True
return False

def create_and_copy_build_logs_json(self, logs, level_specific_logs):
"""
Create a build logs detailed json file in ./_site directory and copy
that file in the ./static and ./public/static directories
:param logs: A list of all lines in build log file
:param level_specific_logs: A dict containing logs divided in their
respective categories
:return: A boolean, whether the files were copied or not
"""
ci_build_jsons = {
'site_path': './_site/ci-build-detailed-logs.json',
'public_path': './public/static/ci-build-detailed-logs.json',
'static_path': './static/ci-build-detailed-logs.json'
}
with open(ci_build_jsons['site_path'], 'w+') as build_logs_file:
data = {
'logs': logs,
'logs_level_Specific': level_specific_logs
}
json.dump(data, build_logs_file, indent=4)
return self.copy_build_logs_json(ci_build_jsons)

def get_build_logs(self, log_file_path):
KVGarg marked this conversation as resolved.
Show resolved Hide resolved
"""
:param log_file_path: build logs file path
:return: a tuple of two where the first element in tuple refers to
a list of build logs in the file, and the second element is a dict
which categorizes the build logs into 5 categories - INFO, DEBUG,
WARNING, ERROR nad CRITICAL
"""
log_lines = []
log_level_specific_lines = {
'INFO': [],
'DEBUG': [],
'WARNING': [],
'ERROR': [],
'CRITICAL': []
}
with open(log_file_path) as log_file:
previous_found_level = None
for line in log_file:
log_lines.append(line)
levels = re.findall(r'\[[A-Z]+]', line)
if levels:
level = levels[0]
level = previous_found_level = level[1:-1]
log_level_specific_lines[level].append(line)
elif previous_found_level:
log_level_specific_lines[previous_found_level].append(
line)
return log_lines, log_level_specific_lines

def check_build_logs_stored(self):
"""
Check whether the build logs json file is copied to _site and public
directories or not
:return: A Boolean
"""
log_file_path = './_site/community.log'
log_file_exists = os.path.isfile(log_file_path)
if log_file_exists:
logs, level_specific_logs = self.get_build_logs(log_file_path)
return self.create_and_copy_build_logs_json(logs,
level_specific_logs)
return False

def get_build_info(self):
"""
Get the information about build, like who deployed the website i.e.
owner, name of the organization or user etc.
:return: A dict having information about build related details
"""
data = {
'Org name': get_org_name(),
'Owner': get_owner(),
'Deploy URL': get_deploy_url(),
}
try:
data['Upstream deploy URL'] = get_upstream_deploy_url()
except RuntimeError:
data['Upstream deploy URL'] = 'Not found'
return data

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context = get_header_and_footer(context)
context['build_info'] = self.get_build_info()
context['logs_stored'] = self.check_build_logs_stored()
return context
16 changes: 5 additions & 11 deletions community/urls.py
Original file line number Diff line number Diff line change
@@ -6,10 +6,10 @@
from django.conf.urls.static import static
from django.conf import settings

from community.views import HomePageView, info
from community.views import HomePageView
from gci.views import index as gci_index
from gci.feeds import LatestTasksFeed as gci_tasks_rss
from log.view_log import index as log_index
from ci_build.view_log import BuildLogsView
from data.views import index as contributors_index
from gamification.views import index as gamification_index
from meta_review.views import index as meta_review_index
@@ -78,12 +78,6 @@ def get_organization():
distill_func=get_index,
distill_file='index.html',
),
distill_url(
'info.txt', info,
name='index',
distill_func=get_index,
distill_file='info.txt',
),
distill_url(
r'gci/tasks/rss.xml', gci_tasks_rss(),
name='gci-tasks-rss',
@@ -97,10 +91,10 @@ def get_organization():
distill_file='gci/index.html',
),
distill_url(
r'log/', log_index,
name='log',
r'ci/build/', BuildLogsView.as_view(),
name='ci_build',
distill_func=get_index,
distill_file='log/index.html',
distill_file='ci/build/index.html',
),
distill_url(
r'contributors/$', contributors_index,
21 changes: 0 additions & 21 deletions community/views.py
Original file line number Diff line number Diff line change
@@ -4,14 +4,10 @@

from trav import Travis

from django.http import HttpResponse
from django.views.generic.base import TemplateView

from .git import (
get_deploy_url,
get_org_name,
get_owner,
get_upstream_deploy_url,
get_remote_url
)
from data.models import Team
@@ -114,20 +110,3 @@ def get_context_data(self, **kwargs):
context['top_gamification_users'] = self.get_top_gamification_users(
count=5)
return context


def info(request):
data = {
'Org name': get_org_name(),
'Owner': get_owner(),
'Deploy URL': get_deploy_url(),
}
try:
upstream_deploy_url = get_upstream_deploy_url()
data['Upstream deploy URL'] = upstream_deploy_url
except RuntimeError:
data['Upstream deploy URL'] = 'Not found'

s = '\n'.join(name + ': ' + value
for name, value in data.items())
return HttpResponse(s)
12 changes: 0 additions & 12 deletions log/view_log.py

This file was deleted.

6 changes: 3 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ testpaths =
gci
gsoc
gamification
log
ci_build
meta_review
model
unassigned_issues
@@ -69,7 +69,7 @@ source =
gci
gsoc
gamification
log
ci_build
meta_review
model
unassigned_issues
@@ -80,7 +80,7 @@ omit =
community/git.py
gci/*.py
gsoc/*.py
log/*.py
ci_build/*.py
meta_review/handler.py
model/*.py
openhub/*.py
84 changes: 84 additions & 0 deletions static/css/build_logs.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.build-info-section section,
.build-logs-section section {
min-width: 300px;
width: 80%;
}

.build-information,
.build-logs {
background-color: black;
padding-left: 10px;
font-weight: bold;
color: white;
}

.build-information p {
font-size: 1.5em;
margin: 0;
}

.build-logs {
max-height: 900px;
overflow: scroll;
overflow-x: hidden;
overflow-y: auto;
}

.build-logs p {
margin: 0;
}

.build-logs-section .log-chooser {
width: 25%;
min-width: 150px;
border-radius: 100px;
box-shadow: 0 0 25px 2px black;
color: #454343;
background-color: #c7da99;
padding-left: 10px;
margin: auto 0 auto auto;
}

.build-logs-section .log-chooser input,
.build-logs-section .log-chooser input:focus:not(.browser-default) {
border-bottom: none;
margin-bottom: 0;
}

.build-logs-section .small-screen,
.build-logs-section .fa-close {
display: none;
}

.form-fields {
margin: auto 0 auto auto;
width: 60%;
padding-top: 10px;
}

.search-field {
width: 60%;
min-width: 180px;
}

.section-header {
display: flex;
align-items: center;
}

.section-header form {
display: flex;
}

@media only screen and (max-width: 660px) {
.build-logs-section .search-field {
display: none;
}
.build-logs-section .small-screen {
display: flex;
align-items: center;
margin: auto;
margin-right: 3px;
font-size: 2em;
}
}
102 changes: 102 additions & 0 deletions static/js/build_logs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
$(document).ready(function(){
$('select').formSelect();

var log_chooser_input = $('#log-chooser-input');
var search_input = $('#search');
var search_icon = $('.build-logs-section .small-screen');
var close_icon = $('.build-logs-section .fa-close');
var log_chooser_div = $('.build-logs-section .log-chooser');
var search_field_div = $('.build-logs-section .search-field');
var log_type = null;
var logs_data = null;
var searched_keyword = '';

function addLogsHTML(info){
var info_el = $('<p></p>').text(info);
$('.build-logs').append(info_el);
}

function updateBuildLogsHTML(){
$('.build-logs p').remove();
if(logs_data.length > 0) {
for(var entry in logs_data){
if(logs_data[entry]){
addLogsHTML(logs_data[entry]);
}
}
}
else {
var info = 'There are no log entries for tag ' + log_type + '.';
addLogsHTML(info);
}
}

function updateBuildLogs(type){
$.getJSON("/static/ci-build-detailed-logs.json", function(data) {
log_type = type;
if(log_type === 'logs') {
logs_data = data[log_type];
}
else {
logs_data = data.logs_level_Specific[log_type];
}
updateBuildLogsHTML();
})
.fail(function(data, textStatus, error) {
var err = "Request Failed: " + textStatus + ", " + error;
console.error(err);
});
}

function searchBuildLogs(){
var found = false;
var info = '';
for(var entry in logs_data){
if(logs_data[entry]){
info = logs_data[entry];
if(info.includes(searched_keyword)){
found = true;
addLogsHTML(info);
}
}
}
if(!found){
if(log_type === 'logs'){
info = searched_keyword + ' not found in logs!';
}
else {
info = searched_keyword + ' not found in ' + log_type +
' level logs!';
}
addLogsHTML(info);
}
}

updateBuildLogs('logs');

log_chooser_input.on('change', function(){
updateBuildLogs(log_chooser_input.val());
});

search_input.on('keypress', function(key){
if(key.which === 13){
searched_keyword = search_input.val();
$('.build-logs p').remove();
searchBuildLogs();
}
});

search_icon.on('click', function(){
search_icon.css('display', 'none');
close_icon.css('display', 'block');
log_chooser_div.css('display', 'none');
search_field_div.css('display', 'flex');
});
close_icon.on('click', function(){
search_icon.css('display', 'flex');
close_icon.css('display', 'none');
log_chooser_div.css('display', 'flex');
search_field_div.css('display', 'none');
});

});
4 changes: 2 additions & 2 deletions templates/base.html
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@
</a>
<a href="#" data-target="mobile-menu" class="sidenav-trigger"><i class="fa fa-bars"></i></a>
<ul class="right hide-on-med-and-down nav-menu-font-size">
<li><a href="/" class="nav-menu-font-size">Home</a></li>
<li><a href="{% url 'index' %}" class="nav-menu-font-size">Home</a></li>
<li><a href="/#about" class="nav-menu-font-size">About</a></li>
<li><a href="#" class="nav-menu-font-size">Join</a></li>
<li><a href="{{ org.blog_url }}" target="_blank" class="nav-menu-font-size">Blog</a></li>
@@ -65,7 +65,7 @@
<li><a href="{% url 'inactive_issues_json' %}" title="List of all the issues on organization's main repository on which assignee has not shown any activity for more than 2 months.">Inactive issues</a></li>
<li><a href="{% url 'unassigned_issues_activity_json' %}" title="List of all the issues on organization main repository on which someone has opened a pull request without getting assigned to it.">Unassigned issues activity</a></li>
<li><a href="#">Newcomer issues</a></li>
<li><a href="{% url 'log' %}">Project CI Build</a></li>
<li><a href="{% url 'ci_build' %}">Project CI Build</a></li>
{% if isTravis %}
<li><a href="{{ travisLink }}" title="This website was built automatically using Travis CI.">TravisCI build info</a></li>
{% endif %}{# if isTravis #}
74 changes: 74 additions & 0 deletions templates/build_logs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{% extends 'base.html' %}
{% load staticfiles %}
{% block title_block %}
Community | Build Logs
{% endblock %}

{% block add_css_files %}
<link rel="stylesheet" href="{% static 'css/build_logs.css' %}">
{% endblock %}

{% block add_js_files %}
<script src="{% static 'js/build_logs.js' %}"></script>
{% endblock %}

{% block main-content %}
<div class="web-page-details apply-flex center-content">
<h3 style="padding-right: 15px">~</h3>
<div class="page-name">
<h3>Project CI Build</h3>
</div>
<h3 style="padding-left: 15px">~</h3>
</div>

<div class="build-info-section apply-flex center-content">
<section>
<h3>Information</h3>
<div class="build-information">
{% for key, value in build_info.items %}
<p>{{ key }}: {{ value }}</p>
{% endfor %}{# for key, value in build_info.items #}
</div>
</section>
</div>


<div class="build-logs-section apply-flex center-content">
<section>
<div class="section-header">
<h3>Logs</h3>
<div class="form-fields">
<form>
<i class="fa fa-search social-icons small-screen"></i>
<div class="input-field apply-flex center-content search-field">
<i class="fa fa-search social-icons"></i>
<input id="search" type="search" placeholder="Type your query, and press enter"
required autocomplete="off">
<i class="fa fa-close social-icons"></i>
</div>
<div class="input-field log-chooser">
<select id="log-chooser-input">
<option value="logs" selected>All logs</option>
<optgroup label="Log Levels-">
<option value="INFO">INFO</option>
<option value="DEBUG">DEBUG</option>
<option value="ERROR">ERROR</option>
<option value="WARNING">WARNING</option>
<option value="CRITICAL">CRITICAL</option>
</optgroup>
</select>
</div>
</form>
</div>
</div>
<div class="build-logs">
{% if logs_stored %}
<p>Great! Wait for build logs to get displayed.</p>
{% else %}
<p>No logs found! Please run '.ci/build.sh' on the project.</p>
{% endif %}{# if logs_stored #}
</div>
</section>
</div>

{% endblock %}