dycw-actions 0.8.11__py3-none-any.whl → 0.14.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 (46) hide show
  1. actions/.DS_Store +0 -0
  2. actions/__init__.py +1 -1
  3. actions/clean_dir/lib.py +7 -4
  4. actions/cli.py +23 -2
  5. actions/constants.py +2 -0
  6. actions/git_clone_with/__init__.py +1 -0
  7. actions/git_clone_with/cli.py +41 -0
  8. actions/git_clone_with/constants.py +7 -0
  9. actions/git_clone_with/lib.py +78 -0
  10. actions/git_clone_with/settings.py +20 -0
  11. actions/pre_commit/conformalize_repo/action_dicts.py +39 -40
  12. actions/pre_commit/conformalize_repo/cli.py +16 -4
  13. actions/pre_commit/conformalize_repo/constants.py +14 -0
  14. actions/pre_commit/conformalize_repo/lib.py +350 -220
  15. actions/pre_commit/conformalize_repo/settings.py +42 -16
  16. actions/pre_commit/constants.py +3 -3
  17. actions/pre_commit/format_requirements/lib.py +5 -2
  18. actions/pre_commit/replace_sequence_strs/lib.py +5 -2
  19. actions/pre_commit/touch_empty_py/lib.py +7 -4
  20. actions/pre_commit/touch_py_typed/lib.py +9 -5
  21. actions/pre_commit/update_requirements/cli.py +10 -2
  22. actions/pre_commit/update_requirements/lib.py +78 -15
  23. actions/pre_commit/update_requirements/settings.py +23 -0
  24. actions/pre_commit/utilities.py +131 -39
  25. actions/publish_package/lib.py +33 -20
  26. actions/random_sleep/lib.py +12 -7
  27. actions/re_encrypt/__init__.py +1 -0
  28. actions/re_encrypt/cli.py +36 -0
  29. actions/re_encrypt/constants.py +7 -0
  30. actions/re_encrypt/lib.py +115 -0
  31. actions/re_encrypt/settings.py +26 -0
  32. actions/register_gitea_runner/configs/entrypoint.sh +8 -8
  33. actions/register_gitea_runner/lib.py +23 -14
  34. actions/run_hooks/lib.py +27 -14
  35. actions/setup_cronjob/lib.py +19 -13
  36. actions/setup_ssh_config/__init__.py +1 -0
  37. actions/setup_ssh_config/cli.py +17 -0
  38. actions/setup_ssh_config/constants.py +7 -0
  39. actions/setup_ssh_config/lib.py +30 -0
  40. actions/tag_commit/lib.py +16 -9
  41. actions/types.py +5 -9
  42. actions/utilities.py +1 -16
  43. {dycw_actions-0.8.11.dist-info → dycw_actions-0.14.0.dist-info}/METADATA +5 -3
  44. {dycw_actions-0.8.11.dist-info → dycw_actions-0.14.0.dist-info}/RECORD +46 -30
  45. {dycw_actions-0.8.11.dist-info → dycw_actions-0.14.0.dist-info}/WHEEL +1 -1
  46. {dycw_actions-0.8.11.dist-info → dycw_actions-0.14.0.dist-info}/entry_points.txt +0 -0
@@ -5,7 +5,7 @@ from collections.abc import Iterator, MutableSet
5
5
  from contextlib import contextmanager
6
6
  from dataclasses import dataclass
7
7
  from pathlib import Path
8
- from typing import TYPE_CHECKING, Any, assert_never
8
+ from typing import TYPE_CHECKING, Any, assert_never, overload
9
9
 
10
10
  import tomlkit
11
11
  from libcst import Module, parse_module
@@ -16,8 +16,9 @@ from utilities.functions import ensure_class, ensure_str, get_func_name
16
16
  from utilities.iterables import OneEmptyError, OneNonUniqueError, one
17
17
  from utilities.packaging import Requirement
18
18
  from utilities.types import PathLike, StrDict
19
+ from utilities.typing import is_str_dict
19
20
 
20
- from actions.constants import PATH_CACHE, YAML_INSTANCE
21
+ from actions.constants import PATH_CACHE, PYPROJECT_TOML, YAML_INSTANCE
21
22
  from actions.logging import LOGGER
22
23
  from actions.utilities import are_equal_modulo_new_line, write_text, yaml_dump
23
24
 
@@ -26,26 +27,26 @@ if TYPE_CHECKING:
26
27
 
