qontract-reconcile 0.10.1rc1066__py3-none-any.whl → 0.10.1rc1068__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qontract-reconcile
3
- Version: 0.10.1rc1066
3
+ Version: 0.10.1rc1068
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
@@ -10,7 +10,7 @@ reconcile/aws_iam_password_reset.py,sha256=q96mwr2KeEQ5bpNniGlgIMZTxiuLSodcYfX-t
10
10
  reconcile/aws_support_cases_sos.py,sha256=hl_9L53yQYRQxKs3IWrd69Cc60XK067g_bJRM9B0udo,2975
11
11
  reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=O1wFp52EyF538c6txaWBs8eMtUIy19gyHZ6VzJ6QXS8,3512
12
12
  reconcile/checkpoint.py,sha256=_JhMxrye5BgkRMxWYuf7Upli6XayPINKSsuo3ynHTRc,5010
13
- reconcile/cli.py,sha256=PHoUlP86m-TdTpB3hyoHbOEDWR0_ZO-GSBQEGTmbTmc,107514
13
+ reconcile/cli.py,sha256=ipCFQNRFmaoo_DoeAvMY3bTYfaovOgWhRvL6TYuk1G8,107605
14
14
  reconcile/closedbox_endpoint_monitoring_base.py,sha256=rLh16BOlBOxTmJ8Si3wWyyEpmMlhh4Znx1Gc36qsmOc,4865
15
15
  reconcile/cluster_deployment_mapper.py,sha256=5gumAaRCcFXsabUJ1dnuUy9WrP_FEEM5JnOnE8ch9sE,2326
16
16
  reconcile/dashdotdb_base.py,sha256=l34QDu1G96_Ctnh7ZXdxXgSeCE93GQMdLAkWxmN6vDA,4775
@@ -161,7 +161,7 @@ reconcile/aws_version_sync/merge_request_manager/merge_request_manager.py,sha256
161
161
  reconcile/change_owners/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
162
162
  reconcile/change_owners/approver.py,sha256=Z3_11vnK2WNOxjEEXVDh0224-_-qbt9d6mBeVE-7fsc,2259
163
163
  reconcile/change_owners/bundle.py,sha256=ZIlXRo6Z2raeWSCUqYsexBdol-q-r9kWJs5O_YPaEYk,5273
164
- reconcile/change_owners/change_log_tracking.py,sha256=zFpean5UB3-u5VQLJHzik8GmhBwYoNorR-l90-D1Pis,4160
164
+ reconcile/change_owners/change_log_tracking.py,sha256=XE-DbH3ktABaeEVdP6EoVsI6s3Nk21l6WKbHd3zMouM,5555
165
165
  reconcile/change_owners/change_owners.py,sha256=0HRJhDm0oW3uYJFgzynqA1gA0lbhalhSkmWOiQmr-NM,17062
166
166
  reconcile/change_owners/change_types.py,sha256=TjVtvmkU0s8w2NA6qvWQccB6PwlCrChFySlsHLYZjpE,32027
167
167
  reconcile/change_owners/changes.py,sha256=pa3cNAL-Xawh700ARJJQjY0p09NA1J2329RcE0F0MHM,17224
@@ -251,6 +251,7 @@ reconcile/gql_definitions/common/app_interface_repo_settings.py,sha256=rud0rz9NI
251
251
  reconcile/gql_definitions/common/app_interface_state_settings.py,sha256=VXIK0Hmyv6GTShI86IGkjxyHGwufqUBAh617XKUAKaI,2507
252
252
  reconcile/gql_definitions/common/app_interface_vault_settings.py,sha256=w8quvdG0cSq71ZyJokPPp7MyMpoDb6-HLQ3o9JHVGRQ,1771
253
253
  reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py,sha256=ckdoGse7O5uAWdZdNinkWicA2EflUb5pe8jWEBtflE8,3236
254
+ reconcile/gql_definitions/common/apps.py,sha256=lC7uZjyHAvJXhCDPJJ-dQJInBJkUCNZoe129XMa67wo,1868
254
255
  reconcile/gql_definitions/common/aws_vpc_requests.py,sha256=2lpyy-QSfHPSTvV_zbnqzqUoFzVNl-CJDmoqd_zVSX4,2366
255
256
  reconcile/gql_definitions/common/aws_vpcs.py,sha256=Dss9dQ3xagnz3Ltg1e9mtG2PAmQGBbUzKCmmzvuN28s,1892
256
257
  reconcile/gql_definitions/common/clusters.py,sha256=Dr5AsSsTuqjAxkI9fU0fdiaP6u5qkmRpkkCcYDnU584,21868
