wexample-wex-addon-process 4.1.4__tar.gz → 5.0.0__tar.gz
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.
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/PKG-INFO +6 -7
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/README.md +4 -5
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/pyproject.toml +2 -2
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/builtin/builtin_process.py +32 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/builtin/builtin_process_registry.py +29 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/process/create.py +108 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/process/remove.py +46 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/process/update.py +107 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/run/cancel.py +54 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/run/create.py +144 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/selection/create.py +69 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/selection/remove.py +46 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/selection/update.py +66 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/const/process.py +6 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/exception/record_not_found_exception.py +24 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/process_addon_manager.py +7 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/process_type/process_context.py +5 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/runner/process_runner.py +70 -12
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/selection/git_changes_selection.py +36 -0
- wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/service/__init__.py +0 -0
- wexample_wex_addon_process-5.0.0/tests/.gitkeep +0 -0
- wexample_wex_addon_process-5.0.0/tests/unit/__init__.py +0 -0
- wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/helper/git_commit.py +0 -83
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/commands → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/builtin}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/commands/run → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/commands/worker → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/process}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/const → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/run}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/commands/run/execute.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/exception → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/selection}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/helper → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/commands/worker}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/commands/worker/start.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/process_type → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/const}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/const/filestate.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/process_type/family → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/exception}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/exception/run_cancelled_exception.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/process_type/filestate → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/helper}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/record → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/process_type}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/process_type/abstract_process_type.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/runner → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/process_type/family}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/process_type/family/abstract_process_type_family.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/process_type/family/file_state_process_type_family.py +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/selection → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/process_type/filestate}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/process_type/filestate/file_state_option_process_type.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/process_type/filestate/file_state_report_process_type.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/process_type/process_type_registry.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/process_type/selection.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/py.typed +0 -0
- {wexample_wex_addon_process-4.1.4/src/wexample_wex_addon_process/service → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/record}/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/record/record_file.py +0 -0
- {wexample_wex_addon_process-4.1.4/tests/unit → wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/runner}/__init__.py +0 -0
- /wexample_wex_addon_process-4.1.4/tests/.gitkeep → /wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/selection/__init__.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/selection/abstract_code_from_directory_selection.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/selection/abstract_process_selection.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/selection/selection_registry.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/src/wexample_wex_addon_process/service/process_run_service.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/tests/unit/test_artifacts.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/tests/unit/test_long_runs.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/tests/unit/test_run_overrides.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/tests/unit/test_selection.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/tests/unit/test_skip_and_failure.py +0 -0
- {wexample_wex_addon_process-4.1.4 → wexample_wex_addon_process-5.0.0}/tests/unit/test_verdict_locations.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: wexample-wex-addon-process
|
|
3
|
-
Version:
|
|
3
|
+
Version: 5.0.0
|
|
4
4
|
Summary: Executes process runs defined on disk—either directly or by consuming them from a queue as a worker—against filestate selections
|
|
5
5
|
Author-Email: weeger <contact@wexample.com>
|
|
6
6
|
License: MIT
|
|
@@ -10,7 +10,7 @@ Classifier: Operating System :: OS Independent
|
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Requires-Dist: wexample-file>=9.2.0
|
|
12
12
|
Requires-Dist: wexample-queue>=2.0.0
|
|
13
|
-
Requires-Dist: wexample-wex-addon-app>=
|
|
13
|
+
Requires-Dist: wexample-wex-addon-app>=34.0.0
|
|
14
14
|
Provides-Extra: dev
|
|
15
15
|
Requires-Dist: pytest; extra == "dev"
|
|
16
16
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -18,7 +18,7 @@ Description-Content-Type: text/markdown
|
|
|
18
18
|
|
|
19
19
|
# wex-addon-process
|
|
20
20
|
|
|
21
|
-
Version:
|
|
21
|
+
Version: 5.0.0
|
|
22
22
|
|
|
23
23
|
`wexample-wex-addon-process` runs the treatments a board declares. A *process* says what to run and on which selection of files; a *run* is one execution of it, asked for by writing a record and picked up by a worker.
|
|
24
24
|
|
|
@@ -360,13 +360,11 @@ This package is part of the Wexample Suite — a collection of high-quality, mod
|
|
|
360
360
|
|
|
361
361
|
The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.
|
|
362
362
|
|
|
363
|
-
Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.
|
|
364
|
-
|
|
365
363
|
## Dependencies
|
|
366
364
|
|
|
367
365
|
- wexample-file: >=9.2.0
|
|
368
366
|
- wexample-queue: >=2.0.0
|
|
369
|
-
- wexample-wex-addon-app: >=
|
|
367
|
+
- wexample-wex-addon-app: >=34.0.0
|
|
370
368
|
|
|
371
369
|
## Versioning & Compatibility Policy
|
|
372
370
|
|
|
@@ -392,6 +390,8 @@ This packages suite embodies this spirit. Trusted by professionals and enthusias
|
|
|
392
390
|
|
|
393
391
|
Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.
|
|
394
392
|
|
|
393
|
+
Built and maintained by [Romain Weeger](https://weeger.io).
|
|
394
|
+
|
|
395
395
|
## Known Limitations & Roadmap
|
|
396
396
|
|
|
397
397
|
Current limitations and planned features are tracked in the GitHub issues.
|
|
@@ -411,7 +411,6 @@ See the [project roadmap](https://github.com/wexample/python-wex-addon-process/i
|
|
|
411
411
|
## Useful Links
|
|
412
412
|
|
|
413
413
|
- **Homepage**: https://github.com/wexample/python-wex-addon-process
|
|
414
|
-
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
|
|
415
414
|
- **Issue Tracker**: https://github.com/wexample/python-wex-addon-process/issues
|
|
416
415
|
- **Discussions**: https://github.com/wexample/python-wex-addon-process/discussions
|
|
417
416
|
- **PyPI**: [pypi.org/project/wexample-wex-addon-process](https://pypi.org/project/wexample-wex-addon-process/)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# wex-addon-process
|
|
2
2
|
|
|
3
|
-
Version:
|
|
3
|
+
Version: 5.0.0
|
|
4
4
|
|
|
5
5
|
`wexample-wex-addon-process` runs the treatments a board declares. A *process* says what to run and on which selection of files; a *run* is one execution of it, asked for by writing a record and picked up by a worker.
|
|
6
6
|
|
|
@@ -342,13 +342,11 @@ This package is part of the Wexample Suite — a collection of high-quality, mod
|
|
|
342
342
|
|
|
343
343
|
The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.
|
|
344
344
|
|
|
345
|
-
Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.
|
|
346
|
-
|
|
347
345
|
## Dependencies
|
|
348
346
|
|
|
349
347
|
- wexample-file: >=9.2.0
|
|
350
348
|
- wexample-queue: >=2.0.0
|
|
351
|
-
- wexample-wex-addon-app: >=
|
|
349
|
+
- wexample-wex-addon-app: >=34.0.0
|
|
352
350
|
|
|
353
351
|
## Versioning & Compatibility Policy
|
|
354
352
|
|
|
@@ -374,6 +372,8 @@ This packages suite embodies this spirit. Trusted by professionals and enthusias
|
|
|
374
372
|
|
|
375
373
|
Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.
|
|
376
374
|
|
|
375
|
+
Built and maintained by [Romain Weeger](https://weeger.io).
|
|
376
|
+
|
|
377
377
|
## Known Limitations & Roadmap
|
|
378
378
|
|
|
379
379
|
Current limitations and planned features are tracked in the GitHub issues.
|
|
@@ -393,7 +393,6 @@ See the [project roadmap](https://github.com/wexample/python-wex-addon-process/i
|
|
|
393
393
|
## Useful Links
|
|
394
394
|
|
|
395
395
|
- **Homepage**: https://github.com/wexample/python-wex-addon-process
|
|
396
|
-
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
|
|
397
396
|
- **Issue Tracker**: https://github.com/wexample/python-wex-addon-process/issues
|
|
398
397
|
- **Discussions**: https://github.com/wexample/python-wex-addon-process/discussions
|
|
399
398
|
- **PyPI**: [pypi.org/project/wexample-wex-addon-process](https://pypi.org/project/wexample-wex-addon-process/)
|
|
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "wexample-wex-addon-process"
|
|
9
|
-
version = "
|
|
9
|
+
version = "5.0.0"
|
|
10
10
|
description = "Executes process runs defined on disk—either directly or by consuming them from a queue as a worker—against filestate selections"
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "weeger", email = "contact@wexample.com" },
|
|
@@ -20,7 +20,7 @@ classifiers = [
|
|
|
20
20
|
dependencies = [
|
|
21
21
|
"wexample-file>=9.2.0",
|
|
22
22
|
"wexample-queue>=2.0.0",
|
|
23
|
-
"wexample-wex-addon-app>=
|
|
23
|
+
"wexample-wex-addon-app>=34.0.0",
|
|
24
24
|
]
|
|
25
25
|
|
|
26
26
|
[project.readme]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class BuiltinProcess:
|
|
9
|
+
"""A process an addon ships: the same in every app, declared by no record.
|
|
10
|
+
|
|
11
|
+
What a process record says, said in code — a type, the options it is handed, and
|
|
12
|
+
the selection it runs on, a selection computed in code named by its provider, since
|
|
13
|
+
there is no selection record to point at either. A run names it by its identity, as
|
|
14
|
+
it names a process an app holds; nothing in an app can change it.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
name: str
|
|
18
|
+
selection: str
|
|
19
|
+
title: str
|
|
20
|
+
type: str
|
|
21
|
+
|
|
22
|
+
options: dict[str, Any] = field(default_factory=dict)
|
|
23
|
+
severity: str | None = None
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def identity(self) -> str:
|
|
27
|
+
"""The uuid a run and a consumer know it by, following from its name."""
|
|
28
|
+
from wexample_wex_core.helper.data_record import record_identity
|
|
29
|
+
|
|
30
|
+
from wexample_wex_addon_process.const.process import KIND_PROCESS
|
|
31
|
+
|
|
32
|
+
return record_identity(KIND_PROCESS, self.name)
|
wexample_wex_addon_process-5.0.0/src/wexample_wex_addon_process/builtin/builtin_process_registry.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from wexample_wex_addon_process.builtin.builtin_process import BuiltinProcess
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BuiltinProcessRegistry:
|
|
10
|
+
"""The processes the loaded addons ship, by the identity a run names them with."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, processes: list[BuiltinProcess]) -> None:
|
|
13
|
+
self._processes = {process.identity: process for process in processes}
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def from_kernel(cls, kernel: Any) -> BuiltinProcessRegistry:
|
|
17
|
+
return cls(
|
|
18
|
+
[
|
|
19
|
+
process
|
|
20
|
+
for addon in kernel.get_addons().values()
|
|
21
|
+
for process in addon.get_builtin_processes()
|
|
22
|
+
]
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def all(self) -> list[BuiltinProcess]:
|
|
26
|
+
return sorted(self._processes.values(), key=lambda process: process.name)
|
|
27
|
+
|
|
28
|
+
def get(self, identity: str) -> BuiltinProcess | None:
|
|
29
|
+
return self._processes.get(identity)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from wexample_cli.const.tags import EffectTag, ScopeTag
|
|
6
|
+
from wexample_cli.decorator.api_command import api_command
|
|
7
|
+
from wexample_cli.decorator.command import command
|
|
8
|
+
from wexample_cli.decorator.middleware import middleware
|
|
9
|
+
from wexample_cli.decorator.option import option
|
|
10
|
+
from wexample_wex_addon_app.middleware.app_middleware import AppMiddleware
|
|
11
|
+
from wexample_wex_core.const.globals import COMMAND_TYPE_ADDON
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from wexample_app.response.abstract_response import AbstractResponse
|
|
15
|
+
from wexample_cli.context.execution_context import ExecutionContext
|
|
16
|
+
from wexample_wex_addon_app.workdir.managed_workdir import ManagedWorkdir
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@option(name="title", type=str, required=True, description="What the process is called.")
|
|
20
|
+
@option(
|
|
21
|
+
name="type",
|
|
22
|
+
short_name="ty",
|
|
23
|
+
type=str,
|
|
24
|
+
required=True,
|
|
25
|
+
description="The process type it runs, by its registry name.",
|
|
26
|
+
)
|
|
27
|
+
@option(
|
|
28
|
+
name="selection",
|
|
29
|
+
type=str,
|
|
30
|
+
required=True,
|
|
31
|
+
description="Uuid of the selection it runs on, a record under `.wex/data/selection/`.",
|
|
32
|
+
)
|
|
33
|
+
@option(
|
|
34
|
+
name="options",
|
|
35
|
+
type=str,
|
|
36
|
+
required=False,
|
|
37
|
+
default="{}",
|
|
38
|
+
description="Its options, a JSON object, handed to the type as they are.",
|
|
39
|
+
)
|
|
40
|
+
@option(
|
|
41
|
+
name="severity",
|
|
42
|
+
short_name="sv",
|
|
43
|
+
type=str,
|
|
44
|
+
required=False,
|
|
45
|
+
description="How serious what it finds is (`warning`, `error`…); left out, the reader's default.",
|
|
46
|
+
)
|
|
47
|
+
@api_command(commit_subject="process creation")
|
|
48
|
+
@middleware(middleware=AppMiddleware)
|
|
49
|
+
@command(
|
|
50
|
+
type=COMMAND_TYPE_ADDON,
|
|
51
|
+
description="Create a process of the app, its record under `.wex/data/process/`. The selection it names must be one the app holds.",
|
|
52
|
+
tags=[
|
|
53
|
+
EffectTag.CREATE,
|
|
54
|
+
ScopeTag.APP,
|
|
55
|
+
ScopeTag.LOCAL,
|
|
56
|
+
],
|
|
57
|
+
)
|
|
58
|
+
def process__process__create(
|
|
59
|
+
context: ExecutionContext,
|
|
60
|
+
app_workdir: ManagedWorkdir,
|
|
61
|
+
title: str,
|
|
62
|
+
type: str,
|
|
63
|
+
selection: str,
|
|
64
|
+
options: str = "{}",
|
|
65
|
+
severity: str | None = None,
|
|
66
|
+
) -> AbstractResponse:
|
|
67
|
+
import json
|
|
68
|
+
from datetime import UTC, datetime
|
|
69
|
+
|
|
70
|
+
from wexample_app.response.dict_response import DictResponse
|
|
71
|
+
from wexample_wex_core.helper.data_record import data_kind_dir, new_record_path
|
|
72
|
+
|
|
73
|
+
from wexample_wex_addon_process.const.process import (
|
|
74
|
+
KIND_PROCESS,
|
|
75
|
+
KIND_SELECTION,
|
|
76
|
+
PROCESS_KEY_DATE_CREATED,
|
|
77
|
+
PROCESS_KEY_OPTIONS,
|
|
78
|
+
PROCESS_KEY_SELECTION_ID,
|
|
79
|
+
PROCESS_KEY_SEVERITY,
|
|
80
|
+
PROCESS_KEY_TITLE,
|
|
81
|
+
PROCESS_KEY_TYPE,
|
|
82
|
+
)
|
|
83
|
+
from wexample_wex_addon_process.record.record_file import record_path, write_record
|
|
84
|
+
|
|
85
|
+
app_path = app_workdir.get_path()
|
|
86
|
+
if not record_path(app_path, KIND_SELECTION, selection).is_file():
|
|
87
|
+
from wexample_wex_addon_process.exception.record_not_found_exception import (
|
|
88
|
+
RecordNotFoundException,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
raise RecordNotFoundException(kind=KIND_SELECTION, record_id=selection)
|
|
92
|
+
|
|
93
|
+
record = new_record_path(data_kind_dir(app_path, KIND_PROCESS))
|
|
94
|
+
values = {
|
|
95
|
+
PROCESS_KEY_TITLE: title,
|
|
96
|
+
PROCESS_KEY_TYPE: type,
|
|
97
|
+
PROCESS_KEY_SELECTION_ID: selection,
|
|
98
|
+
PROCESS_KEY_OPTIONS: json.loads(options),
|
|
99
|
+
PROCESS_KEY_DATE_CREATED: datetime.now(UTC).isoformat(timespec="seconds"),
|
|
100
|
+
}
|
|
101
|
+
if severity:
|
|
102
|
+
values[PROCESS_KEY_SEVERITY] = severity
|
|
103
|
+
write_record(record, values)
|
|
104
|
+
|
|
105
|
+
return DictResponse(
|
|
106
|
+
kernel=context.kernel,
|
|
107
|
+
content={"id": record.stem, "path": str(record), "written": [str(record)]},
|
|
108
|
+
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from wexample_cli.const.tags import EffectTag, ScopeTag
|
|
6
|
+
from wexample_cli.decorator.api_command import api_command
|
|
7
|
+
from wexample_cli.decorator.command import command
|
|
8
|
+
from wexample_cli.decorator.middleware import middleware
|
|
9
|
+
from wexample_cli.decorator.option import option
|
|
10
|
+
from wexample_wex_addon_app.middleware.app_middleware import AppMiddleware
|
|
11
|
+
from wexample_wex_core.const.globals import COMMAND_TYPE_ADDON
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from wexample_app.response.abstract_response import AbstractResponse
|
|
15
|
+
from wexample_cli.context.execution_context import ExecutionContext
|
|
16
|
+
from wexample_wex_addon_app.workdir.managed_workdir import ManagedWorkdir
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@option(name="id", type=str, required=True, description="Uuid of the process to take away.")
|
|
20
|
+
@api_command(commit_subject="process removal")
|
|
21
|
+
@middleware(middleware=AppMiddleware)
|
|
22
|
+
@command(
|
|
23
|
+
type=COMMAND_TYPE_ADDON,
|
|
24
|
+
description="Take a process of the app away, its record and the directory beside it. Its runs stay: they are the history of what it did.",
|
|
25
|
+
tags=[
|
|
26
|
+
EffectTag.DELETE,
|
|
27
|
+
ScopeTag.APP,
|
|
28
|
+
ScopeTag.LOCAL,
|
|
29
|
+
],
|
|
30
|
+
)
|
|
31
|
+
def process__process__remove(
|
|
32
|
+
context: ExecutionContext,
|
|
33
|
+
app_workdir: ManagedWorkdir,
|
|
34
|
+
id: str,
|
|
35
|
+
) -> AbstractResponse:
|
|
36
|
+
from wexample_app.response.dict_response import DictResponse
|
|
37
|
+
from wexample_wex_core.helper.data_record import record_remove
|
|
38
|
+
|
|
39
|
+
from wexample_wex_addon_process.const.process import KIND_PROCESS
|
|
40
|
+
from wexample_wex_addon_process.record.record_file import record_path
|
|
41
|
+
|
|
42
|
+
removed = record_remove(record_path(app_workdir.get_path(), KIND_PROCESS, id))
|
|
43
|
+
return DictResponse(
|
|
44
|
+
kernel=context.kernel,
|
|
45
|
+
content={"id": id, "written": [str(path) for path in removed]},
|
|
46
|
+
)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from wexample_cli.const.tags import EffectTag, ScopeTag
|
|
6
|
+
from wexample_cli.decorator.api_command import api_command
|
|
7
|
+
from wexample_cli.decorator.command import command
|
|
8
|
+
from wexample_cli.decorator.middleware import middleware
|
|
9
|
+
from wexample_cli.decorator.option import option
|
|
10
|
+
from wexample_wex_addon_app.middleware.app_middleware import AppMiddleware
|
|
11
|
+
from wexample_wex_core.const.globals import COMMAND_TYPE_ADDON
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from wexample_app.response.abstract_response import AbstractResponse
|
|
15
|
+
from wexample_cli.context.execution_context import ExecutionContext
|
|
16
|
+
from wexample_wex_addon_app.workdir.managed_workdir import ManagedWorkdir
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@option(name="id", type=str, required=True, description="Uuid of the process to rewrite.")
|
|
20
|
+
@option(name="title", type=str, required=True, description="What the process is called.")
|
|
21
|
+
@option(
|
|
22
|
+
name="type",
|
|
23
|
+
short_name="ty",
|
|
24
|
+
type=str,
|
|
25
|
+
required=True,
|
|
26
|
+
description="The process type it runs, by its registry name.",
|
|
27
|
+
)
|
|
28
|
+
@option(
|
|
29
|
+
name="selection",
|
|
30
|
+
type=str,
|
|
31
|
+
required=False,
|
|
32
|
+
description="Uuid of the selection it runs on, a record under `.wex/data/selection/`; left out, it keeps its own.",
|
|
33
|
+
)
|
|
34
|
+
@option(
|
|
35
|
+
name="options",
|
|
36
|
+
type=str,
|
|
37
|
+
required=False,
|
|
38
|
+
default="{}",
|
|
39
|
+
description="Its options, a JSON object, handed to the type as they are.",
|
|
40
|
+
)
|
|
41
|
+
@option(
|
|
42
|
+
name="severity",
|
|
43
|
+
short_name="sv",
|
|
44
|
+
type=str,
|
|
45
|
+
required=False,
|
|
46
|
+
description="How serious what it finds is (`warning`, `error`…); left out, the reader's default.",
|
|
47
|
+
)
|
|
48
|
+
@api_command(commit_subject="process edition")
|
|
49
|
+
@middleware(middleware=AppMiddleware)
|
|
50
|
+
@command(
|
|
51
|
+
type=COMMAND_TYPE_ADDON,
|
|
52
|
+
description="Rewrite a process of the app from the fields a form holds. Fields of the record it does not take stay as they were.",
|
|
53
|
+
tags=[
|
|
54
|
+
EffectTag.WRITE,
|
|
55
|
+
ScopeTag.APP,
|
|
56
|
+
ScopeTag.LOCAL,
|
|
57
|
+
],
|
|
58
|
+
)
|
|
59
|
+
def process__process__update(
|
|
60
|
+
context: ExecutionContext,
|
|
61
|
+
app_workdir: ManagedWorkdir,
|
|
62
|
+
id: str,
|
|
63
|
+
title: str,
|
|
64
|
+
type: str,
|
|
65
|
+
selection: str | None = None,
|
|
66
|
+
options: str = "{}",
|
|
67
|
+
severity: str | None = None,
|
|
68
|
+
) -> AbstractResponse:
|
|
69
|
+
import json
|
|
70
|
+
|
|
71
|
+
from wexample_app.response.dict_response import DictResponse
|
|
72
|
+
|
|
73
|
+
from wexample_wex_addon_process.const.process import (
|
|
74
|
+
KIND_PROCESS,
|
|
75
|
+
KIND_SELECTION,
|
|
76
|
+
PROCESS_KEY_OPTIONS,
|
|
77
|
+
PROCESS_KEY_SELECTION_ID,
|
|
78
|
+
PROCESS_KEY_SEVERITY,
|
|
79
|
+
PROCESS_KEY_TITLE,
|
|
80
|
+
PROCESS_KEY_TYPE,
|
|
81
|
+
)
|
|
82
|
+
from wexample_wex_addon_process.exception.record_not_found_exception import (
|
|
83
|
+
RecordNotFoundException,
|
|
84
|
+
)
|
|
85
|
+
from wexample_wex_addon_process.record.record_file import record_path, write_record
|
|
86
|
+
|
|
87
|
+
app_path = app_workdir.get_path()
|
|
88
|
+
record = record_path(app_path, KIND_PROCESS, id)
|
|
89
|
+
if not record.is_file():
|
|
90
|
+
raise RecordNotFoundException(kind=KIND_PROCESS, record_id=id)
|
|
91
|
+
values = {
|
|
92
|
+
PROCESS_KEY_TITLE: title,
|
|
93
|
+
PROCESS_KEY_TYPE: type,
|
|
94
|
+
PROCESS_KEY_OPTIONS: json.loads(options),
|
|
95
|
+
}
|
|
96
|
+
if selection:
|
|
97
|
+
if not record_path(app_path, KIND_SELECTION, selection).is_file():
|
|
98
|
+
raise RecordNotFoundException(kind=KIND_SELECTION, record_id=selection)
|
|
99
|
+
values[PROCESS_KEY_SELECTION_ID] = selection
|
|
100
|
+
if severity:
|
|
101
|
+
values[PROCESS_KEY_SEVERITY] = severity
|
|
102
|
+
write_record(record, values)
|
|
103
|
+
|
|
104
|
+
return DictResponse(
|
|
105
|
+
kernel=context.kernel,
|
|
106
|
+
content={"id": id, "path": str(record), "written": [str(record)]},
|
|
107
|
+
)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from wexample_cli.const.tags import EffectTag, ScopeTag
|
|
6
|
+
from wexample_cli.decorator.api_command import api_command
|
|
7
|
+
from wexample_cli.decorator.command import command
|
|
8
|
+
from wexample_cli.decorator.middleware import middleware
|
|
9
|
+
from wexample_cli.decorator.option import option
|
|
10
|
+
from wexample_wex_addon_app.middleware.app_middleware import AppMiddleware
|
|
11
|
+
from wexample_wex_core.const.globals import COMMAND_TYPE_ADDON
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from wexample_app.response.abstract_response import AbstractResponse
|
|
15
|
+
from wexample_cli.context.execution_context import ExecutionContext
|
|
16
|
+
from wexample_wex_addon_app.workdir.managed_workdir import ManagedWorkdir
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@option(name="id", type=str, required=True, description="Uuid of the run to stop.")
|
|
20
|
+
@api_command(commit_subject="process run cancel")
|
|
21
|
+
@middleware(middleware=AppMiddleware)
|
|
22
|
+
@command(
|
|
23
|
+
type=COMMAND_TYPE_ADDON,
|
|
24
|
+
description="Ask a run to stop. Whoever executes it reads the request between two items, so the file under way is finished first.",
|
|
25
|
+
tags=[
|
|
26
|
+
EffectTag.WRITE,
|
|
27
|
+
ScopeTag.APP,
|
|
28
|
+
ScopeTag.LOCAL,
|
|
29
|
+
],
|
|
30
|
+
)
|
|
31
|
+
def process__run__cancel(
|
|
32
|
+
context: ExecutionContext,
|
|
33
|
+
app_workdir: ManagedWorkdir,
|
|
34
|
+
id: str,
|
|
35
|
+
) -> AbstractResponse:
|
|
36
|
+
from wexample_app.response.dict_response import DictResponse
|
|
37
|
+
|
|
38
|
+
from wexample_wex_addon_process.const.process import (
|
|
39
|
+
KIND_PROCESS_RUN,
|
|
40
|
+
RUN_KEY_CANCEL,
|
|
41
|
+
)
|
|
42
|
+
from wexample_wex_addon_process.record.record_file import record_path, write_record
|
|
43
|
+
|
|
44
|
+
path = record_path(app_workdir.get_path(), KIND_PROCESS_RUN, id)
|
|
45
|
+
if not path.is_file():
|
|
46
|
+
from wexample_wex_addon_process.exception.record_not_found_exception import (
|
|
47
|
+
RecordNotFoundException,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
raise RecordNotFoundException(kind=KIND_PROCESS_RUN, record_id=id)
|
|
51
|
+
write_record(path, {RUN_KEY_CANCEL: True})
|
|
52
|
+
|
|
53
|
+
# Nothing to commit: runs stay out of the project's history.
|
|
54
|
+
return DictResponse(kernel=context.kernel, content={"id": id, "path": str(path), "written": []})
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from wexample_cli.const.tags import EffectTag, ScopeTag
|
|
6
|
+
from wexample_cli.decorator.api_command import api_command
|
|
7
|
+
from wexample_cli.decorator.command import command
|
|
8
|
+
from wexample_cli.decorator.middleware import middleware
|
|
9
|
+
from wexample_cli.decorator.option import option
|
|
10
|
+
from wexample_wex_addon_app.middleware.app_middleware import AppMiddleware
|
|
11
|
+
from wexample_wex_core.const.globals import COMMAND_TYPE_ADDON
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from wexample_app.response.abstract_response import AbstractResponse
|
|
15
|
+
from wexample_cli.context.execution_context import ExecutionContext
|
|
16
|
+
from wexample_wex_addon_app.workdir.managed_workdir import ManagedWorkdir
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@option(
|
|
20
|
+
name="process",
|
|
21
|
+
type=str,
|
|
22
|
+
required=True,
|
|
23
|
+
description="Uuid of the process to run: a record under `.wex/data/process/`, or one an addon ships (`/data/process` lists them).",
|
|
24
|
+
)
|
|
25
|
+
@option(
|
|
26
|
+
name="options",
|
|
27
|
+
short_name="o",
|
|
28
|
+
type=str,
|
|
29
|
+
required=False,
|
|
30
|
+
description="Options of the run's own, a JSON object laid over the process's.",
|
|
31
|
+
)
|
|
32
|
+
@option(
|
|
33
|
+
name="action",
|
|
34
|
+
type=str,
|
|
35
|
+
required=False,
|
|
36
|
+
description="What the run does instead of the process's own action.",
|
|
37
|
+
)
|
|
38
|
+
@option(
|
|
39
|
+
name="items",
|
|
40
|
+
type=str,
|
|
41
|
+
required=False,
|
|
42
|
+
description="What it goes through instead of the selection, a JSON list of paths.",
|
|
43
|
+
)
|
|
44
|
+
@option(
|
|
45
|
+
name="commit_work",
|
|
46
|
+
short_name="cw",
|
|
47
|
+
type=bool,
|
|
48
|
+
is_flag=True,
|
|
49
|
+
default=False,
|
|
50
|
+
description="Have the run commit the paths it declares it wrote, once it is done.",
|
|
51
|
+
)
|
|
52
|
+
@option(
|
|
53
|
+
name="work_author",
|
|
54
|
+
short_name="wa",
|
|
55
|
+
type=str,
|
|
56
|
+
required=False,
|
|
57
|
+
description="`Name <email>` the run's commit is signed by.",
|
|
58
|
+
)
|
|
59
|
+
@api_command(commit_subject="process run")
|
|
60
|
+
@middleware(middleware=AppMiddleware)
|
|
61
|
+
@command(
|
|
62
|
+
type=COMMAND_TYPE_ADDON,
|
|
63
|
+
description="Open a run of a process, pending, its record under `.wex/data/process_run/` — what a worker picks up, or `process::run/execute` runs by hand. Runs stay out of the project's history: their directory ignores them.",
|
|
64
|
+
tags=[
|
|
65
|
+
EffectTag.CREATE,
|
|
66
|
+
ScopeTag.APP,
|
|
67
|
+
ScopeTag.LOCAL,
|
|
68
|
+
],
|
|
69
|
+
)
|
|
70
|
+
def process__run__create(
|
|
71
|
+
context: ExecutionContext,
|
|
72
|
+
app_workdir: ManagedWorkdir,
|
|
73
|
+
process: str,
|
|
74
|
+
action: str | None = None,
|
|
75
|
+
items: str | None = None,
|
|
76
|
+
options: str | None = None,
|
|
77
|
+
commit_work: bool = False,
|
|
78
|
+
work_author: str | None = None,
|
|
79
|
+
) -> AbstractResponse:
|
|
80
|
+
import json
|
|
81
|
+
from datetime import UTC, datetime
|
|
82
|
+
|
|
83
|
+
from wexample_app.response.dict_response import DictResponse
|
|
84
|
+
from wexample_wex_core.helper.data_record import data_kind_dir, new_record_path
|
|
85
|
+
|
|
86
|
+
from wexample_wex_addon_process.builtin.builtin_process_registry import (
|
|
87
|
+
BuiltinProcessRegistry,
|
|
88
|
+
)
|
|
89
|
+
from wexample_wex_addon_process.const.process import (
|
|
90
|
+
KIND_PROCESS,
|
|
91
|
+
KIND_PROCESS_RUN,
|
|
92
|
+
RUN_KEY_ACTION,
|
|
93
|
+
RUN_KEY_AUTHOR,
|
|
94
|
+
RUN_KEY_COMMIT,
|
|
95
|
+
RUN_KEY_DATE_CREATED,
|
|
96
|
+
RUN_KEY_ITEMS,
|
|
97
|
+
RUN_KEY_OPTIONS,
|
|
98
|
+
RUN_KEY_PROCESS_ID,
|
|
99
|
+
RUN_KEY_STATE,
|
|
100
|
+
STATE_PENDING,
|
|
101
|
+
)
|
|
102
|
+
from wexample_wex_addon_process.record.record_file import record_path, write_record
|
|
103
|
+
|
|
104
|
+
app_path = app_workdir.get_path()
|
|
105
|
+
if (
|
|
106
|
+
not record_path(app_path, KIND_PROCESS, process).is_file()
|
|
107
|
+
and BuiltinProcessRegistry.from_kernel(context.kernel).get(process) is None
|
|
108
|
+
):
|
|
109
|
+
from wexample_wex_addon_process.exception.record_not_found_exception import (
|
|
110
|
+
RecordNotFoundException,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
raise RecordNotFoundException(kind=KIND_PROCESS, record_id=process)
|
|
114
|
+
|
|
115
|
+
directory = data_kind_dir(app_path, KIND_PROCESS_RUN)
|
|
116
|
+
directory.mkdir(parents=True, exist_ok=True)
|
|
117
|
+
# A process is a declaration worth committing and a run is a dated fact that is
|
|
118
|
+
# not, so the directory holding them says so itself rather than relying on every
|
|
119
|
+
# project to have thought of it.
|
|
120
|
+
ignore = directory / ".gitignore"
|
|
121
|
+
written = []
|
|
122
|
+
if not ignore.is_file():
|
|
123
|
+
ignore.write_text("*\n!.gitignore\n", encoding="utf-8")
|
|
124
|
+
written.append(str(ignore))
|
|
125
|
+
|
|
126
|
+
# The overrides only when there are some: a run that names none is the process as
|
|
127
|
+
# declared, and its record says nothing more.
|
|
128
|
+
values = {
|
|
129
|
+
RUN_KEY_PROCESS_ID: process,
|
|
130
|
+
RUN_KEY_STATE: STATE_PENDING,
|
|
131
|
+
RUN_KEY_ACTION: action,
|
|
132
|
+
RUN_KEY_ITEMS: json.loads(items) if items else None,
|
|
133
|
+
RUN_KEY_OPTIONS: json.loads(options) if options else None,
|
|
134
|
+
RUN_KEY_COMMIT: commit_work,
|
|
135
|
+
RUN_KEY_AUTHOR: work_author if commit_work else None,
|
|
136
|
+
RUN_KEY_DATE_CREATED: datetime.now(UTC).isoformat(timespec="seconds"),
|
|
137
|
+
}
|
|
138
|
+
record = new_record_path(directory)
|
|
139
|
+
write_record(record, {key: value for key, value in values.items() if value is not None})
|
|
140
|
+
|
|
141
|
+
return DictResponse(
|
|
142
|
+
kernel=context.kernel,
|
|
143
|
+
content={"id": record.stem, "path": str(record), "written": written},
|
|
144
|
+
)
|