qontract-reconcile 0.10.2.dev59__py3-none-any.whl → 0.10.2.dev61__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.4
2
2
  Name: qontract-reconcile
3
- Version: 0.10.2.dev59
3
+ Version: 0.10.2.dev61
4
4
  Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
5
5
  Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
6
6
  Project-URL: repository, https://github.com/app-sre/qontract-reconcile
@@ -164,7 +164,7 @@ reconcile/change_owners/README.md,sha256=NEXVw4SioTWTGo9elSQUjqY10RIUoisl4zkzEBv
164
164
  reconcile/change_owners/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
165
165
  reconcile/change_owners/approver.py,sha256=Z3_11vnK2WNOxjEEXVDh0224-_-qbt9d6mBeVE-7fsc,2259
166
166
  reconcile/change_owners/bundle.py,sha256=h30fU-JmLH5a-rCAovpzTeTkkkgZztsZ5A2raee0YuU,5355
167
- reconcile/change_owners/change_log_tracking.py,sha256=ITG3Vqgv_xlvRueVDJQMwkVmnXLAIBZnLIXLt6DT9Ho,9192
167
+ reconcile/change_owners/change_log_tracking.py,sha256=6MXABuPbLQwLeFZE_J2SS9Sx23fAVAtPRWKSBxjQrSo,8850
168
168
  reconcile/change_owners/change_owners.py,sha256=7tESnSX2-psNGPIF63OeK5f-m3iqwanaGjt03FIjWXU,17111
169
169
  reconcile/change_owners/change_types.py,sha256=5eSvS2_npUriq9RN4LdAWdYUiNzF91K1pDUEVYDIQ4k,32023
170
170
  reconcile/change_owners/changes.py,sha256=YTqwUYutQ6JVSSYmC2Ph5ROCiVix42Vnzy47-i57z4Q,18119
@@ -615,7 +615,7 @@ reconcile/utils/oc_map.py,sha256=ougQ-Wlsa8ymoE_lPQ7g2LlpsUOsHVeRCLYW_6fjeWU,897
615
615
  reconcile/utils/ocm_base_client.py,sha256=t5kxhklEqOpenXPkXiwQIk8d3D7hIUndBm5qGusS0bc,6681
616
616
  reconcile/utils/openshift_resource.py,sha256=DI-e04f4NqEUFJ_9HzjY-QMhFt7o2XVauM09mzMC5Vs,24716
617
617
  reconcile/utils/openssl.py,sha256=QVvhzhpChq_4Daf_5wE1qeZJr4thg3DDjJPn4bOPD4E,365
618
- reconcile/utils/output.py,sha256=xh2Not-Xm97KeRx_J5nc2PP5tDwpDLZBeCrWI0S-al4,2034
618
+ reconcile/utils/output.py,sha256=dj3tE_sj3x8ssnAV6hCGmsRI9ttqUUFsIH1r7RujNA8,2038
619
619
  reconcile/utils/pagerduty_api.py,sha256=_24i9S_4X7nlvHb-7clXRE0p1BG4ODjOzKxWO-F9WgI,7627
620
620
  reconcile/utils/parse_dhms_duration.py,sha256=TONpLnec5gHeF7k815YNJpQyDjXhkxZIcv9s8ffbTSY,1840
621
621
  reconcile/utils/password_validator.py,sha256=XwuWg-8CPlcuG7dl_oQ1G1h2gSVSnfMym_VkuprpWVg,2183
@@ -637,7 +637,7 @@ reconcile/utils/state.py,sha256=az4tBmZ0EdbFcAGiBVUxs3cr2-BVWsuDQiNTvjjQq8s,1637
637
637
  reconcile/utils/structs.py,sha256=LcbLEg8WxfRqM6nW7NhcWN0YeqF7SQzxOgntmLs1SgY,352
638
638
  reconcile/utils/template.py,sha256=wTvRU4AnAV_o042tD4Mwls2dwWMuk7MKnde3MaCjaYg,331
