Skip to content
This repository was archived by the owner on Feb 21, 2022. It is now read-only.

Commit ff66f7e

Browse files
gjuro87aexvir
andauthored
Jgrgicevic/sw 593 envs (#342)
* feat: fetch gitlab envs * fix(services): move gitlab icon to static folder * refactor: post rebase changes - change get_or_create usage - regenerate migrations for envs - fixed sending NaN on envs fetch * refactor: rework of gitlab envs Co-authored-by: Jurica Grgicevic <jurica.grgicevic@kiwi.com> Co-authored-by: Alex Viscreanu <alexviscreanu@gmail.com>
1 parent 8eda7d1 commit ff66f7e

File tree

23 files changed

+593
-128
lines changed

23 files changed

+593
-128
lines changed

test/repos/tasks/test_sync_repos.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,22 @@
33
import pytest
44
from faker import Faker
55

6-
from zoo.repos.models import Provider, Repository
6+
from zoo.repos.models import Provider, Repository, RepositoryEnvironment
77
from zoo.repos.tasks import sync_repos
88

99
pytestmark = pytest.mark.django_db
1010

1111

12+
class FakeGitlabEnviroment:
13+
def __init__(self, id=None, name=None, external_url=None, slug=None):
14+
self.fake = Faker()
15+
self.id = self.fake.pyint() if id is None else id
16+
self.name = self.fake.word() if name is None else name
17+
self.slug = self.fake.word() if slug is None else slug
18+
self.external_url = self.fake.url() if external_url is None else external_url
19+
self.state = "available"
20+
21+
1222
class FakeGitProject:
1323
def __init__(self, pid):
1424
self.fake = Faker()
@@ -53,38 +63,58 @@ def generate_project_list(pid=None, owner=None, name=None, url=None, **kwargs):
5363
}
5464

5565

66+
def generate_proj_envs_list():
67+
return [FakeGitlabEnviroment()]
68+
69+
5670
def test_sync_untouched_repo(repository):
5771
project_list = generate_project_list(
5872
repository.remote_id, repository.owner, repository.name, repository.url
5973
)
74+
gitlab_envs = generate_proj_envs_list()
6075
with patch(
6176
"gitlab.v4.objects.ProjectManager.list", return_value=project_list["gitlab"]
6277
), patch(
6378
"github.AuthenticatedUser.AuthenticatedUser.get_repos",
6479
return_value=project_list["github"],
80+
), patch(
81+
"zoo.repos.tasks.get_project_enviroments",
82+
return_value=gitlab_envs,
6583
):
6684
sync_repos()
6785

6886
gitlab_project = project_list["gitlab"][0]
69-
assert gitlab_project.id == repository.remote_id
87+
repository = Repository.objects.get(
88+
remote_id=gitlab_project.id, provider=Provider.GITLAB.value
89+
)
7090
assert gitlab_project.namespace["full_path"] == repository.owner
7191
assert gitlab_project.path == repository.name
7292
assert gitlab_project.web_url == repository.url
7393

94+
repo_env = repository.repository_environments.first()
95+
assert gitlab_envs[0].name == repo_env.name
96+
assert gitlab_envs[0].external_url == repo_env.external_url
97+
7498
github_project = project_list["github"][0]
75-
assert github_project.id == repository.remote_id + 1
99+
repository = Repository.objects.get(
100+
remote_id=github_project.id, provider=Provider.GITHUB.value
101+
)
76102
assert github_project.owner.login == repository.owner
77103
assert github_project.name == repository.name
78104
assert github_project.svn_url == repository.url
79105

80106

81107
def test_sync_moved_repo(repository):
82108
project_list = generate_project_list(repository.remote_id)
109+
gitlab_envs = generate_proj_envs_list()
83110
with patch(
84111
"gitlab.v4.objects.ProjectManager.list", return_value=project_list["gitlab"]
85112
), patch(
86113
"github.AuthenticatedUser.AuthenticatedUser.get_repos",
87114
return_value=project_list["github"],
115+
), patch(
116+
"zoo.repos.tasks.get_project_enviroments",
117+
return_value=gitlab_envs,
88118
):
89119
sync_repos()
90120

@@ -96,6 +126,10 @@ def test_sync_moved_repo(repository):
96126
assert gitlab_project.path == repository.name
97127
assert gitlab_project.web_url == repository.url
98128

