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.
Files changed (20) hide show
  1. {qontract_reconcile-0.10.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/RECORD +19 -17
  3. reconcile/cli.py +3 -3
  4. reconcile/{template_tester.py → resource_template_tester.py} +3 -3
  5. reconcile/saas_auto_promotions_manager/integration.py +28 -3
  6. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py +5 -5
  7. reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager_v2.py +144 -0
  8. reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py +13 -9
  9. reconcile/saas_auto_promotions_manager/merge_request_manager/reconciler.py +207 -0
  10. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +9 -6
  11. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +25 -12
  12. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +3 -0
  13. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +51 -153
  14. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py +11 -9
  15. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_reconciler.py +408 -0
  16. reconcile/test/saas_auto_promotions_manager/test_integration_test.py +23 -88
  17. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_unbatching.py +0 -96
  18. {qontract_reconcile-0.10.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/WHEEL +0 -0
  19. {qontract_reconcile-0.10.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/entry_points.txt +0 -0
  20. {qontract_reconcile-0.10.1rc513.dist-info → qontract_reconcile-0.10.1rc515.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qontract-reconcile
3
- Version: 0.10.1rc513
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
@@ -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=mtVX-Ws_9Bw3xgmjZuIQ9P4ZQZkaZszaJsxw1qa3xXY,84464
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=5hSvC3JUM4r63UFuC1IbeG6YbmdlzQrekwRqF5ggvCY,5667
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=CpTbL2wX4s6iQVZJzu-i8kTJOezCwPxyJTMoNdltqgc,7525
354
- reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py,sha256=gyEn7yp03XDf0P8QEDfXWTcGGehNQ2Ln_sQ3cUq00Bc,6945
355
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py,sha256=Sj3mwmBcml6t-49bPnXdq7snT9N0WKrPk2chU_0ylyE,7188
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=4LPWN7YWr2t_MRpwGf7pQ4AMSBEMYvTqTe5hY1rJyS0,4078
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=Ky5IAi0EzrHqP0eimV4Mq0FMVdrFEN-7P-Nst4wqB34,4276
459
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py,sha256=ZTGXlpgAECZnNqsJbkYGr6fBreC_KejYz4tCJIg8iDM,573
460
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py,sha256=c0-c9wfd-3mOMFsCJUDOCx-EfoiT75hJypz72xwdMb8,5978
461
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py,sha256=9VLJKOW80NMQ3WCKDqtaOa0-StoFxaCzKN-NCPfeklo,9845
462
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_unbatching.py,sha256=IqmVqWw98Gegwz5johzh13cqCONk7D_VbgK1y8VqRP4,3004
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.1rc513.dist-info/METADATA,sha256=TTUNsBsaH5Ftp3hD6tDYHiEwEfjMcxwz7H5SShiJHM8,2349
670
- qontract_reconcile-0.10.1rc513.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
671
- qontract_reconcile-0.10.1rc513.dist-info/entry_points.txt,sha256=rTjAv28I_CHLM8ID3OPqMI_suoQ9s7tFbim4aYjn9kk,376
672
- qontract_reconcile-0.10.1rc513.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
673
- qontract_reconcile-0.10.1rc513.dist-info/RECORD,,
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 template_tester(ctx):
2632
- import reconcile.template_tester
2631
+ def resource_template_tester(ctx):
2632
+ import reconcile.resource_template_tester
2633
2633
 
2634
- run_integration(reconcile.template_tester, ctx.obj)
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: template_tests_v1 {
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[PromotionState, VCS, SaasFilesInventory, MergeRequestManager]:
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
- merge_request_manager = MergeRequestManager(
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 deployment_state, vcs, saas_inventory, merge_request_manager
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
- content_hashes = mr.content_hashes.split(ITEM_SEPARATOR)
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(self) -> list[ProjectMergeRequest]:
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 SAPM_LABEL in mr.attributes.get("labels")]
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
  )