639
639
  reconcile/utils/terraform_client.py,sha256=H8frsS370y8xfivKLNBD1dwlBLHvfuR6JSN_syBL5Qc,36033
640
- reconcile/utils/terrascript_aws_client.py,sha256=faAluZnn7yvPqfxnYH4gvKukpX7a_KwHHoA9usBlSNM,284706
640
+ reconcile/utils/terrascript_aws_client.py,sha256=exae3Cg8EgjY27RFit5czwbx0jafMqksZzaelTWbKKU,284877
641
641
  reconcile/utils/three_way_diff_strategy.py,sha256=oQcHXd9LVhirJfoaOBoHUYuZVGfyL2voKr6KVI34zZE,4833
642
642
  reconcile/utils/throughput.py,sha256=iP4UWAe2LVhDo69mPPmgo9nQ7RxHD6_GS8MZe-aSiuM,344
643
643
  reconcile/utils/vault.py,sha256=aSA8l9cJlPUHpChFGl27nSY-Mpq9FMjBo7Dcgb1BVfM,15036
@@ -745,18 +745,18 @@ reconcile/utils/unleash/client.py,sha256=YrJnauxjcy1ml7W2AHg7dzIH_fVK_GugoRu7IFm
745
745
  reconcile/utils/unleash/server.py,sha256=907gDh9Ee8UxLqusnfpzE-7LUnttB38D4xhVJ0vMf_M,4439
746
746
  tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
747
747
  tools/app_interface_metrics_exporter.py,sha256=f1qwTmQfEcs98uBVRyBa0k7GQXdiSwd7w1hDVjhdGcQ,2303
748
- tools/app_interface_reporter.py,sha256=gR2EgHmgSIxzK5xxDW1SduFU6OkPaf2LlAQjhV3NYIg,17623
748
+ tools/app_interface_reporter.py,sha256=0_oq1-mL0UOh1x5G8CoKaEVJqK-XTKE7PX7IbRTovBc,17224
749
749
  tools/app_sre_tekton_access_reporter.py,sha256=o9prLUgQpwO3msRWc2as1xT1y9OB3znkpgvLr0Ys8_M,3146
750
750
  tools/app_sre_tekton_access_revalidation.py,sha256=66nHEaY-bIqxIhpcmwN8AvQZu6ZXenfkg4Fut0pVZRM,2726
751
751
  tools/glitchtip_access_reporter.py,sha256=o01A6b88t3Wie6tj_tJWWVo2J01LxQ_a9giGm4UzEaU,2901
752
752
  tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
753
- tools/qontract_cli.py,sha256=DCgIaGxZlYG5TVWUifAQGfp81aop9SLu0ezVVg4x2NM,148792
753
+ tools/qontract_cli.py,sha256=HAN-3m8udB8Ea1B4fIpmJoJjLWQERDhIF-9LU9XBCnQ,152477
754
754
  tools/sd_app_sre_alert_report.py,sha256=jQpJdXVID68bSNtJNOGDh0-ei1CfEUS4Itr4MAaBNFA,5062
755
755
  tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
756
756
  tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
757
757
  tools/cli_commands/container_images_report.py,sha256=8fG9XU-eEhJ7hKCdQzBcdPpvIJR-8WGkHOgFEulpfYQ,5213
758
758
  tools/cli_commands/erv2.py,sha256=VxUlNXllo947UwmtvS-42IeI9x_t_X3MHrrSI3K_GRo,23274
759
- tools/cli_commands/gpg_encrypt.py,sha256=NhzwN49UN7P5_FJgTUN5A4BIwNbFokIE4lwDax2iP5k,4891
759
+ tools/cli_commands/gpg_encrypt.py,sha256=JWwds_Qg7KhSJMIGUh8TfI5-Jf17iUtmaEi4kWJxfVE,4907
760
760
  tools/cli_commands/systems_and_tools.py,sha256=EMHOF1AtUDaoSk0bbjl6oUKYAz4rTZjIBaF-6E6GspM,16816
