ci-buildbot 0.11.0__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 (47) hide show
  1. ci_buildbot/__init__.py +1 -0
  2. ci_buildbot/cli.py +420 -0
  3. ci_buildbot/context_processors/__init__.py +8 -0
  4. ci_buildbot/context_processors/base.py +27 -0
  5. ci_buildbot/context_processors/codebuild.py +53 -0
  6. ci_buildbot/context_processors/deployfish.py +32 -0
  7. ci_buildbot/context_processors/docker.py +39 -0
  8. ci_buildbot/context_processors/generic.py +17 -0
  9. ci_buildbot/context_processors/git.py +240 -0
  10. ci_buildbot/context_processors/project.py +167 -0
  11. ci_buildbot/context_processors/unittest.py +58 -0
  12. ci_buildbot/exc.py +4 -0
  13. ci_buildbot/messages/__init__.py +33 -0
  14. ci_buildbot/messages/archive.py +24 -0
  15. ci_buildbot/messages/base.py +68 -0
  16. ci_buildbot/messages/deployfish.py +52 -0
  17. ci_buildbot/messages/deployfish_tasks.py +52 -0
  18. ci_buildbot/messages/docker.py +54 -0
  19. ci_buildbot/messages/docs.py +48 -0
  20. ci_buildbot/messages/general.py +40 -0
  21. ci_buildbot/messages/unittests.py +39 -0
  22. ci_buildbot/settings.py +36 -0
  23. ci_buildbot/templates/archive.tpl +42 -0
  24. ci_buildbot/templates/deploy_failed.tpl +26 -0
  25. ci_buildbot/templates/deploy_start.tpl +27 -0
  26. ci_buildbot/templates/deploy_success.tpl +26 -0
  27. ci_buildbot/templates/deploy_tasks_failed.tpl +26 -0
  28. ci_buildbot/templates/deploy_tasks_start.tpl +27 -0
  29. ci_buildbot/templates/deploy_tasks_success.tpl +26 -0
  30. ci_buildbot/templates/docker_failed.tpl +26 -0
  31. ci_buildbot/templates/docker_start.tpl +26 -0
  32. ci_buildbot/templates/docker_success.tpl +26 -0
  33. ci_buildbot/templates/docs_failed.tpl +26 -0
  34. ci_buildbot/templates/docs_start.tpl +27 -0
  35. ci_buildbot/templates/docs_success.tpl +26 -0
  36. ci_buildbot/templates/general_failed.tpl +26 -0
  37. ci_buildbot/templates/general_start.tpl +27 -0
  38. ci_buildbot/templates/general_success.tpl +26 -0
  39. ci_buildbot/templates/unittests_failed.tpl +26 -0
  40. ci_buildbot/templates/unittests_start.tpl +26 -0
  41. ci_buildbot/templates/unittests_success.tpl +26 -0
  42. ci_buildbot/typedefs.py +4 -0
  43. ci_buildbot-0.11.0.dist-info/METADATA +107 -0
  44. ci_buildbot-0.11.0.dist-info/RECORD +47 -0
  45. ci_buildbot-0.11.0.dist-info/WHEEL +5 -0
  46. ci_buildbot-0.11.0.dist-info/entry_points.txt +2 -0
  47. ci_buildbot-0.11.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1 @@