@@ -604,6 +605,7 @@ reconcile/typed_queries/app_interface_repo_url.py,sha256=9fhgWihjWNYOmK65irBWw9j
604
605
  reconcile/typed_queries/app_interface_state_settings.py,sha256=GdtxrjKs6JONthBzXJO66wHx80v3YyHvbZScj0XFM1Q,447
605
606
  reconcile/typed_queries/app_interface_vault_settings.py,sha256=ffkKVDD5cukQWOorUIrGvpcVr3lCbUHRIz0HWX_h7gI,715
606
607
  reconcile/typed_queries/app_quay_repos_escalation_policies.py,sha256=qpO9z9ev2RSH8sdZprLxhhrrbI0kvzmliSPfIVnfPbE,397
608
+ reconcile/typed_queries/apps.py,sha256=IzgDQnKnvGKvFsgfIkha935I1T24tAYEp_LwrLrwVgQ,339
607
609
  reconcile/typed_queries/aws_vpc_requests.py,sha256=3LmBX9usfK8Uqr-pAux2oap01sXiMdGC_ihln6w4oV8,358
608
610
  reconcile/typed_queries/aws_vpcs.py,sha256=Fd0QCwXOH46UHw3-Xo_1ghtGYgUVJDpKf5Q3r1GpJGI,339
609
611
  reconcile/typed_queries/cloudflare.py,sha256=jOsqgCzMrjomPaIWc1isTcQAGONmMIJDTBcpmCheonA,308
@@ -837,7 +839,7 @@ tools/app_interface_metrics_exporter.py,sha256=zkwkxdAUAxjdc-pzx2_oJXG25fo0Fnyd5
837
839
  tools/app_interface_reporter.py,sha256=oZPib4HPq0aZ2Zui1QGJGk6qQdfpeihujGDBnSdKyGE,17627
838
840
  tools/glitchtip_access_reporter.py,sha256=oPBnk_YoDuljU3v0FaChzOwwnk4vap1xEE67QEjzdqs,2948
839
841
  tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
840
- tools/qontract_cli.py,sha256=k4KO3TgLrvODo55ExCoJc74IVwg6ccOuyTzLkesfI8Y,130446
842
+ tools/qontract_cli.py,sha256=scWaC5D_s4s_F9z1bdxi2yCWk8UAmVIo-6u665Y6ikA,130526
841
843
  tools/sd_app_sre_alert_report.py,sha256=e9vAdyenUz2f5c8-z-5WY0wv-SJ9aePKDH2r4IwB6pc,5063
842
844
  tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
843
845
  tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -868,8 +870,8 @@ tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jr
868
870
  tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
869
871
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
870
872
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
871
- qontract_reconcile-0.10.1rc1066.dist-info/METADATA,sha256=2hmviOFhwYzcMOSmbPA5z3fZwzWq12ISwijO7lzrops,2213
872
- qontract_reconcile-0.10.1rc1066.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
873
- qontract_reconcile-0.10.1rc1066.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
874
- qontract_reconcile-0.10.1rc1066.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
875
- qontract_reconcile-0.10.1rc1066.dist-info/RECORD,,
873
+ qontract_reconcile-0.10.1rc1068.dist-info/METADATA,sha256=t9h0tIlI0IrPewwkSB9j0KcSSRuFAboN84twelBFxLQ,2213
874
+ qontract_reconcile-0.10.1rc1068.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
875
+ qontract_reconcile-0.10.1rc1068.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
876
+ qontract_reconcile-0.10.1rc1068.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
877
+ qontract_reconcile-0.10.1rc1068.dist-info/RECORD,,
@@ -6,9 +6,13 @@ from reconcile.change_owners.bundle import (
6
6
  NoOpFileDiffResolver,
7
7
  QontractServerDiff,
8
8
  )
9
- from reconcile.change_owners.change_owners import fetch_change_type_processors
9
+ from reconcile.change_owners.change_owners import (
10
+ fetch_change_type_processors,
11
+ init_gitlab,
12
+ )
10
13
  from reconcile.change_owners.change_types import ChangeTypeContext
11
14
  from reconcile.change_owners.changes import aggregate_file_moves, parse_bundle_changes
15
+ from reconcile.typed_queries.apps import get_apps
12
16
  from reconcile.utils import gql
13
17
  from reconcile.utils.defer import defer