761
761
  tools/cli_commands/cost_report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
762
762
  tools/cli_commands/cost_report/aws.py,sha256=JtwDfhaYLfa4Uz1LR6OfSBh_3nBlb90kQq6i3MV_ims,4563
@@ -777,7 +777,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
777
777
  tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
778
778
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
779
779
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
780
- qontract_reconcile-0.10.2.dev59.dist-info/METADATA,sha256=Yk3AHwZzFbLs4byLAW2xefKgAtlZ3s3Ap3Y8OUuCQEE,24665
781
- qontract_reconcile-0.10.2.dev59.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
782
- qontract_reconcile-0.10.2.dev59.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
783
- qontract_reconcile-0.10.2.dev59.dist-info/RECORD,,
780
+ qontract_reconcile-0.10.2.dev61.dist-info/METADATA,sha256=QOFjMzvg2cy2BeJ5BHN3OPgfQe1IaDis_HcAfm-G0_Y,24665
781
+ qontract_reconcile-0.10.2.dev61.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
782
+ qontract_reconcile-0.10.2.dev61.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
783
+ qontract_reconcile-0.10.2.dev61.dist-info/RECORD,,
@@ -1,7 +1,8 @@
1
1
  import logging
2
2
  from collections import defaultdict
3
3
  from collections.abc import Callable
4
- from dataclasses import asdict, dataclass, field
4
+
5
+ from pydantic import BaseModel
5
6
 
6
7
  from reconcile.change_owners.bundle import (
7
8
  NoOpFileDiffResolver,
@@ -33,19 +34,17 @@ QONTRACT_INTEGRATION = "change-log-tracking"
33
34
  BUNDLE_DIFFS_OBJ = "bundle-diffs.json"
34
35
 
35
36
 
36
- @dataclass
37
- class ChangeLogItem:
37
+ class ChangeLogItem(BaseModel):
38
38
  commit: str
39
39
  merged_at: str
40
- change_types: list[str] = field(default_factory=list)
40
+ change_types: list[str] = []
41
41
  error: bool = False
42
- apps: list[str] = field(default_factory=list)
42
+ apps: list[str] = []
43
43
  description: str = ""
44
44
 
45
45
 
46
- @dataclass
47
- class ChangeLog:
48
- items: list[ChangeLogItem] = field(default_factory=list)
46
+ class ChangeLog(BaseModel):
47
+ items: list[ChangeLogItem] = []
49
48
 
50
49
  @property
51
50
  def apps(self) -> set[str]:
@@ -89,28 +88,19 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
89
88
  app = ns.app.name
90
89
  app_names_by_cluster_name[cluster].add(app)
91
90
  jenkins_configs = get_jenkins_configs()
91
+ integration_state = init_state(integration=self.name)
92
+ gl = init_gitlab(self.params.gitlab_project_id)
93
+ diff_state = init_state(integration=self.name)
94
+ diff_state.state_path = "bundle-archive/diff"
92
95
 
93
- integration_state = init_state(
94
- integration=self.name,
95
- )
96
96
  if defer:
97
97
  defer(integration_state.cleanup)
98
- diff_state = init_state(
99
- integration=self.name,
100
- )
101
- if defer:
102
98
  defer(diff_state.cleanup)
103
- diff_state.state_path = "bundle-archive/diff"
99
+ defer(gl.cleanup)
104
100
 
105
101
  if not self.params.process_existing:
106
102
  existing_change_log = ChangeLog(**integration_state.get(BUNDLE_DIFFS_OBJ))
107
- existing_change_log_items = [
108
- ChangeLogItem(**i) # type: ignore[arg-type]
109
- for i in existing_change_log.items
110
- ]
111
- gl = init_gitlab(self.params.gitlab_project_id)
112
- if defer:
113
- defer(gl.cleanup)
103
+
114
104
  change_log = ChangeLog()
115
105
  for item in diff_state.ls():
116
106
  key = item.lstrip("/")
@@ -119,7 +109,7 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
119
109
  continue
120
110
  if not self.params.process_existing:
121
111
  existing_change_log_item = next(
122
- (i for i in existing_change_log_items if i.commit == commit), None
112
+ (i for i in existing_change_log.items if i.commit == commit), None
123
113
  )
124
114
  if existing_change_log_item:
125
115
  logging.debug(f"Found existing commit {commit}")
@@ -233,4 +223,4 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
233
223
  change_log.items, key=lambda i: i.merged_at, reverse=True
234
224
  )
