Merge Request #38
Gitlab data
Make sure you have gitlab plugin active and properly configurated PROXIED_APPS: gitlab: upstream: 'http://localhost:8090/gitlab/' private_token: ''
You'll need a valid administrator private_token to validate import_proxy_data It might take a while if the upstream server is external depending on the delay
-
Signed-off-by: Gustavo Jaruga <darksshades@gmail.com> Signed-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
-
Sign-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
-
Signed-off-by: Gustavo Jaruga <darksshades@gmail.com> Signed-off-by: Rodrigo Siqueira de Melo <rodrigosiqueiramelo@gmail.com>
-
Signed-off-by: Gustavo Jaruga <darksshades@gmail.com>
- 8 of 12 commits displayed. Click here to show all
1 | 1 | import json |
2 | 2 | import urllib |
3 | 3 | import urllib2 |
4 | +import logging | |
4 | 5 | |
5 | 6 | from dateutil.parser import parse |
6 | 7 | |
7 | 8 | from django.conf import settings |
8 | 9 | from django.db.models.fields import DateTimeField |
9 | 10 | |
10 | -from colab.proxy.gitlab.models import GitlabProject | |
11 | +from colab.proxy.gitlab.models import (GitlabProject, GitlabMergeRequest, | |
12 | + GitlabComment, GitlabIssue) | |
11 | 13 | from colab.proxy.utils.proxy_data_api import ProxyDataAPI |
12 | 14 | |
15 | +LOGGER = logging.getLogger('colab.plugin.gitlab') | |
16 | + | |
13 | 17 | |
14 | 18 | class GitlabDataAPI(ProxyDataAPI): |
15 | 19 | |
... | ... | @@ -25,42 +29,175 @@ class GitlabDataAPI(ProxyDataAPI): |
25 | 29 | |
26 | 30 | return u'{}{}?{}'.format(upstream, path, params) |
27 | 31 | |
28 | - def fetchProjects(self): | |
32 | + def get_json_data(self, api_url, page, pages=1000): | |
33 | + url = self.get_request_url(api_url, per_page=pages, | |
34 | + page=page) | |
35 | + | |
36 | + try: | |
37 | + data = urllib2.urlopen(url, timeout=10) | |
38 | + json_data = json.load(data) | |
39 | + except urllib2.URLError: | |
40 | + LOGGER.exception("Connection timeout: " + url) | |
41 | + json_data = [] | |
42 | + | |
43 | + return json_data | |
44 | + | |
45 | + def fill_object_data(self, element, _object): | |
46 | + for field in _object._meta.fields: | |
47 | + try: | |
2 |
|
|
48 | + if field.name == "user": | |
49 | + _object.update_user( | |
50 | + element["author"]["username"]) | |
51 | + continue | |
52 | + if field.name == "project": | |
53 | + _object.project_id = element["project_id"] | |
54 | + continue | |
55 | + | |
56 | + if isinstance(field, DateTimeField): | |
57 | + value = parse(element[field.name]) | |
58 | + else: | |
59 | + value = element[field.name] | |
60 | + | |
61 | + setattr(_object, field.name, value) | |
62 | + except KeyError: | |
63 | + continue | |
64 | + | |
65 | + return _object | |
66 | + | |
67 | + def fetch_projects(self): | |
29 | 68 | page = 1 |
30 | 69 | projects = [] |
31 | 70 | |
32 | - # Iterates throughout all projects pages | |
33 | - while(True): | |
34 | - url = self.get_request_url('/api/v3/projects/all', | |
35 | - per_page=100, | |
36 | - page=page) | |
37 | - data = urllib2.urlopen(url) | |
38 | - json_data = json.load(data) | |
71 | + while True: | |
3 |
|
|
72 | + json_data = self.get_json_data('/api/v3/projects/all', page) | |
73 | + page = page + 1 | |
39 | 74 | |
40 | - if len(json_data) == 0: | |
75 | + if not len(json_data): | |
41 | 76 | break |
42 | 77 | |
43 | - page = page + 1 | |
44 | - | |
45 | 78 | for element in json_data: |
46 | 79 | project = GitlabProject() |
47 | - | |
48 | - for field in GitlabProject._meta.fields: | |
49 | - if isinstance(field, DateTimeField): | |
50 | - value = parse(element[field.name]) | |
51 | - else: | |
52 | - value = element[field.name] | |
53 | - | |
54 | - setattr(project, field.name, value) | |
55 | - | |
80 | + self.fill_object_data(element, project) | |
2 |
|
|
56 | 81 | projects.append(project) |
57 | 82 | |
58 | 83 | return projects |
59 | 84 | |
85 | + def fetch_merge_request(self, projects): | |
86 | + all_merge_request = [] | |
87 | + | |
88 | + for project in projects: | |
89 | + page = 1 | |
90 | + while True: | |
91 | + url = '/api/v3/projects/{}/merge_requests'.format(project.id) | |
92 | + json_data_mr = self.get_json_data(url, page) | |
93 | + page = page + 1 | |
94 | + | |
95 | + if len(json_data_mr) == 0: | |
96 | + break | |
97 | + | |
98 | + for element in json_data_mr: | |
99 | + single_merge_request = GitlabMergeRequest() | |
100 | + self.fill_object_data(element, single_merge_request) | |
101 | + all_merge_request.append(single_merge_request) | |
102 | + | |
103 | + return all_merge_request | |
104 | + | |
105 | + def fetch_issue(self, projects): | |
106 | + all_issues = [] | |
107 | + | |
108 | + for project in projects: | |
109 | + page = 1 | |
110 | + while True: | |
111 | + url = '/api/v3/projects/{}/issues'.format(project.id) | |
112 | + json_data_issue = self.get_json_data(url, page) | |
113 | + page = page + 1 | |
114 | + | |
115 | + if len(json_data_issue) == 0: | |
116 | + break | |
117 | + | |
118 | + for element in json_data_issue: | |
119 | + single_issue = GitlabIssue() | |
120 | + self.fill_object_data(element, single_issue) | |
121 | + all_issues.append(single_issue) | |
122 | + | |
123 | + return all_issues | |
124 | + | |
125 | + def fetch_comments(self): | |
126 | + all_comments = [] | |
127 | + all_comments.extend(self.fetch_comments_MR()) | |
128 | + all_comments.extend(self.fetch_comments_issues()) | |
129 | + | |
130 | + return all_comments | |
131 | + | |
132 | + def fetch_comments_MR(self): | |
133 | + all_comments = [] | |
134 | + all_merge_requests = GitlabMergeRequest.objects.all() | |
135 | + | |
136 | + for merge_request in all_merge_requests: | |
137 | + page = 1 | |
138 | + while True: | |
139 | + url = '/api/v3/projects/{}/merge_requests/{}/notes'.format( | |
140 | + merge_request.project_id, merge_request.id) | |
141 | + json_data_mr = self.get_json_data(url, page) | |
142 | + page = page + 1 | |
143 | + | |
144 | + if len(json_data_mr) == 0: | |
145 | + break | |
146 | + | |
147 | + for element in json_data_mr: | |
148 | + single_comment = GitlabComment() | |
149 | + self.fill_object_data(element, single_comment) | |
150 | + single_comment.project = merge_request.project | |
151 | + single_comment.issue_comment = False | |
152 | + single_comment.parent_id = merge_request.id | |
153 | + all_comments.append(single_comment) | |
154 | + | |
155 | + return all_comments | |
156 | + | |
157 | + def fetch_comments_issues(self): | |
158 | + all_comments = [] | |
159 | + all_issues = GitlabIssue.objects.all() | |
160 | + | |
161 | + for issue in all_issues: | |
162 | + page = 1 | |
163 | + while True: | |
164 | + url = '/api/v3/projects/{}/issues/{}/notes'.format( | |
165 | + issue.project_id, issue.id) | |
166 | + json_data_mr = self.get_json_data(url, page) | |
167 | + page = page + 1 | |
168 | + | |
169 | + if len(json_data_mr) == 0: | |
170 | + break | |
171 | + | |
172 | + for element in json_data_mr: | |
173 | + single_comment = GitlabComment() | |
174 | + self.fill_object_data(element, single_comment) | |
175 | + single_comment.project = issue.project | |
176 | + single_comment.issue_comment = True | |
177 | + single_comment.parent_id = issue.id | |
178 | + all_comments.append(single_comment) | |
179 | + | |
180 | + return all_comments | |
181 | + | |
60 | 182 | def fetch_data(self): |
61 | - data = self.fetchProjects() | |
183 | + LOGGER.info("Importing Projects") | |
184 | + projects = self.fetch_projects() | |
185 | + for datum in projects: | |
186 | + datum.save() | |
187 | + | |
188 | + LOGGER.info("Importing Merge Requests") | |
189 | + merge_request_list = self.fetch_merge_request(projects) | |
190 | + for datum in merge_request_list: | |
191 | + datum.save() | |
192 | + | |
193 | + LOGGER.info("Importing Issues") | |
194 | + issue_list = self.fetch_issue(projects) | |
195 | + for datum in issue_list: | |
196 | + datum.save() | |
62 | 197 | |
63 | - for datum in data: | |
198 | + LOGGER.info("Importing Comments") | |
199 | + comments_list = self.fetch_comments() | |
200 | + for datum in comments_list: | |
64 | 201 | datum.save() |
65 | 202 | |
66 | 203 | @property | ... | ... |
... | ... | @@ -0,0 +1,69 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +from __future__ import unicode_literals | |
3 | + | |
4 | +from django.db import models, migrations | |
5 | +import django.db.models.deletion | |
6 | +from django.conf import settings | |
7 | + | |
8 | + | |
9 | +class Migration(migrations.Migration): | |
10 | + | |
11 | + dependencies = [ | |
12 | + migrations.swappable_dependency(settings.AUTH_USER_MODEL), | |
13 | + ('gitlab', '0001_initial'), | |
14 | + ] | |
15 | + | |
16 | + operations = [ | |
17 | + migrations.CreateModel( | |
18 | + name='GitlabComment', | |
19 | + fields=[ | |
20 | + ('id', models.IntegerField(serialize=False, primary_key=True)), | |
21 | + ('body', models.TextField()), | |
22 | + ('created_at', models.DateTimeField(blank=True)), | |
23 | + ('user', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)), | |
24 | + ], | |
25 | + options={ | |
26 | + 'verbose_name': 'Gitlab Comments', | |
27 | + 'verbose_name_plural': 'Gitlab Comments', | |
28 | + }, | |
29 | + bases=(models.Model,), | |
30 | + ), | |
31 | + migrations.CreateModel( | |
32 | + name='GitlabIssue', | |
33 | + fields=[ | |
34 | + ('id', models.IntegerField(serialize=False, primary_key=True)), | |
35 | + ('title', models.TextField()), | |
36 | + ('description', models.TextField()), | |
37 | + ('state', models.TextField()), | |
38 | + ('project', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='gitlab.GitlabProject', null=True)), | |
39 | + ('user', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)), | |
40 | + ], | |
41 | + options={ | |
42 | + 'verbose_name': 'Gitlab Collaboration', | |
43 | + 'verbose_name_plural': 'Gitlab Collaborations', | |
44 | + }, | |
45 | + bases=(models.Model,), | |
46 | + ), | |
47 | + migrations.CreateModel( | |
48 | + name='GitlabMergeRequest', | |
49 | + fields=[ | |
50 | + ('id', models.IntegerField(serialize=False, primary_key=True)), | |
51 | + ('target_branch', models.TextField()), | |
52 | + ('source_branch', models.TextField()), | |
53 | + ('description', models.TextField()), | |
54 | + ('title', models.TextField()), | |
55 | + ('state', models.TextField()), | |
56 | + ('project', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='gitlab.GitlabProject', null=True)), | |
57 | + ('user', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)), | |
58 | + ], | |
59 | + options={ | |
60 | + 'verbose_name': 'Gitlab Merge Request', | |
61 | + 'verbose_name_plural': 'Gitlab Merge Requests', | |
62 | + }, | |
63 | + bases=(models.Model,), | |
64 | + ), | |
65 | + migrations.AlterModelOptions( | |
66 | + name='gitlabproject', | |
67 | + options={'verbose_name': 'Gitlab Project', 'verbose_name_plural': 'Gitlab Projects'}, | |
68 | + ), | |
69 | + ] | ... | ... |
... | ... | @@ -0,0 +1,61 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +from __future__ import unicode_literals | |
3 | + | |
4 | +from django.db import models, migrations | |
5 | +import django.db.models.deletion | |
6 | + | |
7 | + | |
8 | +class Migration(migrations.Migration): | |
9 | + | |
10 | + dependencies = [ | |
11 | + ('gitlab', '0002_auto_20150205_1220'), | |
12 | + ] | |
13 | + | |
14 | + operations = [ | |
15 | + migrations.AlterModelOptions( | |
16 | + name='gitlabissue', | |
17 | + options={'verbose_name': 'Gitlab Issue', 'verbose_name_plural': 'Gitlab Issues'}, | |
18 | + ), | |
19 | + migrations.AddField( | |
20 | + model_name='gitlabcomment', | |
21 | + name='issue_comment', | |
22 | + field=models.BooleanField(default=True), | |
23 | + preserve_default=True, | |
24 | + ), | |
25 | + migrations.AddField( | |
26 | + model_name='gitlabcomment', | |
27 | + name='parent_id', | |
28 | + field=models.IntegerField(null=True), | |
29 | + preserve_default=True, | |
30 | + ), | |
31 | + migrations.AddField( | |
32 | + model_name='gitlabcomment', | |
33 | + name='project', | |
34 | + field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='gitlab.GitlabProject', null=True), | |
35 | + preserve_default=True, | |
36 | + ), | |
37 | + migrations.AddField( | |
38 | + model_name='gitlabissue', | |
39 | + name='created_at', | |
40 | + field=models.DateTimeField(null=True, blank=True), | |
41 | + preserve_default=True, | |
42 | + ), | |
43 | + migrations.AddField( | |
44 | + model_name='gitlabmergerequest', | |
45 | + name='created_at', | |
46 | + field=models.DateTimeField(null=True, blank=True), | |
47 | + preserve_default=True, | |
48 | + ), | |
49 | + migrations.AddField( | |
50 | + model_name='gitlabproject', | |
51 | + name='path_with_namespace', | |
52 | + field=models.TextField(null=True, blank=True), | |
53 | + preserve_default=True, | |
54 | + ), | |
55 | + migrations.AlterField( | |
56 | + model_name='gitlabcomment', | |
57 | + name='created_at', | |
58 | + field=models.DateTimeField(null=True, blank=True), | |
59 | + preserve_default=True, | |
60 | + ), | |
61 | + ] | ... | ... |
1 | 1 | from django.db import models |
2 | 2 | from django.utils.translation import ugettext_lazy as _ |
3 | +from colab.proxy.utils.models import Collaboration | |
4 | +from hitcounter.models import HitCounterModelMixin | |
3 | 5 | |
4 | 6 | |
5 | -class GitlabProject(models.Model): | |
7 | +class GitlabProject(models.Model, HitCounterModelMixin): | |
6 | 8 | |
7 | 9 | id = models.IntegerField(primary_key=True) |
8 | 10 | description = models.TextField() |
... | ... | @@ -11,7 +13,131 @@ class GitlabProject(models.Model): |
11 | 13 | name_with_namespace = models.TextField() |
12 | 14 | created_at = models.DateTimeField(blank=True) |
13 | 15 | last_activity_at = models.DateTimeField(blank=True) |
16 | + path_with_namespace = models.TextField(blank=True, null=True) | |
17 | + | |
18 | + @property | |
19 | + def url(self): | |
20 | + return u'/gitlab/{}'.format(self.path_with_namespace) | |
14 | 21 | |
15 | 22 | class Meta: |
16 | 23 | verbose_name = _('Gitlab Project') |
17 | 24 | verbose_name_plural = _('Gitlab Projects') |
25 | + | |
26 | + | |
27 | +class GitlabMergeRequest(Collaboration): | |
28 | + | |
29 | + id = models.IntegerField(primary_key=True) | |
30 | + target_branch = models.TextField() | |
31 | + source_branch = models.TextField() | |
32 | + project = models.ForeignKey(GitlabProject, null=True, | |
33 | + on_delete=models.SET_NULL) | |
34 | + description = models.TextField() | |
35 | + title = models.TextField() | |
36 | + state = models.TextField() | |
37 | + created_at = models.DateTimeField(blank=True, null=True) | |
38 | + | |
39 | + @property | |
40 | + def modified(self): | |
41 | + return self.created_at | |
42 | + | |
43 | + @property | |
44 | + def tag(self): | |
45 | + return self.state | |
46 | + | |
47 | + type = u'merge_request' | |
48 | + icon_name = u'file' | |
49 | + | |
50 | + @property | |
51 | + def url(self): | |
52 | + return u'/gitlab/{}/merge_requests/{}'.format( | |
53 | + self.project.path_with_namespace, self.id) | |
54 | + | |
55 | + def get_author(self): | |
56 | + return self.user | |
57 | + | |
58 | + class Meta: | |
59 | + verbose_name = _('Gitlab Merge Request') | |
60 | + verbose_name_plural = _('Gitlab Merge Requests') | |
61 | + | |
62 | + | |
63 | +class GitlabIssue(Collaboration): | |
64 | + | |
65 | + id = models.IntegerField(primary_key=True) | |
66 | + project = models.ForeignKey(GitlabProject, null=True, | |
67 | + on_delete=models.SET_NULL) | |
68 | + title = models.TextField() | |
69 | + description = models.TextField() | |
70 | + | |
71 | + state = models.TextField() | |
72 | + created_at = models.DateTimeField(blank=True, null=True) | |
73 | + | |
74 | + icon_name = u'align-right' | |
75 | + type = u'gitlab_issue' | |
76 | + | |
77 | + @property | |
78 | + def modified(self): | |
79 | + return self.created_at | |
80 | + | |
81 | + @property | |
82 | + def url(self): | |
83 | + return u'/gitlab/{}/issues/{}'.format( | |
84 | + self.project.path_with_namespace, self.id) | |
85 | + | |
86 | + class Meta: | |
87 | + verbose_name = _('Gitlab Issue') | |
88 | + verbose_name_plural = _('Gitlab Issues') | |
89 | + | |
90 | + | |
91 | +class GitlabComment(Collaboration): | |
92 | + | |
93 | + id = models.IntegerField(primary_key=True) | |
94 | + body = models.TextField() | |
95 | + created_at = models.DateTimeField(blank=True, null=True) | |
96 | + issue_comment = models.BooleanField(default=True) | |
97 | + | |
98 | + project = models.ForeignKey(GitlabProject, null=True, | |
99 | + on_delete=models.SET_NULL) | |
100 | + | |
101 | + parent_id = models.IntegerField(null=True) | |
102 | + type = u'comment' | |
103 | + | |
104 | + @property | |
105 | + def modified(self): | |
106 | + return self.created_at | |
107 | + | |
108 | + @property | |
109 | + def title(self): | |
110 | + if self.issue_comment: | |
111 | + issue = GitlabIssue.objects.get(id=self.parent_id) | |
112 | + return issue.title | |
113 | + else: | |
114 | + merge_request = GitlabMergeRequest.objects.get(id=self.parent_id) | |
115 | + return merge_request.title | |
116 | + | |
117 | + icon_name = u'align-right' | |
118 | + | |
119 | + @property | |
120 | + def description(self): | |
121 | + return self.body | |
122 | + | |
123 | + @property | |
124 | + def tag(self): | |
125 | + if self.issue_comment: | |
126 | + issue = GitlabIssue.objects.get(id=self.parent_id) | |
127 | + return issue.state | |
128 | + else: | |
129 | + merge_request = GitlabMergeRequest.objects.get(id=self.parent_id) | |
130 | + return merge_request.state | |
131 | + | |
132 | + @property | |
133 | + def url(self): | |
134 | + if self.issue_comment: | |
135 | + return u'/gitlab/{}/issues/{}#notes_{}'.format( | |
136 | + self.project.path_with_namespace, self.parent_id, self.id) | |
137 | + else: | |
138 | + return u'/gitlab/{}/merge_requests/{}#notes_{}'.format( | |
139 | + self.project.path_with_namespace, self.parent_id, self.id) | |
140 | + | |
141 | + class Meta: | |
142 | + verbose_name = _('Gitlab Comments') | |
143 | + verbose_name_plural = _('Gitlab Comments') | ... | ... |
... | ... | @@ -0,0 +1,120 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | + | |
3 | +import string | |
4 | + | |
5 | +from haystack import indexes | |
6 | +from haystack.utils import log as logging | |
7 | + | |
8 | +from .models import (GitlabProject, GitlabMergeRequest, | |
9 | + GitlabIssue, GitlabComment) | |
10 | + | |
11 | + | |
12 | +logger = logging.getLogger('haystack') | |
13 | + | |
14 | +# The string maketrans always return a string encoded with latin1 | |
15 | +# http://stackoverflow.com/questions/1324067/how-do-i-get-str-translate-to-work-with-unicode-strings | |
16 | +table = string.maketrans( | |
17 | + string.punctuation, | |
18 | + '.' * len(string.punctuation) | |
19 | +).decode('latin1') | |
20 | + | |
21 | + | |
22 | +class GitlabProjectIndex(indexes.SearchIndex, indexes.Indexable): | |
23 | + text = indexes.CharField(document=True, use_template=False, stored=False) | |
24 | + title = indexes.CharField(model_attr='name') | |
25 | + description = indexes.CharField(model_attr='description', null=True) | |
26 | + tag = indexes.CharField() | |
27 | + url = indexes.CharField(model_attr='url', indexed=False) | |
28 | + icon_name = indexes.CharField() | |
29 | + type = indexes.CharField() | |
30 | + created = indexes.DateTimeField(model_attr='created_at', null=True) | |
31 | + | |
32 | + def prepare_tag(self, obj): | |
33 | + return "{}".format(obj.name_with_namespace.split('/')[0].strip()) | |
34 | + | |
35 | + def prepare_icon_name(self, obj): | |
36 | + return u'file' | |
37 | + | |
38 | + def get_ful_name(self): | |
39 | + self.objs.name | |
40 | + | |
41 | + def get_model(self): | |
42 | + return GitlabProject | |
43 | + | |
44 | + def prepare_type(self, obj): | |
45 | + return u'gitlab' | |
46 | + | |
47 | + | |
48 | +class GitlabMergeRequestIndex(indexes.SearchIndex, indexes.Indexable): | |
49 | + | |
50 | + text = indexes.CharField(document=True, use_template=False, stored=False) | |
51 | + title = indexes.CharField(model_attr='title') | |
52 | + description = indexes.CharField(model_attr='description') | |
53 | + tag = indexes.CharField(model_attr='state') | |
54 | + url = indexes.CharField(model_attr='url', indexed=False) | |
55 | + icon_name = indexes.CharField() | |
56 | + type = indexes.CharField(model_attr='type') | |
57 | + | |
58 | + modified_by = indexes.CharField(model_attr='modified_by', null=True) | |
59 | + modified_by_url = indexes.CharField(model_attr='modified_by_url', | |
60 | + null=True) | |
61 | + modified = indexes.DateTimeField(model_attr='created_at', null=True) | |
62 | + | |
63 | + def get_model(self): | |
64 | + return GitlabMergeRequest | |
65 | + | |
66 | + def prepare_icon_name(self, obj): | |
67 | + return u'file' | |
68 | + | |
69 | + def prepare_type(self, obj): | |
70 | + return u'merge_request' | |
71 | + | |
72 | + | |
73 | +class GitlabIssueIndex(indexes.SearchIndex, indexes.Indexable): | |
74 | + | |
75 | + text = indexes.CharField(document=True, use_template=False, stored=False) | |
76 | + title = indexes.CharField(model_attr='title') | |
77 | + description = indexes.CharField(model_attr='description') | |
78 | + tag = indexes.CharField(model_attr='state') | |
79 | + url = indexes.CharField(model_attr='url', indexed=False) | |
80 | + icon_name = indexes.CharField() | |
81 | + type = indexes.CharField(model_attr='type') | |
82 | + | |
83 | + modified_by = indexes.CharField(model_attr='modified_by', null=True) | |
84 | + modified_by_url = indexes.CharField(model_attr='modified_by_url', | |
85 | + null=True) | |
86 | + modified = indexes.DateTimeField(model_attr='created_at', null=True) | |
87 | + | |
88 | + def get_model(self): | |
89 | + return GitlabIssue | |
90 | + | |
91 | + def prepare_icon_name(self, obj): | |
92 | + return u'align-right' | |
93 | + | |
94 | + def prepare_type(self, obj): | |
95 | + return u'merge_request' | |
96 | + | |
97 | + | |
98 | +class GitlabCommentIndex(indexes.SearchIndex, indexes.Indexable): | |
99 | + | |
100 | + text = indexes.CharField(document=True, use_template=False, stored=False) | |
101 | + title = indexes.CharField(model_attr='title') | |
102 | + description = indexes.CharField(model_attr='description') | |
103 | + tag = indexes.CharField() | |
104 | + url = indexes.CharField(model_attr='url', indexed=False) | |
105 | + icon_name = indexes.CharField() | |
106 | + type = indexes.CharField(model_attr='type') | |
107 | + | |
108 | + modified_by = indexes.CharField(model_attr='modified_by', null=True) | |
109 | + modified_by_url = indexes.CharField(model_attr='modified_by_url', | |
110 | + null=True) | |
111 | + modified = indexes.DateTimeField(model_attr='created_at', null=True) | |
112 | + | |
113 | + def get_model(self): | |
114 | + return GitlabComment | |
115 | + | |
116 | + def prepare_icon_name(self, obj): | |
117 | + return u'align-right' | |
118 | + | |
119 | + def prepare_tag(self, obj): | |
120 | + return obj.tag | ... | ... |
... | ... | @@ -0,0 +1,114 @@ |
1 | +""" | |
2 | +Test User class. | |
3 | +Objective: Test parameters, and behavior. | |
4 | +""" | |
5 | +from datetime import datetime | |
6 | + | |
7 | + | |
8 | +from django.test import TestCase, Client | |
9 | +from colab.accounts.models import User | |
10 | +from colab.proxy.gitlab.models import GitlabProject, \ | |
11 | + GitlabIssue, GitlabComment, GitlabMergeRequest | |
12 | + | |
13 | + | |
14 | +class GitlabTest(TestCase): | |
15 | + | |
16 | + def setUp(self): | |
17 | + self.user = self.create_user() | |
18 | + self.client = Client() | |
19 | + self.create_gitlab_data() | |
20 | + | |
21 | + super(GitlabTest, self).setUp() | |
22 | + | |
23 | + def tearDown(self): | |
24 | + pass | |
25 | + | |
26 | + def test_data_integrity(self): | |
27 | + self.assertEqual(GitlabProject.objects.all().count(), 1) | |
28 | + self.assertEqual(GitlabMergeRequest.objects.all().count(), 1) | |
29 | + self.assertEqual(GitlabIssue.objects.all().count(), 1) | |
30 | + self.assertEqual(GitlabComment.objects.all().count(), 2) | |
31 | + | |
32 | + def test_project_url(self): | |
33 | + self.assertEqual(GitlabProject.objects.get(id=1).url, | |
34 | + '/gitlab/softwarepublico/colab') | |
35 | + | |
36 | + def test_merge_request_url(self): | |
37 | + self.assertEqual(GitlabMergeRequest.objects.get(id=1).url, | |
38 | + '/gitlab/softwarepublico/colab/merge_requests/1') | |
39 | + | |
40 | + def test_issue_url(self): | |
41 | + self.assertEqual(GitlabIssue.objects.get(id=1).url, | |
42 | + '/gitlab/softwarepublico/colab/issues/1') | |
43 | + | |
44 | + def test_comment_on_mr_url(self): | |
45 | + url = '/gitlab/softwarepublico/colab/merge_requests/1#notes_1' | |
46 | + self.assertEqual(GitlabComment.objects.get(id=1).url, url) | |
47 | + | |
48 | + def test_comment_on_issue_url(self): | |
49 | + self.assertEqual(GitlabComment.objects.get(id=2).url, | |
50 | + '/gitlab/softwarepublico/colab/issues/1#notes_2') | |
51 | + | |
52 | + def create_gitlab_data(self): | |
53 | + g = GitlabProject() | |
54 | + g.id = 1 | |
55 | + g.name = "colab" | |
56 | + g.name_with_namespace = "Software Public / Colab" | |
57 | + g.path_with_namespace = "softwarepublico/colab" | |
58 | + g.created_at = datetime.now() | |
59 | + g.last_activity_at = datetime.now() | |
60 | + g.save() | |
61 | + | |
62 | + mr = GitlabMergeRequest() | |
63 | + mr.id = 1 | |
64 | + mr.project = g | |
65 | + mr.title = "Include plugin support" | |
66 | + mr.description = "Merge request for plugin support" | |
67 | + mr.state = "Closed" | |
68 | + mr.created_at = datetime.now() | |
69 | + mr.update_user(self.user.username) | |
70 | + mr.save() | |
71 | + | |
72 | + i = GitlabIssue() | |
73 | + i.id = 1 | |
74 | + i.project = g | |
75 | + i.title = "Issue for colab" | |
76 | + i.description = "Issue reported to colab" | |
77 | + i.created_at = datetime.now() | |
78 | + i.state = "Open" | |
79 | + i.update_user(self.user.username) | |
80 | + i.save() | |
81 | + | |
82 | + c1 = GitlabComment() | |
83 | + c1.id = 1 | |
84 | + c1.parent_id = mr.id | |
85 | + c1.project = g | |
86 | + c1.body = "Comment to merge request" | |
87 | + c1.created_at = datetime.now() | |
88 | + c1.issue_comment = False | |
89 | + c1.update_user(self.user.username) | |
90 | + c1.save() | |
91 | + | |
92 | + c2 = GitlabComment() | |
93 | + c2.id = 2 | |
94 | + c2.parent_id = i.id | |
95 | + c2.project = g | |
96 | + c2.body = "Comment to issue" | |
97 | + c2.created_at = datetime.now() | |
98 | + c2.issue_comment = True | |
99 | + c2.update_user(self.user.username) | |
100 | + c2.save() | |
101 | + | |
102 | + def create_user(self): | |
103 | + user = User() | |
104 | + user.username = "USERtestCoLaB" | |
105 | + user.set_password("123colab4") | |
106 | + user.email = "usertest@colab.com.br" | |
107 | + user.id = 1 | |
108 | + user.twitter = "usertestcolab" | |
109 | + user.facebook = "usertestcolab" | |
110 | + user.first_name = "USERtestCoLaB" | |
111 | + user.last_name = "COLAB" | |
112 | + user.save() | |
113 | + | |
114 | + return user | ... | ... |
... | ... | @@ -63,10 +63,10 @@ ROBOTS_NOINDEX: false |
63 | 63 | # RAVEN_DSN: 'http://public:secret@example.com/1' |
64 | 64 | |
65 | 65 | ### Colab proxied apps |
66 | -# PROXIED_APPS: | |
67 | -# gitlab: | |
68 | -# upstream: 'http://localhost:8090/gitlab/' | |
69 | -# private_token: '' | |
66 | +PROXIED_APPS: | |
67 | + gitlab: | |
68 | + upstream: 'http://localhost:8090/gitlab/' | |
69 | + private_token: '' | |
70 | 70 | # trac: |
71 | 71 | # upstream: 'http://localhost:5000/trac/' |
72 | 72 | ... | ... |
-
Why such a big block of code is inside a try for KeyError?
-
You highlighted the wrong code. Every attribution of "value = element[somevalue]" in this function has a chance of not existing and give a KeyError. This functions tries to generalize the attributions of the GitlabData expecting the the json data to be the same name, which happens 80% of the time. Others specific attributions are made outside this funcion.
-
Isn't it a bit dangerous? If the server doesn't send the parameter you are expecting you might end-up in an infinite loop. Isn't there a why to calculate the number of pages before hand?
-
The same applies for all loops while True loops in this file.
-
GitlabAPI doesn't provide any way to know how many pages there are... But when you input a nonexistent page or the parser fails, it returns an empty list and breaks the While.
-
What about GitlabProject(**element)? You would need to thread element to be in the right format but it might be a good idea. Perhaps a class method
GitlabProject.from_api
. -
We didn't understand.... the function fill_object_data is used to fill the generic fields of GitlabProject, and any code bellow that are used to fill the specific ones.
-
Great progress here! What about the peer reviews?
32 | + def get_json_data(self, api_url, page, pages=1000): | |
33 | + url = self.get_request_url(api_url, per_page=pages, | |
34 | + page=page) | |
35 | + | |
36 | + try: | |
37 | + data = urllib2.urlopen(url, timeout=10) | |
38 | + json_data = json.load(data) | |
39 | + except urllib2.URLError: | |
40 | + LOGGER.exception("Connection timeout: " + url) | |
41 | + json_data = [] | |
42 | + | |
43 | + return json_data | |
44 | + | |
45 | + def fill_object_data(self, element, _object): | |
46 | + for field in _object._meta.fields: | |
47 | + try: | |
2 |
|
63 | + continue | |
64 | + | |
65 | + return _object | |
66 | + | |
67 | + def fetch_projects(self): | |
29 | 68 | page = 1 |
30 | 69 | projects = [] |
31 | 70 | |
32 | - # Iterates throughout all projects pages | |
33 | - while(True): | |
34 | - url = self.get_request_url('/api/v3/projects/all', | |
35 | - per_page=100, | |
36 | - page=page) | |
37 | - data = urllib2.urlopen(url) | |
38 | - json_data = json.load(data) | |
71 | + while True: | |
3 |
|
41 | 76 | break |
42 | 77 | |
43 | - page = page + 1 | |
44 | - | |
45 | 78 | for element in json_data: |
46 | 79 | project = GitlabProject() |
47 | - | |
48 | - for field in GitlabProject._meta.fields: | |
49 | - if isinstance(field, DateTimeField): | |
50 | - value = parse(element[field.name]) | |
51 | - else: | |
52 | - value = element[field.name] | |
53 | - | |
54 | - setattr(project, field.name, value) | |
55 | - | |
80 | + self.fill_object_data(element, project) | |
2 |
|