27
28
  from utilities.types import PathLike, StrDict
28
29
 
29
- from actions.types import FuncRequirement, HasAppend, HasSetDefault
30
+ from actions.types import ArrayLike, ContainerLike, FuncRequirement
30
31
 
31
32
 
32
- def ensure_aot_contains(array: AoT, /, *tables: Table) -> None:
33
- for table_ in tables:
34
- if table_ not in array:
35
- array.append(table_)
33
+ ##
36
34
 
37
35
 
38
- def ensure_contains(array: HasAppend, /, *objs: Any) -> None:
39
- if isinstance(array, AoT):
40
- msg = f"Use {ensure_aot_contains.__name__!r} instead of {ensure_contains.__name__!r}"
41
- raise TypeError(msg)
36
+ @overload
37
+ def ensure_contains(container: AoT, /, *objs: Table) -> None: ...
38
+ @overload
39
+ def ensure_contains(container: list[str], /, *objs: str) -> None: ...
40
+ @overload
41
+ def ensure_contains(container: list[StrDict], /, *objs: StrDict) -> None: ...
42
+ def ensure_contains(container: ArrayLike, /, *objs: Any) -> None:
42
43
  for obj in objs:
43
- if obj not in array:
44
- array.append(obj)
44
+ if obj not in container:
45
+ container.append(obj)
45
46
 
46
47
 
47
48
  def ensure_contains_partial_dict(
48
- container: HasAppend, partial: StrDict, /, *, extra: StrDict | None = None
49
+ container: list[StrDict], partial: StrDict, /, *, extra: StrDict | None = None
49
50
  ) -> StrDict:
50
51
  try:
51
52
  return get_partial_dict(container, partial, skip_log=True)
