dycw-actions 0.7.1__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 CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.7.1"
3
+ __version__ = "0.7.7"
actions/clean_dir/lib.py CHANGED
@@ -17,6 +17,7 @@ if TYPE_CHECKING:
17
17
 
18
18
 
19
19
  def clean_dir(*, dir_: PathLike = SETTINGS.dir) -> None:
20
+ """Clean a directory."""
20
21
  LOGGER.info(
21
22
  strip_and_dedent("""
22
23
  Running '%s' (version %s) with settings:
actions/cli.py CHANGED
@@ -42,6 +42,11 @@ from actions.publish_package.constants import (
42
42
  )
43
43
  from actions.random_sleep.cli import random_sleep_sub_cmd
44
44
  from actions.random_sleep.constants import RANDOM_SLEEP_DOCSTRING, RANDOM_SLEEP_SUB_CMD
45
+ from actions.register_gitea_runner.cli import register_gitea_runner_sub_cmd
46
+ from actions.register_gitea_runner.constants import (
47
+ REGISTER_GITEA_RUNNER_DOCSTRING,
48
+ REGISTER_GITEA_RUNNER_SUB_CMD,
49
+ )
45
50
  from actions.run_hooks.cli import run_hooks_sub_cmd
46
51
  from actions.run_hooks.constants import RUN_HOOKS_DOCSTRING, RUN_HOOKS_SUB_CMD
47
52
  from actions.setup_cronjob.cli import setup_cronjob_sub_cmd
@@ -69,6 +74,11 @@ _ = _main.command(name=RUN_HOOKS_SUB_CMD, help=RUN_HOOKS_DOCSTRING, **CONTEXT_SE
69
74
  _ = _main.command(
70
75
  name=RANDOM_SLEEP_SUB_CMD, help=RANDOM_SLEEP_DOCSTRING, **CONTEXT_SETTINGS
71
76
  )(random_sleep_sub_cmd)
77
+ _ = _main.command(
78
+ name=REGISTER_GITEA_RUNNER_SUB_CMD,
79
+ help=REGISTER_GITEA_RUNNER_DOCSTRING,
80
+ **CONTEXT_SETTINGS,
81
+ )(register_gitea_runner_sub_cmd)
72
82
  _ = _main.command(
73
83
  name=SETUP_CRONJOB_SUB_CMD, help=SETUP_CRONJOB_DOCSTRING, **CONTEXT_SETTINGS
74
84
  )(setup_cronjob_sub_cmd)
actions/constants.py CHANGED
@@ -2,9 +2,13 @@ from __future__ import annotations
2
2
 
3
3
  from ruamel.yaml import YAML
4
4
  from utilities.importlib import files
5
+ from utilities.pathlib import get_repo_root
6
+ from xdg_base_dirs import xdg_cache_home
5
7
 
6
8
  PATH_ACTIONS = files(anchor="actions")
9
+ PATH_CACHE = xdg_cache_home() / "actions"
10
+ PATH_THROTTLE_CACHE = PATH_CACHE / "throttle" / get_repo_root().name
7
11
  YAML_INSTANCE = YAML()
8
12
 
9
13
 
10
- __all__ = ["PATH_ACTIONS", "YAML_INSTANCE"]
14
+ __all__ = ["PATH_ACTIONS", "PATH_CACHE", "PATH_THROTTLE_CACHE", "YAML_INSTANCE"]
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import sys
4
4
  from contextlib import contextmanager, suppress
5
+ from hashlib import blake2b
5
6
  from itertools import product
6
7
  from pathlib import Path
7
8
  from re import MULTILINE, escape, search, sub
@@ -15,14 +16,12 @@ from ruamel.yaml.scalarstring import LiteralScalarString
15
16
  from tomlkit import TOMLDocument, table
16
17
  from tomlkit.exceptions import NonExistentKey
17
18
  from utilities.inflect import counted_noun
18
- from utilities.pathlib import get_repo_root
19
19
  from utilities.re import extract_groups
20
20
  from utilities.subprocess import ripgrep
21
21
  from utilities.text import repr_str, strip_and_dedent
22
+ from utilities.throttle import throttle
22
23
  from utilities.version import ParseVersionError, Version, parse_version
23
- from utilities.whenever import HOUR, get_now
24
- from whenever import ZonedDateTime
25
- from xdg_base_dirs import xdg_cache_home
24
+ from utilities.whenever import HOUR
26
25
 
27
26
  from actions import __version__
28
27
  from actions.action_dicts.lib import (
@@ -33,7 +32,7 @@ from actions.action_dicts.lib import (
33
32
  run_action_ruff_dict,
34
33
  run_action_tag_dict,
35
34
  )
36
- from actions.constants import YAML_INSTANCE
35
+ from actions.constants import PATH_THROTTLE_CACHE, YAML_INSTANCE
37
36
  from actions.logging import LOGGER
38
37
  from actions.pre_commit.conformalize_repo.constants import (
39
38
  ACTIONS_URL,
@@ -67,6 +66,7 @@ from actions.pre_commit.replace_sequence_strs.constants import (
67
66
  )
68
67
  from actions.pre_commit.touch_empty_py.constants import TOUCH_EMPTY_PY_SUB_CMD
69
68
  from actions.pre_commit.touch_py_typed.constants import TOUCH_PY_TYPED_SUB_CMD
69
+ from actions.pre_commit.update_requirements.constants import UPDATE_REQUIREMENTS_SUB_CMD
70
70
  from actions.pre_commit.utilities import (
71
71
  ensure_aot_contains,
72
72
  ensure_contains,
@@ -83,7 +83,7 @@ from actions.pre_commit.utilities import (
83
83
  yield_toml_doc,
84
84
  yield_yaml_dict,
85
85
  )
86
- from actions.utilities import logged_run, write_text
86
+ from actions.utilities import logged_run
87
87
 
88
88
  if TYPE_CHECKING:
89
89
  from collections.abc import Iterator, MutableSet
@@ -284,6 +284,7 @@ def conformalize_repo(
284
284
  pytest__ubuntu=github__pull_request__pytest__ubuntu,
285
285
  pytest__timeout=pytest__timeout,
286
286
  python_version=python_version,
287
+ repo_name=repo_name,
287
288
  ruff=ruff,
288
289
  script=script,
289
290
  )
@@ -504,6 +505,7 @@ def add_github_pull_request_yaml(
504
505
  pytest__windows: bool = SETTINGS.github__pull_request__pytest__windows,
505
506
  pytest__timeout: int | None = SETTINGS.pytest__timeout,
506
507
  python_version: str = SETTINGS.python_version,
508
+ repo_name: str | None = SETTINGS.repo_name,
507
509
  ruff: bool = SETTINGS.github__pull_request__ruff,
508
510
  script: str | None = SETTINGS.script,
509
511
  ) -> None:
@@ -516,7 +518,7 @@ def add_github_pull_request_yaml(
516
518
  branches = get_list(pull_request, "branches")
517
519
  ensure_contains(branches, "master")
518
520
  schedule = get_list(on, "schedule")
519
- ensure_contains(schedule, {"cron": "0 0 * * *"})
521
+ ensure_contains(schedule, {"cron": get_cron_job(repo_name=repo_name)})
520
522
  jobs = get_dict(dict_, "jobs")
521
523
  if pre_commit:
522
524
  pre_commit_dict = get_dict(jobs, "pre-commit")
@@ -695,6 +697,7 @@ def add_pre_commit_config_yaml(
695
697
  )
696
698
  _add_pre_commit_config_repo(dict_, ACTIONS_URL, TOUCH_EMPTY_PY_SUB_CMD)
697
699
  _add_pre_commit_config_repo(dict_, ACTIONS_URL, TOUCH_PY_TYPED_SUB_CMD)
700
+ _add_pre_commit_config_repo(dict_, ACTIONS_URL, UPDATE_REQUIREMENTS_SUB_CMD)
698
701
  if ruff:
699
702
  _add_pre_commit_config_repo(
700
703
  dict_, RUFF_URL, "ruff-check", args=("add", ["--fix"])
@@ -1050,6 +1053,20 @@ def check_versions() -> None:
1050
1053
  ##
1051
1054
 
1052
1055
 
1056
+ def get_cron_job(*, repo_name: str | None = SETTINGS.repo_name) -> str:
1057
+ if repo_name is None:
1058
+ hour = minute = 0
1059
+ else:
1060
+ digest = blake2b(repo_name.encode(), digest_size=8).digest()
1061
+ value = int.from_bytes(digest, "big")
1062
+ minute = value % 60
1063
+ hour = (value // 60) % 24
1064
+ return f"{hour} {minute} * * *"
1065
+
1066
+
1067
+ ##
1068
+
1069
+
1053
1070
  def get_python_package_name(
1054
1071
  *,
1055
1072
  package_name: str | None = SETTINGS.package_name,
@@ -1123,23 +1140,18 @@ def run_bump_my_version(*, modifications: MutableSet[Path] | None = None) -> Non
1123
1140
  ##
1124
1141
 
1125
1142
 
1126
- def run_pre_commit_update(*, modifications: MutableSet[Path] | None = None) -> None:
1127
- cache = xdg_cache_home() / "conformalize" / get_repo_root().name
1128
- try:
1129
- text = cache.read_text()
1130
- except FileNotFoundError:
1131
- ...
1132
- else:
1133
- prev = ZonedDateTime.parse_iso(text.rstrip("\n"))
1134
- if prev >= (get_now() - 12 * HOUR):
1135
- return
1136
- write_text(cache, get_now().format_iso())
1143
+ def _run_pre_commit_update(*, modifications: MutableSet[Path] | None = None) -> None:
1137
1144
  current = PRE_COMMIT_CONFIG_YAML.read_text()
1138
1145
  logged_run("pre-commit", "autoupdate", print=True)
1139
1146
  if (modifications is not None) and (PRE_COMMIT_CONFIG_YAML.read_text() != current):
1140
1147
  modifications.add(PRE_COMMIT_CONFIG_YAML)
1141
1148
 
1142
1149
 
1150
+ run_pre_commit_update = throttle(
1151
+ delta=12 * HOUR, path=PATH_THROTTLE_CACHE / _run_pre_commit_update.__name__
1152
+ )(_run_pre_commit_update)
1153
+
1154
+
1143
1155
  ##
1144
1156
 
1145
1157
 
@@ -1278,6 +1290,7 @@ __all__ = [
1278
1290
  "add_readme_md",
1279
1291
  "add_ruff_toml",
1280
1292
  "check_versions",
1293
+ "get_cron_job",
1281
1294
  "get_python_package_name",
1282
1295
  "get_version_from_bumpversion_toml",
1283
1296
  "get_version_from_git_show",
@@ -5,8 +5,11 @@ from typing import TYPE_CHECKING
5
5
 
6
6
  from libcst import parse_statement
7
7
  from utilities.text import repr_str, strip_and_dedent
8
+ from utilities.throttle import throttle
9
+ from utilities.whenever import HOUR
8
10
 
9
11
  from actions import __version__
12
+ from actions.constants import PATH_THROTTLE_CACHE
10
13
  from actions.logging import LOGGER
11
14
  from actions.pre_commit.utilities import yield_python_file
12
15
 
@@ -17,7 +20,7 @@ if TYPE_CHECKING:
17
20
  from utilities.types import PathLike
18
21
 
19
22
 
20
- def touch_empty_py(*paths: PathLike) -> None:
23
+ def _touch_empty_py(*paths: PathLike) -> None:
21
24
  LOGGER.info(
22
25
  strip_and_dedent("""
23
26
  Running '%s' (version %s) with settings:
@@ -38,6 +41,11 @@ def touch_empty_py(*paths: PathLike) -> None:
38
41
  sys.exit(1)
39
42
 
40
43
 
44
+ touch_empty_py = throttle(
45
+ delta=12 * HOUR, path=PATH_THROTTLE_CACHE / _touch_empty_py.__name__
46
+ )(_touch_empty_py)
47
+
48
+
41
49
  def _format_path(
42
50
  path: PathLike, /, *, modifications: MutableSet[Path] | None = None
43
51
  ) -> None:
@@ -6,8 +6,11 @@ from typing import TYPE_CHECKING
6
6
 
7
7
  from utilities.iterables import one
8
8
  from utilities.text import repr_str, strip_and_dedent
9
+ from utilities.throttle import throttle
10
+ from utilities.whenever import HOUR
9
11
 
10
12
  from actions import __version__
13
+ from actions.constants import PATH_THROTTLE_CACHE
11
14
  from actions.logging import LOGGER
12
15
 
13
16
  if TYPE_CHECKING:
@@ -16,7 +19,7 @@ if TYPE_CHECKING:
16
19
  from utilities.types import PathLike
17
20
 
18
21
 
19
- def touch_py_typed(*paths: PathLike) -> None:
22
+ def _touch_py_typed(*paths: PathLike) -> None:
20
23
  LOGGER.info(
21
24
  strip_and_dedent("""
22
25
  Running '%s' (version %s) with settings:
@@ -37,6 +40,11 @@ def touch_py_typed(*paths: PathLike) -> None:
37
40
  sys.exit(1)
38
41
 
39
42
 
43
+ touch_py_typed = throttle(
44
+ delta=12 * HOUR, path=PATH_THROTTLE_CACHE / _touch_py_typed.__name__
45
+ )(_touch_py_typed)
46
+
47
+
40
48
  def _format_path(
41
49
  path: PathLike, /, *, modifications: MutableSet[Path] | None = None
42
50
  ) -> None:
@@ -1,8 +1,10 @@
1
+ # ruff: noqa: TC003
1
2
  from __future__ import annotations
2
3
 
3
4
  import re
4
5
  from dataclasses import dataclass, field, replace
5
6
  from functools import total_ordering
7
+ from pathlib import Path
6
8
  from typing import Any, Self, override
7
9
 
8
10
  from pydantic import BaseModel
@@ -22,6 +24,15 @@ type Version2or3 = Version2 | Version3
22
24
  type VersionSet = dict[str, Version2or3]
23
25
 
24
26
 
27
+ ##
28
+
29
+
30
+ class PipListOutput(BaseModel):
31
+ name: str
32
+ version: str
33
+ editable_project_location: Path | None = None
34
+
35
+
25
36
  class PipListOutdatedOutput(BaseModel):
26
37
  name: str
27
38
  version: str
@@ -29,6 +40,10 @@ class PipListOutdatedOutput(BaseModel):
29
40
  latest_filetype: str
30
41
 
31
42
 
43
+ _ = PipListOutput.model_rebuild()
44
+ _ = PipListOutdatedOutput.model_rebuild()
45
+
46
+
32
47
  ##
33
48
 
34
49
 
@@ -100,11 +115,9 @@ def parse_version2(version: str, /) -> Version2:
100
115
  _PARSE_VERSION2_PATTERN = re.compile(r"^(\d+)\.(\d+)(?:-(\w+))?")
101
116
 
102
117
 
103
- _ = PipListOutdatedOutput.model_rebuild()
104
-
105
-
106
118
  __all__ = [
107
119
  "PipListOutdatedOutput",
120
+ "PipListOutput",
108
121
  "TwoSidedVersions",
109
122
  "Version1or2",
110
123
  "Version2",
@@ -5,12 +5,14 @@ from functools import partial
5
5
  from typing import TYPE_CHECKING
6
6
 
7
7
  from pydantic import TypeAdapter
8
+ from utilities.functions import max_nullable
8
9
  from utilities.text import repr_str, strip_and_dedent
9
10
 
10
11
  from actions import __version__
11
12
  from actions.logging import LOGGER
12
13
  from actions.pre_commit.update_requirements.classes import (
13
14
  PipListOutdatedOutput,
15
+ PipListOutput,
14
16
  Version1or2,
15
17
  Version2,
16
18
  Version3,
@@ -28,6 +30,7 @@ if TYPE_CHECKING:
28
30
  from utilities.types import PathLike
29
31
 
30
32
  from actions.pre_commit.update_requirements.classes import Version2or3, VersionSet
33
+ from actions.types import StrDict
31
34
 
32
35
 
33
36
  def update_requirements(*paths: PathLike) -> None:
@@ -66,11 +69,20 @@ def _format_path(
66
69
 
67
70
 
68
71
  def _get_versions() -> VersionSet:
69
- json = logged_run(
72
+ json1 = logged_run(
73
+ "uv", "pip", "list", "--format", "json", "--strict", return_=True
74
+ )
75
+ models1 = TypeAdapter(list[PipListOutput]).validate_json(json1)
76
+ versions1 = {p.name: parse_version2_or_3(p.version) for p in models1}
77
+ json2 = logged_run(
70
78
  "uv", "pip", "list", "--format", "json", "--outdated", "--strict", return_=True
71
79
  )
72
- packages = TypeAdapter(list[PipListOutdatedOutput]).validate_json(json)
73
- return {p.name: parse_version2_or_3(p.latest_version) for p in packages}
80
+ models2 = TypeAdapter(list[PipListOutdatedOutput]).validate_json(json2)
81
+ versions2 = {p.name: parse_version2_or_3(p.latest_version) for p in models2}
82
+ out: StrDict = {}
83
+ for key in set(versions1) | set(versions2):
84
+ out[key] = max_nullable([versions1.get(key), versions2.get(key)])
85
+ return out
74
86
 
75
87
 
76
88
  def _format_req(requirement: Requirement, /, *, versions: VersionSet) -> Requirement:
@@ -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
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ import actions.constants
4
+ from actions.constants import PATH_ACTIONS
5
+
6
+ REGISTER_GITEA_RUNNER_SUB_CMD = "register-gitea-runner"
7
+ REGISTER_GITEA_RUNNER_DOCSTRING = "Register a Gitea runner"
8
+
9
+
10
+ PATH_CACHE = actions.constants.PATH_CACHE / REGISTER_GITEA_RUNNER_SUB_CMD
11
+ PATH_CONFIGS = PATH_ACTIONS / "register_gitea_runner/configs"
12
+ PATH_WAIT_FOR_IT = PATH_CACHE / "wait-for-it.sh"
13
+ URL_WAIT_FOR_IT = "https://raw.githubusercontent.com/vishnubob/wait-for-it/refs/heads/master/wait-for-it.sh"
14
+
15
+
16
+ __all__ = [
17
+ "PATH_CACHE",
18
+ "PATH_CONFIGS",
19
+ "PATH_WAIT_FOR_IT",
20
+ "REGISTER_GITEA_RUNNER_DOCSTRING",
21
+ "REGISTER_GITEA_RUNNER_SUB_CMD",
22
+ "URL_WAIT_FOR_IT",
23
+ ]
@@ -0,0 +1,289 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from re import search
5
+ from string import Template
6
+ from typing import TYPE_CHECKING
7
+
8
+ from requests import get
9
+ from utilities.atomicwrites import writer
10
+ from utilities.subprocess import chmod, run, ssh
11
+ from utilities.text import strip_and_dedent
12
+
13
+ from actions import __version__
14
+ from actions.logging import LOGGER
15
+ from actions.register_gitea_runner.constants import (
16
+ PATH_CACHE,
17
+ PATH_CONFIGS,
18
+ PATH_WAIT_FOR_IT,
19
+ URL_WAIT_FOR_IT,
20
+ )
21
+ from actions.register_gitea_runner.settings import SETTINGS
22
+
23
+ if TYPE_CHECKING:
24
+ from utilities.types import PathLike
25
+
26
+
27
+ def register_gitea_runner(
28
+ *,
29
+ ssh_user: str = SETTINGS.ssh_user,
30
+ ssh_host: str = SETTINGS.ssh_host,
31
+ gitea_container_user: str = SETTINGS.gitea_container_user,
32
+ gitea_container_name: str = SETTINGS.gitea_container_name,
33
+ runner_certificate: PathLike = SETTINGS.runner_certificate,
34
+ runner_capacity: int = SETTINGS.runner_capacity,
35
+ runner_container_name: str = SETTINGS.runner_container_name,
36
+ gitea_host: str = SETTINGS.gitea_host,
37
+ gitea_port: int = SETTINGS.gitea_port,
38
+ runner_instance_name: str = SETTINGS.runner_instance_name,
39
+ ) -> None:
40
+ """Register against a remote instance of Gitea."""
41
+ LOGGER.info(
42
+ strip_and_dedent("""
43
+ Running '%s' (version %s) with settings:
44
+ - ssh_user = %s
45
+ - ssh_host = %s
46
+ - gitea_container_user = %s
47
+ - gitea_container_name = %s
48
+ - runner_certificate = %s
49
+ - runner_capacity = %d
50
+ - runner_container_name = %s
51
+ - gitea_host = %s
52
+ - gitea_port = %d
53
+ - runner_instance_name = %s
54
+ """),
55
+ register_gitea_runner.__name__,
56
+ __version__,
57
+ ssh_user,
58
+ ssh_host,
59
+ gitea_container_user,
60
+ gitea_container_name,
61
+ runner_certificate,
62
+ runner_capacity,
63
+ runner_container_name,
64
+ gitea_host,
65
+ gitea_port,
66
+ runner_instance_name,
67
+ )
68
+ token = ssh(
69
+ ssh_user,
70
+ ssh_host,
71
+ *_docker_exec_generate(user=gitea_container_user, name=gitea_container_name),
72
+ return_=True,
73
+ )
74
+ _start_runner(
75
+ token,
76
+ runner_certificate=runner_certificate,
77
+ runner_capacity=runner_capacity,
78
+ runner_container_name=runner_container_name,
79
+ gitea_host=gitea_host,
80
+ gitea_port=gitea_port,
81
+ runner_instance_name=runner_instance_name,
82
+ )
83
+
84
+
85
+ def register_against_local(
86
+ *,
87
+ gitea_container_user: str = SETTINGS.gitea_container_user,
88
+ gitea_container_name: str = SETTINGS.gitea_container_name,
89
+ runner_certificate: PathLike = SETTINGS.runner_certificate,
90
+ runner_capacity: int = SETTINGS.runner_capacity,
91
+ runner_container_name: str = SETTINGS.runner_container_name,
92
+ gitea_host: str = SETTINGS.gitea_host,
93
+ gitea_port: int = SETTINGS.gitea_port,
94
+ runner_instance_name: str = SETTINGS.runner_instance_name,
95
+ ) -> None:
96
+ """Register against a local instance of Gitea."""
97
+ LOGGER.info("Registering against %s:%d...", gitea_host, gitea_port)
98
+ token = run(
99
+ *_docker_exec_generate(user=gitea_container_user, name=gitea_container_name),
100
+ return_=True,
101
+ logger=LOGGER,
102
+ )
103
+ _start_runner(
104
+ token,
105
+ runner_certificate=runner_certificate,
106
+ runner_capacity=runner_capacity,
107
+ runner_container_name=runner_container_name,
108
+ gitea_host=gitea_host,
109
+ gitea_port=gitea_port,
110
+ runner_instance_name=runner_instance_name,
111
+ )
112
+
113
+
114
+ def _check_certificate(*, certificate: PathLike = SETTINGS.runner_certificate) -> None:
115
+ if not Path(certificate).is_file():
116
+ msg = f"Missing certificate {certificate!r}"
117
+ raise FileNotFoundError(msg)
118
+
119
+
120
+ def _check_token(text: str, /) -> None:
121
+ if not search(r"^[A-Za-z0-9]{40}$", text):
122
+ msg = f"Invalid token; got {text!r}"
123
+ raise ValueError(msg)
124
+
125
+
126
+ def _docker_exec_generate(
127
+ *,
128
+ user: str = SETTINGS.gitea_container_user,
129
+ name: str = SETTINGS.gitea_container_name,
130
+ ) -> list[str]:
131
+ return [
132
+ "docker",
133
+ "exec",
134
+ "--user",
135
+ user,
136
+ name,
137
+ "gitea",
138
+ "actions",
139
+ "generate-runner-token",
140
+ ]
141
+
142
+
143
+ def _docker_run_act_runner_args(
144
+ token: str,
145
+ /,
146
+ *,
147
+ host: str = SETTINGS.gitea_host,
148
+ port: int = SETTINGS.gitea_port,
149
+ runner_certificate: PathLike = SETTINGS.runner_certificate,
150
+ instance_name: str = SETTINGS.runner_instance_name,
151
+ container_name: str = SETTINGS.runner_container_name,
152
+ ) -> list[str]:
153
+ config_host = _get_config_path(token)
154
+ config_cont = "/config.yml"
155
+ entrypoint_host = _get_entrypoint_path(host=host, port=port)
156
+ entrypoint_cont = Path("/usr/local/bin/entrypoint.sh")
157
+ return [
158
+ "docker",
159
+ "run",
160
+ "--detach",
161
+ "--entrypoint",
162
+ str(entrypoint_cont),
163
+ "--env",
164
+ f"CONFIG_FILE={config_cont}",
165
+ "--env",
166
+ f"GITEA_INSTANCE_URL=https://{host}:{port}",
167
+ "--env",
168
+ f"GITEA_RUNNER_NAME={instance_name}",
169
+ "--env",
170
+ f"GITEA_RUNNER_REGISTRATION_TOKEN={token}",
171
+ "--name",
172
+ container_name,
173
+ "--volume",
174
+ "/var/run/docker.sock:/var/run/docker.sock",
175
+ "--volume",
176
+ f"{PATH_WAIT_FOR_IT}:/usr/local/bin/wait-for-it.sh:ro",
177
+ "--volume",
178
+ f"{Path.cwd()}/data:/data",
179
+ "--volume",
180
+ f"{config_host}:{config_cont}:ro",
181
+ "--volume",
182
+ f"{entrypoint_host}:{entrypoint_cont}:ro",
183
+ "--volume",
184
+ f"{runner_certificate}:/etc/ssl/certs/runner-certificate.pem:ro",
185
+ "gitea/act_runner",
186
+ ]
187
+
188
+
189
+ def _docker_stop_runner_args(
190
+ *, name: str = SETTINGS.runner_container_name
191
+ ) -> list[str]:
192
+ return ["docker", "rm", "--force", name]
193
+
194
+
195
+ def _get_config_contents(
196
+ *,
197
+ capacity: int = SETTINGS.runner_capacity,
198
+ certificate: PathLike = SETTINGS.runner_certificate,
199
+ ) -> str:
200
+ src = PATH_CONFIGS / "config.yml"
201
+ return Template(src.read_text()).safe_substitute(
202
+ CAPACITY=capacity, CERTIFICATE=certificate
203
+ )
204
+
205
+
206
+ def _get_config_path(token: str, /) -> Path:
207
+ return PATH_CACHE / f"configs/{token}.yml"
208
+
209
+
210
+ def _get_entrypoint_contents(
211
+ *, host: str = SETTINGS.gitea_host, port: int = SETTINGS.gitea_port
212
+ ) -> str:
213
+ src = PATH_CONFIGS / "entrypoint.sh"
214
+ return Template(src.read_text()).safe_substitute(GITEA_HOST=host, GITEA_PORT=port)
215
+
216
+
217
+ def _get_entrypoint_path(
218
+ *, host: str = SETTINGS.gitea_host, port: int = SETTINGS.gitea_port
219
+ ) -> Path:
220
+ return PATH_CACHE / f"entrypoints/{host}-{port}"
221
+
222
+
223
+ def _start_runner(
224
+ token: str,
225
+ /,
226
+ *,
227
+ runner_certificate: PathLike = SETTINGS.runner_certificate,
228
+ runner_capacity: int = SETTINGS.runner_capacity,
229
+ runner_container_name: str = SETTINGS.runner_container_name,
230
+ gitea_host: str = SETTINGS.gitea_host,
231
+ gitea_port: int = SETTINGS.gitea_port,
232
+ runner_instance_name: str = SETTINGS.runner_instance_name,
233
+ ) -> None:
234
+ _check_certificate(certificate=runner_certificate)
235
+ _check_token(token)
236
+ _write_config(token, capacity=runner_capacity, certificate=runner_certificate)
237
+ _write_entrypoint(host=gitea_host, port=gitea_port)
238
+ _write_wait_for_it()
239
+ run(
240
+ *_docker_stop_runner_args(name=runner_container_name), print=True, logger=LOGGER
241
+ )
242
+ run(
243
+ *_docker_run_act_runner_args(
244
+ token,
245
+ host=gitea_host,
246
+ port=gitea_port,
247
+ runner_certificate=runner_certificate,
248
+ instance_name=runner_instance_name,
249
+ container_name=runner_container_name,
250
+ ),
251
+ print=True,
252
+ logger=LOGGER,
253
+ )
254
+
255
+
256
+ def _write_config(
257
+ token: str,
258
+ /,
259
+ *,
260
+ capacity: int = SETTINGS.runner_capacity,
261
+ certificate: PathLike = SETTINGS.runner_certificate,
262
+ ) -> None:
263
+ dest = _get_config_path(token)
264
+ text = _get_config_contents(capacity=capacity, certificate=certificate)
265
+ with writer(dest, overwrite=True) as temp:
266
+ _ = temp.write_text(text)
267
+
268
+
269
+ def _write_entrypoint(
270
+ *, host: str = SETTINGS.gitea_host, port: int = SETTINGS.gitea_port
271
+ ) -> None:
272
+ dest = _get_entrypoint_path(host=host, port=port)
273
+ text = _get_entrypoint_contents(host=host, port=port)
274
+ with writer(dest, overwrite=True) as temp:
275
+ _ = temp.write_text(text)
276
+ chmod(temp, "u=rwx,g=rx,o=rx")
277
+
278
+
279
+ def _write_wait_for_it() -> None:
280
+ if PATH_WAIT_FOR_IT.is_file():
281
+ return
282
+ with writer(PATH_WAIT_FOR_IT, overwrite=True) as temp:
283
+ resp = get(URL_WAIT_FOR_IT, timeout=60)
284
+ resp.raise_for_status()
285
+ _ = temp.write_bytes(resp.content)
286
+ chmod(temp, "u=rwx,g=rx,o=rx")
287
+
288
+
289
+ __all__ = ["register_against_local"]
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from typed_settings import load_settings, option, settings
6
+ from utilities.getpass import USER
7
+ from utilities.socket import HOSTNAME
8
+
9
+ from actions.utilities import LOADER
10
+
11
+
12
+ @settings
13
+ class Settings:
14
+ ssh_user: str = option(default="user", help="SSH username")
15
+ ssh_host: str = option(default="gitea", help="SSH host")
16
+ gitea_container_user: str = option(default="git", help="Gitea container user name")
17
+ gitea_container_name: str = option(default="gitea", help="Gitea container name")
18
+ gitea_host: str = option(default="gitea", help="Gitea host")
19
+ gitea_port: int = option(default=3000, help="Gitea port")
20
+ runner_capacity: int = option(default=1, help="Runner capacity")
21
+ runner_instance_name: str = option(
22
+ default=f"{USER}--{HOSTNAME}", help="Runner instance name"
23
+ )
24
+ runner_certificate: Path = option(
25
+ default=Path("root.pem"), help="Runner root certificate"
26
+ )
27
+ runner_container_name: str = option(default="runner", help="Runner container name")
28
+
29
+
30
+ SETTINGS = load_settings(Settings, [LOADER])
31
+
32
+
33
+ __all__ = ["SETTINGS", "Settings"]
@@ -1,16 +1,17 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dycw-actions
3
- Version: 0.7.1
3
+ Version: 0.7.7
4
4
  Summary: Library of actions
5
5
  Requires-Dist: click>=8.3.1,<9
6
- Requires-Dist: dycw-utilities>=0.177.0,<1
6
+ Requires-Dist: dycw-utilities>=0.178.0,<1
7
7
  Requires-Dist: inflect>=7.5.0,<8
8
8
  Requires-Dist: libcst>=1.8.6,<2
9
9
  Requires-Dist: packaging>=25.0,<26
10
10
  Requires-Dist: pydantic>=2.12.5,<3
11
11
  Requires-Dist: pyyaml>=6.0.3,<7
12
+ Requires-Dist: requests>=2.32.5,<3
12
13
  Requires-Dist: rich>=14.2.0,<15
13
- Requires-Dist: ruamel-yaml>=0.19.0,<1
14
+ Requires-Dist: ruamel-yaml>=0.19.1,<1
14
15
  Requires-Dist: tomlkit>=0.13.3,<1
15
16
  Requires-Dist: typed-settings[attrs,click]>=25.3.0,<26
16
17
  Requires-Dist: xdg-base-dirs>=6.0.2,<7
@@ -1,14 +1,14 @@
1
- actions/__init__.py,sha256=_OevY0-QRr7A22CyPm0BKMCDflx5qu_IVMMkCcVHxdE,58
1
+ actions/__init__.py,sha256=trsIPKwrk3xNHIWvYXX9uhHoJTOvGbfIIBQNFcFa_Js,58
2
2
  actions/action_dicts/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
3
3
  actions/action_dicts/constants.py,sha256=tYYLr3aRRRvnR6NSADOJMN-B6gtqg2A9gBuheEPyGy4,189
4
4
  actions/action_dicts/lib.py,sha256=MpK_y5Jao0-3p6bWeYX5QQy3-JjMxwyzXRU5LjO25Iw,5547
5
5
  actions/clean_dir/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
6
6
  actions/clean_dir/cli.py,sha256=OrFA2nEN2LyGF22mhTNEBr7KSuKgX54sGy9RyE73qUc,569
7
7
  actions/clean_dir/constants.py,sha256=aDNaYtemEv3lcMXo96Oh4pw_HASMby1GZC1D_gbjPAc,167
8
- actions/clean_dir/lib.py,sha256=s8FdQBd9-PVmPixWFRmpcK6oOHrdutIxtsCSf1N1Tws,1577
8
+ actions/clean_dir/lib.py,sha256=7_-QbvB9Bq2veEl4eYWkBBWN0jSNrjGVlx1gLWS1PwU,1606
9
9
  actions/clean_dir/settings.py,sha256=mqM0Oq-yz4dXKcUi3JmOCvDhoeBNQm_Qe70cGmhdcQE,345
10
- actions/cli.py,sha256=NPiRNWXUyYLcalbDdsQaYDtjdkfSPvR3i6SyVrD5NUQ,4079
11
- actions/constants.py,sha256=SO0SBwEW8Wn5Uzt95OvlwTctyH0K7uvXMnNf1uCkrxk,212
10
+ actions/cli.py,sha256=J9k7_BQzgDHdgzkTqwXVzncRMHm0eAT0WW_c_gAUFlE,4441
11
+ actions/constants.py,sha256=DgcgYPL3l2lAMIVRi7LzB_YsD0H8WDhaMphh5ztRD54,445
12
12
  actions/logging.py,sha256=rMTcQMGndUHTCaXXtyOHt_VXUMhQGRHoN7okpoX0y5I,120
13
13
  actions/pre_commit/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
14
14
  actions/pre_commit/click.py,sha256=BLHjkO0gIW7rgLabuWnszwXmI4yb8Li5D8gt81GR-FQ,270
@@ -16,7 +16,7 @@ actions/pre_commit/conformalize_repo/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8
16
16
  actions/pre_commit/conformalize_repo/cli.py,sha256=rPrxobdo4sKnq0de_UWDtrHqlhF6GTAabRhw_1XBeZY,3063
17
17
  actions/pre_commit/conformalize_repo/configs/gitignore,sha256=8YCRPwysCD8-67yFXaTg6O8TTl4xeNIh7_DVmaU5Ix0,5063
18
18
  actions/pre_commit/conformalize_repo/constants.py,sha256=7WMbc1BwkVPJIf3eh3MaCoWj5A7pSPvNic28nrFTcoA,2148
19
- actions/pre_commit/conformalize_repo/lib.py,sha256=rgUQjX1ScjQcLeXx9cPqFqGYQmHprUhDodxEjp7RonM,47604
19
+ actions/pre_commit/conformalize_repo/lib.py,sha256=cdEggEXiDTt2QHbzP0rIViFriPoaApf3XcGeAo-hiHY,48020
20
20
  actions/pre_commit/conformalize_repo/settings.py,sha256=Oz2AeStS64DFzT1HKJ888_7tiU1TdJIGBarvyKYfp4E,4985
21
21
  actions/pre_commit/constants.py,sha256=NBJ5GBMg5qhMAhAfxx1FKw0CdPwW_wG2cUJJ0dkF5HE,158
22
22
  actions/pre_commit/format_requirements/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
@@ -30,16 +30,16 @@ actions/pre_commit/replace_sequence_strs/lib.py,sha256=FzfwYeL3bhTCYbb1T-Yk1NtdH
30
30
  actions/pre_commit/touch_empty_py/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
31
31
  actions/pre_commit/touch_empty_py/cli.py,sha256=s2S5OfAGcSLtd2aGm1ooa1k20oNK-LQ1PZWz6T30vO8,559
32
32
  actions/pre_commit/touch_empty_py/constants.py,sha256=zSwH60zfn9RhIAbBFnXjHrm2s1nFpPUskX3CZuJpQLk,198
33
- actions/pre_commit/touch_empty_py/lib.py,sha256=avGiqWRi0x7E4zvvyxaqv_ccRpOT8Le7ol4_ETaXx2s,1458
33
+ actions/pre_commit/touch_empty_py/lib.py,sha256=jxT6CRZ3rrBatk3o-D0xDXon3a-G02sCvdMSNuRvCv0,1706
34
34
  actions/pre_commit/touch_py_typed/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
35
35
  actions/pre_commit/touch_py_typed/cli.py,sha256=CDJV4NuUHJlSdJ84dY0XvdwYHMdqygZ7C6x07B-iN3E,559
36
36
  actions/pre_commit/touch_py_typed/constants.py,sha256=kLZOm_wgypp7MaXRYq-6AZqVE4OttOMKmUqt11V2zn0,191
37
- actions/pre_commit/touch_py_typed/lib.py,sha256=Vsi1oDC6nUvWlQdA_a5t-kM5W5o3v0PBZZQe3_QS3Zo,1772
37
+ actions/pre_commit/touch_py_typed/lib.py,sha256=8crPXxI6CwudW13RIJrn3YtrFcZsspyJnTmNRHz4TaU,2020
38
38
  actions/pre_commit/update_requirements/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
39
- actions/pre_commit/update_requirements/classes.py,sha256=STRC3LS_2PkdvHPgPxkNAcSIDiomzsKhyiP5uhcLUe0,3266
39
+ actions/pre_commit/update_requirements/classes.py,sha256=ERC70c1CxQ3rOsQaEtp6FGbK_VaJ4K0jAV5XTB5-L30,3486
40
40
  actions/pre_commit/update_requirements/cli.py,sha256=CBfm8M7hwSRw8KS6ttiNE86IFHJ52V42AxlfakqTDN0,584
41
41
  actions/pre_commit/update_requirements/constants.py,sha256=ve44_RYed_41ckgQNPkb08u7Y1cpLpzutGSL9FdGBF8,228
42
- actions/pre_commit/update_requirements/lib.py,sha256=o3wUfeof-6oLYziHE74Q8WIHk4nyOv5PcK8cFkazm1k,4107
42
+ actions/pre_commit/update_requirements/lib.py,sha256=akSmdqFpDS8ETsdGs4-8lfoKOp_8bBlKyKUXhUlrzpg,4619
43
43
  actions/pre_commit/utilities.py,sha256=L1HCi3l778REPfomMuYbxrrnCn0FDRFaWAfmFR0lsTY,11422
44
44
  actions/publish_package/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
45
45
  actions/publish_package/cli.py,sha256=nAPHCq67mxUb3yHepVGcoQ69qgaQahM1-cxdbHfxQg0,803
@@ -52,6 +52,13 @@ actions/random_sleep/cli.py,sha256=-d9y63oWgvQtNp9j_8v3zt5gKl-GrUq8-b3Ky52R42c,6
52
52
  actions/random_sleep/constants.py,sha256=5GMqCD1f12uyKDVTZBbnDDn6TQa99mUYZb9p-crg5BA,190
53
53
  actions/random_sleep/lib.py,sha256=JzgpeEONdKXSBeNc3ex9goVyJR3bsa76lB_tkH1Ggc0,1762
54
54
  actions/random_sleep/settings.py,sha256=F8gO2j2EEX8moemwhWWCPdRuOpZ_qLtqzSfWhjIy3P8,529
55
+ actions/register_gitea_runner/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
56
+ actions/register_gitea_runner/cli.py,sha256=70RUyzKCZHxyDRMFwCAwDC0LDsUZxBi2T6ctzbFlpc8,1129
57
+ actions/register_gitea_runner/configs/config.yml,sha256=0kpaqAjMRDqdSxkSK8ydOk2IsrlkB4cUkYmbkHAurrg,5683
58
+ actions/register_gitea_runner/configs/entrypoint.sh,sha256=IN40hAu8ufyyFWPIgsX_hWp0ZZZ0c36czCaqmECjBrw,476
59
+ actions/register_gitea_runner/constants.py,sha256=wX1f5qvhIXngBVWbIQRoIaXIdPaUByvG8HS8P0WcCGM,694
60
+ actions/register_gitea_runner/lib.py,sha256=V_K6UHmZOD9V-DF6ZNA2QakNyuyuyjgJZ6AJQFf37lQ,8832
61
+ actions/register_gitea_runner/settings.py,sha256=0UQm8M3qDiBE3jiE333M4FdLjikNAzpc9gk_VlzI0s8,1149
55
62
  actions/run_hooks/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
56
63
  actions/run_hooks/cli.py,sha256=xKBw6iIlHpUlHl6-QWQLSL6KKVjnsihBeJ7h58Rl8P4,616
57
64
  actions/run_hooks/constants.py,sha256=JRhDk08qbzo5C-zwHdXZV5ajvNSKh4GcOcBvOIY6IGU,172
@@ -71,7 +78,7 @@ actions/tag_commit/lib.py,sha256=rq1SqAkNp98cPsNOsFY4F1D6nNi7N3wqVbFPno8lsuI,184
71
78
  actions/tag_commit/settings.py,sha256=TOeKG_GODP--2lBSyGzH_M32jDIfh4vk_Ts06R3_ak4,629
72
79
  actions/types.py,sha256=GRXLoJtYWmRjgfatDDRMcXKZkN9ZtK1Fi2MEyAZ84uk,591
73
80
  actions/utilities.py,sha256=VpFLBiAezgSRlm9dvnyPyQohreaV2Lv7cJ9HAxqZ4WI,4086
74
- dycw_actions-0.7.1.dist-info/WHEEL,sha256=KSLUh82mDPEPk0Bx0ScXlWL64bc8KmzIPNcpQZFV-6E,79
75
- dycw_actions-0.7.1.dist-info/entry_points.txt,sha256=2Uu7wAZOm0mmcsGBEsGB370HAWgVWECRFJ9rKgfC3-I,46
76
- dycw_actions-0.7.1.dist-info/METADATA,sha256=T4208DBQxD3yT09fwfKIiVGyOvSax8tyqNt8MxNGBLM,619
77
- dycw_actions-0.7.1.dist-info/RECORD,,
81
+ dycw_actions-0.7.7.dist-info/WHEEL,sha256=KSLUh82mDPEPk0Bx0ScXlWL64bc8KmzIPNcpQZFV-6E,79
82
+ dycw_actions-0.7.7.dist-info/entry_points.txt,sha256=2Uu7wAZOm0mmcsGBEsGB370HAWgVWECRFJ9rKgfC3-I,46
83
+ dycw_actions-0.7.7.dist-info/METADATA,sha256=CORF-XquPdSrUKd4Doo9mV0OA8RmDHzyWwZUMXgtC8E,654
84
+ dycw_actions-0.7.7.dist-info/RECORD,,