235
225
  if not dry_run:
236
- integration_state.add(BUNDLE_DIFFS_OBJ, asdict(change_log), force=True)
226
+ integration_state.add(BUNDLE_DIFFS_OBJ, change_log.dict(), force=True)
reconcile/utils/output.py CHANGED
@@ -1,9 +1,6 @@
1
1
  import json
2
2
  import re
3
- from collections.abc import (
4
- Iterable,
5
- Mapping,
6
- )
3
+ from collections.abc import Iterable, Mapping
7
4
 
8
5
  import yaml
9
6
  from tabulate import tabulate
@@ -11,11 +8,11 @@ from tabulate import tabulate
11
8
 
12
9
  def print_output(
13
10
  options: Mapping[str, str | bool],
14
- content: list[dict],
11
+ content: Iterable[dict],
15
12
  columns: Iterable[str] = (),
16
13
  ) -> str | None:
17
14
  if options["sort"]:
18
- content.sort(key=lambda c: tuple(c.values()))
15
+ content = sorted(content, key=lambda c: tuple(c.values()))
19
16
  if options.get("to_string"):
20
17
  for c in content:
21
18
  for k, v in c.items():
@@ -6075,6 +6075,10 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
6075
6075
  "scope_name": "InsightsServiceAccount",
6076
6076
  "scope_description": "Insights service account",
6077
6077
  },
6078
+ {
6079
+ "scope_name": "OSDFleetManagerService",
6080
+ "scope_description": "Fleet Manager service account",
6081
+ },
6078
6082
  ],
6079
6083
  **cognito_resource_server_args,
6080
6084
  )
@@ -2,6 +2,7 @@ import contextlib
2
2
  import logging
3
3
  import os
4
4
  import textwrap
5
+ from collections.abc import Mapping, MutableMapping
5
6
  from datetime import (
6
7
  UTC,
7
8
  datetime,
@@ -38,50 +39,14 @@ DASHDOTDB_SECRET = os.environ.get(
38
39
  )
39
40
 
40
41
 
41
- def promql(url, query, auth=None):
42
- """
43
- Run an instant-query on the prometheus instance.
44
-
45
- The returned structure is documented here:
46
- https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries
47
-
48
- :param url: base prometheus url (not the API endpoint).
49
- :type url: string
50
- :param query: this is a second value
51
- :type query: string
52
- :param auth: auth object
53
- :type auth: requests.auth
54
- :return: structure with the metrics
55
- :rtype: dictionary
56
- """
57
-
58
- url = os.path.join(url, "api/v1/query")
59
-
60
- if auth is None:
61
- auth = {}
62
-
63
- params = {"query": query}
64
-
65
- response = requests.get(url, params=params, auth=auth, timeout=60)
66
-
67
- response.raise_for_status()
68
- response = response.json()
69
-
70
- # TODO ensure len response == 1
71
- return response["data"]["result"]
72
-
73
-
74
42
  class Report:
75
- def __init__(self, app, date):
43
+ def __init__(self, app: Mapping, date: datetime) -> None:
76
44
  settings = queries.get_app_interface_settings()
77
45
  self.secret_reader = SecretReader(settings=settings)
78
- # standard date format
79
- if hasattr(date, "strftime"):
80
- date = date.strftime("%Y-%m-%d")
81
-
82
46
  self.app = app
83
- self.date = date
84
- self.report_sections = {}
47
+ # standard date format
48
+ self.date = date.strftime("%Y-%m-%d")
49
+ self.report_sections: dict = {}
85
50
 
86
51
  # promotions
87
52
  self.add_report_section("promotions", self.app.get("promotions"))
@@ -108,10 +73,10 @@ class Report:
108
73
  )
