Merge lp:~pfalcon/linaro-android-frontend/private into lp:linaro-android-frontend

Proposed by Paul Sokolovsky
Status: Merged
Approved by: Paul Sokolovsky
Approved revision: 270
Merged at revision: 255
Proposed branch: lp:~pfalcon/linaro-android-frontend/private
Merge into: lp:linaro-android-frontend
Diff against target: 283 lines (+87/-46)
8 files modified
android_build/frontend/api.py (+8/-12)
android_build/frontend/views.py (+25/-8)
android_build/settings.py (+6/-1)
android_build/templates/index.html (+15/-0)
android_build/templates/new.html (+17/-4)
group-fixture.json (+8/-0)
static/index.js (+5/-1)
static/new.js (+3/-20)
To merge this branch: bzr merge lp:~pfalcon/linaro-android-frontend/private
Reviewer Review Type Date Requested Status
Georgy Redkozubov Approve
Alexander Sack Pending
Linaro Infrastructure Pending
Review via email: mp+101780@code.launchpad.net

Description of the change

These are the changes to Android Build frontend to support private builds.

This can be seen in action on https://ec2-107-22-102-45.compute-1.amazonaws.com .

Specific changes are:

On UI side:

1. On https://ec2-107-22-102-45.compute-1.amazonaws.com , new "Private builds" tab added, showing private builds (builds starting with "~linaro-android-private/")
2. On https://ec2-107-22-102-45.compute-1.amazonaws.com/new , user is shown with dropdown of Android Build related group he's member on, so he can create build belonging to any group (besides his own personal build). This supersedes previous checkbox to create "official" build.

On backend:

1. "linaro-android-private" Launchpad group membership is queried on login. The semantics of that of that group membership is "can create and edit private Android build".
2. For each new build created, group-specific template job is used, named as "template_$group", e.g. template_linaro-android-official-builders. Previously, we had single template job called "blank".

To post a comment you must log in.
Revision history for this message
Georgy Redkozubov (gesha) wrote :

Looks good.

review: Approve
Revision history for this message
Paul Sokolovsky (pfalcon) wrote :