14
18
  from reconcile.utils.runtime.integration import (
@@ -24,8 +28,10 @@ BUNDLE_DIFFS_OBJ = "bundle-diffs.json"
24
28
  @dataclass
25
29
  class ChangeLogItem:
26
30
  commit: str
31
+ created_at: str
27
32
  change_types: list[str] = field(default_factory=list)
28
33
  error: bool = False
34
+ apps: list[str] = field(default_factory=list)
29
35
 
30
36
 
31
37
  @dataclass
@@ -34,6 +40,7 @@ class ChangeLog:
34
40
 
35
41
 
36
42
  class ChangeLogIntegrationParams(PydanticRunParams):
43
+ gitlab_project_id: str
37
44
  process_existing: bool = False
38
45
 
39
46
 
@@ -55,6 +62,8 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
55
62
  )
56
63
  if ctp.labels and "change_log_tracking" in ctp.labels
57
64
  ]
65
+ apps = get_apps()
66
+ app_name_by_path = {a.path: a.name for a in apps}
58
67
 
59
68
  integration_state = init_state(
60
69
  integration=self.name,
@@ -74,6 +83,9 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
74
83
  ChangeLogItem(**i) # type: ignore[arg-type]
75
84
  for i in existing_change_log.items
76
85
  ]
86
+ gl = init_gitlab(self.params.gitlab_project_id)
87
+ if defer:
88
+ defer(gl.cleanup)
77
89
  change_log = ChangeLog()
78
90
  for item in diff_state.ls():
79
91
  key = item.lstrip("/")
@@ -88,8 +100,10 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
88
100
  continue
89
101
 
90
102
  logging.info(f"Processing commit {commit}")
103
+ gl_commit = gl.project.commits.get(commit)
91
104
  change_log_item = ChangeLogItem(
92
105
  commit=commit,
106
+ created_at=gl_commit.created_at,
93
107
  )
94
108
  change_log.items.append(change_log_item)
95
109
  obj = diff_state.get(key, None)
@@ -101,6 +115,22 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
101
115
  changes = aggregate_file_moves(parse_bundle_changes(diff))
102
116
  for change in changes:
103
117
  logging.debug(f"Processing change {change}")
118
+ change_versions = filter(None, [change.old, change.new])
119
+ match change.fileref.schema:
120
+ case "/app-sre/app-1.yml":
121
+ changed_apps = {c["name"] for c in change_versions}
122
+ change_log_item.apps.extend(changed_apps)
123
+ case "/app-sre/saas-file-2.yml" | "/openshift/namespace-1.yml":
124
+ changed_apps = {
125
+ name
126
+ for c in change_versions
127
+ if (name := app_name_by_path.get(c["app"]["$ref"]))
128
+ }
129
+ change_log_item.apps.extend(changed_apps)
130
+
131
+ # TODO(maorfr): switch apps to set
132
+ change_log_item.apps = list(set(change_log_item.apps))
133
+
104
134
  for ctp in change_type_processors:
105
135
  logging.info(f"Processing change type {ctp.name}")
