MT#7247 use param_release not tag for filter release

- migrate tag field from 32 to 64 chars max
- add make migrate rule to deploy changes on db
- add panel project-view
  Checking just one project per review
- panel release-view upgraded to deal with uuids
  no fixed project names
- update API to support dynamic discover of uuids and jobs by release

Change-Id: I0e64b3b341744ec326ee4e123901a1fdcf220baa
changes/45/2245/1
Victor Seva 10 years ago
parent f82463c499
commit 2231de1dec

@ -35,6 +35,11 @@ deploy: venv_prod
./manage.py collectstatic --noinput --settings="repoapi.settings.prod"
chown www-data:www-data -R ./static_media/
migrate: venv_prod
source $(VAR_DIR)/venv_prod/bin/activate && \
./manage.py migrate --settings="repoapi.settings.prod"
chown www-data:www-data $(VAR_DIR)/db.sqlite3
###################################
run_dev: venv_dev

@ -1,6 +1,6 @@
<h1>Releases</h1>
<ul>
{% for r in releases %}
<li><a href="{% url 'panel:release' r %}">{{ r }}</a></li>
<li><a href="{% url 'panel:release-view' r %}">{{ r }}</a></li>
{% endfor %}
</ul>

@ -0,0 +1,303 @@
{% extends "panel/base.html" %}
{% block title %}{{ project }}{% endblock %}
{% block content %}
<div class="container">
<h2>
<a href="{% url 'panel:release-view' release %}">
Release {{ release }}
</a>
</h2>
<div class="panel panel-default project" id="{{ project }}">
<div class="panel-heading">
<h3 class="panel-title">{{ project }}</h3>
</div>
<div class="panel-body">
<div class="panel panel-default hidden uuid-clone">
<div class="panel-heading">
<h3 class="panel-title"></h3>
</div>
<div class="panel-body">
<ul class="list-group list-inline uuid-list">
<li class="list-group-item hidden job"></li>
</ul>
</div>
</div>
</div>
<div class="panel-footer" id="{{ project}}-error"></div>
</div>
</div>
{% endblock %}
{% block extrajs %}
<script type="text/javascript">
$.project = {uuids: new Set(), failed: false, interval: 5000,};
function get_class_status(base, status) {
var result = base;
switch (status) {
case "SUCCESS":
result += "success";
break;
case "UNSTABLE":
result += "warning";
break;
default:
result += "danger";
}
return result;
}
function set_project_status(project, value) {
var div_project = $('#' + project);
var div_uuid = $('.uuid:first', div_project);
console.debug('set_project_status');
if (value) {
var status = value.result;
div_project.addClass(get_class_status("panel-", status));
}
else {
console.debug('uuid that counts: ' + div_uuid.attr('id'));
if (div_uuid.hasClass('panel-warning')) {
div_project.addClass('panel-warning');
}
else if (div_uuid.hasClass('panel-danger')) {
div_project.addClass('panel-danger');
}
else if (div_uuid.hasClass('panel-success')) {
div_project.addClass('panel-success');
}
}
}
function set_uuid_status(project, uuid, job, value) {
var div_uuid = $('#' + project + '-' + uuid);
var status = value.result;
var _class = get_class_status("panel-", status);
switch (status) {
case "SUCCESS":
case "UNSTABLE":
if (job.match(/.+-repos$/)) {
div_uuid.removeClass('panel-warning panel-danger').addClass(_class);
console.debug(project + ' uuid: ' + uuid + " OK. done");
}
else {
console.debug(job + ' nothing to do here.');
}
break;
default:
div_uuid.addClass(_class);
if(! $.project[uuid].failed) {
$.project[uuid].failed = true;
console.debug(project + ' uuid: ' + uuid + ' set failed');
}
set_project_status(project, value);
}
}
function set_job_status(project, uuid, job, value) {
var id = project + '-' + uuid + '-' + job;
var div_job = $('#' + id);
if (value) {
console.debug(job + ' found');
div_job.addClass(get_class_status("list-group-item-", value.result));
div_job.html('<a href="' + value.job_url + value.buildnumber
+ '">' + job + '</a>');
}
else {
console.error(job + ' not found');
// this should not happend!!
}
}
function create_new_job(project, uuid, job) {
var id = project + '-' + uuid;
var div_job = $('#' + id + '-job').clone().removeClass('hidden');
div_job.attr('id', id + '-' + job).html(job);
// put it on the proper place
div_job.appendTo('#' + id + '-list');
console.debug('job ' + job + ' created for ' + project + ' uuid: ' + uuid);
}
/**
* The idea is to have a hidden blocks to clone
* be sure to create proper ids and remove the classes
* you use to select them
*/
function create_new_uuid_panel(project, uuid) {
var id = project + '-' + uuid;
var div_uuid = $('#' + project +' > .panel-body .uuid-clone').clone();
div_uuid.removeClass('hidden');
div_uuid.attr('id', id).removeClass('uuid-clone').addClass('uuid');
// rest of blocks or classes to select inside this
$('.uuid-list', div_uuid).attr('id', id + '-list').removeClass('uuid-list');
$('.job', div_uuid).attr('id', id + '-job').removeClass('job');
var div_title = $('.panel-heading > .panel-title', div_uuid);
div_title.html(uuid);
// put it on the proper place
div_uuid.appendTo('#' + project + ' > .panel-body');
console.debug('uuid ' + uuid + ' created for ' + project);
}
function update_job_view(project, uuid, job, data) {
var value = data.results[0];
set_job_status(project, uuid, job, value);
if (data.count != 0) {
if ($.project[uuid][job].timer) {
clearInterval($.project[uuid][job].timer);
console.debug("clearInterval uuid: "+ uuid + ' ' + job);
}
set_uuid_status(project, uuid, job, value);
}
else {
console.error(job + ' not found');
// this should not happend!!
}
}
function update_job_info(release, project, uuid, job) {
function successFunc(data, textStatus, jqXHR ) {
update_job_view(project, uuid, job, data);
}
function errorFunc(jqXHR, status, error) {
$('#' + project + '-error').html(error);
$.project[uuid][job].failed = true;
}
if (! $.project[uuid].failed) {
if (! $.project[uuid][job].failed ) {
$.ajax({
url: '/jenkinsbuildinfo/?format=json&tag=' + uuid
+ '&param_release={{ release}}&projectname=' + job,
method: 'GET',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: successFunc,
error: errorFunc
});
}
else {
console.debug('uuid: ' + uuid + ' job: ' + job + ' already failed');
}
}
else {
console.debug(project + ' uuid: ' + uuid + ' already failed');
clearInterval($.project[uuid][job].timer);
console.debug("clearInterval uuid:" + uuid + ' ' + job);
set_project_status(project, {result: "FAILED"});
}
}
function update_uuid_info(release, project, uuid) {
function successFunc(data, textStatus, jqXHR ) {
$(data).each(function() {
var job = this.projectname;
$.project[uuid].jobs.add(job);
if (! $.project[uuid][job]) {
$.project[uuid][job] = { failed: false, };
create_new_job(project, uuid, job);
update_job_info(release, project, uuid, job);
}
if (! $.project[uuid][job].failed) {
if (! $.project[uuid][job].timer) {
$.project[uuid][job].timer = setInterval(function() {
update_job_info(release, project, uuid, job); }, $.project.interval);
console.debug('uuid: ' + uuid +
' new job: ' + job +' setInterval ' + $.project.interval);
}
}
else {
console.debug('uuid: ' + job +' already failed');
}
});
}
function errorFunc(jqXHR, status, error) {
$('#' + project + '-error').html(error);
$.project[uuid].failed = true;
}
if (! $.project[uuid].failed) {
$.ajax({
url: '/release/{{ release }}/' + project + '/' + uuid + '/?format=json',
method: 'GET',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: successFunc,
error: errorFunc
});
}
else {
console.debug(project + 'uuid ' + uuid +' already failed');
clearInterval($.project[uuid].timer);
}
}
function get_uuids_for_project(release, project) {
function successFunc(data, textStatus, jqXHR ) {
$(data).each(function() {
var uuid = this.tag;
if (uuid == null) {
console.warn(project + " skip null uuid");
return;
}
$.project.uuids.add(uuid);
if (! $.project[uuid] ) {
$.project[uuid] = { failed: false, jobs: new Set(),};
create_new_uuid_panel(project, uuid);
update_uuid_info(release, project, uuid);
}
if (! $.project[uuid].failed ) {
if (! $.project[uuid].timer) {
$.project[uuid].timer = setInterval(function() {
update_uuid_info(release, project, uuid); }, $.project.interval);
console.debug(project + ' new uuid: ' + uuid +
' setInterval ' + $.project.interval);
}
}
else {
console.debug(project + ' uuid: ' + uuid +' already failed');
clearInterval($.project[uuid].timer);
console.debug(project + " clearInterval: " + uuid);
set_project_status(project, {result: "FAILED"});
}
});
}
function errorFunc(jqXHR, status, error) {
$('#' + project + '-error').html(error);
$.project.failed = true;
}
$.ajax({
url: '/release/{{ release }}/' + project + '/?format=json',
method: 'GET',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: successFunc,
error: errorFunc
});
}
$( document ).ready(function() {
$('.project').each(function(){
var project = $(this).attr('id');
get_uuids_for_project('{{ release }}', project);
});
});
</script>
{% endblock %}

