Skip to content

Commit dcb51ca

Browse files
committed
feat(dryccfile): merge config into dryccfile
1 parent 2835981 commit dcb51ca

3 files changed

Lines changed: 101 additions & 2 deletions

File tree

rootfs/api/models/build.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import logging
2+
from copy import deepcopy
3+
from collections import defaultdict
24
from django.db import models
35
from django.contrib.auth import get_user_model
46
from api.exceptions import DryccException
@@ -63,6 +65,25 @@ def source_based(self):
6365
def version(self):
6466
return 'git-{}'.format(self.sha) if self.source_based else 'latest'
6567

68+
def merge(self, config):
69+
if self.dryccfile and any({"values", "values_refs"} & set(config.diff(None).keys())):
70+
dryccfile = deepcopy(self.dryccfile)
71+
ptype_env, group_env = defaultdict(dict), defaultdict(dict)
72+
for value in config.values:
73+
if "ptype" in value:
74+
ptype_env[value["ptype"]][value["name"]] = value["value"]
75+
if "group" in value:
76+
group_env[value["group"]][value["name"]] = value["value"]
77+
dryccfile['config'] = dict(group_env)
78+
for pipeline in dryccfile['pipeline'].values():
79+
pipeline['env'] = ptype_env[pipeline['ptype']]
80+
pipeline['config'] = config.values_refs.get(pipeline['ptype'], [])
81+
return Build.objects.create(
82+
owner=config.owner, app=self.app, image=self.image, stack=self.stack, sha=self.sha,
83+
procfile=self.procfile, dryccfile=dryccfile, dockerfile=self.dockerfile,
84+
)
85+
return self
86+
6687
def get_image(self, ptype, default_image=None):
6788
pipeline = self.get_pipeline(ptype)
6889
if pipeline and 'build' in pipeline:

rootfs/api/tests/test_config.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,3 +1034,81 @@ def test_config_from_dryccfile(self, mock_requests):
10341034
self.assertEqual(release.failed, False)
10351035
self.assertEqual(release.config.envs("web"), {})
10361036
self.assertEqual(release.config.values_refs, {})
1037+
1038+
# test config modification creates new build with merged dryccfile
1039+
# First, create a build with dryccfile
1040+
build_body_with_dryccfile = copy.deepcopy(build_body)
1041+
build_body_with_dryccfile['dryccfile']['config'] = {
1042+
"mygroup1": {
1043+
"GROUP": "g1",
1044+
"DEBUG": "tr",
1045+
}
1046+
}
1047+
build_body_with_dryccfile['dryccfile']['pipeline']['web.yaml']['env'] = {
1048+
"PENV1": "web"
1049+
}
1050+
build_body_with_dryccfile['dryccfile']['pipeline']['web.yaml']['config'] = [
1051+
"mygroup1"
1052+
]
1053+
with mock.patch('scheduler.resources.pod.Pod.watch') as mock_kube:
1054+
mock_kube.return_value = ['up', 'down']
1055+
url = f"/v2/apps/{app_id}/build"
1056+
response = self.client.post(url, build_body_with_dryccfile)
1057+
self.assertEqual(response.status_code, 201, response.data)
1058+
1059+
# Get the latest release and build
1060+
release = app.release_set.latest()
1061+
initial_build = release.build
1062+
self.assertIsNotNone(initial_build.dryccfile)
1063+
1064+
# Now modify config - this should trigger build.merge() and create a new build
1065+
config_values = [
1066+
{"name": "NEW_CONFIG", "value": "new_value", "group": "mygroup1"},
1067+
{"name": "PENV2", "value": "web2", "ptype": "web"}
1068+
]
1069+
body = {'values': config_values}
1070+
url = f"/v2/apps/{app_id}/config"
1071+
response = self.client.post(url, body)
1072+
self.assertEqual(response.status_code, 201, response.data)
1073+
1074+
# Check that a new release was created
1075+
new_release = app.release_set.latest()
1076+
self.assertNotEqual(release.uuid, new_release.uuid)
1077+
1078+
# Check that a new build was created with merged dryccfile
1079+
new_build = new_release.build
1080+
self.assertIsNotNone(new_build)
1081+
self.assertNotEqual(initial_build.uuid, new_build.uuid)
1082+
1083+
# Verify dryccfile was merged with config values
1084+
self.assertIn('dryccfile', new_build.__dict__)
1085+
dryccfile = new_build.dryccfile
1086+
1087+
# Check config groups were merged
1088+
self.assertIn('config', dryccfile)
1089+
self.assertIn('mygroup1', dryccfile['config'])
1090+
self.assertEqual(dryccfile['config']['mygroup1']['GROUP'], 'g1')
1091+
self.assertEqual(dryccfile['config']['mygroup1']['DEBUG'], 'tr')
1092+
self.assertEqual(dryccfile['config']['mygroup1']['NEW_CONFIG'], 'new_value')
1093+
1094+
# Check ptype envs were merged
1095+
self.assertIn('pipeline', dryccfile)
1096+
self.assertIn('web.yaml', dryccfile['pipeline'])
1097+
self.assertIn('env', dryccfile['pipeline']['web.yaml'])
1098+
self.assertEqual(dryccfile['pipeline']['web.yaml']['env']['PENV1'], 'web')
1099+
self.assertEqual(dryccfile['pipeline']['web.yaml']['env']['PENV2'], 'web2')
1100+
1101+
# Check config refs
1102+
self.assertIn('config', dryccfile['pipeline']['web.yaml'])
1103+
self.assertEqual(dryccfile['pipeline']['web.yaml']['config'], ['mygroup1'])
1104+
1105+
# Verify config values are correct
1106+
config = new_release.config
1107+
expected_envs = {
1108+
'GROUP': 'g1',
1109+
'DEBUG': 'tr',
1110+
'NEW_CONFIG': 'new_value',
1111+
'PENV1': 'web',
1112+
'PENV2': 'web2'
1113+
}
1114+
self.assertEqual(config.envs("web"), expected_envs)

rootfs/api/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,8 @@ def delete(self, request, **kwargs):
477477
def post_save(self, config):
478478
latest_release = models.release.Release.latest(self.get_app())
479479
try:
480-
release = latest_release.new(
481-
self.request.user, config=config, build=latest_release.build)
480+
build = latest_release.build.merge(config) if latest_release.build else None
481+
release = latest_release.new(self.request.user, config=config, build=build)
482482
if release.build and config.app.appsettings_set.latest().autodeploy:
483483
release.deploy(release.ptypes, False)
484484
except BaseException as e:

0 commit comments

Comments
 (0)