LiteBuild 0.2__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.
- litebuild-0.2/LICENSE +7 -0
- litebuild-0.2/LiteBuild.egg-info/PKG-INFO +34 -0
- litebuild-0.2/LiteBuild.egg-info/SOURCES.txt +9 -0
- litebuild-0.2/LiteBuild.egg-info/dependency_links.txt +1 -0
- litebuild-0.2/LiteBuild.egg-info/entry_points.txt +2 -0
- litebuild-0.2/LiteBuild.egg-info/requires.txt +9 -0
- litebuild-0.2/LiteBuild.egg-info/top_level.txt +3 -0
- litebuild-0.2/PKG-INFO +34 -0
- litebuild-0.2/pyproject.toml +45 -0
- litebuild-0.2/setup.cfg +4 -0
- litebuild-0.2/tests/test_build_engine.py +248 -0
litebuild-0.2/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2025 corb555
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: LiteBuild
|
|
3
|
+
Version: 0.2
|
|
4
|
+
Summary: Lightweight build engine
|
|
5
|
+
Author: corb
|
|
6
|
+
License: Copyright 2025 corb555
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
11
|
+
|
|
12
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
13
|
+
Project-URL: Repository, https://github.com/corb555/LiteBuild
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
21
|
+
Classifier: Operating System :: MacOS
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: joblib>=1.5
|
|
26
|
+
Requires-Dist: matplotlib>=3.10
|
|
27
|
+
Requires-Dist: numpy>=2.2.6
|
|
28
|
+
Requires-Dist: pandas>=2.2.3
|
|
29
|
+
Requires-Dist: scikit-learn>=1.6.1
|
|
30
|
+
Requires-Dist: flashtext>=2.7
|
|
31
|
+
Requires-Dist: YMLEditor>=0.5.0
|
|
32
|
+
Requires-Dist: optuna>=4.5.0
|
|
33
|
+
Requires-Dist: shap>=0.47.2
|
|
34
|
+
Dynamic: license-file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
pyproject.toml
|
|
3
|
+
LiteBuild.egg-info/PKG-INFO
|
|
4
|
+
LiteBuild.egg-info/SOURCES.txt
|
|
5
|
+
LiteBuild.egg-info/dependency_links.txt
|
|
6
|
+
LiteBuild.egg-info/entry_points.txt
|
|
7
|
+
LiteBuild.egg-info/requires.txt
|
|
8
|
+
LiteBuild.egg-info/top_level.txt
|
|
9
|
+
tests/test_build_engine.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
litebuild-0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: LiteBuild
|
|
3
|
+
Version: 0.2
|
|
4
|
+
Summary: Lightweight build engine
|
|
5
|
+
Author: corb
|
|
6
|
+
License: Copyright 2025 corb555
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
11
|
+
|
|
12
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
13
|
+
Project-URL: Repository, https://github.com/corb555/LiteBuild
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
21
|
+
Classifier: Operating System :: MacOS
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: joblib>=1.5
|
|
26
|
+
Requires-Dist: matplotlib>=3.10
|
|
27
|
+
Requires-Dist: numpy>=2.2.6
|
|
28
|
+
Requires-Dist: pandas>=2.2.3
|
|
29
|
+
Requires-Dist: scikit-learn>=1.6.1
|
|
30
|
+
Requires-Dist: flashtext>=2.7
|
|
31
|
+
Requires-Dist: YMLEditor>=0.5.0
|
|
32
|
+
Requires-Dist: optuna>=4.5.0
|
|
33
|
+
Requires-Dist: shap>=0.47.2
|
|
34
|
+
Dynamic: license-file
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "LiteBuild"
|
|
7
|
+
version = "0.2"
|
|
8
|
+
description = "Lightweight build engine"
|
|
9
|
+
authors = [{ name = "corb" }]
|
|
10
|
+
readme = { file = "readme.md", content-type = "text/markdown" }
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
dependencies = [
|
|
14
|
+
"joblib>=1.5",
|
|
15
|
+
"matplotlib>=3.10",
|
|
16
|
+
"numpy>=2.2.6",
|
|
17
|
+
"pandas>=2.2.3",
|
|
18
|
+
"scikit-learn>=1.6.1",
|
|
19
|
+
"flashtext>=2.7",
|
|
20
|
+
"YMLEditor>=0.5.0",
|
|
21
|
+
"optuna>=4.5.0",
|
|
22
|
+
"shap>=0.47.2",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
classifiers = [
|
|
26
|
+
"Intended Audience :: Developers",
|
|
27
|
+
"Topic :: Scientific/Engineering :: GIS",
|
|
28
|
+
"Programming Language :: Python :: 3.8",
|
|
29
|
+
"Programming Language :: Python :: 3.9",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Operating System :: POSIX :: Linux",
|
|
33
|
+
"Operating System :: MacOS",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
LiteBuild = "LiteBuild.lite_build_runner:main"
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Repository = "https://github.com/corb555/LiteBuild"
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.packages.find]
|
|
43
|
+
where = ["."]
|
|
44
|
+
exclude = ["tests*"]
|
|
45
|
+
|
litebuild-0.2/setup.cfg
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# tests/test_build_engine.py
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
# Assume build_engine and its dependencies are in the python path
|
|
8
|
+
from build_engine import BuildPlanner, UpdateCode
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# --- Test Fixtures and Test Data ---
|
|
12
|
+
|
|
13
|
+
@pytest.fixture
|
|
14
|
+
def base_config():
|
|
15
|
+
"""Provides a basic, valid configuration for tests."""
|
|
16
|
+
return {
|
|
17
|
+
"GENERAL": {
|
|
18
|
+
"VAR1": "general_value"
|
|
19
|
+
}, "PROFILES": {
|
|
20
|
+
"test_profile": {
|
|
21
|
+
"VAR2": "profile_value"
|
|
22
|
+
}
|
|
23
|
+
}, "WORKFLOW": {
|
|
24
|
+
"StepA": {
|
|
25
|
+
"OUTPUT": "output_a.txt", "REQUIRES": [],
|
|
26
|
+
"RULE": {"NAME": "rule_a", "COMMAND": "echo A > {OUTPUT}"}
|
|
27
|
+
}, "StepB": {
|
|
28
|
+
"OUTPUT": "output_b.txt", "REQUIRES": ["StepA"], "INPUTS": ["{REQUIRES[0]}"],
|
|
29
|
+
"RULE": {"NAME": "rule_b", "COMMAND": "cat {INPUTS[0]} > {OUTPUT}"}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.fixture
|
|
36
|
+
def command_map():
|
|
37
|
+
"""Provides a sample command map, simulating the output of CommandGenerator."""
|
|
38
|
+
return {
|
|
39
|
+
"StepA": {
|
|
40
|
+
"output": "output_a.txt", "input_files": [], "hashes": {
|
|
41
|
+
"command": "hash_cmd_a", "inputs": "hash_inputs_a", "params": "hash_params_a"
|
|
42
|
+
}
|
|
43
|
+
}, "StepB": {
|
|
44
|
+
"output": "output_b.txt", "input_files": ["output_a.txt"], "hashes": {
|
|
45
|
+
"command": "hash_cmd_b", "inputs": "hash_inputs_b", "params": "hash_params_b"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@pytest.fixture
|
|
52
|
+
def execution_graph(base_config):
|
|
53
|
+
"""Provides a sample NetworkX graph."""
|
|
54
|
+
# In a real scenario, this would be generated by DependencyGraph
|
|
55
|
+
import networkx as nx
|
|
56
|
+
G = nx.DiGraph()
|
|
57
|
+
G.add_node("StepA", **base_config["WORKFLOW"]["StepA"])
|
|
58
|
+
G.add_node("StepB", **base_config["WORKFLOW"]["StepB"])
|
|
59
|
+
G.add_edge("StepA", "StepB")
|
|
60
|
+
return G
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# --- Parameterized Tests for `_is_step_outdated` ---
|
|
64
|
+
|
|
65
|
+
# Define the test cases for various outdated scenarios
|
|
66
|
+
# Each tuple is: (test_id, build_state, expected_code, expected_context)
|
|
67
|
+
outdated_test_cases = [pytest.param(
|
|
68
|
+
"up_to_date", {
|
|
69
|
+
"output_a.txt": {
|
|
70
|
+
"mtime": time.time() - 10, "hashes": {
|
|
71
|
+
"command": "hash_cmd_a", "inputs": "hash_inputs_a", "params": "hash_params_a"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}, UpdateCode.UP_TO_DATE, "", id="up_to_date"
|
|
75
|
+
), pytest.param(
|
|
76
|
+
"missing_output", {}, # Build state is empty, so output_a.txt is not tracked
|
|
77
|
+
UpdateCode.MISSING_OUTPUT, "output_a.txt", id="missing_output"
|
|
78
|
+
), pytest.param(
|
|
79
|
+
"not_tracked", {"some_other_file.txt": {}}, # output_a.txt is not a key
|
|
80
|
+
UpdateCode.NOT_TRACKED, "output_a.txt", id="not_tracked"
|
|
81
|
+
), pytest.param(
|
|
82
|
+
"command_changed", {
|
|
83
|
+
"output_a.txt": {
|
|
84
|
+
"mtime": time.time() - 10, "hashes": {
|
|
85
|
+
"command": "hash_cmd_a_DIFFERENT", "inputs": "hash_inputs_a",
|
|
86
|
+
"params": "hash_params_a"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}, UpdateCode.COMMAND_CHANGED, "", id="command_changed"
|
|
90
|
+
), pytest.param(
|
|
91
|
+
"inputs_changed", {
|
|
92
|
+
"output_a.txt": {
|
|
93
|
+
"mtime": time.time() - 10, "hashes": {
|
|
94
|
+
"command": "hash_cmd_a", "inputs": "hash_inputs_a_DIFFERENT",
|
|
95
|
+
"params": "hash_params_a"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}, UpdateCode.INPUTS_CHANGED, "", id="inputs_changed"
|
|
99
|
+
), pytest.param(
|
|
100
|
+
"params_changed", {
|
|
101
|
+
"output_a.txt": {
|
|
102
|
+
"mtime": time.time() - 10, "hashes": {
|
|
103
|
+
"command": "hash_cmd_a", "inputs": "hash_inputs_a",
|
|
104
|
+
"params": "hash_params_a_DIFFERENT"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}, UpdateCode.PARAMS_CHANGED, "", id="params_changed"
|
|
108
|
+
), ]
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@pytest.mark.parametrize(
|
|
112
|
+
"test_id, build_state, expected_code, expected_context", outdated_test_cases
|
|
113
|
+
)
|
|
114
|
+
def test_is_step_outdated_scenarios(
|
|
115
|
+
mocker, base_config, command_map, test_id, build_state, expected_code, expected_context
|
|
116
|
+
):
|
|
117
|
+
"""
|
|
118
|
+
Tests the _is_step_outdated method with various states using parameterization.
|
|
119
|
+
We only test StepA here, as it has no file dependencies.
|
|
120
|
+
"""
|
|
121
|
+
# Mock os.path.exists to simulate file presence or absence
|
|
122
|
+
if expected_code == UpdateCode.MISSING_OUTPUT:
|
|
123
|
+
mocker.patch("os.path.exists", return_value=False)
|
|
124
|
+
else:
|
|
125
|
+
mocker.patch("os.path.exists", return_value=True)
|
|
126
|
+
|
|
127
|
+
# Mock os.path.getmtime to avoid real file system access
|
|
128
|
+
mocker.patch("os.path.getmtime", return_value=time.time() - 20)
|
|
129
|
+
|
|
130
|
+
planner = BuildPlanner(base_config, build_state)
|
|
131
|
+
command_a = command_map["StepA"]
|
|
132
|
+
|
|
133
|
+
update_code, context = planner._is_step_outdated(command_a)
|
|
134
|
+
|
|
135
|
+
assert update_code == expected_code
|
|
136
|
+
assert context == expected_context
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_is_step_outdated_newer_input(mocker, base_config, command_map):
|
|
140
|
+
"""
|
|
141
|
+
Tests the specific case where an input file is newer than the last build.
|
|
142
|
+
We test StepB here, as it depends on StepA.
|
|
143
|
+
"""
|
|
144
|
+
# Simulate that both files exist
|
|
145
|
+
mocker.patch("os.path.exists", return_value=True)
|
|
146
|
+
|
|
147
|
+
# Simulate that the input (output_a.txt) is NEWER than the last build time
|
|
148
|
+
def mock_getmtime(path):
|
|
149
|
+
if "output_a.txt" in path:
|
|
150
|
+
return time.time() # Now
|
|
151
|
+
return time.time() - 20 # 20 seconds ago
|
|
152
|
+
|
|
153
|
+
mocker.patch("os.path.getmtime", side_effect=mock_getmtime)
|
|
154
|
+
|
|
155
|
+
build_state = {
|
|
156
|
+
"output_b.txt": {
|
|
157
|
+
"mtime": time.time() - 10, # Last build was 10 seconds ago
|
|
158
|
+
"hashes": {
|
|
159
|
+
"command": "hash_cmd_b", "inputs": "hash_inputs_b", "params": "hash_params_b"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
planner = BuildPlanner(base_config, build_state)
|
|
165
|
+
command_b = command_map["StepB"]
|
|
166
|
+
|
|
167
|
+
update_code, context = planner._is_step_outdated(command_b)
|
|
168
|
+
|
|
169
|
+
assert update_code == UpdateCode.NEWER_INPUT
|
|
170
|
+
assert context == "output_a.txt"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
# --- Tests for the overall `plan_build` method ---
|
|
174
|
+
|
|
175
|
+
def test_plan_build_full_rebuild(mocker, base_config, command_map, execution_graph):
|
|
176
|
+
"""
|
|
177
|
+
Tests that a full rebuild is planned when the build state is empty.
|
|
178
|
+
"""
|
|
179
|
+
# Mock the command generation and graph creation
|
|
180
|
+
mocker.patch.object(
|
|
181
|
+
BuildPlanner, "_generate_command_map_and_graph", return_value=(command_map, execution_graph)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Mock the outdated check to always return MISSING_OUTPUT for simplicity
|
|
185
|
+
mocker.patch.object(
|
|
186
|
+
BuildPlanner, "_is_step_outdated",
|
|
187
|
+
return_value=(UpdateCode.MISSING_OUTPUT, "mock_output.txt")
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
planner = BuildPlanner(base_config, build_state={})
|
|
191
|
+
plan = planner.plan_build(profile_name="test_profile")
|
|
192
|
+
|
|
193
|
+
assert len(plan.steps_to_run) == 2
|
|
194
|
+
assert len(plan.steps_to_skip) == 0
|
|
195
|
+
assert plan.steps_to_run[0].node_name == "StepA"
|
|
196
|
+
assert plan.steps_to_run[1].node_name == "StepB"
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_plan_build_partial_rebuild(mocker, base_config, command_map, execution_graph):
|
|
200
|
+
"""
|
|
201
|
+
Tests that a partial rebuild is planned when only one step is outdated,
|
|
202
|
+
and the change is correctly propagated to its descendants.
|
|
203
|
+
"""
|
|
204
|
+
mocker.patch.object(
|
|
205
|
+
BuildPlanner, "_generate_command_map_and_graph", return_value=(command_map, execution_graph)
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Mock the outdated check: StepA is outdated, StepB is not (yet).
|
|
209
|
+
def mock_is_outdated(command):
|
|
210
|
+
if command['output'] == "output_a.txt":
|
|
211
|
+
return (UpdateCode.COMMAND_CHANGED, "")
|
|
212
|
+
return (UpdateCode.UP_TO_DATE, "")
|
|
213
|
+
|
|
214
|
+
mocker.patch.object(BuildPlanner, "_is_step_outdated", side_effect=mock_is_outdated)
|
|
215
|
+
|
|
216
|
+
planner = BuildPlanner(base_config, build_state={"mock": "state"})
|
|
217
|
+
plan = planner.plan_build(profile_name="test_profile")
|
|
218
|
+
|
|
219
|
+
# StepA is outdated, and StepB must be rebuilt because its dependency changed.
|
|
220
|
+
assert len(plan.steps_to_run) == 2
|
|
221
|
+
assert len(plan.steps_to_skip) == 0
|
|
222
|
+
|
|
223
|
+
# Check the reasons for the rebuild
|
|
224
|
+
step_a_plan = next(s for s in plan.steps_to_run if s.node_name == "StepA")
|
|
225
|
+
step_b_plan = next(s for s in plan.steps_to_run if s.node_name == "StepB")
|
|
226
|
+
|
|
227
|
+
assert step_a_plan.update_code == UpdateCode.COMMAND_CHANGED
|
|
228
|
+
assert step_b_plan.update_code == UpdateCode.DEPENDENCY_CHANGED
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def test_plan_build_no_rebuild(mocker, base_config, command_map, execution_graph):
|
|
232
|
+
"""
|
|
233
|
+
Tests that no steps are planned to run when everything is up-to-date.
|
|
234
|
+
"""
|
|
235
|
+
mocker.patch.object(
|
|
236
|
+
BuildPlanner, "_generate_command_map_and_graph", return_value=(command_map, execution_graph)
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# Mock the outdated check to always return UP_TO_DATE
|
|
240
|
+
mocker.patch.object(
|
|
241
|
+
BuildPlanner, "_is_step_outdated", return_value=(UpdateCode.UP_TO_DATE, "")
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
planner = BuildPlanner(base_config, build_state={"mock": "state"})
|
|
245
|
+
plan = planner.plan_build(profile_name="test_profile")
|
|
246
|
+
|
|
247
|
+
assert len(plan.steps_to_run) == 0
|
|
248
|
+
assert len(plan.steps_to_skip) == 2
|