qontract-reconcile 0.10.1rc514__py3-none-any.whl → 0.10.1rc515__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qontract_reconcile-0.10.1rc514.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc514.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/RECORD +17 -15
- reconcile/saas_auto_promotions_manager/integration.py +28 -3
- reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py +5 -5
- reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager_v2.py +144 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py +13 -9
- reconcile/saas_auto_promotions_manager/merge_request_manager/reconciler.py +207 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +9 -6
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +25 -12
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +3 -0
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +51 -153
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py +11 -9
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_reconciler.py +408 -0
- reconcile/test/saas_auto_promotions_manager/test_integration_test.py +23 -88
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_unbatching.py +0 -96
- {qontract_reconcile-0.10.1rc514.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc514.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc514.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/top_level.txt +0 -0
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py
CHANGED
@@ -11,16 +11,22 @@ from gitlab.v4.objects import ProjectMergeRequest
|
|
11
11
|
from reconcile.gql_definitions.fragments.saas_target_namespace import (
|
12
12
|
SaasTargetNamespace,
|
13
13
|
)
|
14
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request_manager_v2 import (
|
15
|
+
SAPM_LABEL,
|
16
|
+
)
|
14
17
|
from reconcile.saas_auto_promotions_manager.merge_request_manager.mr_parser import (
|
15
18
|
MRParser,
|
16
19
|
OpenMergeRequest,
|
17
20
|
)
|
21
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.reconciler import (
|
22
|
+
Diff,
|
23
|
+
Reconciler,
|
24
|
+
)
|
18
25
|
from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer import (
|
19
26
|
CHANNELS_REF,
|
20
27
|
CONTENT_HASHES,
|
21
28
|
IS_BATCHABLE,
|
22
29
|
PROMOTION_DATA_SEPARATOR,
|
23
|
-
SAPM_LABEL,
|
24
30
|
SAPM_VERSION,
|
25
31
|
VERSION_REF,
|
26
32
|
Renderer,
|
@@ -32,17 +38,16 @@ from reconcile.saas_auto_promotions_manager.subscriber import (
|
|
32
38
|
from reconcile.utils.vcs import VCS, MRCheckStatus
|
33
39
|
|
34
40
|
from .data_keys import (
|
41
|
+
CHANNEL,
|
35
42
|
DESCRIPTION,
|
36
43
|
HAS_CONFLICTS,
|
37
44
|
LABELS,
|
38
45
|
OPEN_MERGE_REQUESTS,
|
39
46
|
PIPELINE_RESULTS,
|
47
|
+
REF,
|
40
48
|
SUBSCRIBER_BATCHABLE,
|
41
49
|
SUBSCRIBER_CHANNELS,
|
42
50
|
SUBSCRIBER_CONTENT_HASH,
|
43
|
-
SUBSCRIBER_DESIRED_CONFIG_HASHES,
|
44
|
-
SUBSCRIBER_DESIRED_REF,
|
45
|
-
SUBSCRIBER_TARGET_NAMESPACE,
|
46
51
|
SUBSCRIBER_TARGET_PATH,
|
47
52
|
)
|
48
53
|
|
@@ -96,7 +101,7 @@ def vcs_builder(
|
|
96
101
|
|
97
102
|
|
98
103
|
@pytest.fixture
|
99
|
-
def mr_parser_builder() -> Callable[[
|
104
|
+
def mr_parser_builder() -> Callable[[Iterable[OpenMergeRequest]], MRParser]:
|
100
105
|
def builder(data: Iterable[OpenMergeRequest]) -> MRParser:
|
101
106
|
mr_parser = create_autospec(spec=MRParser)
|
102
107
|
mr_parser.retrieve_open_mrs.side_effect = [data]
|
@@ -105,24 +110,32 @@ def mr_parser_builder() -> Callable[[Mapping], MRParser]:
|
|
105
110
|
return builder
|
106
111
|
|
107
112
|
|
113
|
+
@pytest.fixture
|
114
|
+
def reconciler_builder() -> Callable[[Diff], Reconciler]:
|
115
|
+
def builder(data: Diff) -> Reconciler:
|
116
|
+
reconciler = create_autospec(spec=Reconciler)
|
117
|
+
reconciler.reconcile.side_effect = [data]
|
118
|
+
return reconciler
|
119
|
+
|
120
|
+
return builder
|
121
|
+
|
122
|
+
|
108
123
|
@pytest.fixture
|
109
124
|
def subscriber_builder(
|
110
125
|
saas_target_namespace_builder: Callable[..., SaasTargetNamespace],
|
111
|
-
):
|
126
|
+
) -> Callable[..., Subscriber]:
|
112
127
|
def builder(data: Mapping) -> Subscriber:
|
113
128
|
subscriber = Subscriber(
|
114
129
|
saas_name="",
|
115
130
|
template_name="",
|
116
|
-
target_namespace=saas_target_namespace_builder(
|
117
|
-
data.get(SUBSCRIBER_TARGET_NAMESPACE, {})
|
118
|
-
),
|
131
|
+
target_namespace=saas_target_namespace_builder({}),
|
119
132
|
ref="",
|
120
133
|
target_file_path=data.get(SUBSCRIBER_TARGET_PATH, ""),
|
121
134
|
use_target_config_hash=True,
|
122
135
|
)
|
123
|
-
subscriber.desired_hashes =
|
124
|
-
subscriber.desired_ref = data.get(
|
125
|
-
for channel in data.get(
|
136
|
+
subscriber.desired_hashes = []
|
137
|
+
subscriber.desired_ref = data.get(REF, "")
|
138
|
+
for channel in data.get(CHANNEL, []):
|
126
139
|
subscriber.channels.append(
|
127
140
|
Channel(
|
128
141
|
name=channel,
|
@@ -1,185 +1,83 @@
|
|
1
|
-
from collections.abc import
|
2
|
-
|
3
|
-
Iterable,
|
4
|
-
Mapping,
|
5
|
-
)
|
6
|
-
from unittest.mock import create_autospec
|
1
|
+
from collections.abc import Callable
|
2
|
+
from unittest.mock import call, create_autospec
|
7
3
|
|
8
|
-
import pytest
|
9
4
|
from gitlab.v4.objects import ProjectMergeRequest
|
10
5
|
|
11
|
-
from reconcile.saas_auto_promotions_manager.merge_request_manager.
|
12
|
-
|
6
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request_manager_v2 import (
|
7
|
+
MergeRequestManagerV2,
|
13
8
|
)
|
14
9
|
from reconcile.saas_auto_promotions_manager.merge_request_manager.mr_parser import (
|
15
10
|
MRParser,
|
16
11
|
OpenMergeRequest,
|
17
12
|
)
|
13
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.reconciler import (
|
14
|
+
Addition,
|
15
|
+
Deletion,
|
16
|
+
Diff,
|
17
|
+
Reconciler,
|
18
|
+
)
|
18
19
|
from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer import (
|
19
20
|
Renderer,
|
20
21
|
)
|
21
22
|
from reconcile.saas_auto_promotions_manager.subscriber import Subscriber
|
22
|
-
from reconcile.
|
23
|
-
|
24
|
-
|
25
|
-
SUBSCRIBER_CHANNELS,
|
26
|
-
SUBSCRIBER_DESIRED_CONFIG_HASHES,
|
27
|
-
SUBSCRIBER_DESIRED_REF,
|
28
|
-
SUBSCRIBER_TARGET_NAMESPACE,
|
29
|
-
SUBSCRIBER_TARGET_PATH,
|
23
|
+
from reconcile.test.saas_auto_promotions_manager.merge_request_manager.merge_request_manager.data_keys import (
|
24
|
+
CHANNEL,
|
25
|
+
REF,
|
30
26
|
)
|
27
|
+
from reconcile.utils.vcs import VCS
|
31
28
|
|
32
29
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
):
|
38
|
-
subscribers = [
|
39
|
-
subscriber_builder({
|
40
|
-
SUBSCRIBER_TARGET_NAMESPACE: {"path": "namespace1"},
|
41
|
-
SUBSCRIBER_TARGET_PATH: "target1",
|
42
|
-
SUBSCRIBER_DESIRED_REF: "new_sha",
|
43
|
-
SUBSCRIBER_DESIRED_CONFIG_HASHES: [],
|
44
|
-
SUBSCRIBER_CHANNELS: ["channel-a", "channel-b"],
|
45
|
-
})
|
46
|
-
]
|
47
|
-
|
48
|
-
open_mrs = [
|
49
|
-
OpenMergeRequest(
|
50
|
-
raw=create_autospec(ProjectMergeRequest),
|
51
|
-
content_hashes="oldcontent",
|
52
|
-
channels="channel-a,channel-b",
|
53
|
-
failed_mr_check=False,
|
54
|
-
is_batchable=True,
|
55
|
-
)
|
56
|
-
]
|
57
|
-
mr_parser = mr_parser_builder(open_mrs)
|
30
|
+
def test_reconcile(
|
31
|
+
reconciler_builder: Callable[[Diff], Reconciler],
|
32
|
+
subscriber_builder: Callable[..., Subscriber],
|
33
|
+
) -> None:
|
58
34
|
vcs = create_autospec(spec=VCS)
|
59
|
-
|
60
|
-
|
61
|
-
mr_parser=mr_parser,
|
62
|
-
renderer=renderer,
|
63
|
-
)
|
64
|
-
merge_request_manager.housekeeping()
|
65
|
-
merge_request_manager.create_promotion_merge_requests(subscribers=subscribers)
|
66
|
-
|
67
|
-
# There is an open MR with old content for that subscriber
|
68
|
-
# Close old content and open new MR with new content
|
69
|
-
vcs.close_app_interface_mr.assert_called_once()
|
70
|
-
vcs.open_app_interface_merge_request.assert_called_once()
|
71
|
-
|
72
|
-
|
73
|
-
@pytest.mark.parametrize(
|
74
|
-
"hash_prefix, hash_suffix, channel_prefix, channel_suffix",
|
75
|
-
[
|
76
|
-
("", "", "", ""),
|
77
|
-
("hashprefix,", "", "", ""),
|
78
|
-
("", ",hashsuffix", "", ""),
|
79
|
-
("", "", "channelprefix,", ""),
|
80
|
-
("", "", "", ",channelsuffix"),
|
81
|
-
("a,", ",b", "c,", ",d"),
|
82
|
-
],
|
83
|
-
)
|
84
|
-
def test_merge_request_already_opened(
|
85
|
-
mr_parser_builder: Callable[[Iterable], MRParser],
|
86
|
-
renderer: Renderer,
|
87
|
-
subscriber_builder: Callable[[Mapping], Subscriber],
|
88
|
-
hash_prefix: str,
|
89
|
-
hash_suffix: str,
|
90
|
-
channel_prefix: str,
|
91
|
-
channel_suffix: str,
|
92
|
-
):
|
93
|
-
subscriber_channel = "channel-a"
|
35
|
+
mr_parser = create_autospec(spec=MRParser)
|
36
|
+
renderer = create_autospec(spec=Renderer)
|
94
37
|
subscribers = [
|
95
38
|
subscriber_builder({
|
96
|
-
|
97
|
-
|
98
|
-
SUBSCRIBER_DESIRED_REF: "new_sha",
|
99
|
-
SUBSCRIBER_DESIRED_CONFIG_HASHES: [],
|
100
|
-
SUBSCRIBER_CHANNELS: [subscriber_channel],
|
39
|
+
CHANNEL: ["chan1,chan2"],
|
40
|
+
REF: "hash1",
|
101
41
|
})
|
102
42
|
]
|
103
|
-
|
104
|
-
|
105
|
-
open_mrs = [
|
106
|
-
OpenMergeRequest(
|
43
|
+
deletion = Deletion(
|
44
|
+
mr=OpenMergeRequest(
|
107
45
|
raw=create_autospec(spec=ProjectMergeRequest),
|
108
|
-
|
109
|
-
|
110
|
-
is_batchable=True,
|
46
|
+
channels=set(),
|
47
|
+
content_hashes=set(),
|
111
48
|
failed_mr_check=False,
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
vcs = create_autospec(spec=VCS)
|
117
|
-
merge_request_manager = MergeRequestManager(
|
118
|
-
vcs=vcs,
|
119
|
-
mr_parser=mr_parser,
|
120
|
-
renderer=renderer,
|
49
|
+
is_batchable=True,
|
50
|
+
),
|
51
|
+
reason="some reason.",
|
121
52
|
)
|
122
|
-
merge_request_manager.housekeeping()
|
123
|
-
merge_request_manager.create_promotion_merge_requests(subscribers=subscribers)
|
124
|
-
|
125
|
-
# There is already an open merge request for this subscriber content
|
126
|
-
# Do not open another one
|
127
|
-
vcs.close_app_interface_mr.assert_not_called()
|
128
|
-
vcs.open_app_interface_merge_request.assert_not_called()
|
129
53
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
("hashprefix,", "", "", ""),
|
136
|
-
("", ",hashsuffix", "", ""),
|
137
|
-
("", "", "channelprefix,", ""),
|
138
|
-
("", "", "", ",channelsuffix"),
|
139
|
-
("a,", ",b", "c,", ",d"),
|
140
|
-
],
|
141
|
-
)
|
142
|
-
def test_ignore_unrelated_channels(
|
143
|
-
mr_parser_builder: Callable[[Iterable], MRParser],
|
144
|
-
renderer: Renderer,
|
145
|
-
subscriber_builder: Callable[[Mapping], Subscriber],
|
146
|
-
hash_prefix: str,
|
147
|
-
hash_suffix: str,
|
148
|
-
channel_prefix: str,
|
149
|
-
channel_suffix: str,
|
150
|
-
):
|
151
|
-
subscribers = [
|
152
|
-
subscriber_builder({
|
153
|
-
SUBSCRIBER_TARGET_NAMESPACE: {"path": "namespace1"},
|
154
|
-
SUBSCRIBER_TARGET_PATH: "target1",
|
155
|
-
SUBSCRIBER_DESIRED_REF: "new_sha",
|
156
|
-
SUBSCRIBER_DESIRED_CONFIG_HASHES: [],
|
157
|
-
SUBSCRIBER_CHANNELS: ["channel-a"],
|
158
|
-
})
|
159
|
-
]
|
160
|
-
content_hash = Subscriber.combined_content_hash(subscribers=subscribers)
|
161
|
-
|
162
|
-
open_mrs = [
|
163
|
-
OpenMergeRequest(
|
164
|
-
raw=create_autospec(spec=ProjectMergeRequest),
|
165
|
-
content_hashes=f"{hash_prefix}{content_hash}{hash_suffix}",
|
166
|
-
channels=f"{channel_prefix}other-channel{channel_suffix}",
|
167
|
-
is_batchable=True,
|
168
|
-
failed_mr_check=False,
|
54
|
+
additions = [
|
55
|
+
Addition(
|
56
|
+
content_hashes={Subscriber.combined_content_hash(subscribers=subscribers)},
|
57
|
+
channels={"chan1,chan2"},
|
58
|
+
batchable=True,
|
169
59
|
)
|
170
60
|
]
|
171
|
-
mr_parser = mr_parser_builder(open_mrs)
|
172
61
|
|
173
|
-
|
174
|
-
|
62
|
+
reconciler = reconciler_builder(
|
63
|
+
Diff(
|
64
|
+
deletions=[deletion],
|
65
|
+
additions=additions,
|
66
|
+
)
|
67
|
+
)
|
68
|
+
manager = MergeRequestManagerV2(
|
175
69
|
vcs=vcs,
|
176
70
|
mr_parser=mr_parser,
|
71
|
+
reconciler=reconciler,
|
177
72
|
renderer=renderer,
|
178
73
|
)
|
179
|
-
merge_request_manager.housekeeping()
|
180
|
-
merge_request_manager.create_promotion_merge_requests(subscribers=subscribers)
|
181
74
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
vcs.
|
75
|
+
manager.reconcile(subscribers=subscribers)
|
76
|
+
|
77
|
+
assert len(manager._sapm_mrs) == len(additions)
|
78
|
+
vcs.close_app_interface_mr.assert_has_calls([
|
79
|
+
call(deletion.mr.raw, deletion.reason),
|
80
|
+
])
|
81
|
+
vcs.open_app_interface_merge_request.assert_has_calls([
|
82
|
+
call(mr) for mr in manager._sapm_mrs
|
83
|
+
])
|
@@ -6,6 +6,9 @@ from unittest.mock import call
|
|
6
6
|
|
7
7
|
from gitlab.v4.objects import ProjectMergeRequest
|
8
8
|
|
9
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request_manager_v2 import (
|
10
|
+
SAPM_LABEL,
|
11
|
+
)
|
9
12
|
from reconcile.saas_auto_promotions_manager.merge_request_manager.mr_parser import (
|
10
13
|
MRParser,
|
11
14
|
)
|
@@ -14,7 +17,6 @@ from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer impor
|
|
14
17
|
CONTENT_HASHES,
|
15
18
|
IS_BATCHABLE,
|
16
19
|
PROMOTION_DATA_SEPARATOR,
|
17
|
-
SAPM_LABEL,
|
18
20
|
SAPM_VERSION,
|
19
21
|
VERSION_REF,
|
20
22
|
)
|
@@ -60,17 +62,17 @@ def test_valid_parsing(
|
|
60
62
|
mr_parser = MRParser(
|
61
63
|
vcs=vcs,
|
62
64
|
)
|
63
|
-
open_mrs = mr_parser.retrieve_open_mrs()
|
65
|
+
open_mrs = mr_parser.retrieve_open_mrs(label=SAPM_LABEL)
|
64
66
|
assert len(open_mrs) == 2
|
65
67
|
|
66
68
|
assert open_mrs[0].raw == expectd_mrs[0]
|
67
|
-
assert open_mrs[0].channels == "channel0"
|
68
|
-
assert open_mrs[0].content_hashes == "hash0"
|
69
|
+
assert open_mrs[0].channels == {"channel0"}
|
70
|
+
assert open_mrs[0].content_hashes == {"hash0"}
|
69
71
|
assert open_mrs[0].is_batchable
|
70
72
|
|
71
73
|
assert open_mrs[1].raw == expectd_mrs[1]
|
72
|
-
assert open_mrs[1].channels == "channel1"
|
73
|
-
assert open_mrs[1].content_hashes == "hash1"
|
74
|
+
assert open_mrs[1].channels == {"channel1"}
|
75
|
+
assert open_mrs[1].content_hashes == {"hash1"}
|
74
76
|
assert not open_mrs[1].is_batchable
|
75
77
|
|
76
78
|
|
@@ -107,7 +109,7 @@ def test_labels_filter(
|
|
107
109
|
mr_parser = MRParser(
|
108
110
|
vcs=vcs,
|
109
111
|
)
|
110
|
-
open_mrs = mr_parser.retrieve_open_mrs()
|
112
|
+
open_mrs = mr_parser.retrieve_open_mrs(label=SAPM_LABEL)
|
111
113
|
assert len(open_mrs) == 1
|
112
114
|
assert open_mrs[0].raw == expectd_mrs[0]
|
113
115
|
|
@@ -261,7 +263,7 @@ def test_bad_mrs(
|
|
261
263
|
),
|
262
264
|
]
|
263
265
|
|
264
|
-
open_mrs = mr_parser.retrieve_open_mrs()
|
266
|
+
open_mrs = mr_parser.retrieve_open_mrs(label=SAPM_LABEL)
|
265
267
|
assert len(open_mrs) == 0
|
266
268
|
vcs.close_app_interface_mr.assert_has_calls(expected_calls) # type: ignore[attr-defined]
|
267
269
|
assert vcs.close_app_interface_mr.call_count == len(expected_calls) # type: ignore[attr-defined]
|
@@ -299,7 +301,7 @@ def test_remove_duplicates(
|
|
299
301
|
mr_parser = MRParser(
|
300
302
|
vcs=vcs,
|
301
303
|
)
|
302
|
-
open_mrs = mr_parser.retrieve_open_mrs()
|
304
|
+
open_mrs = mr_parser.retrieve_open_mrs(label=SAPM_LABEL)
|
303
305
|
vcs.close_app_interface_mr.assert_has_calls([ # type: ignore[attr-defined]
|
304
306
|
call(
|
305
307
|
expected_mrs[1],
|