Merge lp:~milo/linaro-ci-dashboard/android-build-app-models into lp:linaro-ci-dashboard

Proposed by Milo Casagrande
Status: Merged
Merged at revision: 19
Proposed branch: lp:~milo/linaro-ci-dashboard/android-build-app-models
Merge into: lp:linaro-ci-dashboard
Diff against target: 490 lines (+361/-3)
12 files modified
Makefile (+3/-1)
README (+1/-1)
dashboard/android_build/migrations/0001_initial.py (+99/-0)
dashboard/android_build/models/__init__.py (+1/-0)
dashboard/android_build/models/android_loop.py (+132/-0)
dashboard/android_build/urls.py (+41/-0)
dashboard/frontend/migrations/0001_initial.py (+9/-1)
dashboard/frontend/models/loop.py (+2/-0)
dashboard/jenkinsserver/migrations/0002_auto__add_jenkinsconfig.py (+42/-0)
dashboard/jenkinsserver/models/jenkins_config.py (+29/-0)
dashboard/settings.py (+1/-0)
dashboard/urls.py (+1/-0)
To merge this branch: bzr merge lp:~milo/linaro-ci-dashboard/android-build-app-models
Reviewer Review Type Date Requested Status
Stevan Radaković code Needs Fixing
Georgy Redkozubov Needs Fixing
James Tunnicliffe Pending
Review via email: mp+117576@code.launchpad.net

Description of the change

Proposing a first branch to be merged with the master dashboard project.

In this branch:
- a new app was added: android_build
- the data model for an android specific build has been defined: there are still some TODOs in the code, that are up for comment
- added preliminary URLs for the new application, that are based on the already present work
- enabled the new application in settings.py
- added migration data for the data structure
- fixed a couple of errors on Makefile and README

We wanted to get a first review and check that we are on the right track with it.

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

AndroidLoop model misses MAKE_TARGETS and EXTERNAL_TARBALL fields. They are present in the spec on wiki and used in current build scripts.
Other thoughts are about:
 "Besides being interpreted by build scripts as described below, all configuration variables are also exported to the environment, so they may affect build procedure for particular target (for good or for bad, please make sure you don't select variable names which clash with well-known variables used by make or autotools)."
My guess is that we need field to hold all other variables that are not predefined.

review: Needs Fixing
Revision history for this message
Milo Casagrande (milo) wrote :

On Wed, Aug 1, 2012 at 9:40 AM, Georgy Redkozubov
<email address hidden> wrote:
> Review: Needs Fixing
>
> AndroidLoop model misses MAKE_TARGETS and EXTERNAL_TARBALL fields. They are present in the spec on wiki and used in current build scripts.
> Other thoughts are about:
> "Besides being interpreted by build scripts as described below, all configuration variables are also exported to the environment, so they may affect build procedure for particular target (for good or for bad, please make sure you don't select variable names which clash with well-known variables used by make or autotools)."
> My guess is that we need field to hold all other variables that are not predefined.

Yes, indeed.
I also thought it was possible to create primay keys based on multiple
columns with Django, but it is not possible, so I will have to
simplify the models a little bit (basically removing some of the
foreign keys we are using now).

--
Milo Casagrande
Infrastructure Engineer
Linaro.org <www.linaro.org> │ Open source software for ARM SoCs

Revision history for this message
Milo Casagrande (milo) wrote :

I pushed a new version of the data model.
I simplified it a little bit: now there are only AndroidLoop and Repository as real models. All the necessary info are inside AndroidLoop.

I added a new field in AndroidLoop, user_defined_values, that is set as a TextField in Django, so we should get a text area for users to fill in with their own values. I also added the missing bits.

For the repository model, now it is a ManytoMany relation with a unique value composed of repository+branch, so that we do not have duplicates in that table. I aslo check for uniqueness of those values before saving, otherwise we will have a ValueError.

18. By Milo Casagrande

Merged lp:~milo/linaro-ci-dashboard/better-html.

Revision history for this message
Stevan Radaković (stevanr) wrote :

Hi Milo, thanks for working on this !!1 :)

I have a couple of general comments for AndroidLoop class.
I really don't think we should make a separate application for it right now, and even if we have some cool reasons to do so, then the code should be re-factored so that the IntegrationLoop has a separate application for itself as well. Then what about the base Loop class? (I think you get the point)
The other thing is that all the WhateverLoop classes should extend from the Loop class. If they have something in common, then the method (or property) in question should be moved to the base Loop class as well.

Also you mention the Repository model in the comments above, but I can't seem to locate it in the diff. Can you elaborate please? :)

On to the code implementation suggestions:

