diff options
| author | Michael Wood <michael.g.wood@intel.com> | 2016-05-26 16:12:21 +0100 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-06-15 08:35:04 +0100 |
| commit | 32d1e2dd25f288790450db48766cf115854712ba (patch) | |
| tree | 0957025538fdd29b111884891f14becc55dcc018 /bitbake/lib | |
| parent | a786ac14f1c6c02c38dc141125035445413f1250 (diff) | |
| download | poky-32d1e2dd25f288790450db48766cf115854712ba.tar.gz | |
bitbake: toaster: port Built recipes table to toastertables
(Bitbake rev: 9434d3925bb7768876aae8d649ea00b8d849c6e9)
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib')
| -rw-r--r-- | bitbake/lib/toaster/toastergui/buildtables.py | 129 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/templates/recipes.html | 111 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/urls.py | 7 | ||||
| -rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 111 |
4 files changed, 135 insertions, 223 deletions
diff --git a/bitbake/lib/toaster/toastergui/buildtables.py b/bitbake/lib/toaster/toastergui/buildtables.py index cf07ea8789..dc742b9fe5 100644 --- a/bitbake/lib/toaster/toastergui/buildtables.py +++ b/bitbake/lib/toaster/toastergui/buildtables.py | |||
| @@ -150,3 +150,132 @@ class BuiltPackagesTable(BuildTablesMixin, BuiltPackagesTableBase): | |||
| 150 | yield column | 150 | yield column |
| 151 | 151 | ||
| 152 | self.columns = list(remove_dep_cols(self.columns)) | 152 | self.columns = list(remove_dep_cols(self.columns)) |
| 153 | |||
| 154 | |||
| 155 | class BuiltRecipesTable(BuildTablesMixin): | ||
| 156 | """ Table to show the recipes that have been built in this build """ | ||
| 157 | |||
| 158 | def __init__(self, *args, **kwargs): | ||
| 159 | super(BuiltRecipesTable, self).__init__(*args, **kwargs) | ||
| 160 | self.title = "Recipes built" | ||
| 161 | self.default_orderby = "name" | ||
| 162 | |||
| 163 | def setup_queryset(self, *args, **kwargs): | ||
| 164 | build = Build.objects.get(pk=kwargs['build_id']) | ||
| 165 | self.static_context_extra['build'] = build | ||
| 166 | self.queryset = build.get_recipes() | ||
| 167 | self.queryset = self.queryset.order_by(self.default_orderby) | ||
| 168 | |||
| 169 | def setup_columns(self, *args, **kwargs): | ||
| 170 | recipe_name_tmpl =\ | ||
| 171 | '<a href="{% url "recipe" extra.build.pk data.pk %}">'\ | ||
| 172 | '{{data.name}}'\ | ||
| 173 | '</a>' | ||
| 174 | |||
| 175 | recipe_version_tmpl =\ | ||
| 176 | '<a href="{% url "recipe" extra.build.pk data.pk %}">'\ | ||
| 177 | '{{data.version}}'\ | ||
| 178 | '</a>' | ||
| 179 | |||
| 180 | recipe_file_tmpl =\ | ||
| 181 | '{{data.file_path}}'\ | ||
| 182 | '{% if data.pathflags %}<i>({{data.pathflags}})</i>'\ | ||
| 183 | '{% endif %}' | ||
| 184 | |||
| 185 | git_rev_template = ''' | ||
| 186 | {% with vcs_ref=data.layer_version.commit %} | ||
| 187 | {% include 'snippets/gitrev_popover.html' %} | ||
| 188 | {% endwith %} | ||
| 189 | ''' | ||
| 190 | |||
| 191 | depends_on_tmpl = ''' | ||
| 192 | {% with deps=data.r_dependencies_recipe.all %} | ||
| 193 | {% with count=deps|length %} | ||
| 194 | {% if count %} | ||
| 195 | <a class="btn" title=" | ||
| 196 | <a href='{% url "recipe" extra.build.pk data.pk %}#dependencies'> | ||
| 197 | {{data.name}}</a> dependencies" | ||
| 198 | data-content="<ul class='unstyled'> | ||
| 199 | {% for dep in deps|dictsort:"depends_on.name"%} | ||
| 200 | <li><a href='{% url "recipe" extra.build.pk dep.depends_on.pk %}'> | ||
| 201 | {{dep.depends_on.name}}</a></li> | ||
| 202 | {% endfor %} | ||
| 203 | </ul>"> | ||
| 204 | {{count}} | ||
| 205 | </a> | ||
| 206 | {% endif %}{% endwith %}{% endwith %} | ||
| 207 | ''' | ||
| 208 | |||
| 209 | rev_depends_tmpl = ''' | ||
| 210 | {% with revs=data.r_dependencies_depends.all %} | ||
| 211 | {% with count=revs|length %} | ||
| 212 | {% if count %} | ||
| 213 | <a class="btn" | ||
| 214 | title=" | ||
| 215 | <a href='{% url "recipe" extra.build.pk data.pk %}#brought-in-by'> | ||
| 216 | {{data.name}}</a> reverse dependencies" | ||
| 217 | data-content="<ul class='unstyled'> | ||
| 218 | {% for dep in revs|dictsort:"recipe.name" %} | ||
| 219 | <li> | ||
| 220 | <a href='{% url "recipe" extra.build.pk dep.recipe.pk %}'> | ||
| 221 | {{dep.recipe.name}} | ||
| 222 | </a></li> | ||
| 223 | {% endfor %} | ||
| 224 | </ul>"> | ||
| 225 | {{count}} | ||
| 226 | </a> | ||
| 227 | {% endif %}{% endwith %}{% endwith %} | ||
| 228 | ''' | ||
| 229 | |||
| 230 | self.add_column(title="Name", | ||
| 231 | field_name="name", | ||
| 232 | static_data_name='name', | ||
| 233 | orderable=True, | ||
| 234 | static_data_template=recipe_name_tmpl) | ||
| 235 | |||
| 236 | self.add_column(title="Version", | ||
| 237 | field_name="version", | ||
| 238 | static_data_name='version', | ||
| 239 | static_data_template=recipe_version_tmpl) | ||
| 240 | |||
| 241 | self.add_column(title="Dependencies", | ||
| 242 | static_data_name="dependencies", | ||
| 243 | static_data_template=depends_on_tmpl, | ||
| 244 | hidden=True) | ||
| 245 | |||
| 246 | self.add_column(title="Reverse dependencies", | ||
| 247 | static_data_name="revdeps", | ||
| 248 | static_data_template=rev_depends_tmpl, | ||
| 249 | help_text='Recipe build-time reverse dependencies' | ||
| 250 | ' (i.e. the recipes that depend on this recipe)', | ||
| 251 | hidden=True) | ||
| 252 | |||
| 253 | self.add_column(title="Recipe file", | ||
| 254 | field_name="file_path", | ||
| 255 | static_data_name="file_path", | ||
| 256 | static_data_template=recipe_file_tmpl) | ||
| 257 | |||
| 258 | self.add_column(title="Section", | ||
| 259 | field_name="section", | ||
| 260 | orderable=True) | ||
| 261 | |||
| 262 | self.add_column(title="License", | ||
| 263 | field_name="license", | ||
| 264 | help_text='Multiple license names separated by the' | ||
| 265 | ' pipe character indicates a choice between licenses.' | ||
| 266 | ' Multiple license names separated by the ampersand' | ||
| 267 | ' character indicates multiple licenses exist that' | ||
| 268 | ' cover different parts of the source', | ||
| 269 | orderable=True) | ||
| 270 | |||
| 271 | self.add_column(title="Layer", | ||
| 272 | field_name="layer_version__layer__name", | ||
| 273 | orderable=True) | ||
| 274 | |||
| 275 | self.add_column(title="Layer branch", | ||
| 276 | field_name="layer_version__branch", | ||
| 277 | orderable=True) | ||
| 278 | |||
| 279 | self.add_column(title="Layer commit", | ||
| 280 | static_data_name="commit", | ||
| 281 | static_data_template=git_rev_template) | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/recipes.html b/bitbake/lib/toaster/toastergui/templates/recipes.html deleted file mode 100644 index fe06f8b205..0000000000 --- a/bitbake/lib/toaster/toastergui/templates/recipes.html +++ /dev/null | |||
| @@ -1,111 +0,0 @@ | |||
| 1 | {% extends "basebuildpage.html" %} | ||
| 2 | |||
| 3 | {% load projecttags %} | ||
| 4 | |||
| 5 | {% block title %} Recipes - {{build.target_set.all|dictsort:"target"|join:", "}} {{build.machine}} - {{build.project.name}} - Toaster {% endblock %} | ||
| 6 | {% block localbreadcrumb %} | ||
| 7 | <li>Recipes</li> | ||
| 8 | {% endblock %} | ||
| 9 | |||
| 10 | {% block nav-recipes %} | ||
| 11 | <li class="active"><a href="{% url 'recipes' build.pk %}">Recipes</a></li> | ||
| 12 | {% endblock %} | ||
| 13 | |||
| 14 | {% block buildinfomain %} | ||
| 15 | <div class="col-md-10"> | ||
| 16 | <div class="page-header"> | ||
| 17 | <h1> | ||
| 18 | {% if request.GET.search and objects.paginator.count > 0 %} | ||
| 19 | {{objects.paginator.count}} recipe{{objects.paginator.count|pluralize}} found | ||
| 20 | {%elif request.GET.search and objects.paginator.count == 0%} | ||
| 21 | No recipes found | ||
| 22 | {%else%} | ||
| 23 | Recipes | ||
| 24 | {%endif%} | ||
| 25 | </h1> | ||
| 26 | </div> | ||
| 27 | |||
| 28 | {% if objects.paginator.count == 0 %} | ||
| 29 | <div class="alert"> | ||
| 30 | <form class="no-results input-append" id="searchform"> | ||
| 31 | <input id="search" name="search" class="input-xxlarge" type="text" value="{%if request.GET.search%}{{request.GET.search}}{%endif%}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="input-append-addon btn" tabindex="-1"><i class="glyphicon glyphicon-remove"></i></a>{% endif %} | ||
| 32 | <button class="btn" type="submit" value="Search">Search</button> | ||
| 33 | <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all recipes</button> | ||
| 34 | </form> | ||
| 35 | </div> | ||
| 36 | |||
| 37 | {% else %} | ||
| 38 | {% include "basetable_top.html" %} | ||
| 39 | |||
| 40 | {% for recipe in objects %} | ||
| 41 | |||
| 42 | <tr class="data"> | ||
| 43 | <td class="recipe__name"> | ||
| 44 | <a href="{% url "recipe" build.pk recipe.pk %}">{{recipe.name}}</a> | ||
| 45 | </td> | ||
| 46 | <td class="recipe__version"> | ||
| 47 | <a href="{% url "recipe" build.pk recipe.pk %}">{{recipe.version}}</a> | ||
| 48 | </td> | ||
| 49 | <!-- Depends --> | ||
| 50 | <td class="depends_on"> | ||
| 51 | {% with deps=recipe_deps|get_dict_value:recipe.pk %} | ||
| 52 | {% with count=deps|length %} | ||
| 53 | {% if count %} | ||
| 54 | <a class="btn" | ||
| 55 | title="<a href='{% url "recipe" build.pk recipe.pk %}#dependencies'>{{recipe.name}}</a> dependencies" | ||
| 56 | data-content="<ul class='list-unstyled'> | ||
| 57 | {% for i in deps|dictsort:"depends_on.name"%} | ||
| 58 | <li><a href='{% url "recipe" build.pk i.depends_on.pk %}'>{{i.depends_on.name}}</a></li> | ||
| 59 | {% endfor %} | ||
| 60 | </ul>"> | ||
| 61 | {{count}} | ||
| 62 | </a> | ||
| 63 | {% endif %} | ||
| 64 | {% endwith %} | ||
| 65 | {% endwith %} | ||
| 66 | </td> | ||
| 67 | <!-- Brought in by --> | ||
| 68 | <td class="depends_by"> | ||
| 69 | {% with revs=recipe_revs|get_dict_value:recipe.pk %} | ||
| 70 | {% with count=revs|length %} | ||
| 71 | {% if count %} | ||
| 72 | <a class="btn" | ||
| 73 | title="<a href='{% url "recipe" build.pk recipe.pk %}#brought-in-by'>{{recipe.name}}</a> reverse dependencies" | ||
| 74 | data-content="<ul class='list-unstyled'> | ||
| 75 | {% for i in revs|dictsort:"recipe.name" %} | ||
| 76 | <li><a href='{% url "recipe" build.pk i.recipe.pk %}'>{{i.recipe.name}}</a></li> | ||
| 77 | {% endfor %} | ||
| 78 | </ul>"> | ||
| 79 | {{count}} | ||
| 80 | </a> | ||
| 81 | {% endif %} | ||
| 82 | {% endwith %} | ||
| 83 | {% endwith %} | ||
| 84 | </td> | ||
| 85 | <!-- Recipe file --> | ||
| 86 | <td class="recipe_file">{{recipe.file_path}} {% if recipe.pathflags %}<i>({{recipe.pathflags}})</i>{% endif %}</td> | ||
| 87 | <!-- Section --> | ||
| 88 | <td class="recipe_section">{{recipe.section}}</td> | ||
| 89 | <!-- License --> | ||
| 90 | <td class="recipe_license">{{recipe.license}}</td> | ||
| 91 | <!-- Layer --> | ||
| 92 | <td class="layer_version__layer__name">{{recipe.layer_version.layer.name}}</td> | ||
| 93 | <!-- Layer branch --> | ||
| 94 | <td class="layer_version__branch">{{recipe.layer_version.branch}}</td> | ||
| 95 | <!-- Layer commit --> | ||
| 96 | <td class="layer_version__layer__commit"> | ||
| 97 | <a class="btn" | ||
| 98 | data-content="<ul class='list-unstyled'> | ||
| 99 | <li>{{recipe.layer_version.commit}}</li> | ||
| 100 | </ul>"> | ||
| 101 | {{recipe.layer_version.commit|truncatechars:13}} | ||
| 102 | </a> | ||
| 103 | </td> | ||
| 104 | </tr> | ||
| 105 | |||
| 106 | {% endfor %} | ||
| 107 | |||
| 108 | {% include "basetable_bottom.html" %} | ||
| 109 | {% endif %} | ||
| 110 | </div> | ||
| 111 | {% endblock %} | ||
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py index 3ce0d51011..0636c956b2 100644 --- a/bitbake/lib/toaster/toastergui/urls.py +++ b/bitbake/lib/toaster/toastergui/urls.py | |||
| @@ -40,8 +40,13 @@ urlpatterns = patterns('toastergui.views', | |||
| 40 | url(r'^build/(?P<build_id>\d+)/tasks/(?P<task_id>\d+)/$', 'tasks_task', name='tasks_task'), | 40 | url(r'^build/(?P<build_id>\d+)/tasks/(?P<task_id>\d+)/$', 'tasks_task', name='tasks_task'), |
| 41 | url(r'^build/(?P<build_id>\d+)/task/(?P<task_id>\d+)$', 'task', name='task'), | 41 | url(r'^build/(?P<build_id>\d+)/task/(?P<task_id>\d+)$', 'task', name='task'), |
| 42 | 42 | ||
| 43 | url(r'^build/(?P<build_id>\d+)/recipes/$', 'recipes', name='recipes'), | 43 | url(r'^build/(?P<build_id>\d+)/recipes/$', |
| 44 | buildtables.BuiltRecipesTable.as_view( | ||
| 45 | template_name="buildinfo-toastertable.html"), | ||
| 46 | name='recipes'), | ||
| 47 | |||
| 44 | url(r'^build/(?P<build_id>\d+)/recipe/(?P<recipe_id>\d+)/active_tab/(?P<active_tab>\d{1})$', 'recipe', name='recipe'), | 48 | url(r'^build/(?P<build_id>\d+)/recipe/(?P<recipe_id>\d+)/active_tab/(?P<active_tab>\d{1})$', 'recipe', name='recipe'), |
| 49 | |||
| 45 | url(r'^build/(?P<build_id>\d+)/recipe/(?P<recipe_id>\d+)$', 'recipe', name='recipe'), | 50 | url(r'^build/(?P<build_id>\d+)/recipe/(?P<recipe_id>\d+)$', 'recipe', name='recipe'), |
| 46 | url(r'^build/(?P<build_id>\d+)/recipe_packages/(?P<recipe_id>\d+)$', 'recipe_packages', name='recipe_packages'), | 51 | url(r'^build/(?P<build_id>\d+)/recipe_packages/(?P<recipe_id>\d+)$', 'recipe_packages', name='recipe_packages'), |
| 47 | 52 | ||
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index de1e4139a1..3a25d5ea1e 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -1274,117 +1274,6 @@ def diskio(request, build_id): | |||
| 1274 | def cputime(request, build_id): | 1274 | def cputime(request, build_id): |
| 1275 | return tasks_common(request, build_id, 'cputime', '') | 1275 | return tasks_common(request, build_id, 'cputime', '') |
| 1276 | 1276 | ||
| 1277 | def recipes(request, build_id): | ||
| 1278 | template = 'recipes.html' | ||
| 1279 | (pagesize, orderby) = _get_parameters_values(request, 100, 'name:+') | ||
| 1280 | mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } | ||
| 1281 | retval = _verify_parameters( request.GET, mandatory_parameters ) | ||
| 1282 | if retval: | ||
| 1283 | return _redirect_parameters( 'recipes', request.GET, mandatory_parameters, build_id = build_id) | ||
| 1284 | (filter_string, search_term, ordering_string) = _search_tuple(request, Recipe) | ||
| 1285 | |||
| 1286 | build = Build.objects.get(pk=build_id) | ||
| 1287 | |||
| 1288 | queryset = build.get_recipes() | ||
| 1289 | queryset = _get_queryset(Recipe, queryset, filter_string, search_term, ordering_string, 'name') | ||
| 1290 | |||
| 1291 | recipes = _build_page_range(Paginator(queryset, pagesize),request.GET.get('page', 1)) | ||
| 1292 | |||
| 1293 | # prefetch the forward and reverse recipe dependencies | ||
| 1294 | deps = { } | ||
| 1295 | revs = { } | ||
| 1296 | queryset_dependency=Recipe_Dependency.objects.filter(recipe__layer_version__build_id = build_id).select_related("depends_on", "recipe") | ||
| 1297 | for recipe in recipes: | ||
| 1298 | deplist = [ ] | ||
| 1299 | for recipe_dep in [x for x in queryset_dependency if x.recipe_id == recipe.id]: | ||
| 1300 | deplist.append(recipe_dep) | ||
| 1301 | deps[recipe.id] = deplist | ||
| 1302 | revlist = [ ] | ||
| 1303 | for recipe_dep in [x for x in queryset_dependency if x.depends_on_id == recipe.id]: | ||
| 1304 | revlist.append(recipe_dep) | ||
| 1305 | revs[recipe.id] = revlist | ||
| 1306 | |||
| 1307 | context = { | ||
| 1308 | 'objectname': 'recipes', | ||
| 1309 | 'build': build, | ||
| 1310 | 'project': build.project, | ||
| 1311 | 'objects': recipes, | ||
| 1312 | 'default_orderby' : 'name:+', | ||
| 1313 | 'recipe_deps' : deps, | ||
| 1314 | 'recipe_revs' : revs, | ||
| 1315 | 'tablecols':[ | ||
| 1316 | { | ||
| 1317 | 'name':'Recipe', | ||
| 1318 | 'qhelp':'Information about a single piece of software, including where to download the source, configuration options, how to compile the source files and how to package the compiled output', | ||
| 1319 | 'orderfield': _get_toggle_order(request, "name"), | ||
| 1320 | 'ordericon':_get_toggle_order_icon(request, "name"), | ||
| 1321 | }, | ||
| 1322 | { | ||
| 1323 | 'name':'Recipe version', | ||
| 1324 | 'qhelp':'The recipe version and revision', | ||
| 1325 | }, | ||
| 1326 | { | ||
| 1327 | 'name':'Dependencies', | ||
| 1328 | 'qhelp':'Recipe build-time dependencies (i.e. other recipes)', | ||
| 1329 | 'clclass': 'depends_on', 'hidden': 1, | ||
| 1330 | }, | ||
| 1331 | { | ||
| 1332 | 'name':'Reverse dependencies', | ||
| 1333 | 'qhelp':'Recipe build-time reverse dependencies (i.e. the recipes that depend on this recipe)', | ||
| 1334 | 'clclass': 'depends_by', 'hidden': 1, | ||
| 1335 | }, | ||
| 1336 | { | ||
| 1337 | 'name':'Recipe file', | ||
| 1338 | 'qhelp':'Path to the recipe .bb file', | ||
| 1339 | 'orderfield': _get_toggle_order(request, "file_path"), | ||
| 1340 | 'ordericon':_get_toggle_order_icon(request, "file_path"), | ||
| 1341 | 'orderkey' : 'file_path', | ||
| 1342 | 'clclass': 'recipe_file', 'hidden': 0, | ||
| 1343 | }, | ||
| 1344 | { | ||
| 1345 | 'name':'Section', | ||
| 1346 | 'qhelp':'The section in which recipes should be categorized', | ||
| 1347 | 'orderfield': _get_toggle_order(request, "section"), | ||
| 1348 | 'ordericon':_get_toggle_order_icon(request, "section"), | ||
| 1349 | 'orderkey' : 'section', | ||
| 1350 | 'clclass': 'recipe_section', 'hidden': 0, | ||
| 1351 | }, | ||
| 1352 | { | ||
| 1353 | 'name':'License', | ||
| 1354 | 'qhelp':'The list of source licenses for the recipe. Multiple license names separated by the pipe character indicates a choice between licenses. Multiple license names separated by the ampersand character indicates multiple licenses exist that cover different parts of the source', | ||
| 1355 | 'orderfield': _get_toggle_order(request, "license"), | ||
| 1356 | 'ordericon':_get_toggle_order_icon(request, "license"), | ||
| 1357 | 'orderkey' : 'license', | ||
| 1358 | 'clclass': 'recipe_license', 'hidden': 0, | ||
| 1359 | }, | ||
| 1360 | { | ||
| 1361 | 'name':'Layer', | ||
| 1362 | 'qhelp':'The name of the layer providing the recipe', | ||
| 1363 | 'orderfield': _get_toggle_order(request, "layer_version__layer__name"), | ||
| 1364 | 'ordericon':_get_toggle_order_icon(request, "layer_version__layer__name"), | ||
| 1365 | 'orderkey' : 'layer_version__layer__name', | ||
| 1366 | 'clclass': 'layer_version__layer__name', 'hidden': 0, | ||
| 1367 | }, | ||
| 1368 | { | ||
| 1369 | 'name':'Layer branch', | ||
| 1370 | 'qhelp':'The Git branch of the layer providing the recipe', | ||
| 1371 | 'orderfield': _get_toggle_order(request, "layer_version__branch"), | ||
| 1372 | 'ordericon':_get_toggle_order_icon(request, "layer_version__branch"), | ||
| 1373 | 'orderkey' : 'layer_version__branch', | ||
| 1374 | 'clclass': 'layer_version__branch', 'hidden': 1, | ||
| 1375 | }, | ||
| 1376 | { | ||
| 1377 | 'name':'Layer commit', | ||
| 1378 | 'qhelp':'The Git commit of the layer providing the recipe', | ||
| 1379 | 'clclass': 'layer_version__layer__commit', 'hidden': 1, | ||
| 1380 | }, | ||
| 1381 | ] | ||
| 1382 | } | ||
| 1383 | |||
| 1384 | response = render(request, template, context) | ||
| 1385 | _set_parameters_values(pagesize, orderby, request) | ||
| 1386 | return response | ||
| 1387 | |||
| 1388 | def configuration(request, build_id): | 1277 | def configuration(request, build_id): |
| 1389 | template = 'configuration.html' | 1278 | template = 'configuration.html' |
| 1390 | 1279 | ||
