pypeline-runner 1.2.0__tar.gz → 1.4.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.
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/PKG-INFO +3 -4
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/pyproject.toml +7 -7
- pypeline_runner-1.4.0/src/pypeline/__init__.py +1 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/domain/pipeline.py +32 -6
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/kickstart/templates/project/bootstrap.ps1 +1 -1
- pypeline_runner-1.4.0/src/pypeline/kickstart/templates/project/pypeline.ps1 +7 -0
- pypeline_runner-1.4.0/src/pypeline/kickstart/templates/project/pypeline.yaml +9 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/main.py +4 -2
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/pypeline.py +9 -6
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/steps/create_venv.py +0 -1
- pypeline_runner-1.2.0/src/pypeline/__init__.py +0 -1
- pypeline_runner-1.2.0/src/pypeline/kickstart/templates/project/pypeline.ps1 +0 -1
- pypeline_runner-1.2.0/src/pypeline/kickstart/templates/project/pypeline.yaml +0 -12
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/LICENSE +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/README.md +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/__run.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/domain/__init__.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/domain/artifacts.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/domain/config.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/domain/execution_context.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/domain/project_slurper.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/kickstart/__init__.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/kickstart/create.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/kickstart/templates/project/.gitignore +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/kickstart/templates/project/poetry.toml +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/kickstart/templates/project/pyproject.toml +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/kickstart/templates/project/scoopfile.json +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/kickstart/templates/project/steps/my_step.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/py.typed +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/steps/__init__.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/steps/scoop_install.py +0 -0
- {pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/steps/west_install.py +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: pypeline-runner
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Configure and execute pipelines with Python (similar to GitHub workflows or Jenkins pipelines).
|
|
5
|
-
Home-page: https://github.com/cuinixam/pypeline
|
|
6
5
|
License: MIT
|
|
7
6
|
Author: cuinixam
|
|
8
7
|
Author-email: me@cuinixam.com
|
|
@@ -20,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
20
19
|
Classifier: Topic :: Software Development :: Libraries
|
|
21
20
|
Requires-Dist: py-app-dev (>=2.3.3,<3.0.0)
|
|
22
21
|
Requires-Dist: pyyaml (>=6.0,<7.0)
|
|
23
|
-
Requires-Dist: typer
|
|
22
|
+
Requires-Dist: typer (>=0.12,<0.13)
|
|
24
23
|
Project-URL: Bug Tracker, https://github.com/cuinixam/pypeline/issues
|
|
25
24
|
Project-URL: Changelog, https://github.com/cuinixam/pypeline/blob/main/CHANGELOG.md
|
|
26
25
|
Project-URL: Documentation, https://pypeline-runner.readthedocs.io
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "pypeline-runner"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.4.0"
|
|
4
4
|
description = "Configure and execute pipelines with Python (similar to GitHub workflows or Jenkins pipelines)."
|
|
5
5
|
authors = ["cuinixam <me@cuinixam.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -28,14 +28,14 @@ pypeline = "pypeline.main:main"
|
|
|
28
28
|
[tool.poetry.dependencies]
|
|
29
29
|
python = "^3.10"
|
|
30
30
|
py-app-dev = "^2.3.3"
|
|
31
|
-
typer =
|
|
31
|
+
typer = "^0.12"
|
|
32
32
|
pyyaml = "^6.0"
|
|
33
33
|
|
|
34
34
|
[tool.poetry.group.dev.dependencies]
|
|
35
|
-
pytest = "^
|
|
36
|
-
pytest-cov = "^
|
|
37
|
-
pre-commit = "^
|
|
38
|
-
ruff = "^0.
|
|
35
|
+
pytest = "^8.3"
|
|
36
|
+
pytest-cov = "^6.0"
|
|
37
|
+
pre-commit = "^4.0"
|
|
38
|
+
ruff = "^0.9"
|
|
39
39
|
|
|
40
40
|
[tool.poetry.group.docs.dependencies]
|
|
41
41
|
myst-parser = ">=0.16"
|
|
@@ -72,7 +72,7 @@ match = "(?!main$)"
|
|
|
72
72
|
prerelease = true
|
|
73
73
|
|
|
74
74
|
[tool.pytest.ini_options]
|
|
75
|
-
addopts = "-vv -Wdefault --cov=pypeline --cov-report=term-missing:skip-covered"
|
|
75
|
+
addopts = "-vv -Wdefault --cov=pypeline --cov-report=term-missing:skip-covered --cov-branch"
|
|
76
76
|
pythonpath = ["src"]
|
|
77
77
|
|
|
78
78
|
[tool.coverage.run]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.4.0"
|
|
@@ -5,12 +5,15 @@ from typing import (
|
|
|
5
5
|
Any,
|
|
6
6
|
Dict,
|
|
7
7
|
Generic,
|
|
8
|
+
Iterator,
|
|
8
9
|
List,
|
|
9
10
|
Optional,
|
|
10
11
|
OrderedDict,
|
|
12
|
+
Tuple,
|
|
11
13
|
Type,
|
|
12
14
|
TypeAlias,
|
|
13
15
|
TypeVar,
|
|
16
|
+
Union,
|
|
14
17
|
)
|
|
15
18
|
|
|
16
19
|
from mashumaro import DataClassDictMixin
|
|
@@ -29,8 +32,8 @@ class PipelineStepConfig(DataClassDictMixin):
|
|
|
29
32
|
module: Optional[str] = None
|
|
30
33
|
#: Step class name
|
|
31
34
|
class_name: Optional[str] = None
|
|
32
|
-
#: Command to run. For simple steps that don't need a class
|
|
33
|
-
run: Optional[str] = None
|
|
35
|
+
#: Command to run. For simple steps that don't need a class. Example: run: [echo, 'Hello World!']
|
|
36
|
+
run: Optional[Union[str, List[str]]] = None
|
|
34
37
|
#: Step description
|
|
35
38
|
description: Optional[str] = None
|
|
36
39
|
#: Step timeout in seconds
|
|
@@ -39,7 +42,27 @@ class PipelineStepConfig(DataClassDictMixin):
|
|
|
39
42
|
config: Optional[Dict[str, Any]] = None
|
|
40
43
|
|
|
41
44
|
|
|
42
|
-
PipelineConfig: TypeAlias = OrderedDict[str, List[PipelineStepConfig]]
|
|
45
|
+
PipelineConfig: TypeAlias = Union[List[PipelineStepConfig], OrderedDict[str, List[PipelineStepConfig]]]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PipelineConfigIterator:
|
|
49
|
+
"""
|
|
50
|
+
Iterates over the pipeline configuration, yielding group name and steps configuration.
|
|
51
|
+
|
|
52
|
+
This class abstracts the iteration logic for PipelineConfig, which can be:
|
|
53
|
+
- A list of steps (group name is None)
|
|
54
|
+
- An OrderedDict with group names as keys and lists of steps as values.
|
|
55
|
+
|
|
56
|
+
The iterator yields tuples of (group_name, steps).
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(self, pipeline_config: PipelineConfig) -> None:
|
|
60
|
+
self._items = pipeline_config.items() if isinstance(pipeline_config, OrderedDict) else [(None, pipeline_config)]
|
|
61
|
+
|
|
62
|
+
def __iter__(self) -> Iterator[Tuple[Optional[str], List[PipelineStepConfig]]]:
|
|
63
|
+
"""Return an iterator."""
|
|
64
|
+
yield from self._items
|
|
65
|
+
|
|
43
66
|
|
|
44
67
|
TExecutionContext = TypeVar("TExecutionContext", bound=ExecutionContext)
|
|
45
68
|
|
|
@@ -47,7 +70,7 @@ TExecutionContext = TypeVar("TExecutionContext", bound=ExecutionContext)
|
|
|
47
70
|
class PipelineStep(Generic[TExecutionContext], Runnable):
|
|
48
71
|
"""One can create subclasses of PipelineStep that specify the type of ExecutionContext they require."""
|
|
49
72
|
|
|
50
|
-
def __init__(self, execution_context: TExecutionContext, group_name: str, config: Optional[Dict[str, Any]] = None) -> None:
|
|
73
|
+
def __init__(self, execution_context: TExecutionContext, group_name: Optional[str], config: Optional[Dict[str, Any]] = None) -> None:
|
|
51
74
|
super().__init__(self.get_needs_dependency_management())
|
|
52
75
|
self.execution_context = execution_context
|
|
53
76
|
self.group_name = group_name
|
|
@@ -56,7 +79,10 @@ class PipelineStep(Generic[TExecutionContext], Runnable):
|
|
|
56
79
|
|
|
57
80
|
@property
|
|
58
81
|
def output_dir(self) -> Path:
|
|
59
|
-
|
|
82
|
+
output_dir = self.execution_context.create_artifacts_locator().build_dir
|
|
83
|
+
if self.group_name:
|
|
84
|
+
output_dir = output_dir / self.group_name
|
|
85
|
+
return output_dir
|
|
60
86
|
|
|
61
87
|
@abstractmethod
|
|
62
88
|
def update_execution_context(self) -> None:
|
|
@@ -73,7 +99,7 @@ class PipelineStep(Generic[TExecutionContext], Runnable):
|
|
|
73
99
|
|
|
74
100
|
|
|
75
101
|
class PipelineStepReference(Generic[TExecutionContext]):
|
|
76
|
-
def __init__(self, group_name: str, _class: Type[PipelineStep[TExecutionContext]], config: Optional[Dict[str, Any]] = None) -> None:
|
|
102
|
+
def __init__(self, group_name: Optional[str], _class: Type[PipelineStep[TExecutionContext]], config: Optional[Dict[str, Any]] = None) -> None:
|
|
77
103
|
self.group_name = group_name
|
|
78
104
|
self._class = _class
|
|
79
105
|
self.config = config
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
function Invoke-Bootstrap {
|
|
7
7
|
# Download bootstrap scripts from external repository
|
|
8
|
-
Invoke-RestMethod https://raw.githubusercontent.com/avengineers/bootstrap-installer/v1.15.
|
|
8
|
+
Invoke-RestMethod https://raw.githubusercontent.com/avengineers/bootstrap-installer/v1.15.1/install.ps1 | Invoke-Expression
|
|
9
9
|
# Execute bootstrap script
|
|
10
10
|
. .\.bootstrap\bootstrap.ps1
|
|
11
11
|
}
|
|
@@ -8,6 +8,7 @@ from py_app_dev.core.logging import logger, setup_logger, time_it
|
|
|
8
8
|
|
|
9
9
|
from pypeline import __version__
|
|
10
10
|
from pypeline.domain.execution_context import ExecutionContext
|
|
11
|
+
from pypeline.domain.pipeline import PipelineConfigIterator
|
|
11
12
|
from pypeline.domain.project_slurper import ProjectSlurper
|
|
12
13
|
from pypeline.kickstart.create import KickstartProject
|
|
13
14
|
from pypeline.pypeline import PipelineScheduler, PipelineStepsExecutor
|
|
@@ -69,8 +70,9 @@ def run(
|
|
|
69
70
|
project_slurper = ProjectSlurper(project_dir)
|
|
70
71
|
if print:
|
|
71
72
|
logger.info("Pipeline steps:")
|
|
72
|
-
for group, step_configs in project_slurper.pipeline
|
|
73
|
-
|
|
73
|
+
for group, step_configs in PipelineConfigIterator(project_slurper.pipeline):
|
|
74
|
+
if group:
|
|
75
|
+
logger.info(f" Group: {group}")
|
|
74
76
|
for step_config in step_configs:
|
|
75
77
|
logger.info(f" {step_config.step}")
|
|
76
78
|
return
|
|
@@ -17,7 +17,7 @@ from py_app_dev.core.runnable import Executor
|
|
|
17
17
|
|
|
18
18
|
from .domain.artifacts import ProjectArtifactsLocator
|
|
19
19
|
from .domain.execution_context import ExecutionContext
|
|
20
|
-
from .domain.pipeline import PipelineConfig, PipelineStep, PipelineStepConfig, PipelineStepReference, TExecutionContext
|
|
20
|
+
from .domain.pipeline import PipelineConfig, PipelineConfigIterator, PipelineStep, PipelineStepConfig, PipelineStepReference, TExecutionContext
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class PipelineLoader(Generic[TExecutionContext]):
|
|
@@ -35,13 +35,13 @@ class PipelineLoader(Generic[TExecutionContext]):
|
|
|
35
35
|
|
|
36
36
|
def load_steps_references(self) -> List[PipelineStepReference[TExecutionContext]]:
|
|
37
37
|
result = []
|
|
38
|
-
for group_name, steps_config in self.pipeline_config
|
|
38
|
+
for group_name, steps_config in PipelineConfigIterator(self.pipeline_config):
|
|
39
39
|
result.extend(self._load_steps(group_name, steps_config, self.project_root_dir))
|
|
40
40
|
return result
|
|
41
41
|
|
|
42
42
|
@staticmethod
|
|
43
43
|
def _load_steps(
|
|
44
|
-
group_name: str,
|
|
44
|
+
group_name: Optional[str],
|
|
45
45
|
steps_config: List[PipelineStepConfig],
|
|
46
46
|
project_root_dir: Path,
|
|
47
47
|
) -> List[PipelineStepReference[TExecutionContext]]:
|
|
@@ -53,7 +53,9 @@ class PipelineLoader(Generic[TExecutionContext]):
|
|
|
53
53
|
elif step_config.file:
|
|
54
54
|
step_class = PipelineLoader._load_user_step(project_root_dir.joinpath(step_config.file), step_class_name)
|
|
55
55
|
elif step_config.run:
|
|
56
|
-
|
|
56
|
+
# We want the run field to always return a list of strings (the command and its arguments).
|
|
57
|
+
run_command = step_config.run.split(" ") if isinstance(step_config.run, str) else step_config.run
|
|
58
|
+
step_class = PipelineLoader._create_run_command_step_class(run_command, step_class_name)
|
|
57
59
|
else:
|
|
58
60
|
raise UserNotificationException(f"Step '{step_class_name}' has no 'module' nor 'file' nor `run` defined." " Please check your pipeline configuration.")
|
|
59
61
|
result.append(PipelineStepReference[TExecutionContext](group_name, cast(Type[PipelineStep[TExecutionContext]], step_class), step_config.config))
|
|
@@ -86,7 +88,7 @@ class PipelineLoader(Generic[TExecutionContext]):
|
|
|
86
88
|
return step_class
|
|
87
89
|
|
|
88
90
|
@staticmethod
|
|
89
|
-
def _create_run_command_step_class(command: str, name: str) -> Type[PipelineStep[ExecutionContext]]:
|
|
91
|
+
def _create_run_command_step_class(command: List[str], name: str) -> Type[PipelineStep[ExecutionContext]]:
|
|
90
92
|
"""Dynamically creates a step class for a given command."""
|
|
91
93
|
|
|
92
94
|
class TmpDynamicRunCommandStep(PipelineStep[ExecutionContext]):
|
|
@@ -103,7 +105,8 @@ class PipelineLoader(Generic[TExecutionContext]):
|
|
|
103
105
|
|
|
104
106
|
def run(self) -> int:
|
|
105
107
|
self.execution_context.create_process_executor(
|
|
106
|
-
[
|
|
108
|
+
# We have to disable type checking for the command because mypy considers that a List[str] is not compatible with a List[Union[str, Path]] :(
|
|
109
|
+
self.command, # type: ignore
|
|
107
110
|
cwd=self.project_root_dir,
|
|
108
111
|
).execute()
|
|
109
112
|
return 0
|
|
@@ -19,7 +19,6 @@ class CreateVEnv(PipelineStep[ExecutionContext]):
|
|
|
19
19
|
def __init__(self, execution_context: ExecutionContext, group_name: str, config: Optional[Dict[str, Any]] = None) -> None:
|
|
20
20
|
super().__init__(execution_context, group_name, config)
|
|
21
21
|
self.logger = logger.bind()
|
|
22
|
-
self.logger = logger.bind()
|
|
23
22
|
|
|
24
23
|
@property
|
|
25
24
|
def install_dirs(self) -> List[Path]:
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.2.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.\.venv\Scripts\pypeline.exe $args
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
pipeline:
|
|
2
|
-
venv:
|
|
3
|
-
- step: CreateVEnv
|
|
4
|
-
module: pypeline.steps.create_venv
|
|
5
|
-
config:
|
|
6
|
-
bootstrap_script: .bootstrap/bootstrap.py
|
|
7
|
-
install:
|
|
8
|
-
- step: ScoopInstall
|
|
9
|
-
module: pypeline.steps.scoop_install
|
|
10
|
-
custom:
|
|
11
|
-
- step: MyStep
|
|
12
|
-
file: steps/my_step.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/kickstart/templates/project/.gitignore
RENAMED
|
File without changes
|
{pypeline_runner-1.2.0 → pypeline_runner-1.4.0}/src/pypeline/kickstart/templates/project/poetry.toml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|