...
+class AndroidLoop(IntegrationLoop):
+ """Defines the base class for an Android integration loop."""
+ class Meta:
+ app_label = 'android_build'
+
+ # The default file name for the manifest file.
+ DEFAULT_MANIFEST_FILE = 'default.xml'
+ DEFAULT_REPO = 'git://android.git.kernel.org/platform/manifest.git'
+ DEFAULT_BRANCH = 'master'
+ DEFAULT_BINUTILS = '2.20.1'
+ DEFAULT_GCC = '4.4.0'
+ DEFAULT_REPO = 'git://android.git.kernel.org/platform/manifest.git'
+ DEFAULT_BRANCH = 'master'

We have double constants? And furthermore, isn't the config file better place for these, even if android specific?

+from django.db import models
+from django.conf import settings
+
+class JenkinsConfig(models.Model):
+ class Meta:
+ app_label = 'jenkinsserver'
+
+ config_template = models.CharField(max_length=255)
+ config = models.CharField(max_length=255, blank=True)
+
+ def save(self, *args, **kwargs):
+ super(JenkinsConfig, self).save(*args, **kwargs)

I support the implementation of this model and providing the (super)user possibility to control jenkins configuration from our app. I don't see tht need of the config-template tho, except for development purposes, and in that case we can put it in the settings file as a hardcoded path (since we still don't have different setups for production and developtment databases).

I'd like to keep the review open, I'll have some few more comments for the AndroidLoop fields later today or tomorrow.

review: Needs Fixing (code)
Revision history for this message
Milo Casagrande (milo) wrote :
Download full text (3.5 KiB)

Hello Stevan!

Thanks for taking a look!

On Mon, Aug 13, 2012 at 5:31 PM, Stevan Radaković
<email address hidden> wrote:
>
> I have a couple of general comments for AndroidLoop class.
> I really don't think we should make a separate application for it right now, and even if we have some cool reasons to do so, then the code should be re-factored so that the IntegrationLoop has a separate application for itself as well. Then what about the base Loop class? (I think you get the point)

Yeah... this was one of our "problems" at the beginning of the work:
deciding if we had to create a separate app, or work on top of the
existing one.
We chose the former.

My main concern was for maintanability (smaller code base for each
Loop). Even after a brief talk with Danilo we decided to keep the
separate app for the moment. if we decide to use the same app for
everything, it shouldn't be that hard to move everything inside.

> The other thing is that all the WhateverLoop classes should extend from the Loop class. If they have something in common, then the method (or property) in question should be moved to the base Loop class as well.

Good point, I actually didn't remember if we had to use Loop or IntegrationLoop.

> Also you mention the Repository model in the comments above, but I can't seem to locate it in the diff. Can you elaborate please? :)

That was in the initial model, but I later removed it and stored
everything inside AndroidLoop.

> On to the code implementation suggestions:
>
> ...
> +class AndroidLoop(IntegrationLoop):
> + """Defines the base class for an Android integration loop."""
> + class Meta:
> + app_label = 'android_build'
> +
> + # The default file name for the manifest file.
> + DEFAULT_MANIFEST_FILE = 'default.xml'
> + DEFAULT_REPO = 'git://android.git.kernel.org/platform/manifest.git'
> + DEFAULT_BRANCH = 'master'
> + DEFAULT_BINUTILS = '2.20.1'
> + DEFAULT_GCC = '4.4.0'
> + DEFAULT_REPO = 'git://android.git.kernel.org/platform/manifest.git'
> + DEFAULT_BRANCH = 'master'
>
> We have double constants? And furthermore, isn't the config file better place for these, even if android specific?

Hmmm... wrong merge here, I didn't even see it.
For storing them in the config file, I have no idea. In this case you
intend config.xml or some Django config?
I honestly do not know which is the best way to store default values
for database entries in Django...

> +from django.db import models
> +from django.conf import settings
> +
> +class JenkinsConfig(models.Model):
> + class Meta:
> + app_label = 'jenkinsserver'
> +
> + config_template = models.CharField(max_length=255)
> + config = models.CharField(max_length=255, blank=True)
> +
> + def save(self, *args, **kwargs):
> + super(JenkinsConfig, self).save(*args, **kwargs)
>
> I support the implementation of this model and providing the (super)user possibility to control jenkins configuration from our app. I don't see tht need of the config-template tho, except for development purposes, and in that case we can put it in the settings file as a hardcoded path (since we still don't have different setups for production and dev...

Read more...

19. By Milo Casagrande

Fixed problem from review.

20. By Milo Casagrande

Removed null.

21. By Milo Casagrande

Fixed typo, update migrations.

22. By Milo Casagrande

Fixed wordings of fields.

23. By Milo Casagrande

Added new fields.

24. By Milo Casagrande

Updated migrations.

25. By Milo Casagrande

Added better name to fields.

Revision history for this message
Stevan Radaković (stevanr) wrote :
Download full text (8.1 KiB)

