qontract-reconcile 0.10.1rc513__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.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/RECORD +19 -17
- reconcile/cli.py +3 -3
- reconcile/{template_tester.py → resource_template_tester.py} +3 -3
- 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.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.
|
3
|
+
Version: 0.10.1rc515
|
4
4
|
Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
|
5
5
|
Home-page: https://github.com/app-sre/qontract-reconcile
|
6
6
|
Author: Red Hat App-SRE Team
|
{qontract_reconcile-0.10.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/RECORD
RENAMED
@@ -9,7 +9,7 @@ reconcile/aws_iam_password_reset.py,sha256=NwErtrqgBiXr7eGCAHdtGGOx0S7-4JnSc29Ie
|
|
9
9
|
reconcile/aws_support_cases_sos.py,sha256=Jk6_XjDeJSYxgRGqcEAOcynt9qJF2r5HPIPcSKmoBv8,2974
|
10
10
|
reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=W_VJagnsJR1v5oqjlI3RJJE0_nhtJ0m81RS8zWA5u5c,3538
|
11
11
|
reconcile/checkpoint.py,sha256=R2WFXUXLTB4sWMi4GeA4eegsuf_1-Q4vH8M0Toh3Ij4,5036
|
12
|
-
reconcile/cli.py,sha256=
|
12
|
+
reconcile/cli.py,sha256=ek511mirANFglUXz_lrnIjmHZ48ZDJOx-53OFf-fSO4,84491
|
13
13
|
reconcile/closedbox_endpoint_monitoring_base.py,sha256=SMhkcQqprWvThrIJa3U_3uh5w1h-alleW1QnCJFY4Qw,4909
|
14
14
|
reconcile/cluster_deployment_mapper.py,sha256=2Ah-nu-Mdig0pjuiZl_XLrmVAjYzFjORR3dMlCgkmw0,2352
|
15
15
|
reconcile/dashdotdb_base.py,sha256=a5aPLVxyqPSbjdB0Ty-uliOtxwvEbbEljHJKxdK3-Zk,4813
|
@@ -96,6 +96,7 @@ reconcile/queries.py,sha256=ZGV4CZzzYz5whcoHk8X9gwfgJ9GnHxz6K07NkGpoBBo,50361
|
|
96
96
|
reconcile/query_validator.py,sha256=BAjGrU8_VhzTOv5k0-uz0hY9ziZyconv8VAhgre1Auc,1497
|
97
97
|
reconcile/requests_sender.py,sha256=914iluuF4UVgG3VyxxtnHOu4yf6YKS2fIy6PViSsFTQ,3875
|
98
98
|
reconcile/resource_scraper.py,sha256=vo1N9vLJCYWvXlTwFRIpEuWjx_39ZV9zxJlpoPq4g3U,2330
|
99
|
+
reconcile/resource_template_tester.py,sha256=DsKvBuNLPxm4Fa-e1YHHySnhThm5i_j-nF3G4b02Mz0,2416
|
99
100
|
reconcile/saas_file_validator.py,sha256=WdRVwAdEWO3uH3atefZhZRiQEZje7SQBfVZI6L6c7cA,1955
|
100
101
|
reconcile/sendgrid_teammates.py,sha256=oO8QbLb4s1o8A6CGiCagN9CmS05BSS_WLztuY0Ym9D8,4773
|
101
102
|
reconcile/service_dependencies.py,sha256=PMKP9vc6oL-78rzyF_RE8DzLSQMSqN8vCqt9sWpBLAM,4470
|
@@ -105,7 +106,6 @@ reconcile/slack_usergroups.py,sha256=4Xikz_zKPHE5Q_hf2vOOs9vlItxgCqZPn7YJgn1Brik
|
|
105
106
|
reconcile/sql_query.py,sha256=qLTUU2Hc0BmJoSl9cCUsIfdEaEaOQp7y__E4KLjjcaA,25732
|
106
107
|
reconcile/status.py,sha256=cY4IJFXemhxptRJqR4qaaOWqei9e4jgLXuVSGajMsjg,544
|
107
108
|
reconcile/status_board.py,sha256=xOKicOelyGv3h2sFJxa9FBj8HDroZyGhMaRWaNRGpQQ,8100
|
108
|
-
reconcile/template_tester.py,sha256=vZz8GM46waQUGd3OVnhW5OLTqctFMH_Hh1QXxT5hduM,2384
|
109
109
|
reconcile/terraform_aws_route53.py,sha256=R8eZHlvP368nvtmLd_cMSK3RGxD7jso9qE7NP92iniU,9986
|
110
110
|
reconcile/terraform_cloudflare_dns.py,sha256=auU4bzeLwd4S8D8oqpqJbrCUoEdELXrgi7vHOedjYFk,13332
|
111
111
|
reconcile/terraform_cloudflare_resources.py,sha256=EbQQaoDnZ7brvRCpbFtwlD7KLk2hDVNcjhrJGaAywEk,15023
|
@@ -345,14 +345,16 @@ reconcile/rhidp/sso_client/base.py,sha256=EfQ2ewcOKh5idg46UKAkY6z0m_nGQfvnQKffa2
|
|
345
345
|
reconcile/rhidp/sso_client/integration.py,sha256=kA8g7c38ZBSdrRtyfEqy_WgSreD1PbwY7ZIN-3tZRPc,2221
|
346
346
|
reconcile/rhidp/sso_client/metrics.py,sha256=Tq7tSOsqL3XdcPUdozxqzSPIodUeOV87UCTqpuuqqhw,1013
|
347
347
|
reconcile/saas_auto_promotions_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
348
|
-
reconcile/saas_auto_promotions_manager/integration.py,sha256=
|
348
|
+
reconcile/saas_auto_promotions_manager/integration.py,sha256=1nm3aV5a0frEPTSww4ue1mfQ_Px6XaRZoaBRhPgJiAU,6472
|
349
349
|
reconcile/saas_auto_promotions_manager/publisher.py,sha256=4_M9Oykhj-kEZPUn05E2DY5gD6-x32Dgf7K3NPOkGEg,2029
|
350
350
|
reconcile/saas_auto_promotions_manager/subscriber.py,sha256=cLhPlkT71J2LIice3SLmH1WpsqzV46gd0peMxrnqyRw,7452
|
351
351
|
reconcile/saas_auto_promotions_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
352
352
|
reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request.py,sha256=PNu7sE-tDUY61E03z5w0b93fdowZ8auCl0S4_vhYOKQ,1333
|
353
|
-
reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py,sha256=
|
354
|
-
reconcile/saas_auto_promotions_manager/merge_request_manager/
|
355
|
-
reconcile/saas_auto_promotions_manager/merge_request_manager/
|
353
|
+
reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py,sha256=P4RH6y-qC9RKJxVguyOfOAe42a6AP1Ez-NlyMSH3j8I,7492
|
354
|
+
reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager_v2.py,sha256=AwCyvnNAKwRbESodHN2-fWG8Wpxua0nzQkcIsz4Gevg,5411
|
355
|
+
reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py,sha256=x8Gg-YjEFWEeDPJH3Y8SrfcJbwhLuAqCz4kIhfEyaaA,7060
|
356
|
+
reconcile/saas_auto_promotions_manager/merge_request_manager/reconciler.py,sha256=DgMw24exjuor9s4Y8y0Ftsjs5l7rl8D7dksMoJ1RF0A,7639
|
357
|
+
reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py,sha256=VSKCwY8jZ6NYwIT6edmVnpzY7cgjhn5fhX9xtlw2LD8,7341
|
356
358
|
reconcile/saas_auto_promotions_manager/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
357
359
|
reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py,sha256=mihuWynroB1Cea1Lsvf6V8Nb8PGiBdcLC0uhCX_52Y0,6966
|
358
360
|
reconcile/skupper_network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -452,14 +454,14 @@ reconcile/test/test_vpc_peerings_validator.py,sha256=dFSmjc_dMN2GqMbntCFpa7PUZmy
|
|
452
454
|
reconcile/test/test_wrong_region.py,sha256=7KzL7OaICQ9Z3DW27zt_ykMN7_87owAFC-2CYjvGoyA,2138
|
453
455
|
reconcile/test/saas_auto_promotions_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
454
456
|
reconcile/test/saas_auto_promotions_manager/conftest.py,sha256=tZNs35EuWulP53Cqt61RteOGY_uH4gfhtXfGQ8-awwM,3081
|
455
|
-
reconcile/test/saas_auto_promotions_manager/test_integration_test.py,sha256=
|
457
|
+
reconcile/test/saas_auto_promotions_manager/test_integration_test.py,sha256=UIafVpeof9Zd3Q17mEDIUwgdBGf8oFxkf7h8tLfmwCE,2077
|
456
458
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
457
459
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
458
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py,sha256=
|
459
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py,sha256=
|
460
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py,sha256=
|
461
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py,sha256=
|
462
|
-
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/
|
460
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py,sha256=7O3lbk1EmEtUofqGncfiwMYvDPXrkQNPB59zlQ_zXkM,4588
|
461
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py,sha256=Z1IV51OUuzhd-3S8W-k7ixC-fkaglCokn0eakK0Z73s,606
|
462
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py,sha256=ryROiiQNtZvuG820CB-RQ9FMmLAGshezyMDNDiJNA_E,2369
|
463
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py,sha256=dcGHzxuafKSxmswSO1qF2WlKaqsmEvtERC6Lb8kDAN0,10019
|
464
|
+
reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_reconciler.py,sha256=-rSv-C-JFaY0gsjSFgcXz9ASNQQOzwizaQEbVYJtLHg,14906
|
463
465
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
464
466
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py,sha256=2rCSstewp4LPoEJHm5N7dGJexEtY8ndLHvoGZYjmpsc,1678
|
465
467
|
reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/data_keys.py,sha256=beHYQ9kgDLeBZgC2FvxQA3tHx1PO-RAMN8_kVcSdikI,90
|
@@ -666,8 +668,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
|
|
666
668
|
tools/test/test_qontract_cli.py,sha256=d18KrdhtUGqoC7_kWZU128U0-VJEj-0rjFkLVufcI6I,2755
|
667
669
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
668
670
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
669
|
-
qontract_reconcile-0.10.
|
670
|
-
qontract_reconcile-0.10.
|
671
|
-
qontract_reconcile-0.10.
|
672
|
-
qontract_reconcile-0.10.
|
673
|
-
qontract_reconcile-0.10.
|
671
|
+
qontract_reconcile-0.10.1rc515.dist-info/METADATA,sha256=Bgwt_oRZlcfCQ6ycYlopR_xt-fRVu3kWrlOW7wMuaqo,2349
|
672
|
+
qontract_reconcile-0.10.1rc515.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
673
|
+
qontract_reconcile-0.10.1rc515.dist-info/entry_points.txt,sha256=rTjAv28I_CHLM8ID3OPqMI_suoQ9s7tFbim4aYjn9kk,376
|
674
|
+
qontract_reconcile-0.10.1rc515.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
675
|
+
qontract_reconcile-0.10.1rc515.dist-info/RECORD,,
|
reconcile/cli.py
CHANGED
@@ -2628,10 +2628,10 @@ def prometheus_rules_tester(ctx, thread_pool_size, cluster_name):
|
|
2628
2628
|
|
2629
2629
|
@integration.command(short_help="Tests templating of resources.")
|
2630
2630
|
@click.pass_context
|
2631
|
-
def
|
2632
|
-
import reconcile.
|
2631
|
+
def resource_template_tester(ctx):
|
2632
|
+
import reconcile.resource_template_tester
|
2633
2633
|
|
2634
|
-
run_integration(reconcile.
|
2634
|
+
run_integration(reconcile.resource_template_tester, ctx.obj)
|
2635
2635
|
|
2636
2636
|
|
2637
2637
|
@integration.command(
|
@@ -11,13 +11,13 @@ from reconcile.status import ExitCodes
|
|
11
11
|
from reconcile.utils import gql
|
12
12
|
from reconcile.utils.semver_helper import make_semver
|
13
13
|
|
14
|
-
QONTRACT_INTEGRATION = "template-tester"
|
14
|
+
QONTRACT_INTEGRATION = "resource-template-tester"
|
15
15
|
QONTRACT_INTEGRATION_VERSION = make_semver(0, 1, 0)
|
16
16
|
|
17
17
|
|
18
18
|
TEMPLATE_TESTS_QUERY = """
|
19
19
|
{
|
20
|
-
tests:
|
20
|
+
tests: resource_template_tests_v1 {
|
21
21
|
name
|
22
22
|
resourcePath
|
23
23
|
expectedResult
|
@@ -30,7 +30,7 @@ def load_resource(path: str) -> dict:
|
|
30
30
|
return yaml.safe_load(gql.get_resource(path)["content"])
|
31
31
|
|
32
32
|
|
33
|
-
def run(dry_run):
|
33
|
+
def run(dry_run: bool) -> None:
|
34
34
|
gqlapi = gql.get_api()
|
35
35
|
template_tests = gqlapi.query(TEMPLATE_TESTS_QUERY)["tests"]
|
36
36
|
settings = queries.get_app_interface_settings()
|
@@ -9,9 +9,15 @@ from reconcile.openshift_saas_deploy import (
|
|
9
9
|
from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request_manager import (
|
10
10
|
MergeRequestManager,
|
11
11
|
)
|
12
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request_manager_v2 import (
|
13
|
+
MergeRequestManagerV2,
|
14
|
+
)
|
12
15
|
from reconcile.saas_auto_promotions_manager.merge_request_manager.mr_parser import (
|
13
16
|
MRParser,
|
14
17
|
)
|
18
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.reconciler import (
|
19
|
+
Reconciler,
|
20
|
+
)
|
15
21
|
from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer import (
|
16
22
|
Renderer,
|
17
23
|
)
|
@@ -45,6 +51,7 @@ class SaasAutoPromotionsManager:
|
|
45
51
|
deployment_state: PromotionState,
|
46
52
|
vcs: VCS,
|
47
53
|
saas_file_inventory: SaasFilesInventory,
|
54
|
+
merge_request_manager_v2: MergeRequestManagerV2,
|
48
55
|
merge_request_manager: MergeRequestManager,
|
49
56
|
thread_pool_size: int,
|
50
57
|
dry_run: bool,
|
@@ -52,6 +59,7 @@ class SaasAutoPromotionsManager:
|
|
52
59
|
self._deployment_state = deployment_state
|
53
60
|
self._vcs = vcs
|
54
61
|
self._saas_file_inventory = saas_file_inventory
|
62
|
+
self._merge_request_manager_v2 = merge_request_manager_v2
|
55
63
|
self._merge_request_manager = merge_request_manager
|
56
64
|
self._thread_pool_size = thread_pool_size
|
57
65
|
self._dry_run = dry_run
|
@@ -88,11 +96,14 @@ class SaasAutoPromotionsManager:
|
|
88
96
|
self._merge_request_manager.create_promotion_merge_requests(
|
89
97
|
subscribers=subscribers_with_diff
|
90
98
|
)
|
99
|
+
self._merge_request_manager_v2.reconcile(subscribers=subscribers_with_diff)
|
91
100
|
|
92
101
|
|
93
102
|
def init_external_dependencies(
|
94
103
|
dry_run: bool,
|
95
|
-
) -> tuple[
|
104
|
+
) -> tuple[
|
105
|
+
PromotionState, VCS, SaasFilesInventory, MergeRequestManagerV2, MergeRequestManager
|
106
|
+
]:
|
96
107
|
"""
|
97
108
|
Lets initialize everything that involves calls to external dependencies:
|
98
109
|
- VCS -> Gitlab / Github queries
|
@@ -120,17 +131,29 @@ def init_external_dependencies(
|
|
120
131
|
allow_opening_mrs=allow_opening_mrs,
|
121
132
|
)
|
122
133
|
mr_parser = MRParser(vcs=vcs)
|
123
|
-
|
134
|
+
merge_request_manager_v2 = MergeRequestManagerV2(
|
124
135
|
vcs=vcs,
|
136
|
+
reconciler=Reconciler(),
|
125
137
|
mr_parser=mr_parser,
|
126
138
|
renderer=Renderer(),
|
127
139
|
)
|
140
|
+
merge_request_manager = MergeRequestManager(
|
141
|
+
mr_parser=mr_parser,
|
142
|
+
renderer=Renderer(),
|
143
|
+
vcs=vcs,
|
144
|
+
)
|
128
145
|
saas_files = get_saas_files()
|
129
146
|
saas_inventory = SaasFilesInventory(saas_files=saas_files)
|
130
147
|
deployment_state = PromotionState(
|
131
148
|
state=init_state(integration=OPENSHIFT_SAAS_DEPLOY, secret_reader=secret_reader)
|
132
149
|
)
|
133
|
-
return
|
150
|
+
return (
|
151
|
+
deployment_state,
|
152
|
+
vcs,
|
153
|
+
saas_inventory,
|
154
|
+
merge_request_manager_v2,
|
155
|
+
merge_request_manager,
|
156
|
+
)
|
134
157
|
|
135
158
|
|
136
159
|
@defer
|
@@ -143,6 +166,7 @@ def run(
|
|
143
166
|
deployment_state,
|
144
167
|
vcs,
|
145
168
|
saas_inventory,
|
169
|
+
merge_request_manager_v2,
|
146
170
|
merge_request_manager,
|
147
171
|
) = init_external_dependencies(dry_run=dry_run)
|
148
172
|
if defer:
|
@@ -153,6 +177,7 @@ def run(
|
|
153
177
|
vcs=vcs,
|
154
178
|
saas_file_inventory=saas_inventory,
|
155
179
|
merge_request_manager=merge_request_manager,
|
180
|
+
merge_request_manager_v2=merge_request_manager_v2,
|
156
181
|
thread_pool_size=thread_pool_size,
|
157
182
|
dry_run=dry_run,
|
158
183
|
)
|
@@ -16,7 +16,6 @@ from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer impor
|
|
16
16
|
CHANNELS_REF,
|
17
17
|
CONTENT_HASHES,
|
18
18
|
IS_BATCHABLE,
|
19
|
-
SAPM_LABEL,
|
20
19
|
VERSION_REF,
|
21
20
|
Renderer,
|
22
21
|
)
|
@@ -25,6 +24,8 @@ from reconcile.utils.vcs import VCS
|
|
25
24
|
|
26
25
|
ITEM_SEPARATOR = ","
|
27
26
|
|
27
|
+
SAPM_LABEL = "SAPM"
|
28
|
+
|
28
29
|
|
29
30
|
class MergeRequestManager:
|
30
31
|
"""
|
@@ -68,14 +69,13 @@ class MergeRequestManager:
|
|
68
69
|
"Closing this MR because it failed MR check and isn't marked un-batchable yet.",
|
69
70
|
)
|
70
71
|
# Remember these hashes as unbatchable
|
71
|
-
|
72
|
-
self._unbatchable_hashes.update(content_hashes)
|
72
|
+
self._unbatchable_hashes.update(mr.content_hashes)
|
73
73
|
else:
|
74
74
|
open_mrs_after_unbatching.append(mr)
|
75
75
|
self._open_mrs = open_mrs_after_unbatching
|
76
76
|
|
77
77
|
def housekeeping(self) -> None:
|
78
|
-
self._open_mrs = self._mr_parser.retrieve_open_mrs()
|
78
|
+
self._open_mrs = self._mr_parser.retrieve_open_mrs(label=SAPM_LABEL)
|
79
79
|
self._unbatch_failed_mrs()
|
80
80
|
|
81
81
|
def _aggregate_subscribers_per_channel_combo(
|
@@ -160,7 +160,7 @@ class MergeRequestManager:
|
|
160
160
|
channels=channel_combo,
|
161
161
|
is_batchable=combined_content_hash not in self._unbatchable_hashes,
|
162
162
|
)
|
163
|
-
title = self._renderer.render_title(channels=channel_combo)
|
163
|
+
title = self._renderer.render_title(is_draft=False, channels=channel_combo)
|
164
164
|
logging.info(
|
165
165
|
"Open MR for update in channel(s) %s",
|
166
166
|
channel_combo,
|
@@ -0,0 +1,144 @@
|
|
1
|
+
import logging
|
2
|
+
from collections import defaultdict
|
3
|
+
from collections.abc import Iterable
|
4
|
+
|
5
|
+
from gitlab.exceptions import GitlabGetError
|
6
|
+
|
7
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.merge_request import (
|
8
|
+
SAPMMR,
|
9
|
+
)
|
10
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.mr_parser import (
|
11
|
+
MRParser,
|
12
|
+
)
|
13
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.reconciler import (
|
14
|
+
Addition,
|
15
|
+
Promotion,
|
16
|
+
Reconciler,
|
17
|
+
)
|
18
|
+
from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer import (
|
19
|
+
Renderer,
|
20
|
+
)
|
21
|
+
from reconcile.saas_auto_promotions_manager.subscriber import Subscriber
|
22
|
+
from reconcile.utils.vcs import VCS
|
23
|
+
|
24
|
+
BATCH_SIZE_LIMIT = 5
|
25
|
+
SAPM_LABEL = "SAPMCanary"
|
26
|
+
|
27
|
+
|
28
|
+
class MergeRequestManagerV2:
|
29
|
+
"""
|
30
|
+
Manager for SAPM merge requests.
|
31
|
+
|
32
|
+
This class uses MRParser to fetch current state (currently open MRs).
|
33
|
+
This class calculates the desired state (i.e., desired promotions).
|
34
|
+
Desired state and current state are given to the Reconciler, which will
|
35
|
+
then determine a Diff (Additions and Deletions of MRs).
|
36
|
+
|
37
|
+
This class interacts with VCS to realize the result of the Diff.
|
38
|
+
"""
|
39
|
+
|
40
|
+
def __init__(
|
41
|
+
self, vcs: VCS, mr_parser: MRParser, reconciler: Reconciler, renderer: Renderer
|
42
|
+
):
|
43
|
+
self._vcs = vcs
|
44
|
+
self._mr_parser = mr_parser
|
45
|
+
self._renderer = renderer
|
46
|
+
self._reconciler = reconciler
|
47
|
+
self._content_hash_to_subscriber: dict[str, list[Subscriber]] = {}
|
48
|
+
self._sapm_mrs: list[SAPMMR] = []
|
49
|
+
|
50
|
+
def _aggregate_desired_state(
|
51
|
+
self, subscribers: Iterable[Subscriber]
|
52
|
+
) -> list[Promotion]:
|
53
|
+
subscribers_per_channel_combo: dict[str, list[Subscriber]] = defaultdict(list)
|
54
|
+
for subscriber in subscribers:
|
55
|
+
channel_combo = ",".join([c.name for c in subscriber.channels])
|
56
|
+
subscribers_per_channel_combo[channel_combo].append(subscriber)
|
57
|
+
|
58
|
+
desired_promotions: list[Promotion] = []
|
59
|
+
for channel_combo, subs in subscribers_per_channel_combo.items():
|
60
|
+
combined_content_hash = Subscriber.combined_content_hash(subscribers=subs)
|
61
|
+
self._content_hash_to_subscriber[combined_content_hash] = subs
|
62
|
+
desired_promotions.append(
|
63
|
+
Promotion(
|
64
|
+
content_hashes={combined_content_hash},
|
65
|
+
channels={channel_combo},
|
66
|
+
)
|
67
|
+
)
|
68
|
+
return desired_promotions
|
69
|
+
|
70
|
+
def _render_mr(self, addition: Addition) -> None:
|
71
|
+
subs: list[Subscriber] = []
|
72
|
+
for content_hash in addition.content_hashes:
|
73
|
+
subs.extend(self._content_hash_to_subscriber[content_hash])
|
74
|
+
content_by_path: dict[str, str] = {}
|
75
|
+
has_error = False
|
76
|
+
for sub in subs:
|
77
|
+
if sub.target_file_path not in content_by_path:
|
78
|
+
try:
|
79
|
+
content_by_path[sub.target_file_path] = (
|
80
|
+
self._vcs.get_file_content_from_app_interface_master(
|
81
|
+
file_path=sub.target_file_path
|
82
|
+
)
|
83
|
+
)
|
84
|
+
except GitlabGetError as e:
|
85
|
+
if e.response_code == 404:
|
86
|
+
logging.error(
|
87
|
+
"The saas file %s does not exist anylonger. Most likely qontract-server data not in synch. This should resolve soon on its own.",
|
88
|
+
sub.target_file_path,
|
89
|
+
)
|
90
|
+
has_error = True
|
91
|
+
break
|
92
|
+
raise e
|
93
|
+
content_by_path[sub.target_file_path] = (
|
94
|
+
self._renderer.render_merge_request_content(
|
95
|
+
subscriber=sub,
|
96
|
+
current_content=content_by_path[sub.target_file_path],
|
97
|
+
)
|
98
|
+
)
|
99
|
+
if has_error:
|
100
|
+
return
|
101
|
+
|
102
|
+
description_hashes = ",".join(addition.content_hashes)
|
103
|
+
description_channels = ",".join(addition.channels)
|
104
|
+
|
105
|
+
description = self._renderer.render_description(
|
106
|
+
content_hashes=description_hashes,
|
107
|
+
channels=description_channels,
|
108
|
+
is_batchable=addition.batchable,
|
109
|
+
)
|
110
|
+
title = self._renderer.render_title(
|
111
|
+
is_draft=True, channels=description_channels
|
112
|
+
)
|
113
|
+
logging.info(
|
114
|
+
"Open MR for update in channel(s) %s",
|
115
|
+
description_channels,
|
116
|
+
)
|
117
|
+
self._sapm_mrs.append(
|
118
|
+
SAPMMR(
|
119
|
+
sapm_label=SAPM_LABEL,
|
120
|
+
content_by_path=content_by_path,
|
121
|
+
title=title,
|
122
|
+
description=description,
|
123
|
+
)
|
124
|
+
)
|
125
|
+
|
126
|
+
def reconcile(self, subscribers: Iterable[Subscriber]) -> None:
|
127
|
+
current_state = self._mr_parser.retrieve_open_mrs(label=SAPM_LABEL)
|
128
|
+
desired_state = self._aggregate_desired_state(subscribers=subscribers)
|
129
|
+
diff = self._reconciler.reconcile(
|
130
|
+
batch_limit=BATCH_SIZE_LIMIT,
|
131
|
+
desired_promotions=desired_state,
|
132
|
+
open_mrs=current_state,
|
133
|
+
)
|
134
|
+
for deletion in diff.deletions:
|
135
|
+
self._vcs.close_app_interface_mr(
|
136
|
+
mr=deletion.mr.raw,
|
137
|
+
comment=deletion.reason,
|
138
|
+
)
|
139
|
+
|
140
|
+
for addition in diff.additions:
|
141
|
+
self._render_mr(addition=addition)
|
142
|
+
|
143
|
+
for rendered_mr in self._sapm_mrs:
|
144
|
+
self._vcs.open_app_interface_merge_request(mr=rendered_mr)
|
@@ -9,7 +9,6 @@ from reconcile.saas_auto_promotions_manager.merge_request_manager.renderer impor
|
|
9
9
|
CONTENT_HASHES,
|
10
10
|
IS_BATCHABLE,
|
11
11
|
PROMOTION_DATA_SEPARATOR,
|
12
|
-
SAPM_LABEL,
|
13
12
|
SAPM_VERSION,
|
14
13
|
VERSION_REF,
|
15
14
|
)
|
@@ -19,12 +18,15 @@ from reconcile.utils.vcs import VCS, MRCheckStatus
|
|
19
18
|
@dataclass
|
20
19
|
class OpenMergeRequest:
|
21
20
|
raw: ProjectMergeRequest
|
22
|
-
content_hashes: str
|
23
|
-
channels: str
|
21
|
+
content_hashes: set[str]
|
22
|
+
channels: set[str]
|
24
23
|
failed_mr_check: bool
|
25
24
|
is_batchable: bool
|
26
25
|
|
27
26
|
|
27
|
+
ITEM_SEPARATOR = ","
|
28
|
+
|
29
|
+
|
28
30
|
class MRParser:
|
29
31
|
"""
|
30
32
|
We store state in MR descriptions.
|
@@ -49,11 +51,13 @@ class MRParser:
|
|
49
51
|
return ""
|
50
52
|
return groups[0]
|
51
53
|
|
52
|
-
def _fetch_sapm_managed_open_merge_requests(
|
54
|
+
def _fetch_sapm_managed_open_merge_requests(
|
55
|
+
self, label: str
|
56
|
+
) -> list[ProjectMergeRequest]:
|
53
57
|
all_open_mrs = self._vcs.get_open_app_interface_merge_requests()
|
54
|
-
return [mr for mr in all_open_mrs if
|
58
|
+
return [mr for mr in all_open_mrs if label in mr.attributes.get("labels")]
|
55
59
|
|
56
|
-
def retrieve_open_mrs(self) -> list[OpenMergeRequest]:
|
60
|
+
def retrieve_open_mrs(self, label: str) -> list[OpenMergeRequest]:
|
57
61
|
"""
|
58
62
|
This function parses the state and returns a list of valid, parsed open MRs (current state).
|
59
63
|
If any issue is encountered during parsing, we consider this MR
|
@@ -66,7 +70,7 @@ class MRParser:
|
|
66
70
|
"""
|
67
71
|
open_mrs: list[OpenMergeRequest] = []
|
68
72
|
seen: set[tuple[str, str, str]] = set()
|
69
|
-
for mr in self._fetch_sapm_managed_open_merge_requests():
|
73
|
+
for mr in self._fetch_sapm_managed_open_merge_requests(label=label):
|
70
74
|
attrs = mr.attributes
|
71
75
|
desc = attrs.get("description")
|
72
76
|
has_conflicts = attrs.get("has_conflicts", False)
|
@@ -177,8 +181,8 @@ class MRParser:
|
|
177
181
|
open_mrs.append(
|
178
182
|
OpenMergeRequest(
|
179
183
|
raw=mr,
|
180
|
-
content_hashes=content_hashes,
|
181
|
-
channels=channels_refs,
|
184
|
+
content_hashes=set(content_hashes.split(ITEM_SEPARATOR)),
|
185
|
+
channels=set(channels_refs.split(ITEM_SEPARATOR)),
|
182
186
|
failed_mr_check=mr_check_status == MRCheckStatus.FAILED,
|
183
187
|
is_batchable=is_batchable_str == "True",
|
184
188
|
)
|