asac also OKed this via IRC.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'android_build/frontend/api.py'
2--- android_build/frontend/api.py 2012-02-01 15:48:33 +0000
3+++ android_build/frontend/api.py 2012-04-12 17:22:20 +0000
4@@ -13,7 +13,7 @@
5 from android_build.frontend.views import (
6 can_edit,
7 is_builder,
8- is_official_builder,
9+ group2prefix,
10 )
11
12
13@@ -184,23 +184,19 @@
14 @builder_required
15 def new(request):
16 try:
17- is_official = request.POST.get('official', 'false') == 'true'
18- if is_official:
19- if not is_official_builder(request):
20- return HttpResponse(
21- "You are not allowed to create an official build", status=403)
22- ownerName = 'linaro-android'
23- else:
24- ownerName = request.user.username
25+ group = request.POST['group']
26+ if not request.user.groups.filter(name=group).exists():
27+ return HttpResponse(
28+ "You are not allowed to create build for requested group", status=403)
29+ ownerName = group2prefix(request, group)
30+
31 buildName = request.POST['name']
32 if not valid_build_name.match(buildName):
33 return HttpResponse("Invalid name.", status=400)
34 new_job_name = ownerName + '_' + buildName
35- xml_base = getJobConfig(settings.TEMPLATE_JOB_NAME)
36+ xml_base = getJobConfig(settings.TEMPLATE_JOB_NAME % group)
37 if isinstance(xml_base, HttpResponse):
38 return xml_base
39- if is_official:
40- xml_base = resetRetentionSettings(xml_base)
41 new_config = replaceConfigDefault(xml_base, request.POST['config'])
42 resp = postConfig('createItem?name=' + new_job_name, new_config)
43 if resp:
44
45=== modified file 'android_build/frontend/views.py'
46--- android_build/frontend/views.py 2011-03-25 00:09:03 +0000
47+++ android_build/frontend/views.py 2012-04-12 17:22:20 +0000
48@@ -7,6 +7,8 @@
49 from django.contrib.auth.decorators import (
50 login_required
51 )
52+from django.contrib.auth.models import Group
53+
54
55 config_template = '''\
56 var globalConfig = {
57@@ -14,20 +16,35 @@
58 }
59 '''
60
61+def prefix2group(prefix):
62+ rev_map = {}
63+ # If prefix is in adhoc map, return corresponding group
64+ for k, v in settings.GROUP_TO_PREFIX_MAP.iteritems():
65+ if v == prefix:
66+ return k
67+ # Otherwise, check if prefix matches groups known to Django
68+ if Group.objects.filter(name=prefix).exists():
69+ return prefix
70+ # Otherwise, it should be personal build
71+ return "linaro-android-builders"
72+
73+def group2prefix(request, group):
74+ val = settings.GROUP_TO_PREFIX_MAP.get(group, group)
75+ if val == "$user":
76+ return request.user.username
77+ return val
78+
79 def is_builder(request):
80 return request.user.groups.filter(name='linaro-android-builders').exists()
81
82-def is_official_builder(request):
83- return request.user.groups.filter(
84- name='linaro-android-official-builders').exists()
85-
86 def can_edit(request, build_name):
87 if request.user.is_authenticated():
88 owner_name = build_name.split('/')[0][1:]
89- if owner_name == 'linaro-android':
90- return is_official_builder(request)
91+ group = prefix2group(owner_name)
92+ if group == "linaro-android-builders":
93+ return owner_name == request.user.username
94 else:
95- return owner_name == request.user.username
96+ return request.user.groups.filter(name=group).exists()
97 else:
98 return False
99
100@@ -81,6 +98,6 @@
101 return HttpResponse("sorry you are not allowed here", status=403)
102 data = {
103 'request': request,
104- 'canMakeOfficialBuilds': is_official_builder(request),
105+ 'groups': request.user.groups.all(),
106 }
107 return _render(request, 'new.html', data)
108
109=== modified file 'android_build/settings.py'
110--- android_build/settings.py 2011-04-20 17:38:47 +0000
111+++ android_build/settings.py 2012-04-12 17:22:20 +0000
112@@ -98,6 +98,11 @@
113 FRONTEND_JENKINS_USER = 'admin'
114 FRONTEND_JENKINS_PASSWORD = 'password'
115 # Name of preconfigured job used as a template for all other jobs
116-TEMPLATE_JOB_NAME = 'blank'
117+TEMPLATE_JOB_NAME = 'template_%s'
118+# We generally use group name as a prefix, but allow for adhoc mapping
119+GROUP_TO_PREFIX_MAP = {
120+ "linaro-android-builders": "$user",
121+ "linaro-android-official-builders": "linaro-android",
122+}
123
124 USE_OWN_COMBO=False
125
126=== modified file 'android_build/templates/index.html'
127--- android_build/templates/index.html 2012-03-29 15:00:38 +0000
128+++ android_build/templates/index.html 2012-04-12 17:22:20 +0000
129@@ -143,6 +143,7 @@
130 <li><a id="official-tab" href="#official-builds">Official Builds</a></li>
131 <li><a id="mine-tab" href="#my-builds">My Builds</a></li>
132 <li><a id="all-tab" href="#all-builds">All Builds</a></li>
133+ <li><a id="private-tab" href="#private-builds">Private Builds</a></li>
134 </ul>
135 <div>
136 <div id="official-builds">
137@@ -181,6 +182,20 @@
138 </select>
139 <div class="build-table" id="all-build-table"></div>
140 </div>
141+
142+ <div id="private-builds">
143+ Search: <input class="search" />
144+ Outcome: <select>
145+ <option value="Any" selected="selected">Any</option>
146+ <option value="OK">Success</option>
147+ <option value="FAILED">Failure</option>
148+ <option value="ABORTED">Aborted</option>
149+ <option value="RUNNING">Building</option>
150+ <option value="">Never built</option>
151+ </select>
152+ <div class="build-table" id="private-build-table"></div>
153+ </div>
154+
155 </div>
156 </div>
157 {% endblock %}
158
159=== modified file 'android_build/templates/new.html'
160--- android_build/templates/new.html 2011-03-15 01:09:15 +0000
161+++ android_build/templates/new.html 2012-04-12 17:22:20 +0000
162@@ -7,13 +7,26 @@
163 <h2>New Build</h2>
164 <div>
165 <label for="name">Name:</label>
166- ~<span id="ownerName">{{ request.user.username }}</span>/<input id="name" value="">
167+ ~<select id="group">
168+{% for g in groups %}
169+<option value="{{g.name}}">
170+{% if g.name == "linaro-android-builders" %}
171+ {{request.user.username}}
172+{% else %}
173+ {% if g.name == "linaro-android-official-builders" %}
174+ linaro-android
175+ {% else %}
176+ {{g.name}}
177+ {% endif %}
178+{% endif %}
179+</option>
180+{% endfor %}
181+</select>/<input id="name" value="">
182 <span id="taken-warning" class="hidden" style="color: red">name taken</span>
183 <span id="invalid-name-warning" class="hidden" style="color: red">invalid name</span>
184 <br />
185- {% if canMakeOfficialBuilds %}
186- <input type="checkbox" id="official" value="official" /><label for="official">Create an official build</label><br />
187- {% endif %}
188+ <br />
189+
190 <textarea id="configuration" cols="80" rows="10">MANIFEST_REPO=git://android.git.kernel.org/platform/manifest.git
191 MANIFEST_BRANCH=master
192 MANIFEST_FILENAME=default.xml
193
194=== modified file 'group-fixture.json'
195--- group-fixture.json 2011-03-08 01:06:18 +0000
196+++ group-fixture.json 2012-04-12 17:22:20 +0000
197@@ -14,5 +14,13 @@
198 },
199 "pk" : 2,
200 "model" : "auth.group"
201+ },
202+ {
203+ "fields" : {
204+ "permissions" : [],
205+ "name" : "linaro-android-private"
206+ },
207+ "pk" : 3,
208+ "model" : "auth.group"
209 }
210 ]
211
212=== modified file 'static/index.js'
213--- static/index.js 2011-03-17 02:41:11 +0000
214+++ static/index.js 2012-04-12 17:22:20 +0000
215@@ -219,7 +219,11 @@
216 function (item) { return item.getValue('name').search(userRegexp) == 0; } :
217 function (item) { return false; })
218 ),
219- makeDT("#all-build-table")
220+ makeDT("#all-build-table"),
221+ makeDT(
222+ "#private-build-table",
223+ function (item) { return item.getValue('name').search(/^~linaro-android-private\//) == 0; }
224+ )
225 ];
226
227 function extractJobsFromResponse(data) {
228
229=== modified file 'static/new.js'
230--- static/new.js 2011-03-17 01:37:06 +0000
231+++ static/new.js 2012-04-12 17:22:20 +0000
232@@ -25,13 +25,13 @@
233 }
234 var j = 0;
235 var tmp;
236- var names = getOfficial() ? official_used_names : user_used_names;
237+ var names = user_used_names;
238 while (names.indexOf(tmp = 'testBuild-' + j.toString()) >= 0) {
239 j++;
240 }
241 Y.one('#name').set('value', tmp);
242 checkName = function (e) {
243- var names = getOfficial() ? official_used_names : user_used_names;
244+ var names = user_used_names;
245 var curValue = Y.one('#name').get('value');
246 if (curValue.search(/^[a-z0-9][a-z0-9\+\.\-]*$/) < 0) {
247 Y.one('#taken-warning').addClass('hidden');
248@@ -52,11 +52,10 @@
249 Y.io.header('X-CSRFToken', Y.Cookie.get("csrftoken"));
250
251 function saveBuild(e, buildNow) {
252- Y.log(getOfficial());
253 var data = {
254 config: Y.one('#configuration').get('value'),
255 name: Y.one('#name').get('value'),
256- official: getOfficial()
257+ group: Y.one('#group').get('value')
258 };
259 if (buildNow) {
260 data.buildNow = true;
261@@ -80,22 +79,6 @@
262 );
263 }
264
265- function officialChange (e) {
266- if (getOfficial()) {
267- Y.one('#ownerName').setContent("linaro-android");
268- } else {
269- Y.one('#ownerName').setContent(globalConfig.userName);
270- }
271- checkName && checkName();
272- }
273-
274- Y.all('#official').on('change', officialChange);
275- function getOfficial() {
276- var officialNode = Y.one('#official');
277- return officialNode && officialNode.get('checked');
278- }
279- officialChange();
280-
281 Y.on(
282 'click',
283 function (e) {

Subscribers

People subscribed via source and target branches