On 08/13/2012 06:04 PM, Milo Casagrande wrote:
> Hello Stevan!
>
> Thanks for taking a look!
>
> On Mon, Aug 13, 2012 at 5:31 PM, Stevan Radaković
> <email address hidden> wrote:
>> I have a couple of general comments for AndroidLoop class.
>> I really don't think we should make a separate application for it right now, and even if we have some cool reasons to do so, then the code should be re-factored so that the IntegrationLoop has a separate application for itself as well. Then what about the base Loop class? (I think you get the point)
> Yeah... this was one of our "problems" at the beginning of the work:
> deciding if we had to create a separate app, or work on top of the
> existing one.
> We chose the former.
>
> My main concern was for maintanability (smaller code base for each
> Loop). Even after a brief talk with Danilo we decided to keep the
> separate app for the moment. if we decide to use the same app for
> everything, it shouldn't be that hard to move everything inside.

Though I have nothing against the reasons why you decided to make this a
separate application (pros and cons, at the moment maintainability
really does sound better), I can't agree with the implementation,
because now we have mixed ways of doing things. As I pointed out, if
we're separating loops into applications, then part of your change
should be a re-factoring of the IntegrationLoop, thus bringing it into
separate application as well. If we leave it as it is, we will have
mixed and even more unmaintainable solution, with developers wandering
where the IntegrationLoop is and why all loop derivatives have their own
app, and integration one does not. There are some new currents in the
implementation discussion (drop frontend etc.) so maybe we should
organize a quick session with danilo and discuss this a bit more before
making any decisions since this is still the core of our app and we will
have to carry these changes as our burden or our comfort through future
developing :)

>> The other thing is that all the WhateverLoop classes should extend from the Loop class. If they have something in common, then the method (or property) in question should be moved to the base Loop class as well.
> Good point, I actually didn't remember if we had to use Loop or IntegrationLoop.
>
>> Also you mention the Repository model in the comments above, but I can't seem to locate it in the diff. Can you elaborate please? :)
> That was in the initial model, but I later removed it and stored
> everything inside AndroidLoop.
>
>> On to the code implementation suggestions:
>>
>> ...
>> +class AndroidLoop(IntegrationLoop):
>> + """Defines the base class for an Android integration loop."""
>> + class Meta:
>> + app_label = 'android_build'
>> +
>> + # The default file name for the manifest file.
>> + DEFAULT_MANIFEST_FILE = 'default.xml'
>> + DEFAULT_REPO = 'git://android.git.kernel.org/platform/manifest.git'
>> + DEFAULT_BRANCH = 'master'
>> + DEFAULT_BINUTILS = '2.20.1'
>> + DEFAULT_GCC = '4.4.0'
>> + DEFAULT_REPO = 'git://android.git.kernel.org/platform/manifest.git'
>> + DEFAULT_BRANCH = 'master'
>>
>> We have double constants? And furtherm...

Read more...

Revision history for this message
Milo Casagrande (milo) wrote :
Download full text (4.9 KiB)

Hello Stevan!

On Tue, Aug 14, 2012 at 1:53 PM, Stevan Radaković
<email address hidden> wrote:
>
> Though I have nothing against the reasons why you decided to make this a
> separate application (pros and cons, at the moment maintainability
> really does sound better), I can't agree with the implementation,
> because now we have mixed ways of doing things. As I pointed out, if
> we're separating loops into applications, then part of your change
> should be a re-factoring of the IntegrationLoop, thus bringing it into
> separate application as well.

Indeed, but we didn't want to do that without discussing further the approach.
Whatever we decide, refactoring wouldn't be a big problem: code is
already self contained that shouldn't be hard to do.

> If we leave it as it is, we will have
> mixed and even more unmaintainable solution, with developers wandering
> where the IntegrationLoop is and why all loop derivatives have their own
> app, and integration one does not. There are some new currents in the
> implementation discussion (drop frontend etc.) so maybe we should
> organize a quick session with danilo and discuss this a bit more before
> making any decisions since this is still the core of our app and we will
> have to carry these changes as our burden or our comfort through future
> developing :)

Totally agree with you.
Bare in mind that me and gesha are for splitting it up into separate apps. :-)

I was looking around and I saw also use of "sub-apps": a single Django
app, with multile apps inside. This might even be our case.
But let's schedule a meeting to discuss about it.

> Well I dunno putting string directly in the default section for a field
> is a common practice, but you can also use settings.py in django, and
> getting the value as i.e. "settings.ANDROID_DEFAULT_REPO"...

I thought about settings.py, but didn't really want to use it for
that, more for a locality point of view, keeping fields related to a
single app within itself, and keeping settings.py only for general
stuff.