1
+ __version__ = "0.11.0"
ci_buildbot/cli.py ADDED
@@ -0,0 +1,420 @@
1
+ #!/usr/bin/env python
2
+ import pprint
3
+ import sys
4
+
5
+ import click
6
+ import slack
7
+ from slack.errors import SlackApiError
8
+
9
+ import ci_buildbot
10
+
11
+ from .messages import (
12
+ ArchiveCodeMessage,
13
+ DeployfishDeployFailureMessage,
14
+ DeployfishDeployStartMessage,
15
+ DeployfishDeploySuccessMessage,
16
+ DeployfishTasksDeployFailureMessage,
17
+ DeployfishTasksDeployStartMessage,
18
+ DeployfishTasksDeploySuccessMessage,
19
+ DockerFailureMessage,
20
+ DockerStartMessage,
21
+ DockerSuccessMessage,
22
+ DocsFailureMessage,
23
+ DocsStartMessage,
24
+ DocsSuccessMessage,
25
+ GeneralFailureMessage,
26
+ GeneralStartMessage,
27
+ GeneralSuccessMessage,
28
+ UnittestsFailureMessage,
29
+ UnittestsStartMessage,
30
+ UnittestsSuccessMessage,
31
+ )
32
+ from .settings import Settings
33
+
34
+
35
+ @click.group(invoke_without_command=True)
36
+ @click.option(
37
+ "--version/--no-version",
38
+ "-v",
39
+ default=False,
40
+ help="Print the current version and exit.",
41
+ )
42
+ @click.pass_context
43
+ def cli(ctx, version):
44
+ """
45
+ buildbot command line interaface.
46
+ """
47
+ ctx.obj["settings"] = Settings()
48
+ ctx.obj["slack"] = slack.WebClient(token=ctx.obj["settings"].api_token)
49
+
50
+ if version:
51
+ print(ci_buildbot.__version__)
52
+ sys.exit(0)
53
+
54
+
55
+ @cli.command("settings", short_help="Print our application settings.")
56
+ @click.pass_context
57
+ def settings(ctx):
58
+ """
59
+ Print our settings to stdout. This should be the completely evaluated
60
+ settings including those imported from any environment variable.
61
+ """
62
+ pp = pprint.PrettyPrinter(indent=2)
63
+ pp.pprint(ctx.obj["settings"].dict())
64
+
65
+
66
+ @cli.command("channels", short_help="Print our available channels.")
67
+ @click.pass_context
68
+ def channels(ctx):
69
+ pp = pprint.PrettyPrinter(indent=2)
70
+ pp.pprint(ctx.obj["slack"].conversations_list(types="private_channel")["channels"])
71
+
72
+
73
+ @cli.group("report", short_help="Report about a build step")
74
+ def report():
75
+ pass
76
+
77
+
78
+ @report.command("archive", short_help="Report about an archive-to-code-drop step")
79
+ @click.pass_context
80
+ def archive(ctx):
81
+ blocks = ArchiveCodeMessage().format()
82
+ client = ctx.obj["slack"]
83
+ try:
84
+ client.chat_postMessage(
85
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
86
+ )
87
+ except SlackApiError as e:
88
+ print(f"Got an error: {e.response['error']}")
89
+
90
+
91
+ @report.group(
92
+ "docker",
93
+ short_help="A group of commands that report about a Docker bmage build step",
94
+ )
95
+ def report_docker():
96
+ pass
97
+
98
+
99
+ @report_docker.command("start", short_help="Report about starting a docker build")
100
+ @click.option(
101
+ "--changelog/--no-changelog", default=False, help="Include the git changelog."
102
+ )
103
+ @click.argument("image")
104
+ @click.pass_context
105
+ def report_docker_start(ctx, image: str, changelog: bool = False) -> None:
106
+ blocks = DockerStartMessage().format(image=image, changelog=changelog)
107
+ client = ctx.obj["slack"]
108
+ try:
109
+ client.chat_postMessage(
110
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
111
+ )
112
+ except SlackApiError as e:
113
+ print(f"Got an error: {e.response['error']}")
114
+
115
+
116
+ @report_docker.command("success", short_help="Report a successful docker build")
117
+ @click.argument("image")
118
+ @click.pass_context
119
+ def report_docker_success(ctx, image):
120
+ blocks = DockerSuccessMessage().format(image=image)
121
+ client = ctx.obj["slack"]
122
+ try:
123
+ client.chat_postMessage(
124
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
125
+ )
126
+ except SlackApiError as e:
127
+ print(f"Got an error: {e.response['error']}")
128
+
129
+
130
+ @report_docker.command("failure", short_help="Report a failed docker build")
131
+ @click.argument("image")
132
+ @click.pass_context
133
+ def report_docker_failure(ctx, image):
134
+ blocks = DockerFailureMessage().format(image=image)
135
+ client = ctx.obj["slack"]
136
+ try:
137
+ client.chat_postMessage(
138
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
139
+ )
140
+ except SlackApiError as e:
141
+ print(f"Got an error: {e.response['error']}")
142
+
143
+
144
+ @report.group(
145
+ "unittests",
146
+ short_help="A group of commands that report about a test runner build step",
147
+ )
148
+ def report_unittests():
149
+ pass
150
+
151
+
152
+ @report_unittests.command(
153
+ "start", short_help="Report about starting a test runner build"
154
+ )
155
+ @click.pass_context
156
+ def report_unittests_start(ctx):
157
+ blocks = UnittestsStartMessage().format()
158
+ client = ctx.obj["slack"]
159
+ try:
160
+ client.chat_postMessage(
161
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
162
+ )
163
+ except SlackApiError as e:
164
+ print(f"Got an error: {e.response['error']}")
165
+
166
+
167
+ @report_unittests.command("success", short_help="Report a successful test runner build")
168
+ @click.argument("report_group")
169
+ @click.pass_context
170
+ def report_unittests_success(ctx, report_group):
171
+ blocks = UnittestsSuccessMessage().format(report_group=report_group)
172
+ client = ctx.obj["slack"]
173
+ try:
174
+ client.chat_postMessage(
175
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
176
+ )
177
+ except SlackApiError as e:
178
+ print(f"Got an error: {e.response['error']}")
179
+
180
+
181
+ @report_unittests.command("failure", short_help="Report a failed test runner build")
182
+ @click.argument("report_group")
183
+ @click.pass_context
184
+ def report_unittests_failure(ctx, report_group):
185
+ blocks = UnittestsFailureMessage().format(report_group=report_group)
186
+ client = ctx.obj["slack"]
187
+ try:
188
+ client.chat_postMessage(
189
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
190
+ )
191
+ except SlackApiError as e:
192
+ print(f"Got an error: {e.response['error']}")
193
+
194
+
195
+ @report.group(
196
+ "deployfish",
197
+ short_help="A group of commands that report about a Deployfish service build step",
198
+ )
199
+ def report_deployfish():
200
+ pass
201
+
202
+
203
+ @report_deployfish.command(
204
+ "start", short_help="Report about starting a deployfish service deploy"
205
+ )
206
+ @click.argument("service")
207
+ @click.pass_context
208
+ def report_deployfish_start(ctx, service):
209
+ blocks = DeployfishDeployStartMessage().format(service=service)
210
+ client = ctx.obj["slack"]
211
+ try:
212
+ client.chat_postMessage(
213
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
214
+ )
215
+ except SlackApiError as e:
216
+ print(f"Got an error: {e.response['error']}")
217
+
218
+
219
+ @report_deployfish.command(
220
+ "success", short_help="Report a successful deployfish service deploy"
221
+ )
222
+ @click.argument("service")
223
+ @click.pass_context
224
+ def report_deployfish_success(ctx, service):
225
+ blocks = DeployfishDeploySuccessMessage().format(service=service)
226
+ client = ctx.obj["slack"]
227
+ try:
228
+ client.chat_postMessage(
229
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
230
+ )
231
+ except SlackApiError as e:
232
+ print(f"Got an error: {e.response['error']}")
233
+
234
+
235
+ @report_deployfish.command(
236
+ "failure", short_help="Report a failed deployfish service deploy"
237
+ )
238
+ @click.argument("service")
239
+ @click.pass_context
240
+ def report_deployfish_failure(ctx, service):
241
+ blocks = DeployfishDeployFailureMessage().format(service=service)
242
+ client = ctx.obj["slack"]
243
+ try:
244
+ client.chat_postMessage(
245
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
246
+ )
247
+ except SlackApiError as e:
248
+ print(f"Got an error: {e.response['error']}")
249
+
250
+
251
+ @report.group(
252
+ "deployfish-tasks",
253
+ short_help="A group of commands that report about a Deployfish one-off tasks "
254
+ "build step",
255
+ )
256
+ def report_deployfish_tasks():
257
+ pass
258
+
259
+
260
+ @report_deployfish_tasks.command(
261
+ "start", short_help="Report about starting a deployfish one-off tasks deploy"
262
+ )
263
+ @click.argument("tasks", nargs=-1, required=True)
264
+ @click.pass_context
265
+ def report_deployfish_tasks_start(ctx, tasks):
266
+ blocks = DeployfishTasksDeployStartMessage().format(tasks=tasks)
267
+ client = ctx.obj["slack"]
268
+ try:
269
+ client.chat_postMessage(
270
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
271
+ )
272
+ except SlackApiError as e:
273
+ print(f"Got an error: {e.response['error']}")
274
+
275
+
276
+ @report_deployfish_tasks.command(
277
+ "success", short_help="Report a successful deployfish one-off tasks deploy"
278
+ )
279
+ @click.argument("tasks", nargs=-1, required=True)
280
+ @click.pass_context
281
+ def report_deployfish_tasks_success(ctx, tasks):
282
+ blocks = DeployfishTasksDeploySuccessMessage().format(tasks=tasks)
283
+ client = ctx.obj["slack"]
284
+ try:
285
+ client.chat_postMessage(
286
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
287
+ )
288
+ except SlackApiError as e:
289
+ print(f"Got an error: {e.response['error']}")
290
+
291
+
292
+ @report_deployfish_tasks.command(
293
+ "failure", short_help="Report a failed deployfish one-off tasks deploy"
294
+ )
295
+ @click.argument("tasks", nargs=-1, required=True)
296
+ @click.pass_context
297
+ def report_deployfish_tasks_failure(ctx, tasks):
298
+ blocks = DeployfishTasksDeployFailureMessage().format(tasks=tasks)
299
+ client = ctx.obj["slack"]
300
+ try:
301
+ client.chat_postMessage(
302
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
303
+ )
304
+ except SlackApiError as e:
305
+ print(f"Got an error: {e.response['error']}")
306
+
307
+
308
+ @report.group(
309
+ "docs",
310
+ short_help="A group of commands that report about a Deployfish service build step",
311
+ )
312
+ def report_docs():
313
+ pass
314
+
315
+
316
+ @report_docs.command(
317
+ "start", short_help="Report about starting a Sphinx docs build and deploy"
318
+ )
319
+ @click.pass_context
320
+ def report_docs_start(ctx):
321
+ blocks = DocsStartMessage().format()
322
+ client = ctx.obj["slack"]
323
+ try:
324
+ client.chat_postMessage(
325
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
326
+ )
327
+ except SlackApiError as e:
328
+ print(f"Got an error: {e.response['error']}")
329
+
330
+
331
+ @report_docs.command(
332
+ "success", short_help="Report a successful Sphinx docs build and deploy"
333
+ )
334
+ @click.pass_context
335
+ def report_docs_success(ctx):
336
+ blocks = DocsSuccessMessage().format()
337
+ client = ctx.obj["slack"]
338
+ try:
339
+ client.chat_postMessage(
340
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
341
+ )
342
+ except SlackApiError as e:
343
+ print(f"Got an error: {e.response['error']}")
344
+
345
+
346
+ @report_docs.command(
347
+ "failure", short_help="Report a failed Sphinx docs build and deploy"
348
+ )
349
+ @click.pass_context
350
+ def report_docs_failure(ctx):
351
+ blocks = DocsFailureMessage().format()
352
+ client = ctx.obj["slack"]
353
+ try:
354
+ client.chat_postMessage(
355
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
356
+ )
357
+ except SlackApiError as e:
358
+ print(f"Got an error: {e.response['error']}")
359
+
360
+
361
+ @report.group(
362
+ "general",
363
+ short_help="A group of commands that report about a Deployfish service build step",
364
+ )
365
+ def report_general():
366
+ pass
367
+
368
+
369
+ @report_general.command(
370
+ "start", short_help="Report about starting a general service deploy"
371
+ )
372
+ @click.argument("label")
373
+ @click.pass_context
374
+ def report_general_start(ctx, label):
375
+ blocks = GeneralStartMessage().format(label=label)
376
+ client = ctx.obj["slack"]
377
+ try:
378
+ client.chat_postMessage(
379
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
380
+ )
381
+ except SlackApiError as e:
382
+ print(f"Got an error: {e.response['error']}")
383
+
384
+
385
+ @report_general.command(
386
+ "success", short_help="Report a successful general service deploy"
387
+ )
388
+ @click.argument("label")
389
+ @click.pass_context
390
+ def report_general_success(ctx, label):
391
+ blocks = GeneralSuccessMessage().format(label=label)
392
+ client = ctx.obj["slack"]
393
+ try:
394
+ client.chat_postMessage(
395
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
396
+ )
397
+ except SlackApiError as e:
398
+ print(f"Got an error: {e.response['error']}")
399
+
400
+
401
+ @report_general.command("failure", short_help="Report a failed general service deploy")
402
+ @click.argument("label")
403
+ @click.pass_context
404
+ def report_general_failure(ctx, label):
405
+ blocks = GeneralFailureMessage().format(label=label)
406
+ client = ctx.obj["slack"]
407
+ try:
408
+ client.chat_postMessage(
409
+ channel=ctx.obj["settings"].channel, blocks=blocks, as_user=True
410
+ )
411
+ except SlackApiError as e:
412
+ print(f"Got an error: {e.response['error']}")
413
+
414
+
415
+ def main():
416
+ cli(obj={})
417
+
418
+
419
+ if __name__ == "__main__":
420
+ main()
@@ -0,0 +1,8 @@
1
+ from .base import * # noqa:F403,F401
2
+ from .codebuild import * # noqa:F403,F401
3
+ from .deployfish import * # noqa:F403,F401
4
+ from .docker import * # noqa:F403,F401
5
+ from .generic import * # noqa:F403,F401
6
+ from .git import * # noqa:F403,F401
7
+ from .project import * # noqa:F403,F401
8
+ from .unittest import * # noqa:F403,F401
@@ -0,0 +1,27 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from ..typedefs import MessageContext
4
+
5
+
6
+ class AbstractContextProcessor(ABC):
7
+ """
8
+ Base class for all context processors.
9
+ """
10
+
11
+ def __init__(self, **kwargs): # noqa: B027
12
+ """
13
+ Args:
14
+ kwargs: the keyword arguments passed to the context processor
15
+
16
+ """
17
+
18
+ @abstractmethod
19
+ def annotate(self, context: MessageContext) -> None:
20
+ """
21
+ Add values to the message context ``context``.
22
+
23
+ Args:
24
+ context: the current message context
25
+
26
+ """
27
+ ...
@@ -0,0 +1,53 @@
1
+ import os
2
+ import time
3
+
4
+ from ..typedefs import MessageContext
5
+ from .base import AbstractContextProcessor
6
+
7
+
8
+ class CodebuildProcessor(AbstractContextProcessor):
9
+ """
10
+ Adds the following keys to the context:
11
+
12
+ * ``build_id``: the CodeBuild build id
13
+ * ``build_project_name``: the CodeBuild project name
14
+ * ``build_status_url``: the URL to the CodeBuild build status page
15
+ * ``account_id``: the AWS account id
16
+ * ``pipeline_url``: the URL to the CodePipeline pipeline status page
17
+ * ``pipeline``: the CodePipeline pipeline name
18
+ * ``status``: the CodePipeline pipeline status
19
+ * ``region``: the AWS region
20
+ * ``build_time``: the elapsed time for the build in minutes and seconds
21
+ """
22
+
23
+ def get_build_log_url(self, context: MessageContext) -> None:
24
+ fields = os.environ["CODEBUILD_BUILD_ARN"].split(":")
25
+ context["account_id"] = fields[4]
26
+ context["build_project_name"] = fields[5].split("/")[1]
27
+ context["build_id"] = fields[6]
28
+ context["build_status_url"] = (
29
+ f"<https://{context['region']}.console.aws.amazon.com/codesuite/codebuild/"
30
+ f"{context['account_id']}/projects/{context['build_project_name']}/build/"
31
+ f"{context['build_project_name']}%3A{context['build_id']}/"
32
+ "log?region=us-west-2|Click here>"
33
+ )
34
+
35
+ def get_pipeline_url(self, context: MessageContext) -> None:
36
+ # TODO: detect region from the environment instead of hardcoding it to us-west-2
37
+ context["pipeline"] = os.environ["CODEBUILD_INITIATOR"].split("/")[1]
38
+ context["pipeline_url"] = (
39
+ f"<https://{context['region']}.console.aws.amazon.com/codesuite/codepipeline/pipelines/{context['pipeline']}/view?region=us-west-2|{context['pipeline']}>"
40
+ )
41
+
42
+ def annotate(self, context: MessageContext) -> None:
43
+ context["status"] = (
44
+ "Success" if "CODEBUILD_BUILD_SUCCEEDING" in os.environ else "Failed"
45
+ )
46
+ context["region"] = os.environ["AWS_DEFAULT_REGION"]
47
+ context["build_id"] = os.environ.get("CODEBUILD_BUILD_ID", None)
48
+ build_seconds = time.time() - float(os.environ["CODEBUILD_START_TIME"]) / 1000
49
+ build_minutes = int(build_seconds // 60)
50
+ build_seconds = int(build_seconds - build_minutes * 60)
51
+ context["build_time"] = f"{build_minutes}m {build_seconds}s"
52
+ self.get_build_log_url(context)
53
+ self.get_pipeline_url(context)
@@ -0,0 +1,32 @@
1
+ from ..typedefs import MessageContext
2
+ from .base import AbstractContextProcessor
3
+
4
+
5
+ class DeployfishDeployProcessor(AbstractContextProcessor):
6
+ """
7
+ Adds the following keys to the context:
8
+
9
+ * ``service``: the name of the ECS service being deployed
10
+ """
11
+
12
+ def __init__(self, **kwargs) -> None:
13
+ super().__init__(**kwargs)
14
+ self.service: str = kwargs["service"]
15
+
16
+ def annotate(self, context: MessageContext) -> None:
17
+ context["service"] = self.service
18
+
19
+
20
+ class DeployfishTasksDeployProcessor(AbstractContextProcessor):
21
+ """
22
+ Adds the following keys to the context:
23
+
24
+ * ``tasks``: a list of the names of the ECS tasks being deployed
25
+ """
26
+
27
+ def __init__(self, **kwargs) -> None:
28
+ super().__init__(**kwargs)
29
+ self.tasks: list[str] = kwargs["tasks"]
30
+
31
+ def annotate(self, context: MessageContext) -> None:
32
+ context["tasks"] = self.tasks
@@ -0,0 +1,39 @@
1
+ from pathlib import Path
2
+
3
+ import docker
4
+
5
+ from ..typedefs import MessageContext
6
+ from .base import AbstractContextProcessor
7
+
8
+
9
+ class DockerImageNameProcessor(AbstractContextProcessor):
10
+ """
11
+ Adds the key ``short_image`` to the context, which is the basename of
12
+ the Docker image without the repository name.
13
+ """
14
+
15
+ def __init__(self, **kwargs) -> None:
16
+ super().__init__(**kwargs)
17
+ self.image: str = kwargs["image"]
18
+
19
+ def annotate(self, context: MessageContext) -> None:
20
+ context["short_image"] = Path(self.image).name
21
+
22
+
23
+ class DockerProcessor(AbstractContextProcessor):
24
+ """
25
+ Adds the following keys to the context:
26
+
27
+ * ``image_id``: the short id of the Docker image
28
+ * ``image_size``: the size of the Docker image in MB
29
+ """
30
+
31
+ def __init__(self, **kwargs) -> None:
32
+ super().__init__(**kwargs)
33
+ self.image: str = kwargs["image"]
34
+
35
+ def annotate(self, context: MessageContext) -> None:
36
+ client = docker.from_env()
37
+ image = client.images.get(self.image)
38
+ context["image_id"] = image.short_id.split(":")[1]
39
+ context["image_size"] = image.attrs["Size"] / (1024 * 1024)
@@ -0,0 +1,17 @@
1
+ from ..typedefs import MessageContext
2
+ from .base import AbstractContextProcessor
3
+
4
+
5
+ class GenericProcessor(AbstractContextProcessor):
6
+ """
7
+ Adds the following keys to the context:
8
+
9
+ * ``label``: a user supplied label we got from the --label command line option
10
+ """
11
+
12
+ def __init__(self, **kwargs) -> None:
13
+ super().__init__(**kwargs)
14
+ self.label: str | None = kwargs["label"]
15
+
16
+ def annotate(self, context: MessageContext) -> None:
17
+ context["label"] = self.label