@@ -55,52 +56,123 @@ def ensure_contains_partial_dict(
55
56
  return dict_
56
57
 
57
58
 
58
- def ensure_contains_partial_str(container: HasAppend, text: str, /) -> str:
59
+ def ensure_contains_partial_str(list_: Array | list[str], text: str, /) -> str:
59
60
  try:
60
- return get_partial_str(container, text, skip_log=True)
61
+ return get_partial_str(list_, text, skip_log=True)
61
62
  except OneEmptyError:
62
- container.append(text)
63
+ list_.append(text)
63
64
  return text
64
65
 
65
66
 
66
- def ensure_not_contains(array: Array, /, *objs: Any) -> None:
67
+ @overload
68
+ def ensure_not_contains(container: AoT, /, *objs: Table) -> None: ...
69
+ @overload
70
+ def ensure_not_contains(container: list[str], /, *objs: str) -> None: ...
71
+ @overload
72
+ def ensure_not_contains(container: list[StrDict], /, *objs: StrDict) -> None: ...
73
+ def ensure_not_contains(container: ArrayLike, /, *objs: Any) -> None:
67
74
  for obj in objs:
68
75
  try:
69
- index = next(i for i, o in enumerate(array) if o == obj)
76
+ index = next(i for i, o in enumerate(container) if o == obj)
70
77
  except StopIteration:
71
78
  pass
72
79
  else:
73
- del array[index]
80
+ del container[index]
81
+
82
+
83
+ ##
84
+
85
+
86
+ def get_aot(container: ContainerLike, key: str, /) -> AoT:
87
+ return ensure_class(container[key], AoT)
88
+
89
+
90
+ def get_array(container: ContainerLike, key: str, /) -> Array:
91
+ return ensure_class(container[key], Array)
92
+
93
+
94
+ def get_dict(dict_: StrDict, key: str, /) -> StrDict:
95
+ if is_str_dict(value := dict_[key]):
96
+ return value
97
+ raise TypeError(value)
98
+
99
+
100
+ def get_list_dicts(dict_: StrDict, key: str, /) -> list[StrDict]:
101
+ list_ = ensure_class(dict_[key], list)
102
+ for i in list_:
103
+ if not is_str_dict(i):
104
+ raise TypeError(i)
105
+ return list_
106
+
107
+
108
+ def get_list_strs(dict_: StrDict, key: str, /) -> list[str]:
109
+ list_ = ensure_class(dict_[key], list)
110
+ for i in list_:
111
+ if not isinstance(i, str):
112
+ raise TypeError(i)
113
+ return list_
114
+
115
+
116
+ def get_table(container: ContainerLike, key: str, /) -> Table:
117
+ return ensure_class(container[key], Table)
74
118
 
75
119
 
76
120
  ##
77
121
 
78
122
 
79
- def get_aot(container: HasSetDefault, key: str, /) -> AoT:
80
- return ensure_class(container.setdefault(key, aot()), AoT)
123
+ def get_set_aot(container: ContainerLike, key: str, /) -> AoT:
124
+ try:
125
+ return get_aot(container, key)
126
+ except KeyError:
127
+ value = container[key] = aot()
128
+ return value
129
+
130
+
131
+ def get_set_array(container: ContainerLike, key: str, /) -> Array:
132
+ try:
133
+ return get_array(container, key)
134
+ except KeyError:
135
+ value = container[key] = array()
136
+ return value
81
137
 
82
138
 
83
- def get_array(container: HasSetDefault, key: str, /) -> Array:
84
- return ensure_class(container.setdefault(key, array()), Array)
139
+ def get_set_dict(dict_: StrDict, key: str, /) -> StrDict:
140
+ try:
141
+ return get_dict(dict_, key)
142
+ except KeyError:
143
+ value = dict_[key] = {}
144
+ return value
85
145
 
86
146
 
87
- def get_dict(container: HasSetDefault, key: str, /) -> StrDict:
88
- return ensure_class(container.setdefault(key, {}), dict)
147
+ def get_set_list_dicts(dict_: StrDict, key: str, /) -> list[StrDict]:
148
+ try:
149
+ return get_list_dicts(dict_, key)
150
+ except KeyError:
151
+ value = dict_[key] = []
152
+ return value
89
153
 
90
154
 
91
- def get_list(container: HasSetDefault, key: str, /) -> list[Any]:
92
- return ensure_class(container.setdefault(key, []), list)
155
+ def get_set_list_strs(dict_: StrDict, key: str, /) -> list[str]:
156
+ try:
157
+ return get_list_strs(dict_, key)
158
+ except KeyError:
159
+ value = dict_[key] = []
160
+ return value
93
161
 
94
162
 
95
- def get_table(container: HasSetDefault, key: str, /) -> Table:
96
- return ensure_class(container.setdefault(key, table()), Table)
163
+ def get_set_table(container: ContainerLike, key: str, /) -> Table:
164
+ try:
165
+ return get_table(container, key)
166
+ except KeyError:
167
+ value = container[key] = table()
168
+ return value
97
169
 
98
170
 
99
171
  ##
100
172
 
101
173
 
102
174
  def get_partial_dict(
103
- iterable: Iterable[Any], dict_: StrDict, /, *, skip_log: bool = False
175
+ iterable: Iterable[StrDict], dict_: StrDict, /, *, skip_log: bool = False
104
176
  ) -> StrDict:
105
177
  try:
106
178
  return one(i for i in iterable if is_partial_dict(dict_, i))
@@ -177,19 +249,21 @@ def is_partial_str(obj: Any, text: str, /) -> bool:
177
249
  def get_pyproject_dependencies(doc: TOMLDocument, /) -> PyProjectDependencies:
178
250
  out = PyProjectDependencies()
179
251
  if (project_key := "project") in doc:
180
- project = get_table(doc, project_key)
252
+ project = get_set_table(doc, project_key)
181
253
  if (dep_key := "dependencies") in project:
182
- out.dependencies = get_array(project, dep_key)
254
+ out.dependencies = get_set_array(project, dep_key)
183
255
  if (opt_dep_key := "optional-dependencies") in project:
184
- opt_dependencies = get_table(project, opt_dep_key)
256
+ opt_dependencies = get_set_table(project, opt_dep_key)
185
257
  out.opt_dependencies = {}
186
258
  for key in opt_dependencies:
187
- out.opt_dependencies[ensure_str(key)] = get_array(opt_dependencies, key)
259
+ out.opt_dependencies[ensure_str(key)] = get_set_array(
260
+ opt_dependencies, key
261
+ )
188
262
  if (dep_grps_key := "dependency-groups") in doc:
189
- dep_grps = get_table(doc, dep_grps_key)
263
+ dep_grps = get_set_table(doc, dep_grps_key)
190
264
  out.dep_groups = {}
191
265
  for key in dep_grps:
192
- out.dep_groups[ensure_str(key)] = get_array(dep_grps, key)
266
+ out.dep_groups[ensure_str(key)] = get_set_array(dep_grps, key)
193
267
  return out
194
268
 
195
269
 
@@ -295,6 +369,17 @@ def yield_json_dict(
295
369
  ##
296
370
 
297
371
 
372
+ @contextmanager
373
+ def yield_pyproject_toml(
374
+ *, modifications: MutableSet[Path] | None = None
375
+ ) -> Iterator[TOMLDocument]:
376
+ with yield_toml_doc(PYPROJECT_TOML, modifications=modifications) as doc:
377
+ yield doc
378
+
379
+
380
+ ##
381
+
382
+
298
383
  @contextmanager
299
384
  def yield_mutable_write_context[T](
300
385
  path: PathLike,
@@ -370,7 +455,6 @@ def yield_yaml_dict(
370
455
  __all__ = [
371
456
  "PyProjectDependencies",
372
457
  "WriteContext",
373
- "ensure_aot_contains",
374
458
  "ensure_contains",
375
459
  "ensure_contains_partial_dict",
376
460
  "ensure_contains_partial_str",
@@ -378,10 +462,17 @@ __all__ = [
378
462
  "get_aot",
379
463
  "get_array",
380
464
  "get_dict",
381
- "get_list",
465
+ "get_list_dicts",
466
+ "get_list_strs",
382
467
  "get_partial_dict",
383
468
  "get_partial_str",
384
469
  "get_pyproject_dependencies",
470
+ "get_set_aot",
471
+ "get_set_array",
472
+ "get_set_dict",
473
+ "get_set_list_dicts",
474
+ "get_set_list_strs",
475
+ "get_set_table",
385
476
  "get_table",
386
477
  "is_partial_dict",
387
478
  "is_partial_str",
@@ -389,6 +480,7 @@ __all__ = [
389
480
  "yield_immutable_write_context",
390
481
  "yield_json_dict",
391
482
  "yield_mutable_write_context",
483
+ "yield_pyproject_toml",
392
484
  "yield_python_file",
393
485
  "yield_text_file",
394
486
  "yield_toml_doc",
@@ -2,15 +2,20 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING
4
4
 
5
+ from utilities.functions import get_func_name
6
+ from utilities.tabulate import func_param_desc
5
7
  from utilities.tempfile import TemporaryDirectory
6
8
 
9
+ from actions import __version__
7
10
  from actions.logging import LOGGER
8
11
  from actions.publish_package.settings import SETTINGS
9
- from actions.utilities import log_func_call, logged_run
12
+ from actions.utilities import logged_run
10
13
 
11
14
  if TYPE_CHECKING:
12
15
  from typed_settings import Secret
13
16
 
17
+ from actions.types import SecretLike
18
+
14
19
 
15
20
  def publish_package(
16
21
  *,
@@ -20,26 +25,34 @@ def publish_package(
20
25
  trusted_publishing: bool = SETTINGS.trusted_publishing,
21
26
  native_tls: bool = SETTINGS.native_tls,
22
27
  ) -> None:
23
- variables = [
24
- f"{username=}",
25
- f"{password=}",
26
- f"{publish_url=}",
27
- f"{trusted_publishing=}",
28
- f"{native_tls=}",
29
- ]
30
- LOGGER.info(log_func_call(publish_package, *variables))
31
- with TemporaryDirectory() as temp:
32
- logged_run("uv", "build", "--out-dir", str(temp), "--wheel", "--clear")
33
- logged_run(
34
- "uv",
35
- "publish",
36
- *([] if username is None else ["--username", username]),
37
- *([] if password is None else ["--password", password]),
38
- *([] if publish_url is None else ["--publish-url", publish_url]),
39
- *(["--trusted-publishing", "always"] if trusted_publishing else []),
40
- *(["--native-tls"] if native_tls else []),
41
- f"{temp}/*",
28
+ LOGGER.info(
29
+ func_param_desc(
30
+ publish_package,
31
+ __version__,
32
+ f"{username=}",
33
+ f"{password=}",
34
+ f"{publish_url=}",
35
+ f"{trusted_publishing=}",
36
+ f"{native_tls=}",
42
37
  )
38
+ )
39
+ build_head: list[str] = ["uv", "build", "--out-dir"]
40
+ build_tail: list[str] = ["--wheel", "--clear"]
41
+ publish: list[SecretLike] = ["uv", "publish"]
42
+ if username is not None:
43
+ publish.extend(["--username", username])
44
+ if password is not None:
45
+ publish.extend(["--password", password])
46
+ if publish_url is not None:
47
+ publish.extend(["--publish-url", publish_url])
48
+ if trusted_publishing:
49
+ publish.extend(["--trusted-publishing", "always"])
50
+ if native_tls:
51
+ publish.append("--native-tls")
52
+ with TemporaryDirectory() as temp:
53
+ logged_run(*build_head, str(temp), *build_tail)
54
+ logged_run(*publish, f"{temp}/*")
55
+ LOGGER.info("Finished running %r", get_func_name(publish_package))
43
56
 
44
57
 
45
58
  __all__ = ["publish_package"]
@@ -4,12 +4,14 @@ from math import ceil, floor
4
4
  from random import choice
5
5
  from time import sleep
6
6
 
7
+ from utilities.functions import get_func_name
8
+ from utilities.tabulate import func_param_desc
7
9
  from utilities.whenever import get_now
8
10
  from whenever import TimeDelta, ZonedDateTime
9
11
 
12
+ from actions import __version__
10
13
  from actions.logging import LOGGER
11
14
  from actions.random_sleep.settings import SETTINGS
12
- from actions.utilities import log_func_call
13
15
 
14
16
 
15
17
  def random_sleep(
@@ -19,15 +21,18 @@ def random_sleep(
19
21
  step: int = SETTINGS.step,
20
22
  log_freq: int = SETTINGS.log_freq,
21
23
  ) -> None:
22
- variables = [f"{min=}", f"{max=}", f"{step=}", f"{log_freq=}"]
23
- LOGGER.info(log_func_call(random_sleep, *variables))
24
+ LOGGER.info(
25
+ func_param_desc(
26
+ random_sleep, __version__, f"{min=}", f"{max=}", f"{step=}", f"{log_freq=}"
27
+ )
28
+ )
24
29
  start = get_now()
25
- delta = TimeDelta(seconds=choice(range(min, max, step)))
26
- LOGGER.info("Sleeping for %s...", delta)
27
- end = (start + delta).round(mode="ceil")
30
+ duration = TimeDelta(seconds=choice(range(min, max, step)))
31
+ LOGGER.info("Sleeping for %s...", duration)
32
+ end = (start + duration).round(mode="ceil")
28
33
  while (now := get_now()) < end:
29
34
  _intermediate(start, now, end, log_freq=log_freq)
30
- LOGGER.info("Finished sleeping for %s", delta)
35
+ LOGGER.info("Finished running %r", get_func_name(random_sleep))
31
36
 
32
37
 
33
38
  def _intermediate(
@@ -0,0 +1 @@
1
+ from __future__ import annotations
@@ -0,0 +1,36 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import TYPE_CHECKING
5
+
6
+ import click
7
+ from click import argument
8
+ from typed_settings import click_options
9
+ from utilities.logging import basic_config
10
+ from utilities.os import is_pytest
11
+
12
+ from actions.logging import LOGGER
13
+ from actions.re_encrypt.lib import re_encrypt
14
+ from actions.re_encrypt.settings import Settings
15
+ from actions.utilities import LOADER
16
+
17
+ if TYPE_CHECKING:
18
+ from utilities.types import PathLike
19
+
20
+
21
+ @argument("path", type=click.Path(exists=True, dir_okay=False, path_type=Path))
22
+ @click_options(Settings, [LOADER], show_envvars_in_help=True)
23
+ def re_encrypt_sub_cmd(settings: Settings, /, *, path: PathLike) -> None:
24
+ if is_pytest():
25
+ return
26
+ basic_config(obj=LOGGER)
27
+ re_encrypt(
28
+ path,
29
+ key_file=settings.key_file,
30
+ key=settings.key,
31
+ new_key_file=settings.new_key_file,
32
+ new_key=settings.new_key,
33
+ )
34
+
35
+
36
+ __all__ = ["re_encrypt_sub_cmd"]
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ RE_ENCRYPT_DOCSTRING = "Re-encrypt a JSON file"
4
+ RE_ENCRYPT_SUB_CMD = "re-encrypt"
5
+
6
+
7
+ __all__ = ["RE_ENCRYPT_DOCSTRING", "RE_ENCRYPT_SUB_CMD"]
@@ -0,0 +1,115 @@
1
+ from __future__ import annotations
2
+
3
+ from contextlib import contextmanager
4
+ from os import environ
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING, assert_never
7
+
8
+ from typed_settings import Secret
9
+ from utilities.atomicwrites import writer
10
+ from utilities.os import temp_environ
11
+ from utilities.subprocess import run
12
+ from utilities.tabulate import func_param_desc
13
+ from utilities.tempfile import TemporaryFile
14
+ from xdg_base_dirs import xdg_config_home
15
+
16
+ from actions import __version__
17
+ from actions.logging import LOGGER
18
+ from actions.re_encrypt.settings import SETTINGS
19
+
20
+ if TYPE_CHECKING:
21
+ from collections.abc import Iterator
22
+
23
+ from utilities.types import PathLike
24
+
25
+
26
+ def re_encrypt(
27
+ path: PathLike,
28
+ /,
29
+ *,
30
+ key_file: PathLike | None = SETTINGS.key_file,
31
+ key: Secret[str] | None = SETTINGS.key,
32
+ new_key_file: PathLike | None = SETTINGS.new_key_file,
33
+ new_key: Secret[str] | None = SETTINGS.new_key,
34
+ ) -> None:
35
+ """Re-encrypt a JSON file."""
36
+ LOGGER.info(
37
+ func_param_desc(
38
+ re_encrypt,
39
+ __version__,
40
+ f"{path=}",
41
+ f"{key_file=}",
42
+ f"{key=}",
43
+ f"{new_key_file=}",
44
+ f"{new_key=}",
45
+ )
46
+ )
47
+ with _yield_env(key_file=key_file, key=key):
48
+ decrypted = run(
49
+ "sops",
50
+ "decrypt",
51
+ "--input-type",
52
+ "json",
53
+ "--output-type",
54
+ "json",
55
+ "--ignore-mac",
56
+ str(path),
57
+ return_=True,
58
+ )
59
+ with _yield_env(key_file=new_key_file, key=new_key):
60
+ identity = _get_recipient()
61
+ with TemporaryFile(text=decrypted) as temp:
62
+ encrypted = run(
63
+ "sops",
64
+ "encrypt",
65
+ "--age",
66
+ identity,
67
+ "--input-type",
68
+ "json",
69
+ "--output-type",
70
+ "json",
71
+ str(temp),
72
+ return_=True,
73
+ )
74
+ with writer(path, overwrite=True) as temp:
75
+ _ = temp.write_text(encrypted)
76
+ LOGGER.info("Finished re-encrypting '%s'", path)
77
+
78
+
79
+ @contextmanager
80
+ def _yield_env(
81
+ *,
82
+ key_file: PathLike | None = SETTINGS.key_file,
83
+ key: Secret[str] | None = SETTINGS.key,
84
+ ) -> Iterator[None]:
85
+ match key_file, key:
86
+ case Path() | str(), _:
87
+ with temp_environ(SOPS_AGE_KEY_FILE=str(key_file)):
88
+ yield
89
+ case None, Secret():
90
+ with temp_environ(SOPS_AGE_KEY=key.get_secret_value()):
91
+ yield
92
+ case None, None:
93
+ path = xdg_config_home() / "sops/age/keys.txt"
94
+ with temp_environ(SOPS_AGE_KEY_FILE=str(path)):
95
+ yield
96
+ case never:
97
+ assert_never(never)
98
+
99
+
100
+ def _get_recipient() -> str:
101
+ try:
102
+ key_file = environ["SOPS_AGE_KEY_FILE"]
103
+ except KeyError:
104
+ with TemporaryFile(text=environ["SOPS_AGE_KEY"]) as temp:
105
+ return _get_recipient_from_path(temp)
106
+ else:
107
+ return _get_recipient_from_path(key_file)
108
+
109
+
110
+ def _get_recipient_from_path(path: PathLike, /) -> str:
111
+ recipient, *_ = run("age-keygen", "-y", str(path), return_=True).splitlines()
112
+ return recipient
113
+
114
+
115
+ __all__ = ["re_encrypt"]
@@ -0,0 +1,26 @@
1
+ # ruff: noqa: TC003
2
+ from __future__ import annotations
3
+
4
+ from pathlib import Path
5
+
6
+ from typed_settings import Secret, load_settings, option, secret, settings
7
+
8
+ from actions.utilities import LOADER
9
+
10
+
11
+ @settings
12
+ class Settings:
13
+ key_file: Path | None = option(default=None, help="The key file")
14
+ key: Secret[str] | None = secret(default=None, help="The age identity")
15
+ new_key_file: Path | None = option(
16
+ default=None, help="The new key file for encryption"
17
+ )
18
+ new_key: Secret[str] | None = secret(
19
+ default=None, help="The new age identity for encryption"
20
+ )
21
+
22
+
23
+ SETTINGS = load_settings(Settings, [LOADER])
24
+
25
+
26
+ __all__ = ["SETTINGS", "Settings"]
@@ -6,16 +6,16 @@ echo_date() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2; }
6
6
 
7
7
  # main
8
8
  wait-for-it.sh \
9
- --host="${GITEA_HOST}" \
10
- --port="${GITEA_PORT}" \
11
- --strict \
12
- -- \
13
- echo "${GITEA_HOST}:${GITEA_PORT} is up"
9
+ --host="${GITEA_HOST}" \
10
+ --port="${GITEA_PORT}" \
11
+ --strict \
12
+ -- \
13
+ echo "${GITEA_HOST}:${GITEA_PORT} is up"
14
14
 
15
15
  if ! command -v update-ca-certificates >/dev/null 2>&1; then
16
- echo_date "Installing 'ca-certificates'..."
17
- apk update
18
- apk add --no-cache ca-certificates
16
+ echo_date "Installing 'ca-certificates'..."
17
+ apk update
18
+ apk add --no-cache ca-certificates
19
19
  fi
20
20
 
21
21
  update-ca-certificates || true
@@ -7,8 +7,11 @@ from typing import TYPE_CHECKING
7
7
 
8
8
  from requests import get
9
9
  from utilities.atomicwrites import writer
10
+ from utilities.functions import get_func_name
10
11
  from utilities.subprocess import chmod, rm_cmd, ssh, sudo_cmd
12
+ from utilities.tabulate import func_param_desc
11
13
 
14
+ from actions import __version__
12
15
  from actions.logging import LOGGER
13
16
  from actions.register_gitea_runner.constants import (
14
17
  PATH_CACHE,
@@ -17,7 +20,7 @@ from actions.register_gitea_runner.constants import (
17
20
  URL_WAIT_FOR_IT,
18
21
  )
19
22
  from actions.register_gitea_runner.settings import SETTINGS
20
- from actions.utilities import log_func_call, logged_run
23
+ from actions.utilities import logged_run
21
24
 
22
25
  if TYPE_CHECKING:
23
26
  from utilities.types import PathLike
@@ -37,19 +40,22 @@ def register_gitea_runner(
37
40
  runner_instance_name: str = SETTINGS.runner_instance_name,
38
41
  ) -> None:
39
42
  """Register against a remote instance of Gitea."""
40
- variables = [
41
- f"{ssh_user=}",
42
- f"{ssh_host=}",
43
- f"{gitea_container_user=}",
44
- f"{gitea_container_name=}",
45
- f"{runner_certificate=}",
46
- f"{runner_capacity=}",
47
- f"{runner_container_name=}",
48
- f"{gitea_host=}",
49
- f"{gitea_port=}",
50
- f"{runner_instance_name=}",
51
- ]
52
- LOGGER.info(log_func_call(register_gitea_runner, *variables))
43
+ LOGGER.info(
44
+ func_param_desc(
45
+ register_gitea_runner,
46
+ __version__,
47
+ f"{ssh_user=}",
48
+ f"{ssh_host=}",
49
+ f"{gitea_container_user=}",
50
+ f"{gitea_container_name=}",
51
+ f"{runner_certificate=}",
52
+ f"{runner_capacity=}",
53
+ f"{runner_container_name=}",
54
+ f"{gitea_host=}",
55
+ f"{gitea_port=}",
56
+ f"{runner_instance_name=}",
57
+ )
58
+ )
53
59
  token = ssh(
54
60
  ssh_user,
55
61
  ssh_host,
@@ -66,6 +72,7 @@ def register_gitea_runner(
66
72
  gitea_port=gitea_port,
67
73
  runner_instance_name=runner_instance_name,
68
74
  )
75
+ LOGGER.info("Finished running %r", get_func_name(register_gitea_runner))
69
76
 
70
77
 
71
78
  def register_against_local(
@@ -155,6 +162,8 @@ def _docker_run_act_runner_args(
155
162
  f"GITEA_RUNNER_REGISTRATION_TOKEN={token}",
156
163
  "--name",
157
164
  container_name,
165
+ "--restart",
166
+ "always",
158
167
  "--volume",
159
168
  "/var/run/docker.sock:/var/run/docker.sock",
160
169
  "--volume",