106
136
  ctx = ChangeTypeContext(
@@ -115,5 +145,8 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
115
145
  if ctp.name not in change_log_item.change_types:
116
146
  change_log_item.change_types.append(ctp.name)
117
147
 
148
+ change_log.items = sorted(
149
+ change_log.items, key=lambda i: i.created_at, reverse=True
150
+ )
118
151
  if not dry_run:
119
152
  integration_state.add(BUNDLE_DIFFS_OBJ, asdict(change_log), force=True)
reconcile/cli.py CHANGED
@@ -3558,13 +3558,14 @@ def change_owners(
3558
3558
 
3559
3559
 
3560
3560
  @integration.command(short_help="Analyze bundle diffs by change types.")
3561
+ @gitlab_project_id
3561
3562
  @click.option(
3562
3563
  "--process-existing/--no-process-existing",
3563
3564
  default=False,
3564
3565
  help="wait for pending/running pipelines before acting.",
3565
3566
  )
3566
3567
  @click.pass_context
3567
- def change_log_tracking(ctx, process_existing):
3568
+ def change_log_tracking(ctx, gitlab_project_id, process_existing):
3568
3569
  from reconcile.change_owners.change_log_tracking import (
3569
3570
  ChangeLogIntegration,
3570
3571
  ChangeLogIntegrationParams,
@@ -3573,6 +3574,7 @@ def change_log_tracking(ctx, process_existing):
3573
3574
  run_class_integration(
3574
3575
  ChangeLogIntegration(
3575
3576
  ChangeLogIntegrationParams(
3577
+ gitlab_project_id=gitlab_project_id,
3576
3578
  process_existing=process_existing,
3577
3579
  )
3578
3580
  ),
@@ -0,0 +1,72 @@
1
+ """
2
+ Generated by qenerate plugin=pydantic_v1. DO NOT MODIFY MANUALLY!
3
+ """
4
+ from collections.abc import Callable # noqa: F401 # pylint: disable=W0611
5
+ from datetime import datetime # noqa: F401 # pylint: disable=W0611
6
+ from enum import Enum # noqa: F401 # pylint: disable=W0611
7
+ from typing import ( # noqa: F401 # pylint: disable=W0611
8
+ Any,
9
+ Optional,
10
+ Union,
11
+ )
12
+
13
+ from pydantic import ( # noqa: F401 # pylint: disable=W0611
14
+ BaseModel,
15
+ Extra,
16
+ Field,
17
+ Json,
18
+ )
19
+
20
+
21
+ DEFINITION = """
22
+ query Apps {
23
+ apps: apps_v1 {
24
+ path
25
+ name
26
+ parentApp {
27
+ path
28
+ name
29
+ }
30
+ }
31
+ }
32
+ """
33
+
34
+
35
+ class ConfiguredBaseModel(BaseModel):
36
+ class Config:
37
+ smart_union=True
38
+ extra=Extra.forbid
39
+
40
+
41
+ class AppV1_AppV1(ConfiguredBaseModel):
42
+ path: str = Field(..., alias="path")
43
+ name: str = Field(..., alias="name")
44
+
45
+
46
+ class AppV1(ConfiguredBaseModel):
47
+ path: str = Field(..., alias="path")
48
+ name: str = Field(..., alias="name")
49
+ parent_app: Optional[AppV1_AppV1] = Field(..., alias="parentApp")
50
+
51
+
52
+ class AppsQueryData(ConfiguredBaseModel):
53
+ apps: Optional[list[AppV1]] = Field(..., alias="apps")
54
+
55
+
56
+ def query(query_func: Callable, **kwargs: Any) -> AppsQueryData:
57
+ """
58
+ This is a convenience function which queries and parses the data into
59
+ concrete types. It should be compatible with most GQL clients.
60
+ You do not have to use it to consume the generated data classes.
61
+ Alternatively, you can also mime and alternate the behavior
62
+ of this function in the caller.
63
+
64
+ Parameters:
65
+ query_func (Callable): Function which queries your GQL Server
66
+ kwargs: optional arguments that will be passed to the query function
67
+
68
+ Returns:
69
+ AppsQueryData: queried data parsed into generated classes
70
+ """
71
+ raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs)
72
+ return AppsQueryData(**raw_data)
@@ -0,0 +1,11 @@
1
+ from collections.abc import Callable
2
+
3
+ from reconcile.gql_definitions.common.apps import AppV1, query
4
+ from reconcile.utils import gql
5
+
6
+
7
+ def get_apps(query_func: Callable | None = None) -> list[AppV1]:
8
+ if not query_func:
9
+ gqlapi = gql.get_api()
10
+ query_func = gqlapi.query
11
+ return query(query_func=query_func).apps or []
tools/qontract_cli.py CHANGED
@@ -48,6 +48,7 @@ from reconcile.aus.base import (
48
48
  from reconcile.aus.models import OrganizationUpgradeSpec
49
49
  from reconcile.change_owners.bundle import NoOpFileDiffResolver
50
50
  from reconcile.change_owners.change_log_tracking import (
51
+ BUNDLE_DIFFS_OBJ,
51
52
  ChangeLog,
52
53
  ChangeLogIntegration,
53
54
  ChangeLogIntegrationParams,
@@ -2893,7 +2894,7 @@ def change_log_tracking(ctx):
2893
2894
  state = init_state(
2894
2895
  integration=ChangeLogIntegration(ChangeLogIntegrationParams()).name
2895
2896
  )
2896
- change_log = ChangeLog(**state.get("bundle-diffs.json"))
2897
+ change_log = ChangeLog(**state.get(BUNDLE_DIFFS_OBJ))
2897
2898
  data: list[dict[str, str]] = []
2898
2899
  for item in change_log.items:
2899
2900
  change_log_item = ChangeLogItem(**item)
@@ -2905,12 +2906,13 @@ def change_log_tracking(ctx):
2905
2906
  ]
2906
2907
  item = {
2907
2908
  "commit": f"[{commit}]({repo_url}/commit/{commit})",
2909
+ "apps": ", ".join(change_log_item.apps),
2908
2910
  "changes": ", ".join(covered_change_types_descriptions),
2909
2911
  "error": change_log_item.error,
2910
2912
  }
2911
2913
  data.append(item)
2912
2914
 
2913
- columns = ["commit", "changes", "error"]
2915
+ columns = ["commit", "apps", "changes", "error"]
2914
2916
  print_output(ctx.obj["options"], data, columns)
2915
2917
 
2916
2918