109
74
 
110
75
  @property
111
- def path(self):
112
- return "data/reports/{}/{}.yml".format(self.app["name"], self.date)
76
+ def path(self) -> str:
77
+ return f"data/reports/{self.app['name']}/{self.date}.yml"
113
78
 
114
- def content(self):
79
+ def content(self) -> dict:
115
80
  return {
116
81
  "$schema": "/app-sre/report-1.yml",
117
82
  "labels": {"app": self.app["name"]},
@@ -122,21 +87,20 @@ class Report:
122
87
  "content": yaml.safe_dump(self.report_sections, sort_keys=False),
123
88
  }
124
89
 
125
- def to_yaml(self):
90
+ def to_yaml(self) -> str:
126
91
  return yaml.safe_dump(self.content(), sort_keys=False)
127
92
 
128
- def to_message(self):
93
+ def to_message(self) -> dict:
129
94
  return {"file_path": self.path, "content": self.to_yaml()}
130
95
 
131
- def add_report_section(self, header, content):
132
- if not content:
133
- content = None
134
-
135
- self.report_sections[header] = content
96
+ def add_report_section(self, header: str, content: list[dict] | None) -> None:
97
+ self.report_sections[header] = content or None
136
98
 
137
99
  @staticmethod
138
- def get_vulnerability_content(container_vulnerabilities):
139
- parsed_metrics = []
100
+ def get_vulnerability_content(
101
+ container_vulnerabilities: Mapping | None,
102
+ ) -> list[dict]:
103
+ parsed_metrics: list[dict] = []
140
104
  if not container_vulnerabilities:
141
105
  return parsed_metrics
142
106
 
@@ -150,8 +114,8 @@ class Report:
150
114
  return parsed_metrics
151
115
 
152
116
  @staticmethod
153
- def get_post_deploy_jobs_content(post_deploy_jobs):
154
- results = []
117
+ def get_post_deploy_jobs_content(post_deploy_jobs: Mapping | None) -> list[dict]:
118
+ results: list[dict] = []
155
119
  if not post_deploy_jobs:
156
120
  return results
157
121
 
@@ -165,8 +129,8 @@ class Report:
165
129
  return results
166
130
 
167
131
  @staticmethod
168
- def get_validations_content(deployment_validations):
169
- parsed_metrics = []
132
+ def get_validations_content(deployment_validations: Mapping | None) -> list[dict]:
133
+ parsed_metrics: list[dict] = []
170
134
  if not deployment_validations:
171
135
  return parsed_metrics
172
136
 
@@ -180,8 +144,8 @@ class Report:
180
144
  return parsed_metrics
181
145
 
182
146
  @staticmethod
183
- def get_slo_content(service_slo):
184
- parsed_metrics = []
147
+ def get_slo_content(service_slo: Mapping | None) -> list[dict]:
148
+ parsed_metrics: list[dict] = []
185
149
  if not service_slo:
186
150
  return parsed_metrics
187
151
 
@@ -200,7 +164,7 @@ class Report:
200
164
  return parsed_metrics
201
165
 
202
166
  @staticmethod
203
- def get_activity_content(activity):
167
+ def get_activity_content(activity: Mapping) -> list[dict]:
204
168
  if not activity:
205
169
  return []
206
170
 
@@ -214,7 +178,9 @@ class Report:
214
178
  ]
215
179
 
216
180
 
217
- def get_apps_data(date, month_delta=1, thread_pool_size=10):
181
+ def get_apps_data(
182
+ date: datetime, month_delta: int = 1, thread_pool_size: int = 10
183
+ ) -> list[dict]:
218
184
  settings = queries.get_app_interface_settings()
219
185
  secret_reader = SecretReader(settings)