129+
repo_env = repository.repository_environments.first()
130+
assert gitlab_envs[0].name == repo_env.name
131+
assert gitlab_envs[0].external_url == repo_env.external_url
132+
99133
github_project = project_list["github"][0]
100134
repository = Repository.objects.get(
101135
remote_id=github_project.id, provider=Provider.GITHUB.value

test/services/test_forms.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,13 @@ def test_service_form__complete__incorrect_status(repository):
116116
"environments-0-service_urls_0": fake.url(),
117117
"environments-0-service_urls_1": fake.url(),
118118
"environments-0-DELETE": False,
119+
"environments-0-type": "zoo",
119120
"environments-1-name": fake.word(),
120121
"environments-1-dashboard_url": fake.url(),
121122
"environments-1-service_urls_0": fake.url(),
122123
"environments-1-service_urls_1": fake.url(),
123124
"environments-1-DELETE": False,
125+
"environments-1-type": "zoo",
124126
}
125127

126128

zoo/base/assets/js/components/RepoInput.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import { match } from "ramda"
3737
import RepoInputSuggestions from "./RepoInputSuggestions"
3838
import $ from 'jquery/src/jquery'
39+
import { gitlabEnvs } from "../../../../services/assets/js/gitlab_envs.js"
40+
3941
4042
function createPopup () {
4143
$('i.magic.icon').popup({
@@ -51,6 +53,11 @@ function popupAction (action) {
5153
$('i.magic.icon').popup(action)
5254
}
5355
56+
function loadGitlabEnvs(repoId) {
57+
gitlabEnvsInfo["repoId"] = repoId
58+
gitlabEnvs.load(gitlabEnvsInfo)
59+
}
60+
5461
export default {
5562
template: "#repo-input-text-field-markup",
5663
data () {
@@ -153,6 +160,7 @@ export default {
153160
this.$refs.suggestions.selectSuggestion();
154161
this.isOnEditMode = false
155162
this.$store.commit("refreshEnteredText")
163+
loadGitlabEnvs(parseInt(this.inputValue))
156164
},
157165
},
158166
components: {

zoo/factories.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from zoo.auditing.check_discovery import Kind
1919
from zoo.auditing.models import Issue
2020
from zoo.datacenters.models import InfraNode
21-
from zoo.repos.models import Repository
21+
from zoo.repos.models import Repository, RepositoryEnvironment
2222
from zoo.services.models import Environment, Impact, Link, Service, Status, Tier
2323

2424

@@ -33,6 +33,15 @@ class Meta:
3333
url = LazyAttribute(lambda o: f"https://gitlab.com/{o.owner}/{o.name}")
3434

3535

36+
class RepositoryEnvironmentFactory(DjangoModelFactory):
37+
class Meta:
38+
model = RepositoryEnvironment
39+
40+
name = Faker("domain_word")
41+
repository = SubFactory(RepositoryFactory)
42+
external_url = LazyAttribute(lambda o: f"https://gitlab.com/{o.name}/{o.name}")
43+
44+
3645
class IssueFactory(DjangoModelFactory):
3746
class Meta:
3847
model = Issue

zoo/repos/admin.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@
66
@admin.register(models.Repository)
77
class RepoAdmin(admin.ModelAdmin):
88
search_fields = ("remote_id", "owner", "name", "provider")
9+
10+
11+
@admin.register(models.RepositoryEnvironment)
12+
class RepoEnvAdmin(admin.ModelAdmin):
13+
search_fields = ("name", "external_url")

zoo/repos/forms.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from django.forms import widgets
22

3+
from ..services.constants import EnviromentType
34
from .models import Repository
45

56

@@ -19,4 +20,5 @@ def get_context(self, name, value, attrs):
1920
)
2021

2122
context["widget"]["value"] = value
23+
context["env_type_gitlab"] = EnviromentType.GITLAB.value
2224
return context

zoo/repos/gitlab.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313
log = structlog.get_logger()
1414

1515

16+
def get_project_enviroments(remote_id):
17+
try:
18+
project = gitlab.projects.get(remote_id)
19+
return project.environments.list(as_list=False)
20+
except (GitlabGetError, GitlabListError):
21+
return []
22+
23+
1624
def get_project(remote_id):
1725
try:
1826
project = gitlab.projects.get(remote_id)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Generated by Django 2.2.19 on 2021-04-30 14:24
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
("repos", "0007_endpoint"),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name="RepositoryEnvironment",
16+
fields=[
17+
(
18+
"id",
19+
models.AutoField(
20+
auto_created=True,
21+
primary_key=True,
22+
serialize=False,
23+
verbose_name="ID",
24+
),
25+
),
26+
("name", models.CharField(max_length=200)),
27+
("external_url", models.CharField(max_length=300, null=True)),
28+
(
29+
"repository",
30+
models.ForeignKey(
31+
on_delete=django.db.models.deletion.CASCADE,
32+
related_name="repository_environments",
33+
related_query_name="repository_environment",
34+
to="repos.Repository",
35+
),
36+
),
37+
],
38+
options={
39+
"ordering": ["name"],
40+
"unique_together": {("repository", "name")},
41+
},
42+
),
43+
]

zoo/repos/models.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,19 @@ class Meta:
8686
)
8787
summary = models.CharField(max_length=500, null=True, blank=True)
8888
operation = models.CharField(max_length=200, null=True, blank=True)
89+
90+
91+
class RepositoryEnvironment(models.Model):
92+
class Meta:
93+
unique_together = ("repository", "name")
94+
ordering = ["name"]
95+
96+
repository = models.ForeignKey(
97+
Repository,
98+
on_delete=models.CASCADE,
99+
related_name="repository_environments",
100+
related_query_name="repository_environment",
101+
)
102+
103+
name = models.CharField(max_length=200)
104+
external_url = models.CharField(max_length=300, null=True)

zoo/repos/tasks.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
from ..auditing import runner
1313
from ..auditing.check_discovery import CHECKS as AUDITING_CHECKS
1414
from ..repos.models import Endpoint
15+
from ..services.constants import EnviromentType
1516
from ..services.models import Environment, Service
1617
from .exceptions import MissingFilesError, RepositoryNotFoundError
1718
from .github import get_repositories as get_github_repositories
19+
from .gitlab import get_project_enviroments
1820
from .gitlab import get_repositories as get_gitlab_repositories
19-
from .models import Repository
21+
from .models import Repository, RepositoryEnvironment
2022
from .utils import download_repository, get_scm_module, openapi_definition
2123
from .zoo_yml import parse, validate
2224

@@ -39,14 +41,17 @@
3941

4042
@shared_task
4143
def sync_repos():
44+
45+
i = 0
4246
for project in itertools.chain(
4347
get_github_repositories(), get_gitlab_repositories()
4448
):
4549
if settings.SYNC_REPOS_SKIP_FORKS and project["is_fork"]:
4650
continue
4751
if settings.SYNC_REPOS_SKIP_PERSONAL and project["is_personal"]:
4852
continue
49-
53+
i += 1
54+
log.info("sync_repos.fetch", repo_number=i, project=project)
5055
try:
5156
repo = Repository.objects.get(
5257
remote_id=project["id"], provider=project["provider"]
@@ -68,6 +73,12 @@ def sync_repos():
6873
repo.full_clean()
6974
repo.save()
7075

76+
if project["provider"] == "gitlab":
77+
log.info("sync_repos.calling.sync_enviroments_from_gitlab")
78+
sync_enviroments_from_gitlab(repo)
79+
80+
log.info("sync_repos.total", repo_number=i)
81+
7182

7283
@shared_task
7384
def schedule_pulls():
@@ -208,3 +219,46 @@ def get_zoo_file_content(proj: Dict) -> str:
208219
return provider.get_file_content(
209220
proj["id"], settings.ZOO_YAML_FILE, settings.ZOO_YAML_DEFAULT_REF
210221
)
222+
223+
224+
def sync_enviroments_from_gitlab(repo: Repository):
225+
gl_envs = get_project_enviroments(repo.remote_id)
226+
227+
if not gl_envs:
228+
log.info("sync_enviroments_from_gitlab.no_envs")
229+
return
230+
231+
envs = []
232+
i = 0
233+
log.info("sync_enviroments_from_gitlab.start")
234+
for gl_env in gl_envs:
235+
if gl_env.state != "available":
236+
continue
237+
env, _ = RepositoryEnvironment.objects.get_or_create(
238+
repository_id=repo.id, name=gl_env.name
239+
)
240+
env.external_url = gl_env.external_url
241+
env.save()
242+
envs.append(env)
243+
i += 1
244+
245+
RepositoryEnvironment.objects.filter(repository_id=repo.id).exclude(
246+
id__in=[env.id for env in envs]
247+
).delete()
248+
249+
# update gitlab envs on every service
250+
services = Service.objects.filter(repository_id=repo.id)
251+
for service in services:
252+
Environment.objects.filter(
253+
service_id=service.id, type=EnviromentType.GITLAB.value
254+
).exclude(name__in=[env.name for env in envs]).delete()
255+
for env in envs:
256+
service_env, _ = Environment.objects.get_or_create(
257+
service_id=service.id,
258+
name=env.name,
259+
type=EnviromentType.GITLAB.value,
260+
)
261+
service_env.dashboard_url = env.external_url
262+
service_env.save()
263+
264+
log.info("sync_enviroments_from_gitlab.total.synced", envs_synced=i)

0 commit comments

Comments
 (0)