@ -2,42 +2,37 @@
{% block title %}{{ release }}{% endblock %}
{% block content %}
<div class="container">
<h2>Release {{ release }}</h2>
<ul>
{% for p in projects %}
<div class="panel panel-default" id="{{ p }}-panel">
<h2>Release {{ release }}</h2>
{% for project in projects %}
<div class="panel panel-default project" id="{{ project }}">
<div class="panel-heading">
<h3 class="panel-title">{{ p }}</h3>
<h3 class="panel-title">
<a href="{% url 'panel:project-view' release project %}">
{{ project }}
</a>
</h3>
</div>
<div class="project panel-body">
<ul class="list-group list-inline build_info" id="{{ p }}">
<li class="list-group-item bi source" id="{{ p }}-get-code">
<div class="status">{{ p }}-get-source</div>
</li>
<li class="list-group-item bi tests" id="{{ p }}-source-tests">
<div class="status">{{ p }}-source-tests</div>
</li>
<li class="list-group-item bi debs" id="{{ p }}-source">
<div class="status">{{ p }}-source</div>
</li>
<li class="list-group-item bi debs" id="{{ p }}-binaries">
<div class="status">{{ p }}-binaries</div>
</li>
<li class="list-group-item bi debs" id="{{ p }}-repos">
<div class="status">{{ p }}-repos</div>
</li>
</ul>
<div class="panel-body">
<div class="panel panel-default hidden uuid-clone">
<div class="panel-heading">
<h3 class="panel-title"></h3>
</div>
<div class="panel-body">
<ul class="list-group list-inline uuid-list">
<li class="list-group-item hidden job"></li>
</ul>
</div>
</div>
</div>
<div class="panel-footer error"></div>
<div class="panel-footer" id="{{ project}}-error"></div>
</div>
{% endfor %}
</ul>
{% endfor %}
</div>
{% endblock %}
{% block extrajs %}
<script type="text/javascript">
$.release = {failed_projects: {}, interval: 60000,};
$.release = {};
function get_class_status(base, status) {
var result = base;
@ -54,93 +49,193 @@ function get_class_status(base, status) {
return result;
}
function set_project_status(project, project_build, value) {
var _project = $('#' + project + '-panel');
function set_project_status(project, value) {
var div_project = $('#' + project);
var div_uuid = $('.uuid:first', div_project);
console.debug('set_project_status');
if (value) {
var status = value.result;
div_project.addClass(get_class_status("panel-", status));
}
else {
console.debug('uuid that counts: ' + div_uuid.attr('id'));
if (div_uuid.hasClass('panel-warning')) {
div_project.addClass('panel-warning');
}
else if (div_uuid.hasClass('panel-danger')) {
div_project.addClass('panel-danger');
}
else if (div_uuid.hasClass('panel-success')) {
div_project.addClass('panel-success');
}
}
}
function set_uuid_status(project, uuid, job, value) {
var div_uuid = $('#' + project + '-' + uuid);
var status = value.result;
var _class = get_class_status("panel-", status);
switch (status) {
case "SUCCESS":
case "UNSTABLE":
if (project_build.match(/.+-repos$/)) {
_project.removeClass('panel-warning panel-danger').addClass(_class);
console.debug(project + " OK. done");
if (job.match(/.+-repos$/)) {
div_uuid.removeClass('panel-warning panel-danger').addClass(_class);
console.debug(project + ' uuid: ' + uuid + " OK. done");
}
else {
console.debug(project_build + ' nothing to do here.');
console.debug(job + ' nothing to do here.');
}
break;
default:
_project.addClass(_class);
if(! $.release.failed_projects[project]) {
$.release.failed_projects[project] = true;
console.debug(project_build + " set failed");
div_uuid.addClass(_class);
if(! $.release[project][uuid].failed) {
$.release[project][uuid].failed = true;
console.debug(project + ' uuid: ' + uuid + ' set failed');
}
set_project_status(project, value);
}
}
function set_build_status(project_build, value) {
var _project_build = $('#' + project_build);
function set_job_status(project, uuid, job, value) {
var id = project + '-' + uuid + '-' + job;
var div_job = $('#' + id);
if (value) {
var div_status = $('.status', _project_build);
var _class = get_class_status("list-group-item-", value.result);
console.debug("found " + project_build);
_project_build.removeClass('disabled').addClass(_class);
_project_build.show();
div_status.html('<a href="' + value.job_url + value.buildnumber +'">' + project_build + '</a>');
console.debug(job + ' found');
div_job.addClass(get_class_status("list-group-item-", value.result));
div_job.html('<a href="' + value.job_url + value.buildnumber
+ '">' + job + '</a>');
}
else {
console.debug("not found " + project_build);
_project_build.addClass('disabled');
_project_build.hide();
console.error(job + ' not found');
// this should not happend!!
}
}
function update_view(project, project_build, data) {
function create_new_job(project, uuid, job) {
var id = project + '-' + uuid;
var div_job = $('#' + id + '-job').clone().removeClass('hidden');
div_job.attr('id', id + '-' + job).html(job);
// put it on the proper place
div_job.appendTo('#' + id + '-list');
console.debug('job ' + job + ' created for ' + project + ' uuid: ' + uuid);
}
/**
* The idea is to have a hidden blocks to clone
* be sure to create proper ids and remove the classes
* you use to select them
*/
function create_new_uuid_panel(project, uuid) {
var id = project + '-' + uuid;
var div_uuid = $('#' + project +' > .panel-body .uuid-clone').clone();
div_uuid.removeClass('hidden');
div_uuid.attr('id', id).removeClass('uuid-clone').addClass('uuid');
// rest of blocks or classes to select inside this
$('.uuid-list', div_uuid).attr('id', id + '-list').removeClass('uuid-list');
$('.job', div_uuid).attr('id', id + '-job').removeClass('job');
var div_title = $('.panel-heading > .panel-title', div_uuid);
div_title.html(uuid);
// put it on the proper place
div_uuid.appendTo('#' + project + ' > .panel-body');
console.debug('uuid ' + uuid + ' created for ' + project);
}
function update_job_view(project, uuid, job, data) {
var value = data.results[0];
set_build_status(project_build, value);
set_job_status(project, uuid, job, value);
if (data.count == 0) {
if (! $.release.failed_projects[project]) {
if (! $.release.failed_projects[project_build]) {
$.release.failed_projects[project_build] = setInterval(function() {
update_build_info(project, project_build); }, $.release.interval);
console.debug('setInterval ' + $.release.interval/1000 +
's for ' + project_build);
}
if (data.count != 0) {
if ($.release[project][uuid][job].timer) {
clearInterval($.release[project][uuid][job].timer);
console.debug("clearInterval uuid: "+ uuid + ' ' + job);
}
set_uuid_status(project, uuid, job, value);
}
else {
console.error(job + ' not found');
// this should not happend!!
}
}
function update_job_info(release, project, uuid, job) {
function successFunc(data, textStatus, jqXHR ) {
update_job_view(project, uuid, job, data);
}
function errorFunc(jqXHR, status, error) {
$('#' + project + '-error').html(error);
$.release[project][uuid][job].failed = true;
}
if (! $.release[project][uuid].failed) {
if (! $.release[project][uuid][job].failed ) {
$.ajax({
url: '/jenkinsbuildinfo/?format=json&tag=' + uuid
+ '&param_release={{ release}}&projectname=' + job,
method: 'GET',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: successFunc,
error: errorFunc
});
}
else {
console.debug(project + " already failed");
clearInterval($.release.failed_projects[project_build]);
console.debug("clearInterval: " + project_build);
set_project_status(project, project_build, {result: "FAILED"});
console.debug('uuid: ' + uuid + ' job: ' + job + ' already failed');
}
}
else {
clearInterval($.release.failed_projects[project_build]);
console.debug("clearInterval: " + project_build);
set_project_status(project, project_build, value);
console.debug(project + ' uuid: ' + uuid + ' already failed');
clearInterval($.release[project][uuid][job].timer);
console.debug("clearInterval uuid:" + uuid + ' ' + job);
set_project_status(project, {result: "FAILED"});
}
}
function update_build_info(project, project_build) {
var parent = $('#' + project_build).parent();
var div_err = $('.error', parent);
function update_uuid_info(release, project, uuid) {
function successFunc(data, textStatus, jqXHR ) {
update_view(project, project_build, data);
$(data).each(function() {
var job = this.projectname;
$.release[project][uuid].jobs.add(job);
if (! $.release[project][uuid][job]) {
$.release[project][uuid][job] = { failed: false, };
create_new_job(project, uuid, job);
update_job_info(release, project, uuid, job);
}
if (! $.release[project][uuid][job].failed) {
if (! $.release[project][uuid][job].timer) {
$.release[project][uuid][job].timer = setInterval(function() {
update_job_info(release, project, uuid, job); }, $.release[project].interval);
console.debug('uuid: ' + uuid +
' new job: ' + job +' setInterval ' + $.release[project].interval);
}
}
else {
console.debug('uuid: ' + job +' already failed');
}
});
}
function errorFunc(jqXHR, status, error) {
div_err.html(error);
$.release.failed_projects[project] = true;
$('#' + project + '-error').html(error);
$.release[project][uuid].failed = true;
}
if (! $.release.failed_projects[project]) {
if (! $.release[project][uuid].failed) {
$.ajax({
url: '/jenkinsbuildinfo/?format=json&tag={{ release}}&projectname=' + project_build,
url: '/release/{{ release }}/' + project + '/' + uuid + '/?format=json',
method: 'GET',
contentType: "application/json; charset=utf-8",
dataType: "json",
@ -149,18 +244,62 @@ function update_build_info(project, project_build) {
});
}
else {
console.debug("update_build_info: "+ project + " already failed");
clearInterval($.release.failed_projects[project_build]);
console.debug("clearInterval: " + project_build);
set_project_status(project, project_build, {result: "FAILED"});
console.debug(project + 'uuid ' + uuid +' already failed');
clearInterval($.release[project][uuid].timer);
}
}
function get_uuids_for_project(release, project) {
function successFunc(data, textStatus, jqXHR ) {
$(data).each(function() {
var uuid = this.tag;
if (uuid == null) {
console.warn(project + " skip null uuid");
return;
}
$.release[project].uuids.add(uuid);
if (! $.release[project][uuid] ) {
$.release[project][uuid] = { failed: false, jobs: new Set(),};
create_new_uuid_panel(project, uuid);
update_uuid_info(release, project, uuid);
}
if (! $.release[project][uuid].failed ) {
if (! $.release[project][uuid].timer) {
$.release[project][uuid].timer = setInterval(function() {
update_uuid_info(release, project, uuid); }, $.release[project].interval);
console.debug(project + ' new uuid: ' + uuid +
' setInterval ' + $.release[project].interval);
}
}
else {
console.debug(project + ' uuid: ' + uuid +' already failed');
clearInterval($.release[project][uuid].timer);
console.debug(project + " clearInterval: " + uuid);
set_project_status(project, {result: "FAILED"});
}
});
}
function errorFunc(jqXHR, status, error) {
$('#' + project + '-error').html(error);
$.release[project].failed = true;
}
$.ajax({
url: '/release/{{ release }}/' + project + '/?format=json',
method: 'GET',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: successFunc,
error: errorFunc
});
}
$( document ).ready(function() {
$('.project > .build_info > .bi').each(function(){
var project_build = $(this).attr('id');
var project = $(this).parent().attr('id');
update_build_info(project, project_build);
$('.project').each(function(){
var project = $(this).attr('id');
$.release[project] = {uuids: new Set(), failed: false, interval: 5000,};
get_uuids_for_project('{{ release }}', project);
});
});
</script>

@ -1,18 +0,0 @@
# Copyright (C) 2015 The Sipwise Team - http://sipwise.com
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from django.test import TestCase
# Create your tests here.

@ -13,10 +13,12 @@
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from django.conf.urls import include, url
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<release>.+)/$', views.release, name='release'),
url(r'^(?P<release>[\w\d\.-]+)/$', views.release, name='release-view'),
url(r'^(?P<release>[\w\d\.-]+)/(?P<project>[\w\d-]+)/$',
views.project, name='project-view'),
]

@ -26,3 +26,8 @@ def index(request):
def release(request, release):
context = {'projects': models.PROJECTS, 'release': release}
return render(request, 'panel/release.html', context)
def project(request, release, project):
context = {'project': project, 'release': release}
return render(request, 'panel/project.html', context)

@ -0,0 +1,86 @@
[
{
"fields": {
"buildnumber": 1,
"date": "2015-05-01T12:57:54.379Z",
"gerrit_change": null,
"gerrit_eventtype": null,
"gerrit_patchset": null,
"job_url": "https://jenkins.mgm.sipwise.com/job/foo-get-code/",
"param_branch": null,
"param_distribution": "wheezy",
"param_ppa": null,
"param_release": "mr3.1-fake",
"param_tag": null,
"projectname": "fake-source",
"repo_name": null,
"result": "FAILED",
"tag": "UUID1"
},
"model": "repoapi.jenkinsbuildinfo",
"pk": 1
},
{
"fields": {
"buildnumber": 1,
"date": "2015-05-04T10:41:53.788Z",
"gerrit_change": null,
"gerrit_eventtype": null,
"gerrit_patchset": null,
"job_url": "http://fake.org/gogo",
"param_branch": null,
"param_distribution": "wheezy",
"param_ppa": null,
"param_release": "mr3.1-fake",
"param_tag": null,
"projectname": "fake-get-code",
"repo_name": null,
"result": "FAILED",
"tag": "UUID0"
},
"model": "repoapi.jenkinsbuildinfo",
"pk": 2
},
{
"fields": {
"buildnumber": 1,
"date": "2015-05-04T10:42:13.259Z",
"gerrit_change": null,
"gerrit_eventtype": null,
"gerrit_patchset": null,
"job_url": "http://fake.org/gogo",
"param_branch": null,
"param_distribution": "wheezy",
"param_ppa": null,
"param_release": "mr3.1-fake",
"param_tag": null,
"projectname": "fake-source-tests",
"repo_name": null,
"result": "SUCCESS",
"tag": "UUID1"
},
"model": "repoapi.jenkinsbuildinfo",
"pk": 3
},
{
"fields": {
"buildnumber": 1,
"date": "2015-05-04T17:04:57.802Z",
"gerrit_change": null,
"gerrit_eventtype": null,
"gerrit_patchset": null,
"job_url": "https://jenkins.mgm.sipwise.com/job/foo-get-code/",
"param_branch": null,
"param_distribution": "wheezy",
"param_ppa": null,
"param_release": "mr3.1-fake",
"param_tag": null,
"projectname": "fake-get-code",
"repo_name": null,
"result": "SUCCESS",
"tag": "UUID1"
},
"model": "repoapi.jenkinsbuildinfo",
"pk": 4
}
]

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('repoapi', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='jenkinsbuildinfo',
name='tag',
field=models.CharField(max_length=64, null=True),
),
]

@ -18,17 +18,32 @@ from django.db import models
class JenkinsBuildInfoManager(models.Manager):
def releases(self):
def releases(self, flat=True):
res = self.get_queryset().values('param_release').distinct()
return res.values_list('param_release', flat=True)
if flat:
return res.values_list('param_release', flat=True)
else:
return res.values('param_release')
def projects(self, release):
res = self.get_queryset().filter(param_release=release).distinct()
return res
def release_uuids_by_project(self, release, project, flat=True):
res = self.get_queryset().filter(
param_release=release, projectname__startswith=project).distinct()
if flat:
return res.values_list('tag', flat=True)
else:
return res.values('tag')
def projects_by_uuid(self, release, project, uuid, flat=True):
res = self.get_queryset().filter(tag=uuid, param_release=release,
projectname__startswith=project)
if flat:
return res.order_by('-date').values_list('projectname', flat=True)
else:
return res.order_by('-date').values('projectname')
class JenkinsBuildInfo(models.Model):
tag = models.CharField(max_length=32, null=True)
tag = models.CharField(max_length=64, null=True)
projectname = models.CharField(max_length=100)
buildnumber = models.IntegerField()
date = models.DateTimeField(auto_now_add=True)

@ -13,7 +13,6 @@
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from django.forms import widgets
from rest_framework import serializers
import repoapi.models as models
@ -22,3 +21,7 @@ class JenkinsBuildInfoSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.JenkinsBuildInfo
class ReleaseListSerializer(serializers.Serializer):
param_release = serializers.CharField(max_length=50)

@ -16,7 +16,8 @@
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
BASE_DIR = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Quick-start development settings - unsuitable for production
@ -132,7 +133,7 @@ STATICFILES_FINDERS = (
'django_assets.finders.AssetsFinder',
)
STATIC_ROOT= os.path.join(BASE_DIR,'static_media/')
STATIC_ROOT = os.path.join(BASE_DIR, 'static_media/')
TEMPLATE_DIRS = (
'repoapi/templates',

@ -16,7 +16,8 @@
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
BASE_DIR = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
VAR_DIR = '/var/lib/repoapi'
if not os.path.exists(VAR_DIR):
@ -123,7 +124,7 @@ STATICFILES_FINDERS = (
'django_assets.finders.AssetsFinder',
)
STATIC_ROOT= os.path.join(BASE_DIR,'static_media/')
STATIC_ROOT = os.path.join(BASE_DIR, 'static_media/')
TEMPLATE_DIRS = (
'repoapi/templates',

@ -0,0 +1,45 @@
# Copyright (C) 2015 The Sipwise Team - http://sipwise.com
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from django.test import TestCase
from repoapi.models import JenkinsBuildInfo
class JBIQueriesTestCase(TestCase):
fixtures = ['test_model_queries.json']
def test_releases(self):
releases = JenkinsBuildInfo.objects.releases()
self.assertItemsEqual(releases, ['mr3.1-fake', ])
def test_release_uuids_by_project(self):
projects = ['fake', ]
uuids_ok = dict()
uuids = dict()
uuids_ok['fake'] = ['UUID1', 'UUID0']
for p in projects:
uuids[p] = JenkinsBuildInfo.objects.release_uuids_by_project(
'mr3.1-fake', p)
self.assertItemsEqual(uuids_ok[p], uuids[p])
def test_projects_by_uuid(self):
projects = JenkinsBuildInfo.objects.projects_by_uuid(
'mr3.1-fake', 'fake', 'UUID0')
self.assertItemsEqual(['fake-get-code', ], projects)
projects = JenkinsBuildInfo.objects.projects_by_uuid(
'mr3.1-fake', 'fake', 'UUID1')
self.assertItemsEqual(
['fake-get-code', 'fake-source-tests', 'fake-source'], projects)

@ -26,6 +26,16 @@ api_patterns = [
url(r'^jenkinsbuildinfo/(?P<pk>[0-9]+)/$',
views.JenkinsBuildInfoDetail.as_view(),
name='jenkinsbuildinfo-detail'),
url(r'^release/$',
views.ReleaseList.as_view(),
name='release-list'),
url(r'^release/(?P<release>[\w\d\.-]+)/(?P<project>[\w\d\.-]+)/$',
views.ProjectUUIDList.as_view(),
name='projectuuid-list'),
url(r'^release/(?P<release>[\w\d\.-]+)'
'/(?P<project>[\w\d\.-]+)/(?P<uuid>[\w\d-]+)/$',
views.UUIDInfoList.as_view(),
name='uuidinfo-list'),
]
api_patterns = format_suffix_patterns(api_patterns)

@ -13,12 +13,13 @@
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
from repoapi import models, serializers
from rest_framework import filters
from . import serializers
from .models import JenkinsBuildInfo as jbi
from rest_framework import generics
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework.views import APIView
import django_filters
@ -27,23 +28,46 @@ def api_root(request, format=None):
return Response({
'jenkinsbuildinfo': reverse('jenkinsbuildinfo-list',
request=request, format=format),
'release': reverse('release-list',
request=request, format=format),
})
class JenkinsBuildInfoFilter(django_filters.FilterSet):
class Meta:
model = models.JenkinsBuildInfo
fields = ['tag', 'projectname', 'date']
model = jbi
fields = ['tag', 'projectname', 'param_release', 'date']
order_by = ['-date', ]
class JenkinsBuildInfoList(generics.ListCreateAPIView):
queryset = models.JenkinsBuildInfo.objects.all()
queryset = jbi.objects.all()
serializer_class = serializers.JenkinsBuildInfoSerializer
filter_class = JenkinsBuildInfoFilter
class JenkinsBuildInfoDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = models.JenkinsBuildInfo.objects.all()
queryset = jbi.objects.all()
serializer_class = serializers.JenkinsBuildInfoSerializer
class ReleaseList(generics.ListAPIView):
queryset = jbi.objects.releases(flat=False)
serializer_class = serializers.ReleaseListSerializer
class ProjectUUIDList(APIView):
def get(self, request, release, project, format=None):
res = jbi.objects.release_uuids_by_project(
release, project, flat=False)
return Response(res)
class UUIDInfoList(APIView):
def get(self, request, release, project, uuid, format=None):
res = jbi.objects.projects_by_uuid(
release, project, uuid, flat=False)
return Response(res)

Loading…
Cancel
Save