220
186
 
@@ -297,9 +263,9 @@ def get_apps_data(date, month_delta=1, thread_pool_size=10):
297
263
  if namespace["app"]["name"] != app["name"]:
298
264
  continue
299
265
  app_namespaces.append(namespace)
300
- vuln_mx = {}
301
- validt_mx = {}
302
- slo_mx = {}
266
+ vuln_mx: dict = {}
267
+ validt_mx: dict = {}
268
+ slo_mx: dict = {}
303
269
  for family in text_string_to_metric_families(vuln_metrics):
304
270
  for sample in family.samples:
305
271
  if sample.name == "imagemanifestvuln_total":
@@ -375,7 +341,7 @@ def get_apps_data(date, month_delta=1, thread_pool_size=10):
375
341
  return apps
376
342
 
377
343
 
378
- def get_build_history(job):
344
+ def get_build_history(job: MutableMapping) -> MutableMapping:
379
345
  try:
380
346
  logging.info(f"getting build history for {job['name']}")
381
347
  job["build_history"] = job["jenkins"].get_build_history(
@@ -386,7 +352,9 @@ def get_build_history(job):
386
352
  return job
387
353
 
388
354
 
389
- def get_build_history_pool(jenkins_map, jobs, timestamp_limit, thread_pool_size):
355
+ def get_build_history_pool(
356
+ jenkins_map: Mapping, jobs: Mapping, timestamp_limit: int, thread_pool_size: int
357
+ ) -> dict:
390
358
  history_to_get = []
391
359
  for instance, _jobs in jobs.items():
392
360
  jenkins = jenkins_map[instance]
@@ -411,7 +379,7 @@ def get_build_history_pool(jenkins_map, jobs, timestamp_limit, thread_pool_size)
411
379
  return history
412
380
 
413
381
 
414
- def get_repo_url(job):
382
+ def get_repo_url(job: Mapping) -> str:
415
383
  repo_url_raw = job["properties"][0]["github"]["url"]
416
384
  return repo_url_raw.strip("/").replace(".git", "")
417
385
 
@@ -424,8 +392,13 @@ def get_repo_url(job):
424
392
  @gitlab_project_id
425
393
  @click.option("--reports-path", help="path to write reports")
426
394
  def main(
427
- configfile, dry_run, log_level, gitlab_project_id, reports_path, thread_pool_size
428
- ):
395
+ configfile: str,
396
+ dry_run: bool,
397
+ log_level: str,
398
+ gitlab_project_id: str,
399
+ reports_path: str,
400
+ thread_pool_size: int,
401
+ ) -> None:
429
402
  init_env(log_level=log_level, config_file=configfile)
430
403
 
431
404
  now = datetime.now()
@@ -476,8 +449,9 @@ def main(
476
449
  gitlab_project_id=gitlab_project_id, sqs_or_gitlab="gitlab"
477
450
  ) as mr_cli:
478
451
  result = mr.submit(cli=mr_cli)
479
- logging.info(["created_mr", result.web_url])
452
+ if result:
453
+ logging.info(["created_mr", result.web_url])
480
454
 
481
455
 
482
456
  if __name__ == "__main__":
483
- main() # pylint: disable=no-value-for-parameter
457
+ main()
@@ -132,7 +132,7 @@ class GPGEncryptCommand:
132
132
 
133
133
  return user["public_gpg_key"]
134
134
 
135
- def _output(self, content: str):
135
+ def _output(self, content: str) -> None:
136
136
  output = self._command_data.output
137
137
  if not output:
138
138
  print(content)
@@ -140,7 +140,7 @@ class GPGEncryptCommand:
140
140
  with open(output, "w", encoding="locale") as f:
141
141
  f.write(content)
142
142
 
143
- def execute(self):
143
+ def execute(self) -> None:
144
144
  secret = self._fetch_secret()
145
145
  gpg_key = self._get_gpg_key()
146
146
  encrypted_content = gpg.gpg_encrypt(