> Ok, on to the model fields:
>
> +class AndroidLoop(IntegrationLoop):
> + """Defines the base class for an Android integration loop."""
> + class Meta:
> + app_label = 'android_build'
> +
> + # The default file name for the manifest file.
> + DEFAULT_MANIFEST_FILE = 'default.xml'
> + DEFAULT_REPO = 'git://android.git.kernel.org/platform/manifest.git'
> + DEFAULT_BRANCH = 'master'
> + DEFAULT_BINUTILS = '2.20.1'
> + DEFAULT_GCC = '4.4.0'
> + DEFAULT_REPO = 'git://android.git.kernel.org/platform/manifest.git'
> + DEFAULT_BRANCH = 'master'
> +
> + # BUILD_TYPE
> + build_type = models.CharField(max_length=100,
> choices=ANDROID_BUILD_TYPES)
> + # MANIFEST_REPO
> + manifest_repo = models.CharField(max_length=255, default=DEFAULT_REPO)
> + # MANIFEST_BRANCH
> + manifest_branch = models.CharField(max_length=50,
> default=DEFAULT_BRANCH)
>
> Are we missing a revision field here as well? I guess users will
> sometimes want something other then :head: revision for their builds...

Consider that our model is a 1:1 representation of what we have in
place now. We didn't really invent anything here, it is...

