dycw-actions 0.6.4__py3-none-any.whl → 0.7.7__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.
- actions/__init__.py +1 -1
- actions/action_dicts/lib.py +8 -8
- actions/clean_dir/cli.py +0 -12
- actions/clean_dir/constants.py +7 -0
- actions/clean_dir/lib.py +1 -0
- actions/cli.py +90 -29
- actions/constants.py +5 -1
- actions/pre_commit/click.py +15 -0
- actions/{conformalize_repo → pre_commit/conformalize_repo}/cli.py +2 -14
- actions/{conformalize_repo → pre_commit/conformalize_repo}/constants.py +8 -2
- actions/{conformalize_repo → pre_commit/conformalize_repo}/lib.py +97 -313
- actions/{conformalize_repo → pre_commit/conformalize_repo}/settings.py +1 -1
- actions/pre_commit/constants.py +8 -0
- actions/pre_commit/format_requirements/cli.py +24 -0
- actions/pre_commit/format_requirements/constants.py +7 -0
- actions/pre_commit/format_requirements/lib.py +52 -0
- actions/pre_commit/replace_sequence_strs/__init__.py +1 -0
- actions/pre_commit/replace_sequence_strs/cli.py +24 -0
- actions/pre_commit/replace_sequence_strs/constants.py +7 -0
- actions/{replace_sequence_strs → pre_commit/replace_sequence_strs}/lib.py +16 -22
- actions/pre_commit/touch_empty_py/__init__.py +1 -0
- actions/pre_commit/touch_empty_py/cli.py +24 -0
- actions/pre_commit/touch_empty_py/constants.py +7 -0
- actions/pre_commit/touch_empty_py/lib.py +62 -0
- actions/pre_commit/touch_py_typed/__init__.py +1 -0
- actions/pre_commit/touch_py_typed/cli.py +24 -0
- actions/pre_commit/touch_py_typed/constants.py +7 -0
- actions/pre_commit/touch_py_typed/lib.py +72 -0
- actions/pre_commit/update_requirements/__init__.py +1 -0
- actions/pre_commit/update_requirements/classes.py +130 -0
- actions/pre_commit/update_requirements/cli.py +24 -0
- actions/pre_commit/update_requirements/constants.py +7 -0
- actions/pre_commit/update_requirements/lib.py +140 -0
- actions/pre_commit/utilities.py +386 -0
- actions/publish_package/cli.py +7 -19
- actions/publish_package/constants.py +7 -0
- actions/publish_package/lib.py +3 -3
- actions/py.typed +0 -0
- actions/random_sleep/cli.py +6 -15
- actions/random_sleep/constants.py +7 -0
- actions/register_gitea_runner/__init__.py +1 -0
- actions/register_gitea_runner/cli.py +32 -0
- actions/register_gitea_runner/configs/config.yml +110 -0
- actions/register_gitea_runner/configs/entrypoint.sh +23 -0
- actions/register_gitea_runner/constants.py +23 -0
- actions/register_gitea_runner/lib.py +289 -0
- actions/register_gitea_runner/settings.py +33 -0
- actions/run_hooks/cli.py +3 -15
- actions/run_hooks/constants.py +7 -0
- actions/run_hooks/lib.py +2 -2
- actions/setup_cronjob/cli.py +0 -12
- actions/setup_cronjob/constants.py +5 -1
- actions/tag_commit/cli.py +7 -19
- actions/tag_commit/constants.py +7 -0
- actions/tag_commit/lib.py +8 -8
- actions/types.py +4 -1
- actions/utilities.py +68 -14
- {dycw_actions-0.6.4.dist-info → dycw_actions-0.7.7.dist-info}/METADATA +5 -3
- dycw_actions-0.7.7.dist-info/RECORD +84 -0
- actions/format_requirements/cli.py +0 -37
- actions/format_requirements/lib.py +0 -121
- actions/publish_package/doc.py +0 -6
- actions/random_sleep/doc.py +0 -6
- actions/replace_sequence_strs/cli.py +0 -37
- actions/run_hooks/doc.py +0 -6
- actions/tag_commit/doc.py +0 -6
- dycw_actions-0.6.4.dist-info/RECORD +0 -56
- /actions/{conformalize_repo → pre_commit}/__init__.py +0 -0
- /actions/{format_requirements → pre_commit/conformalize_repo}/__init__.py +0 -0
- /actions/{conformalize_repo → pre_commit/conformalize_repo}/configs/gitignore +0 -0
- /actions/{replace_sequence_strs → pre_commit/format_requirements}/__init__.py +0 -0
- {dycw_actions-0.6.4.dist-info → dycw_actions-0.7.7.dist-info}/WHEEL +0 -0
- {dycw_actions-0.6.4.dist-info → dycw_actions-0.7.7.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections.abc import Iterator, MutableSet
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import TYPE_CHECKING, Any, assert_never
|
|
9
|
+
|
|
10
|
+
import tomlkit
|
|
11
|
+
from libcst import Module, parse_module
|
|
12
|
+
from rich.pretty import pretty_repr
|
|
13
|
+
from tomlkit import TOMLDocument, aot, array, document, string, table
|
|
14
|
+
from tomlkit.items import AoT, Array, Table
|
|
15
|
+
from utilities.functions import ensure_class, ensure_str
|
|
16
|
+
from utilities.iterables import OneEmptyError, OneNonUniqueError, one
|
|
17
|
+
from utilities.packaging import Requirement
|
|
18
|
+
from utilities.types import PathLike
|
|
19
|
+
|
|
20
|
+
from actions.constants import YAML_INSTANCE
|
|
21
|
+
from actions.logging import LOGGER
|
|
22
|
+
from actions.types import StrDict
|
|
23
|
+
from actions.utilities import are_equal_modulo_new_line, write_text, yaml_dump
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from collections.abc import Callable, Iterable, Iterator, MutableSet
|
|
27
|
+
|
|
28
|
+
from utilities.types import PathLike
|
|
29
|
+
|
|
30
|
+
from actions.types import FuncRequirement, HasAppend, HasSetDefault, StrDict
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def ensure_aot_contains(array: AoT, /, *tables: Table) -> None:
|
|
34
|
+
for table_ in tables:
|
|
35
|
+
if table_ not in array:
|
|
36
|
+
array.append(table_)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def ensure_contains(array: HasAppend, /, *objs: Any) -> None:
|
|
40
|
+
if isinstance(array, AoT):
|
|
41
|
+
msg = f"Use {ensure_aot_contains.__name__!r} instead of {ensure_contains.__name__!r}"
|
|
42
|
+
raise TypeError(msg)
|
|
43
|
+
for obj in objs:
|
|
44
|
+
if obj not in array:
|
|
45
|
+
array.append(obj)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def ensure_contains_partial_dict(
|
|
49
|
+
container: HasAppend, partial: StrDict, /, *, extra: StrDict | None = None
|
|
50
|
+
) -> StrDict:
|
|
51
|
+
try:
|
|
52
|
+
return get_partial_dict(container, partial, skip_log=True)
|
|
53
|
+
except OneEmptyError:
|
|
54
|
+
dict_ = partial | ({} if extra is None else extra)
|
|
55
|
+
container.append(dict_)
|
|
56
|
+
return dict_
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def ensure_contains_partial_str(container: HasAppend, text: str, /) -> str:
|
|
60
|
+
try:
|
|
61
|
+
return get_partial_str(container, text, skip_log=True)
|
|
62
|
+
except OneEmptyError:
|
|
63
|
+
container.append(text)
|
|
64
|
+
return text
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def ensure_not_contains(array: Array, /, *objs: Any) -> None:
|
|
68
|
+
for obj in objs:
|
|
69
|
+
try:
|
|
70
|
+
index = next(i for i, o in enumerate(array) if o == obj)
|
|
71
|
+
except StopIteration:
|
|
72
|
+
pass
|
|
73
|
+
else:
|
|
74
|
+
del array[index]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
##
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_aot(container: HasSetDefault, key: str, /) -> AoT:
|
|
81
|
+
return ensure_class(container.setdefault(key, aot()), AoT)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_array(container: HasSetDefault, key: str, /) -> Array:
|
|
85
|
+
return ensure_class(container.setdefault(key, array()), Array)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def get_dict(container: HasSetDefault, key: str, /) -> StrDict:
|
|
89
|
+
return ensure_class(container.setdefault(key, {}), dict)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def get_list(container: HasSetDefault, key: str, /) -> list[Any]:
|
|
93
|
+
return ensure_class(container.setdefault(key, []), list)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_table(container: HasSetDefault, key: str, /) -> Table:
|
|
97
|
+
return ensure_class(container.setdefault(key, table()), Table)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
##
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def get_partial_dict(
|
|
104
|
+
iterable: Iterable[Any], dict_: StrDict, /, *, skip_log: bool = False
|
|
105
|
+
) -> StrDict:
|
|
106
|
+
try:
|
|
107
|
+
return one(i for i in iterable if is_partial_dict(dict_, i))
|
|
108
|
+
except OneEmptyError:
|
|
109
|
+
if not skip_log:
|
|
110
|
+
LOGGER.exception(
|
|
111
|
+
"Expected %s to contain %s (as a partial)",
|
|
112
|
+
pretty_repr(iterable),
|
|
113
|
+
pretty_repr(dict_),
|
|
114
|
+
)
|
|
115
|
+
raise
|
|
116
|
+
except OneNonUniqueError as error:
|
|
117
|
+
LOGGER.exception(
|
|
118
|
+
"Expected %s to contain %s uniquely (as a partial); got %s, %s and perhaps more",
|
|
119
|
+
pretty_repr(iterable),
|
|
120
|
+
pretty_repr(dict_),
|
|
121
|
+
pretty_repr(error.first),
|
|
122
|
+
pretty_repr(error.second),
|
|
123
|
+
)
|
|
124
|
+
raise
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def is_partial_dict(obj: Any, dict_: StrDict, /) -> bool:
|
|
128
|
+
if not isinstance(obj, dict):
|
|
129
|
+
return False
|
|
130
|
+
results: dict[str, bool] = {}
|
|
131
|
+
for key, obj_value in obj.items():
|
|
132
|
+
try:
|
|
133
|
+
dict_value = dict_[key]
|
|
134
|
+
except KeyError:
|
|
135
|
+
results[key] = False
|
|
136
|
+
else:
|
|
137
|
+
if isinstance(obj_value, dict) and isinstance(dict_value, dict):
|
|
138
|
+
results[key] = is_partial_dict(obj_value, dict_value)
|
|
139
|
+
else:
|
|
140
|
+
results[key] = obj_value == dict_value
|
|
141
|
+
return all(results.values())
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
##
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def get_partial_str(
|
|
148
|
+
iterable: Iterable[Any], text: str, /, *, skip_log: bool = False
|
|
149
|
+
) -> str:
|
|
150
|
+
try:
|
|
151
|
+
return one(i for i in iterable if is_partial_str(i, text))
|
|
152
|
+
except OneEmptyError:
|
|
153
|
+
if not skip_log:
|
|
154
|
+
LOGGER.exception(
|
|
155
|
+
"Expected %s to contain %s (as a partial)",
|
|
156
|
+
pretty_repr(iterable),
|
|
157
|
+
pretty_repr(text),
|
|
158
|
+
)
|
|
159
|
+
raise
|
|
160
|
+
except OneNonUniqueError as error:
|
|
161
|
+
LOGGER.exception(
|
|
162
|
+
"Expected %s to contain %s uniquely (as a partial); got %s, %s and perhaps more",
|
|
163
|
+
pretty_repr(iterable),
|
|
164
|
+
pretty_repr(text),
|
|
165
|
+
pretty_repr(error.first),
|
|
166
|
+
pretty_repr(error.second),
|
|
167
|
+
)
|
|
168
|
+
raise
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def is_partial_str(obj: Any, text: str, /) -> bool:
|
|
172
|
+
return isinstance(obj, str) and (text in obj)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
##
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def get_pyproject_dependencies(doc: TOMLDocument, /) -> PyProjectDependencies:
|
|
179
|
+
out = PyProjectDependencies()
|
|
180
|
+
if (project_key := "project") in doc:
|
|
181
|
+
project = get_table(doc, project_key)
|
|
182
|
+
if (dep_key := "dependencies") in project:
|
|
183
|
+
out.dependencies = get_array(project, dep_key)
|
|
184
|
+
if (opt_dep_key := "optional-dependencies") in project:
|
|
185
|
+
opt_dependencies = get_table(project, opt_dep_key)
|
|
186
|
+
out.opt_dependencies = {}
|
|
187
|
+
for key in opt_dependencies:
|
|
188
|
+
out.opt_dependencies[ensure_str(key)] = get_array(opt_dependencies, key)
|
|
189
|
+
if (dep_grps_key := "dependency-groups") in doc:
|
|
190
|
+
dep_grps = get_table(doc, dep_grps_key)
|
|
191
|
+
out.dep_groups = {}
|
|
192
|
+
for key in dep_grps:
|
|
193
|
+
out.dep_groups[ensure_str(key)] = get_array(dep_grps, key)
|
|
194
|
+
return out
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@dataclass(kw_only=True, slots=True)
|
|
198
|
+
class PyProjectDependencies:
|
|
199
|
+
dependencies: Array | None = None
|
|
200
|
+
opt_dependencies: dict[str, Array] | None = None
|
|
201
|
+
dep_groups: dict[str, Array] | None = None
|
|
202
|
+
|
|
203
|
+
def apply(self, func: FuncRequirement, /) -> None:
|
|
204
|
+
if (deps := self.dependencies) is not None:
|
|
205
|
+
self._apply_to_array(deps, func)
|
|
206
|
+
if (opt_depedencies := self.opt_dependencies) is not None:
|
|
207
|
+
for deps in opt_depedencies.values():
|
|
208
|
+
self._apply_to_array(deps, func)
|
|
209
|
+
if (dep_grps := self.dep_groups) is not None:
|
|
210
|
+
for deps in dep_grps.values():
|
|
211
|
+
self._apply_to_array(deps, func)
|
|
212
|
+
|
|
213
|
+
def _apply_to_array(self, array: Array, func: FuncRequirement, /) -> None:
|
|
214
|
+
strs = list(map(ensure_str, array))
|
|
215
|
+
reqs = list(map(Requirement, strs))
|
|
216
|
+
results = list(map(func, reqs))
|
|
217
|
+
new_strs = list(map(str, results))
|
|
218
|
+
strings = list(map(string, new_strs))
|
|
219
|
+
array.clear()
|
|
220
|
+
ensure_contains(array, *strings)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
##
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@contextmanager
|
|
227
|
+
def yield_json_dict(
|
|
228
|
+
path: PathLike, /, *, modifications: MutableSet[Path] | None = None
|
|
229
|
+
) -> Iterator[StrDict]:
|
|
230
|
+
with yield_mutable_write_context(
|
|
231
|
+
path, json.loads, dict, json.dumps, modifications=modifications
|
|
232
|
+
) as dict_:
|
|
233
|
+
yield dict_
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
##
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@contextmanager
|
|
240
|
+
def yield_python_file(
|
|
241
|
+
path: PathLike, /, *, modifications: MutableSet[Path] | None = None
|
|
242
|
+
) -> Iterator[WriteContext[Module]]:
|
|
243
|
+
with yield_immutable_write_context(
|
|
244
|
+
path,
|
|
245
|
+
parse_module,
|
|
246
|
+
lambda: Module(body=[]),
|
|
247
|
+
lambda module: module.code,
|
|
248
|
+
modifications=modifications,
|
|
249
|
+
) as context:
|
|
250
|
+
yield context
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
##
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
@contextmanager
|
|
257
|
+
def yield_text_file(
|
|
258
|
+
path: PathLike, /, *, modifications: MutableSet[Path] | None = None
|
|
259
|
+
) -> Iterator[WriteContext[str]]:
|
|
260
|
+
with yield_immutable_write_context(
|
|
261
|
+
path, str, lambda: "", str, modifications=modifications
|
|
262
|
+
) as context:
|
|
263
|
+
yield context
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
##
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@contextmanager
|
|
270
|
+
def yield_toml_doc(
|
|
271
|
+
path: PathLike, /, *, modifications: MutableSet[Path] | None = None
|
|
272
|
+
) -> Iterator[TOMLDocument]:
|
|
273
|
+
with yield_mutable_write_context(
|
|
274
|
+
path, tomlkit.parse, document, tomlkit.dumps, modifications=modifications
|
|
275
|
+
) as doc:
|
|
276
|
+
yield doc
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
##
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
@contextmanager
|
|
283
|
+
def yield_mutable_write_context[T](
|
|
284
|
+
path: PathLike,
|
|
285
|
+
loads: Callable[[str], T],
|
|
286
|
+
get_default: Callable[[], T],
|
|
287
|
+
dumps: Callable[[T], str],
|
|
288
|
+
/,
|
|
289
|
+
*,
|
|
290
|
+
modifications: MutableSet[Path] | None = None,
|
|
291
|
+
) -> Iterator[T]:
|
|
292
|
+
with yield_immutable_write_context(
|
|
293
|
+
path, loads, get_default, dumps, modifications=modifications
|
|
294
|
+
) as context:
|
|
295
|
+
yield context.output
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
##
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
@dataclass(kw_only=True, slots=True)
|
|
302
|
+
class WriteContext[T]:
|
|
303
|
+
input: T
|
|
304
|
+
output: T
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
@contextmanager
|
|
308
|
+
def yield_immutable_write_context[T](
|
|
309
|
+
path: PathLike,
|
|
310
|
+
loads: Callable[[str], T],
|
|
311
|
+
get_default: Callable[[], T],
|
|
312
|
+
dumps: Callable[[T], str],
|
|
313
|
+
/,
|
|
314
|
+
*,
|
|
315
|
+
modifications: MutableSet[Path] | None = None,
|
|
316
|
+
) -> Iterator[WriteContext[T]]:
|
|
317
|
+
try:
|
|
318
|
+
current = Path(path).read_text()
|
|
319
|
+
except FileNotFoundError:
|
|
320
|
+
current = None
|
|
321
|
+
input_ = get_default()
|
|
322
|
+
output = get_default()
|
|
323
|
+
else:
|
|
324
|
+
input_ = loads(current)
|
|
325
|
+
output = loads(current)
|
|
326
|
+
yield (context := WriteContext(input=input_, output=output))
|
|
327
|
+
if current is None:
|
|
328
|
+
write_text(path, dumps(context.output), modifications=modifications)
|
|
329
|
+
else:
|
|
330
|
+
match context.output, loads(current):
|
|
331
|
+
case Module() as output_module, Module() as current_module:
|
|
332
|
+
if not are_equal_modulo_new_line(
|
|
333
|
+
output_module.code, current_module.code
|
|
334
|
+
):
|
|
335
|
+
write_text(path, dumps(output_module), modifications=modifications)
|
|
336
|
+
case TOMLDocument() as output_doc, TOMLDocument() as current_doc:
|
|
337
|
+
if not (output_doc == current_doc): # noqa: SIM201
|
|
338
|
+
write_text(path, dumps(output_doc), modifications=modifications)
|
|
339
|
+
case str() as output_text, str() as current_text:
|
|
340
|
+
if not are_equal_modulo_new_line(output_text, current_text):
|
|
341
|
+
write_text(path, dumps(output_text), modifications=modifications)
|
|
342
|
+
case output_obj, current_obj:
|
|
343
|
+
if output_obj != current_obj:
|
|
344
|
+
write_text(path, dumps(output_obj), modifications=modifications)
|
|
345
|
+
case never:
|
|
346
|
+
assert_never(never)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
##
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
@contextmanager
|
|
353
|
+
def yield_yaml_dict(
|
|
354
|
+
path: PathLike, /, *, modifications: MutableSet[Path] | None = None
|
|
355
|
+
) -> Iterator[StrDict]:
|
|
356
|
+
with yield_mutable_write_context(
|
|
357
|
+
path, YAML_INSTANCE.load, dict, yaml_dump, modifications=modifications
|
|
358
|
+
) as dict_:
|
|
359
|
+
yield dict_
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
__all__ = [
|
|
363
|
+
"PyProjectDependencies",
|
|
364
|
+
"ensure_aot_contains",
|
|
365
|
+
"ensure_contains",
|
|
366
|
+
"ensure_contains_partial_dict",
|
|
367
|
+
"ensure_contains_partial_str",
|
|
368
|
+
"ensure_not_contains",
|
|
369
|
+
"get_aot",
|
|
370
|
+
"get_array",
|
|
371
|
+
"get_dict",
|
|
372
|
+
"get_list",
|
|
373
|
+
"get_partial_dict",
|
|
374
|
+
"get_partial_str",
|
|
375
|
+
"get_pyproject_dependencies",
|
|
376
|
+
"get_table",
|
|
377
|
+
"is_partial_dict",
|
|
378
|
+
"is_partial_str",
|
|
379
|
+
"yield_immutable_write_context",
|
|
380
|
+
"yield_json_dict",
|
|
381
|
+
"yield_mutable_write_context",
|
|
382
|
+
"yield_python_file",
|
|
383
|
+
"yield_text_file",
|
|
384
|
+
"yield_toml_doc",
|
|
385
|
+
"yield_yaml_dict",
|
|
386
|
+
]
|
actions/publish_package/cli.py
CHANGED
|
@@ -1,38 +1,26 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from rich.pretty import pretty_repr
|
|
4
3
|
from typed_settings import click_options
|
|
5
4
|
from utilities.logging import basic_config
|
|
6
5
|
from utilities.os import is_pytest
|
|
7
|
-
from utilities.text import strip_and_dedent
|
|
8
6
|
|
|
9
|
-
from actions import __version__
|
|
10
7
|
from actions.logging import LOGGER
|
|
11
8
|
from actions.publish_package.lib import publish_package
|
|
12
9
|
from actions.publish_package.settings import Settings
|
|
13
10
|
from actions.utilities import LOADER
|
|
14
11
|
|
|
15
12
|
|
|
16
|
-
@click_options(Settings, [LOADER], show_envvars_in_help=True
|
|
17
|
-
def publish_package_sub_cmd(
|
|
13
|
+
@click_options(Settings, [LOADER], show_envvars_in_help=True)
|
|
14
|
+
def publish_package_sub_cmd(settings: Settings, /) -> None:
|
|
18
15
|
if is_pytest():
|
|
19
16
|
return
|
|
20
17
|
basic_config(obj=LOGGER)
|
|
21
|
-
LOGGER.info(
|
|
22
|
-
strip_and_dedent("""
|
|
23
|
-
Running '%s' (version %s) with settings:
|
|
24
|
-
%s
|
|
25
|
-
"""),
|
|
26
|
-
publish_package.__name__,
|
|
27
|
-
__version__,
|
|
28
|
-
pretty_repr(publish),
|
|
29
|
-
)
|
|
30
18
|
publish_package(
|
|
31
|
-
username=
|
|
32
|
-
password=
|
|
33
|
-
publish_url=
|
|
34
|
-
trusted_publishing=
|
|
35
|
-
native_tls=
|
|
19
|
+
username=settings.username,
|
|
20
|
+
password=settings.password,
|
|
21
|
+
publish_url=settings.publish_url,
|
|
22
|
+
trusted_publishing=settings.trusted_publishing,
|
|
23
|
+
native_tls=settings.native_tls,
|
|
36
24
|
)
|
|
37
25
|
|
|
38
26
|
|
actions/publish_package/lib.py
CHANGED
|
@@ -8,7 +8,7 @@ from utilities.text import strip_and_dedent
|
|
|
8
8
|
from actions import __version__
|
|
9
9
|
from actions.logging import LOGGER
|
|
10
10
|
from actions.publish_package.settings import SETTINGS
|
|
11
|
-
from actions.utilities import
|
|
11
|
+
from actions.utilities import logged_run
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
14
|
from typed_settings import Secret
|
|
@@ -40,8 +40,8 @@ def publish_package(
|
|
|
40
40
|
native_tls,
|
|
41
41
|
)
|
|
42
42
|
with TemporaryDirectory() as temp:
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
logged_run("uv", "build", "--out-dir", str(temp), "--wheel", "--clear")
|
|
44
|
+
logged_run(
|
|
45
45
|
"uv",
|
|
46
46
|
"publish",
|
|
47
47
|
*([] if username is None else ["--username", username]),
|
actions/py.typed
ADDED
|
File without changes
|
actions/random_sleep/cli.py
CHANGED
|
@@ -1,34 +1,25 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from rich.pretty import pretty_repr
|
|
4
3
|
from typed_settings import click_options
|
|
5
4
|
from utilities.logging import basic_config
|
|
6
5
|
from utilities.os import is_pytest
|
|
7
|
-
from utilities.text import strip_and_dedent
|
|
8
6
|
|
|
9
|
-
from actions import __version__
|
|
10
7
|
from actions.logging import LOGGER
|
|
11
8
|
from actions.random_sleep.lib import random_sleep
|
|
12
9
|
from actions.random_sleep.settings import Settings
|
|
13
10
|
from actions.utilities import LOADER
|
|
14
11
|
|
|
15
12
|
|
|
16
|
-
@click_options(Settings, [LOADER], show_envvars_in_help=True
|
|
17
|
-
def random_sleep_sub_cmd(
|
|
13
|
+
@click_options(Settings, [LOADER], show_envvars_in_help=True)
|
|
14
|
+
def random_sleep_sub_cmd(settings: Settings, /) -> None:
|
|
18
15
|
if is_pytest():
|
|
19
16
|
return
|
|
20
17
|
basic_config(obj=LOGGER)
|
|
21
|
-
LOGGER.info(
|
|
22
|
-
strip_and_dedent("""
|
|
23
|
-
Running '%s' (version %s) with settings:
|
|
24
|
-
%s
|
|
25
|
-
"""),
|
|
26
|
-
random_sleep.__name__,
|
|
27
|
-
__version__,
|
|
28
|
-
pretty_repr(sleep),
|
|
29
|
-
)
|
|
30
18
|
random_sleep(
|
|
31
|
-
min_=
|
|
19
|
+
min_=settings.min,
|
|
20
|
+
max_=settings.max,
|
|
21
|
+
step=settings.step,
|
|
22
|
+
log_freq=settings.log_freq,
|
|
32
23
|
)
|
|
33
24
|
|
|
34
25
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typed_settings import click_options
|
|
4
|
+
from utilities.logging import basic_config
|
|
5
|
+
from utilities.os import is_pytest
|
|
6
|
+
|
|
7
|
+
from actions.logging import LOGGER
|
|
8
|
+
from actions.register_gitea_runner.lib import register_gitea_runner
|
|
9
|
+
from actions.register_gitea_runner.settings import Settings
|
|
10
|
+
from actions.utilities import LOADER
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click_options(Settings, [LOADER], show_envvars_in_help=True)
|
|
14
|
+
def register_gitea_runner_sub_cmd(settings: Settings, /) -> None:
|
|
15
|
+
if is_pytest():
|
|
16
|
+
return
|
|
17
|
+
basic_config(obj=LOGGER)
|
|
18
|
+
register_gitea_runner(
|
|
19
|
+
ssh_user=settings.ssh_user,
|
|
20
|
+
ssh_host=settings.ssh_host,
|
|
21
|
+
gitea_container_user=settings.gitea_container_user,
|
|
22
|
+
gitea_container_name=settings.gitea_container_name,
|
|
23
|
+
runner_certificate=settings.runner_certificate,
|
|
24
|
+
runner_capacity=settings.runner_capacity,
|
|
25
|
+
runner_container_name=settings.runner_container_name,
|
|
26
|
+
gitea_host=settings.gitea_host,
|
|
27
|
+
gitea_port=settings.gitea_port,
|
|
28
|
+
runner_instance_name=settings.runner_instance_name,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
__all__ = ["register_gitea_runner_sub_cmd"]
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Example configuration file, it's safe to copy this as the default config file without any modification.
|
|
2
|
+
|
|
3
|
+
# You don't have to copy this file to your instance,
|
|
4
|
+
# just run `./act_runner generate-config > config.yaml` to generate a config file.
|
|
5
|
+
|
|
6
|
+
log:
|
|
7
|
+
# The level of logging, can be trace, debug, info, warn, error, fatal
|
|
8
|
+
level: info
|
|
9
|
+
|
|
10
|
+
runner:
|
|
11
|
+
# Where to store the registration result.
|
|
12
|
+
file: .runner
|
|
13
|
+
# Execute how many tasks concurrently at the same time.
|
|
14
|
+
capacity: ${CAPACITY}
|
|
15
|
+
# Extra environment variables to run jobs.
|
|
16
|
+
envs:
|
|
17
|
+
A_TEST_ENV_NAME_1: a_test_env_value_1
|
|
18
|
+
A_TEST_ENV_NAME_2: a_test_env_value_2
|
|
19
|
+
# Extra environment variables to run jobs from a file.
|
|
20
|
+
# It will be ignored if it's empty or the file doesn't exist.
|
|
21
|
+
env_file: .env
|
|
22
|
+
# The timeout for a job to be finished.
|
|
23
|
+
# Please note that the Gitea instance also has a timeout (3h by default) for the job.
|
|
24
|
+
# So the job could be stopped by the Gitea instance if it's timeout is shorter than this.
|
|
25
|
+
timeout: 3h
|
|
26
|
+
# The timeout for the runner to wait for running jobs to finish when shutting down.
|
|
27
|
+
# Any running jobs that haven't finished after this timeout will be cancelled.
|
|
28
|
+
shutdown_timeout: 0s
|
|
29
|
+
# Whether skip verifying the TLS certificate of the Gitea instance.
|
|
30
|
+
insecure: false
|
|
31
|
+
# The timeout for fetching the job from the Gitea instance.
|
|
32
|
+
fetch_timeout: 5s
|
|
33
|
+
# The interval for fetching the job from the Gitea instance.
|
|
34
|
+
fetch_interval: 2s
|
|
35
|
+
# The github_mirror of a runner is used to specify the mirror address of the github that pulls the action repository.
|
|
36
|
+
# It works when something like `uses: actions/checkout@v4` is used and DEFAULT_ACTIONS_URL is set to github,
|
|
37
|
+
# and github_mirror is not empty. In this case,
|
|
38
|
+
# it replaces https://github.com with the value here, which is useful for some special network environments.
|
|
39
|
+
github_mirror: ""
|
|
40
|
+
# The labels of a runner are used to determine which jobs the runner can run, and how to run them.
|
|
41
|
+
# Like: "macos-arm64:host" or "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
|
|
42
|
+
# Find more images provided by Gitea at https://gitea.com/docker.gitea.com/runner-images .
|
|
43
|
+
# If it's empty when registering, it will ask for inputting labels.
|
|
44
|
+
# If it's empty when execute `daemon`, will use labels in `.runner` file.
|
|
45
|
+
labels:
|
|
46
|
+
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
|
|
47
|
+
- "ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
|
|
48
|
+
- "ubuntu-20.04:docker://docker.gitea.com/runner-images:ubuntu-20.04"
|
|
49
|
+
|
|
50
|
+
cache:
|
|
51
|
+
# Enable cache server to use actions/cache.
|
|
52
|
+
enabled: true
|
|
53
|
+
# The directory to store the cache data.
|
|
54
|
+
# If it's empty, the cache data will be stored in ${HOME}/.cache/actcache.
|
|
55
|
+
dir: ""
|
|
56
|
+
# The host of the cache server.
|
|
57
|
+
# It's not for the address to listen, but the address to connect from job containers.
|
|
58
|
+
# So 0.0.0.0 is a bad choice, leave it empty to detect automatically.
|
|
59
|
+
host: ""
|
|
60
|
+
# The port of the cache server.
|
|
61
|
+
# 0 means to use a random available port.
|
|
62
|
+
port: 0
|
|
63
|
+
# The external cache server URL. Valid only when enable is true.
|
|
64
|
+
# If it's specified, act_runner will use this URL as the ACTIONS_CACHE_URL rather than start a server by itself.
|
|
65
|
+
# The URL should generally end with "/".
|
|
66
|
+
external_server: ""
|
|
67
|
+
|
|
68
|
+
container:
|
|
69
|
+
# Specifies the network to which the container will connect.
|
|
70
|
+
# Could be host, bridge or the name of a custom network.
|
|
71
|
+
# If it's empty, act_runner will create a network automatically.
|
|
72
|
+
network: ""
|
|
73
|
+
# Whether to use privileged mode or not when launching task containers (privileged mode is required for Docker-in-Docker).
|
|
74
|
+
privileged: false
|
|
75
|
+
# And other options to be used when the container is started (eg, --add-host=my.gitea.url:host-gateway).
|
|
76
|
+
options: "-v ${CERTIFICATE}:/usr/local/share/ca-certificates/root.crt:ro"
|
|
77
|
+
# The parent directory of a job's working directory.
|
|
78
|
+
# NOTE: There is no need to add the first '/' of the path as act_runner will add it automatically.
|
|
79
|
+
# If the path starts with '/', the '/' will be trimmed.
|
|
80
|
+
# For example, if the parent directory is /path/to/my/dir, workdir_parent should be path/to/my/dir
|
|
81
|
+
# If it's empty, /workspace will be used.
|
|
82
|
+
workdir_parent:
|
|
83
|
+
# Volumes (including bind mounts) can be mounted to containers. Glob syntax is supported, see https://github.com/gobwas/glob
|
|
84
|
+
# You can specify multiple volumes. If the sequence is empty, no volumes can be mounted.
|
|
85
|
+
# For example, if you only allow containers to mount the `data` volume and all the json files in `/src`, you should change the config to:
|
|
86
|
+
# valid_volumes:
|
|
87
|
+
# - data
|
|
88
|
+
# - /src/*.json
|
|
89
|
+
# If you want to allow any volume, please use the following configuration:
|
|
90
|
+
# valid_volumes:
|
|
91
|
+
# - '**'
|
|
92
|
+
valid_volumes: ["**"]
|
|
93
|
+
# overrides the docker client host with the specified one.
|
|
94
|
+
# If it's empty, act_runner will find an available docker host automatically.
|
|
95
|
+
# If it's "-", act_runner will find an available docker host automatically, but the docker host won't be mounted to the job containers and service containers.
|
|
96
|
+
# If it's not empty or "-", the specified docker host will be used. An error will be returned if it doesn't work.
|
|
97
|
+
docker_host: ""
|
|
98
|
+
# Pull docker image(s) even if already present
|
|
99
|
+
force_pull: true
|
|
100
|
+
# Rebuild docker image(s) even if already present
|
|
101
|
+
force_rebuild: false
|
|
102
|
+
# Always require a reachable docker daemon, even if not required by act_runner
|
|
103
|
+
require_docker: false
|
|
104
|
+
# Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or act_runner
|
|
105
|
+
docker_timeout: 0s
|
|
106
|
+
|
|
107
|
+
host:
|
|
108
|
+
# The parent directory of a job's working directory.
|
|
109
|
+
# If it's empty, ${HOME}/.cache/act/ will be used.
|
|
110
|
+
workdir_parent:
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
set -euxo
|
|
3
|
+
|
|
4
|
+
# echo
|
|
5
|
+
echo_date() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2; }
|
|
6
|
+
|
|
7
|
+
# main
|
|
8
|
+
wait-for-it.sh \
|
|
9
|
+
--host="${GITEA_HOST}" \
|
|
10
|
+
--port="${GITEA_PORT}" \
|
|
11
|
+
--strict \
|
|
12
|
+
-- \
|
|
13
|
+
echo "${GITEA_HOST}:${GITEA_PORT} is up"
|
|
14
|
+
|
|
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
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
update-ca-certificates || true
|
|
22
|
+
|
|
23
|
+
exec /sbin/tini -- run.sh
|