Read more...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2012-07-19 08:00:53 +0000
3+++ Makefile 2012-08-14 08:45:23 +0000
4@@ -10,8 +10,10 @@
5 create-migration: syncdb
6 python dashboard/manage.py schemamigration frontend --auto || \
7 echo "No changes to frontend models."
8- python dashboard/manage.py schemamigration jenkins --auto || \
9+ python dashboard/manage.py schemamigration jenkinsserver --auto || \
10 echo "No changes to jenkins models."
11+ python dashboard/manage.py schemamigration android_build --auto || \
12+ echo "No changes to android_build models."
13 python dashboard/manage.py migrate
14
15 migrate: syncdb
16
17=== modified file 'README'
18--- README 2012-07-24 21:34:26 +0000
19+++ README 2012-08-14 08:45:23 +0000
20@@ -46,7 +46,7 @@
21 Whenever any of the models are changed, it is strongly advised to run
22 South' schemamigration command:
23
24- $ make migration
25+ $ make migrate
26
27
28 Tests
29
30=== added directory 'dashboard/android_build'
31=== added file 'dashboard/android_build/__init__.py'
32=== added directory 'dashboard/android_build/migrations'
33=== added file 'dashboard/android_build/migrations/0001_initial.py'
34--- dashboard/android_build/migrations/0001_initial.py 1970-01-01 00:00:00 +0000
35+++ dashboard/android_build/migrations/0001_initial.py 2012-08-14 08:45:23 +0000
36@@ -0,0 +1,99 @@
37+# encoding: utf-8
38+import datetime
39+from south.db import db
40+from south.v2 import SchemaMigration
41+from django.db import models
42+
43+class Migration(SchemaMigration):
44+
45+ def forwards(self, orm):
46+
47+ # Adding model 'AndroidLoop'
48+ db.create_table('android_build_androidloop', (
49+ ('loop_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['frontend.Loop'], unique=True, primary_key=True)),
50+ ('build_type', self.gf('django.db.models.fields.CharField')(max_length=100)),
51+ ('manifest_repo', self.gf('django.db.models.fields.CharField')(default='git://android.git.kernel.org/platform/manifest.git', max_length=255)),
52+ ('manifest_branch', self.gf('django.db.models.fields.CharField')(default='master', max_length=50)),
53+ ('repo_quiet', self.gf('django.db.models.fields.BooleanField')(default=False)),
54+ ('manifest_filename', self.gf('django.db.models.fields.CharField')(default='default.xml', max_length=255)),
55+ ('make_targets', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
56+ ('make_jobs', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
57+ ('ramdisk_size', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)),
58+ ('external_tarball', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
59+ ('build_fs_image', self.gf('django.db.models.fields.BooleanField')(default=False)),
60+ ('fs_image_size', self.gf('django.db.models.fields.CharField')(default='2G', max_length=20, blank=True)),
61+ ('user_defined_values', self.gf('django.db.models.fields.TextField')(blank=True)),
62+ ('toolchain_url', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
63+ ('target_product', self.gf('django.db.models.fields.CharField')(max_length=50, blank=True)),
64+ ('target_tools_prefix', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
65+ ('binutils_version', self.gf('django.db.models.fields.CharField')(default='2.20.1', max_length=25)),
66+ ('binutils_url', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
67+ ('gcc_version', self.gf('django.db.models.fields.CharField')(default='4.4.0', max_length=25)),
68+ ('gcc_url', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
69+ ('sysroot_ndk_url', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
70+ ('lava_submit', self.gf('django.db.models.fields.BooleanField')(default=False)),
71+ ('lava_test_plan', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
72+ ('lava_submit_fatal', self.gf('django.db.models.fields.BooleanField')(default=True)),
73+ ('lava_android_binaries', self.gf('django.db.models.fields.BooleanField')(default=True)),
74+ ))
75+ db.send_create_signal('android_build', ['AndroidLoop'])
76+
77+
78+ def backwards(self, orm):
79+
80+ # Deleting model 'AndroidLoop'
81+ db.delete_table('android_build_androidloop')
82+
83+
84+ models = {
85+ 'android_build.androidloop': {
86+ 'Meta': {'object_name': 'AndroidLoop', '_ormbases': ['frontend.Loop']},
87+ 'binutils_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
88+ 'binutils_version': ('django.db.models.fields.CharField', [], {'default': "'2.20.1'", 'max_length': '25'}),
89+ 'build_fs_image': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
90+ 'build_type': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
91+ 'external_tarball': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
92+ 'fs_image_size': ('django.db.models.fields.CharField', [], {'default': "'2G'", 'max_length': '20', 'blank': 'True'}),
93+ 'gcc_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
94+ 'gcc_version': ('django.db.models.fields.CharField', [], {'default': "'4.4.0'", 'max_length': '25'}),
95+ 'lava_android_binaries': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
96+ 'lava_submit': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
97+ 'lava_submit_fatal': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
98+ 'lava_test_plan': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
99+ 'loop_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['frontend.Loop']", 'unique': 'True', 'primary_key': 'True'}),
100+ 'make_jobs': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
101+ 'make_targets': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
102+ 'manifest_branch': ('django.db.models.fields.CharField', [], {'default': "'master'", 'max_length': '50'}),
103+ 'manifest_filename': ('django.db.models.fields.CharField', [], {'default': "'default.xml'", 'max_length': '255'}),
104+ 'manifest_repo': ('django.db.models.fields.CharField', [], {'default': "'git://android.git.kernel.org/platform/manifest.git'", 'max_length': '255'}),
105+ 'ramdisk_size': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
106+ 'repo_quiet': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
107+ 'sysroot_ndk_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
108+ 'target_product': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
109+ 'target_tools_prefix': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
110+ 'toolchain_url': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
111+ 'user_defined_values': ('django.db.models.fields.TextField', [], {'blank': 'True'})
112+ },
113+ 'frontend.loop': {
114+ 'Meta': {'object_name': 'Loop'},
115+ 'config': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['jenkinsserver.JenkinsConfig']"}),
116+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
117+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
118+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['jenkinsserver.JenkinsServer']"})
119+ },
120+ 'jenkinsserver.jenkinsconfig': {
121+ 'Meta': {'object_name': 'JenkinsConfig'},
122+ 'config': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
123+ 'config_template': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
124+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
125+ },
126+ 'jenkinsserver.jenkinsserver': {
127+ 'Meta': {'object_name': 'JenkinsServer'},
128+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
129+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
130+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
131+ 'username': ('django.db.models.fields.CharField', [], {'max_length': '100'})
132+ }
133+ }
134+
135+ complete_apps = ['android_build']
136
137=== added file 'dashboard/android_build/migrations/__init__.py'
138=== added directory 'dashboard/android_build/models'
139=== added file 'dashboard/android_build/models/__init__.py'
140--- dashboard/android_build/models/__init__.py 1970-01-01 00:00:00 +0000
141+++ dashboard/android_build/models/__init__.py 2012-08-14 08:45:23 +0000
142@@ -0,0 +1,1 @@
143+from android_loop import AndroidLoop
144
145=== added file 'dashboard/android_build/models/android_loop.py'
146--- dashboard/android_build/models/android_loop.py 1970-01-01 00:00:00 +0000
147+++ dashboard/android_build/models/android_loop.py 2012-08-14 08:45:23 +0000
148@@ -0,0 +1,132 @@
149+# Copyright (C) 2012 Linaro
150+#
151+# This file is part of linaro-ci-dashboard.
152+#
153+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
154+# it under the terms of the GNU Affero General Public License as published by
155+# the Free Software Foundation, either version 3 of the License, or
156+# (at your option) any later version.
157+#
158+# linaro-ci-dashboard is distributed in the hope that it will be useful,
159+# but WITHOUT ANY WARRANTY; without even the implied warranty of
160+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
161+# GNU Affero General Public License for more details.
162+#
163+# You should have received a copy of the GNU Affero General Public License
164+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
165+
166+from django.db import models
167+from frontend.models.loop import Loop
168+from jenkinsserver.models.jenkins_config import JenkinsConfig
169+from jenkinsserver.models.jenkins_server import JenkinsServer
170+
171+
172+# The internal names for the different build type, and a user visible name
173+BUILD_ANDROID = (r'build-android', 'Android')
174+BUILD_ANDROID_RESTRICTED = (r'build-android-restricted', 'Android Restricted')
175+BUILD_ANDROID_TOOLCHAIN = (r'build-android-toolchain', 'Android Toolchain')
176+BUILD_ANDROID_TOOLCHAIN_LINARO = (r'build-android-toolchain-linaro',
177+ 'Android Toolchain Linaro')
178+# All the supported build types.
179+ANDROID_BUILD_TYPES = (
180+ BUILD_ANDROID,
181+ BUILD_ANDROID_RESTRICTED,
182+ BUILD_ANDROID_TOOLCHAIN,
183+ BUILD_ANDROID_TOOLCHAIN_LINARO,
184+ )
185+
186+# Inetrnal name of the board, and a user visible name
187+BEAGLEBOARD = (r'beagleboard', 'Beagleboard')
188+PANDABOARD = (r'panda', 'Pandaboard')
189+SNOWBALL = (r'snowball', 'Snowball')
190+# The supported boards for the build.
191+TARGET_BOARDS = (BEAGLEBOARD, PANDABOARD, SNOWBALL)
192+
193+
194+class AndroidLoop(Loop):
195+ """Defines the base class for an Android integration loop."""
196+ class Meta:
197+ app_label = 'android_build'
198+
199+ # The default file name for the manifest file.
200+ DEFAULT_MANIFEST_FILE = 'default.xml'
201+ DEFAULT_REPO = 'git://android.git.kernel.org/platform/manifest.git'
202+ DEFAULT_BRANCH = 'master'
203+ DEFAULT_BINUTILS = '2.20.1'
204+ DEFAULT_GCC = '4.4.0'
205+ DEFAULT_IMAGE_SIZE = '2G'
206+
207+ # BUILD_TYPE
208+ build_type = models.CharField(max_length=100, choices=ANDROID_BUILD_TYPES)
209+ # MANIFEST_REPO
210+ manifest_repo = models.CharField(max_length=255, default=DEFAULT_REPO)
211+ # MANIFEST_BRANCH
212+ manifest_branch = models.CharField(max_length=50, default=DEFAULT_BRANCH)
213+ # REPO_QUIET
214+ repo_quiet = models.BooleanField(default=False)
215+ # MANIFEST_FILENAME
216+ manifest_filename = models.CharField(max_length=255,
217+ default=DEFAULT_MANIFEST_FILE)
218+ # MAKE_TARGETS
219+ make_targets = models.CharField(max_length=255, blank=True)
220+ # MAKE_JOBS
221+ make_jobs = models.PositiveIntegerField(default=0)
222+ # RAMDISK_SIZE
223+ ramdisk_size = models.PositiveIntegerField(default=0)
224+ # EXTERNAL_TARBALL
225+ external_tarball = models.CharField(max_length=255, blank=True)
226+ # BUILD_FS_IMAGE
227+ build_fs_image = models.BooleanField(default=False,
228+ verbose_name='Build filesystem image')
229+ # FS_IMAGE_SIZE
230+ fs_image_size = models.CharField(max_length=20,
231+ blank=True,
232+ verbose_name='Filesystem image size',
233+ default=DEFAULT_IMAGE_SIZE)
234+ # Users might want to define their own values.
235+ user_defined_values = models.TextField(blank=True)
236+
237+ # Data needed for build of type build-android.
238+ toolchain_url = models.CharField(max_length=255, blank=True)
239+ target_product = models.CharField(max_length=50, choices=TARGET_BOARDS,
240+ blank=True)
241+ target_tools_prefix = models.CharField(max_length=255, blank=True)
242+
243+ # Data needed for build of type build-android-toolchain.
244+ binutils_version = models.CharField(max_length=25,
245+ default=DEFAULT_BINUTILS)
246+ binutils_url = models.CharField(max_length=255, blank=True)
247+
248+ gcc_version = models.CharField(max_length=25, default=DEFAULT_GCC)
249+ gcc_url = models.CharField(max_length=255, blank=True)
250+
251+ # TODO need to check the default value for this one.
252+ sysroot_ndk_url = models.CharField(max_length=255, blank=True)
253+
254+ # Data needed for LAVA integration.
255+ lava_submit = models.BooleanField(default=False)
256+ # TODO need to know the values here
257+ lava_test_plan = models.CharField(max_length=255, blank=True)
258+ lava_submit_fatal = models.BooleanField(default=True, blank=True)
259+ lava_android_binaries = models.BooleanField(default=True, blank=True)
260+
261+ def save(self, *args, **kwargs):
262+ # TODO: Create encoded config
263+ jenkins_config = JenkinsConfig()
264+ jenkins_config.save()
265+ self.config = jenkins_config
266+ self.server = JenkinsServer.objects.get(id=1)
267+ super(AndroidLoop, self).save(*args, **kwargs)
268+ # We do not want a failure in remote server to affect the
269+ # CI Loop flow.
270+ try:
271+ self.server.create_or_update_integration_loop(self)
272+ except:
273+ # TODO: Log error.
274+ pass
275+
276+ def schedule_build(self):
277+ # Every time before the build is scheduled, update the
278+ # loop config on the remote server.
279+ self.server.create_or_update_integration_loop(self)
280+ super(AndroidLoop, self).schedule_build()
281
282=== added directory 'dashboard/android_build/templates'
283=== added file 'dashboard/android_build/templates/__init__.py'
284=== added directory 'dashboard/android_build/tests'
285=== added file 'dashboard/android_build/tests/__init__.py'
286=== added file 'dashboard/android_build/urls.py'
287--- dashboard/android_build/urls.py 1970-01-01 00:00:00 +0000
288+++ dashboard/android_build/urls.py 2012-08-14 08:45:23 +0000
289@@ -0,0 +1,41 @@
290+# Copyright (C) 2012 Linaro
291+#
292+# This file is part of linaro-ci-dashboard.
293+#
294+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
295+# it under the terms of the GNU Affero General Public License as published by
296+# the Free Software Foundation, either version 3 of the License, or
297+# (at your option) any later version.
298+#
299+# linaro-ci-dashboard is distributed in the hope that it will be useful,
300+# but WITHOUT ANY WARRANTY; without even the implied warranty of
301+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
302+# GNU Affero General Public License for more details.
303+#
304+# You should have received a copy of the GNU Affero General Public License
305+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
306+
307+from django.conf.urls.defaults import patterns, include, url
308+from frontend.views.home_page_view import HomePageView
309+from frontend.views.index_view import IndexView
310+from frontend.views.integration_loop_create_view \
311+ import IntegrationLoopCreateView
312+from frontend.views.integration_loop_update_view \
313+ import IntegrationLoopUpdateView
314+from frontend.views.integration_loop_detail_view \
315+ import IntegrationLoopDetailView
316+from frontend.views.loop_build_view import LoopBuildView
317+
318+urlpatterns = patterns('',
319+ url(r'^$', IndexView.as_view(), name='Index'),
320+ url(r'^index/$', IndexView.as_view(), name='Index'),
321+ url(r'^home/$', HomePageView.as_view(), name='Home'),
322+ url(r'^android/create/$',
323+ IntegrationLoopCreateView.as_view(), name='AndroidLoopCreate'),
324+ url(r'^android/detail/(?P<slug>[\w|\W]+)/$',
325+ IntegrationLoopDetailView.as_view(), name='AndroidLoopDetail'),
326+ url(r'^android/update/(?P<slug>[\w|\W]+)/$',
327+ IntegrationLoopUpdateView.as_view(), name='AndroidLoopUpdate'),
328+ url(r'^loop/build/(?P<slug>[\w|\W]+)/$',
329+ LoopBuildView.as_view(), name='LoopBuild'),
330+)
331
332=== added directory 'dashboard/android_build/views'
333=== added file 'dashboard/android_build/views/__init__.py'
334=== modified file 'dashboard/frontend/migrations/0001_initial.py'
335--- dashboard/frontend/migrations/0001_initial.py 2012-07-25 12:20:01 +0000
336+++ dashboard/frontend/migrations/0001_initial.py 2012-08-14 08:45:23 +0000
337@@ -13,6 +13,7 @@
338 ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
339 ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=200)),
340 ('server', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['jenkinsserver.JenkinsServer'])),
341+ ('config', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['jenkinsserver.JenkinsConfig'])),
342 ))
343 db.send_create_signal('frontend', ['Loop'])
344
345@@ -61,7 +62,8 @@
346 'Meta': {'object_name': 'Loop'},
347 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
348 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'}),
349- 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['jenkinsserver.JenkinsServer']"})
350+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['jenkinsserver.JenkinsServer']"}),
351+ 'config': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['jenkinsserver.JenkinsConfig']"})
352 },
353 'frontend.loopbuild': {
354 'Meta': {'ordering': "['-id']", 'object_name': 'LoopBuild'},
355@@ -78,6 +80,12 @@
356 'password': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
357 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
358 'username': ('django.db.models.fields.CharField', [], {'max_length': '100'})
359+ },
360+ 'jenkinsserver.jenkinsconfig': {
361+ 'Meta': {'object_name': 'JenkinsConfig'},
362+ 'config_template': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
363+ 'config': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
364+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
365 }
366 }
367
368
369=== modified file 'dashboard/frontend/models/loop.py'
370--- dashboard/frontend/models/loop.py 2012-07-26 13:25:06 +0000
371+++ dashboard/frontend/models/loop.py 2012-08-14 08:45:23 +0000
372@@ -19,6 +19,7 @@
373 from django.contrib.auth.models import User
374 from django.db import models
375 from jenkinsserver.models.jenkins_server import JenkinsServer
376+from jenkinsserver.models.jenkins_config import JenkinsConfig
377
378
379 class Loop(models.Model):
380@@ -27,6 +28,7 @@
381
382 name = models.CharField(max_length=200, unique=True)
383 server = models.ForeignKey(JenkinsServer)
384+ config = models.ForeignKey(JenkinsConfig)
385
386 def schedule_build(self):
387 '''Add a LoopBuild record for this Loop.
388
389=== added file 'dashboard/jenkinsserver/migrations/0002_auto__add_jenkinsconfig.py'
390--- dashboard/jenkinsserver/migrations/0002_auto__add_jenkinsconfig.py 1970-01-01 00:00:00 +0000
391+++ dashboard/jenkinsserver/migrations/0002_auto__add_jenkinsconfig.py 2012-08-14 08:45:23 +0000
392@@ -0,0 +1,42 @@
393+# encoding: utf-8
394+import datetime
395+from south.db import db
396+from south.v2 import SchemaMigration
397+from django.db import models
398+
399+class Migration(SchemaMigration):
400+
401+ def forwards(self, orm):
402+
403+ # Adding model 'JenkinsConfig'
404+ db.create_table('jenkinsserver_jenkinsconfig', (
405+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
406+ ('config_template', self.gf('django.db.models.fields.CharField')(max_length=255)),
407+ ('config', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
408+ ))
409+ db.send_create_signal('jenkinsserver', ['JenkinsConfig'])
410+
411+
412+ def backwards(self, orm):
413+
414+ # Deleting model 'JenkinsConfig'
415+ db.delete_table('jenkinsserver_jenkinsconfig')
416+
417+
418+ models = {
419+ 'jenkinsserver.jenkinsconfig': {
420+ 'Meta': {'object_name': 'JenkinsConfig'},
421+ 'config_template': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
422+ 'config': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
423+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
424+ },
425+ 'jenkinsserver.jenkinsserver': {
426+ 'Meta': {'object_name': 'JenkinsServer'},
427+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
428+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
429+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
430+ 'username': ('django.db.models.fields.CharField', [], {'max_length': '100'})
431+ }
432+ }
433+
434+ complete_apps = ['jenkinsserver']
435
436=== added file 'dashboard/jenkinsserver/models/jenkins_config.py'
437--- dashboard/jenkinsserver/models/jenkins_config.py 1970-01-01 00:00:00 +0000
438+++ dashboard/jenkinsserver/models/jenkins_config.py 2012-08-14 08:45:23 +0000
439@@ -0,0 +1,29 @@
440+# Copyright (C) 2012 Linaro
441+#
442+# This file is part of linaro-ci-dashboard.
443+#
444+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
445+# it under the terms of the GNU Affero General Public License as published by
446+# the Free Software Foundation, either version 3 of the License, or
447+# (at your option) any later version.
448+#
449+# linaro-ci-dashboard is distributed in the hope that it will be useful,
450+# but WITHOUT ANY WARRANTY; without even the implied warranty of
451+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
452+# GNU Affero General Public License for more details.
453+#
454+# You should have received a copy of the GNU Affero General Public License
455+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
456+
457+from django.db import models
458+from django.conf import settings
459+
460+class JenkinsConfig(models.Model):
461+ class Meta:
462+ app_label = 'jenkinsserver'
463+
464+ config_template = models.CharField(max_length=255)
465+ config = models.CharField(max_length=255)
466+
467+ def save(self, *args, **kwargs):
468+ super(JenkinsConfig, self).save(*args, **kwargs)
469
470=== modified file 'dashboard/settings.py'
471--- dashboard/settings.py 2012-07-24 21:28:00 +0000
472+++ dashboard/settings.py 2012-08-14 08:45:23 +0000
473@@ -139,6 +139,7 @@
474 'django_openid_auth',
475 'jenkinsserver',
476 'frontend',
477+ 'android_build',
478 'south',
479 # Uncomment the next line to enable the admin:
480 # 'django.contrib.admin',
481
482=== modified file 'dashboard/urls.py'
483--- dashboard/urls.py 2012-07-19 19:58:21 +0000
484+++ dashboard/urls.py 2012-08-14 08:45:23 +0000
485@@ -30,4 +30,5 @@
486 url(r'^js/(?P<path>.*)$', 'django.views.static.serve',
487 {'document_root': settings.JS_PATH}),
488 url(r'^', include('dashboard.frontend.urls')),
489+ url(r'^', include('dashboard.android_build.urls')),
490 )

Subscribers

People subscribed via source and target branches