runem 0.5.0__tar.gz → 0.7.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.
Files changed (95) hide show
  1. {runem-0.5.0 → runem-0.7.0}/HISTORY.md +119 -0
  2. runem-0.7.0/PKG-INFO +162 -0
  3. runem-0.7.0/README.md +117 -0
  4. {runem-0.5.0 → runem-0.7.0}/pyproject.toml +8 -6
  5. runem-0.7.0/runem/VERSION +1 -0
  6. {runem-0.5.0 → runem-0.7.0}/runem/blocking_print.py +10 -2
  7. {runem-0.5.0 → runem-0.7.0}/runem/cli/initialise_options.py +0 -1
  8. {runem-0.5.0 → runem-0.7.0}/runem/command_line.py +4 -7
  9. {runem-0.5.0 → runem-0.7.0}/runem/config.py +8 -4
  10. {runem-0.5.0 → runem-0.7.0}/runem/config_parse.py +2 -1
  11. runem-0.7.0/runem/config_validate.py +47 -0
  12. {runem-0.5.0 → runem-0.7.0}/runem/informative_dict.py +7 -2
  13. {runem-0.5.0 → runem-0.7.0}/runem/job.py +1 -3
  14. {runem-0.5.0 → runem-0.7.0}/runem/job_execute.py +12 -9
  15. {runem-0.5.0 → runem-0.7.0}/runem/job_filter.py +5 -5
  16. {runem-0.5.0 → runem-0.7.0}/runem/job_wrapper_python.py +3 -4
  17. runem-0.7.0/runem/log.py +46 -0
  18. {runem-0.5.0 → runem-0.7.0}/runem/report.py +8 -4
  19. {runem-0.5.0 → runem-0.7.0}/runem/run_command.py +62 -28
  20. {runem-0.5.0 → runem-0.7.0}/runem/runem.py +46 -64
  21. runem-0.7.0/runem/schema.yml +137 -0
  22. {runem-0.5.0 → runem-0.7.0}/runem/types/__init__.py +2 -1
  23. runem-0.7.0/runem/types/errors.py +14 -0
  24. {runem-0.5.0 → runem-0.7.0}/runem/types/hooks.py +1 -1
  25. {runem-0.5.0 → runem-0.7.0}/runem/types/types_jobs.py +21 -24
  26. runem-0.7.0/runem/utils.py +18 -0
  27. runem-0.7.0/runem/yaml_utils.py +19 -0
  28. runem-0.7.0/runem/yaml_validation.py +28 -0
  29. runem-0.7.0/runem.egg-info/PKG-INFO +162 -0
  30. {runem-0.5.0 → runem-0.7.0}/runem.egg-info/SOURCES.txt +6 -0
  31. {runem-0.5.0 → runem-0.7.0}/runem.egg-info/requires.txt +6 -6
  32. {runem-0.5.0 → runem-0.7.0}/scripts/test_hooks/py.py +63 -1
  33. runem-0.7.0/tests/intentional_test_error.py +8 -0
  34. runem-0.7.0/tests/test_config_validate.py +128 -0
  35. {runem-0.5.0 → runem-0.7.0}/tests/test_files.py +3 -3
  36. {runem-0.5.0 → runem-0.7.0}/tests/test_hook_manager.py +5 -4
  37. {runem-0.5.0 → runem-0.7.0}/tests/test_informative_dict.py +21 -20
  38. {runem-0.5.0 → runem-0.7.0}/tests/test_job_filter.py +0 -2
  39. {runem-0.5.0 → runem-0.7.0}/tests/test_job_runner_simple_command.py +2 -1
  40. {runem-0.5.0 → runem-0.7.0}/tests/test_job_wrapper.py +2 -3
  41. {runem-0.5.0 → runem-0.7.0}/tests/test_run_command.py +19 -20
  42. {runem-0.5.0 → runem-0.7.0}/tests/test_runem.py +18 -16
  43. runem-0.7.0/tests/test_yaml_validation.py +66 -0
  44. runem-0.5.0/PKG-INFO +0 -164
  45. runem-0.5.0/README.md +0 -120
  46. runem-0.5.0/runem/VERSION +0 -1
  47. runem-0.5.0/runem/log.py +0 -24
  48. runem-0.5.0/runem/types/errors.py +0 -4
  49. runem-0.5.0/runem/utils.py +0 -6
  50. runem-0.5.0/runem.egg-info/PKG-INFO +0 -164
  51. runem-0.5.0/tests/intentional_test_error.py +0 -5
  52. {runem-0.5.0 → runem-0.7.0}/Containerfile +0 -0
  53. {runem-0.5.0 → runem-0.7.0}/LICENSE +0 -0
  54. {runem-0.5.0 → runem-0.7.0}/MANIFEST.in +0 -0
  55. {runem-0.5.0 → runem-0.7.0}/runem/__init__.py +0 -0
  56. {runem-0.5.0 → runem-0.7.0}/runem/__main__.py +0 -0
  57. {runem-0.5.0 → runem-0.7.0}/runem/base.py +0 -0
  58. {runem-0.5.0 → runem-0.7.0}/runem/cli.py +0 -0
  59. {runem-0.5.0 → runem-0.7.0}/runem/config_metadata.py +0 -0
  60. {runem-0.5.0 → runem-0.7.0}/runem/files.py +0 -0
  61. {runem-0.5.0 → runem-0.7.0}/runem/hook_manager.py +0 -0
  62. {runem-0.5.0 → runem-0.7.0}/runem/job_runner_simple_command.py +0 -0
  63. {runem-0.5.0 → runem-0.7.0}/runem/job_wrapper.py +0 -0
  64. {runem-0.5.0 → runem-0.7.0}/runem/py.typed +0 -0
  65. {runem-0.5.0 → runem-0.7.0}/runem/runem_version.py +0 -0
  66. {runem-0.5.0 → runem-0.7.0}/runem/types/common.py +0 -0
  67. {runem-0.5.0 → runem-0.7.0}/runem/types/filters.py +0 -0
  68. {runem-0.5.0 → runem-0.7.0}/runem/types/options.py +0 -0
  69. {runem-0.5.0 → runem-0.7.0}/runem/types/runem_config.py +0 -0
  70. {runem-0.5.0 → runem-0.7.0}/runem.egg-info/dependency_links.txt +0 -0
  71. {runem-0.5.0 → runem-0.7.0}/runem.egg-info/entry_points.txt +0 -0
  72. {runem-0.5.0 → runem-0.7.0}/runem.egg-info/top_level.txt +0 -0
  73. {runem-0.5.0 → runem-0.7.0}/scripts/test_hooks/__init__.py +0 -0
  74. {runem-0.5.0 → runem-0.7.0}/scripts/test_hooks/json_validators.py +0 -0
  75. {runem-0.5.0 → runem-0.7.0}/scripts/test_hooks/py.typed +0 -0
  76. {runem-0.5.0 → runem-0.7.0}/scripts/test_hooks/runem_hooks.py +0 -0
  77. {runem-0.5.0 → runem-0.7.0}/scripts/test_hooks/yarn.py +0 -0
  78. {runem-0.5.0 → runem-0.7.0}/setup.cfg +0 -0
  79. {runem-0.5.0 → runem-0.7.0}/tests/__init__.py +0 -0
  80. {runem-0.5.0 → runem-0.7.0}/tests/cli/test_initialise_options.py +0 -0
  81. {runem-0.5.0 → runem-0.7.0}/tests/conftest.py +0 -0
  82. {runem-0.5.0 → runem-0.7.0}/tests/data/help_output.3.10.txt +0 -0
  83. {runem-0.5.0 → runem-0.7.0}/tests/data/help_output.3.11.txt +0 -0
  84. {runem-0.5.0 → runem-0.7.0}/tests/sanitise_reports_footer.py +0 -0
  85. {runem-0.5.0 → runem-0.7.0}/tests/test_base.py +0 -0
  86. {runem-0.5.0 → runem-0.7.0}/tests/test_blocking_print.py +0 -0
  87. {runem-0.5.0 → runem-0.7.0}/tests/test_cli.py +0 -0
  88. {runem-0.5.0 → runem-0.7.0}/tests/test_config.py +0 -0
  89. {runem-0.5.0 → runem-0.7.0}/tests/test_config_parse.py +0 -0
  90. {runem-0.5.0 → runem-0.7.0}/tests/test_job.py +0 -0
  91. {runem-0.5.0 → runem-0.7.0}/tests/test_job_execute.py +0 -0
  92. {runem-0.5.0 → runem-0.7.0}/tests/test_job_wrapper_python.py +0 -0
  93. {runem-0.5.0 → runem-0.7.0}/tests/test_report.py +0 -0
  94. {runem-0.5.0 → runem-0.7.0}/tests/test_types/__init__.py +0 -0
  95. {runem-0.5.0 → runem-0.7.0}/tests/test_types/test_public_api.py +0 -0
@@ -4,6 +4,125 @@ Changelog
4
4
 
5
5
  (unreleased)
6
6
  ------------
7
+ - Merge pull request #83 from
8
+ lursight/feat/no_runem_traceback_on_job_fail. [Frank Harrison]
9
+
10
+ Feat/no runem traceback on job fail
11
+ - Feat(error-only): only shows the error not the runem error tracback.
12
+ [Frank Harrison]
13
+
14
+ The runem error traceback is irelevant if the sub-task fails. So we just
15
+ show that task's output instead of the traceback for where we handle the
16
+ error.
17
+ - Feat(error-ctx): shows the failed job label as we show the causing
18
+ error. [Frank Harrison]
19
+ - Feat(remove-failed): always remove the failed job from the list of
20
+ running jobs. [Frank Harrison]
21
+ - Merge pull request #82 from lursight/feat/schema_validation. [Frank
22
+ Harrison]
23
+
24
+ feat(validation): validates the .runem.yml file against the schema
25
+ - Feat(validation): validates the .runem.yml file against the schema.
26
+ [Frank Harrison]
27
+ - Merge pull request #81 from lursight/chore/ruff. [Frank Harrison]
28
+
29
+ Chore/ruff
30
+ - Chore(ruff): some formatting change made whilst configuring ruff.
31
+ [Frank Harrison]
32
+ - Chore(ruff): use ruff as its faster/better. [Frank Harrison]
33
+ - Merge pull request #80 from lursight/chore/update_deps. [Frank
34
+ Harrison]
35
+
36
+ Chore/update deps
37
+ - Chore(deps): updates pylint 3.1.0 -> 3.3.6. [Frank Harrison]
38
+ - Chore(deps): updates pytest 8.3.3 -> 8.3.5 and pytest-cov to latest.
39
+ [Frank Harrison]
40
+ - Merge pull request #79 from
41
+ lursight/feat/removes_dectorate_param_from_log. [Frank Harrison]
42
+
43
+ feat(log): changes the semantics of log's 'decorate' to allow overriding
44
+ - Feat(log): changes the semantics of log's 'decorate' to allow
45
+ overriding. [Frank Harrison]
46
+
47
+ Also renames the log API's param decorate -> prefix.
48
+
49
+ This better represents the intent of the param as decorate was adding a
50
+ default prefix.
51
+
52
+
53
+ 0.6.0 (2025-02-03)
54
+ ------------------
55
+ - Release: version 0.6.0 🚀 [Frank Harrison]
56
+ - Merge pull request #78 from lursight/feat/better_error_display. [Frank
57
+ Harrison]
58
+
59
+ Feat/better error display
60
+ - Fix(spinner): fixes the Spinner show it only shows for --show-spinner.
61
+ [Frank Harrison]
62
+
63
+ Also, fixes it so that it shows only a single spinner
64
+ - Feat(colours): adds better colours to the terminal output. [Frank
65
+ Harrison]
66
+
67
+ This helps to reinfoce time-saved and other aspects of the tool.
68
+ - Feat(better-errors): makes finding the stderr in the list of errors
69
+ easier. [Frank Harrison]
70
+
71
+ We do this by colouring the text for the commands and wrapping the
72
+ errors with a red-box.
73
+
74
+ We colour:
75
+ - command-lines -> yellow
76
+ - job-labels -> blue
77
+ - errors -> red
78
+ - in-progress -> green box
79
+ - Merge pull request #77 from lursight/fix/log-verbosity. [Frank
80
+ Harrison]
81
+
82
+ fix(log-verbosity): fixes verbosity bug when not showing the spinner
83
+ - Fix(log-verbosity): fixes verbosity bug when not showing the spinner.
84
+ [Frank Harrison]
85
+
86
+ We were showing the running procs on every tick, instead of just the
87
+ changes to the running procs, if any.
88
+ - Merge pull request #76 from lursight/chore/types/job-return-type.
89
+ [Frank Harrison]
90
+
91
+ chore(types) fixes exports for JobReturn type
92
+ - Chore(types): exports the JobReturn type from the types submodule.
93
+ [Frank Harrison]
94
+ - Merge pull request #75 from lursight/chore/todos. [Frank Harrison]
95
+
96
+ chore(todos): adds TODOD.txt to track ideas for runem
97
+ - Chore(todos): adds TODOD.txt to track ideas for runem. [Frank
98
+ Harrison]
99
+ - Merge pull request #74 from lursight/chore/help_docs. [Frank Harrison]
100
+
101
+ chore(docs): removes help output from a details block
102
+ - Chore(docs): removes help output from a details block. [Frank
103
+ Harrison]
104
+
105
+ The details block broke the pre-formatted styling of the code-block.
106
+ - Merge pull request #73 from lursight/chore/update_contrib. [Frank
107
+ Harrison]
108
+
109
+ chore(docs): trying to add line-breaks to non-bulletpointed list
110
+ - Chore(docs): trying to add line-breaks to non-bulletpointed list.
111
+ [Frank Harrison]
112
+ - Merge pull request #72 from lursight/chore/update_contrib. [Frank
113
+ Harrison]
114
+
115
+ Chore/update CONTRIBUTING.md and README.md
116
+ - Chore(spell): adds 'pyenv' to dictionary. [Frank Harrison]
117
+ - Chore(docs): improves the README. [Frank Harrison]
118
+ - Docs(contrib): updates the contributing docs. [Frank Harrison]
119
+
120
+ We add some of the basics as well as some more recent changes
121
+
122
+
123
+ 0.5.0 (2024-12-12)
124
+ ------------------
125
+ - Release: version 0.5.0 🚀 [Frank Harrison]
7
126
  - Merge pull request #71 from lursight/feat/pyproject. [Frank Harrison]
8
127
 
9
128
  Feat/pyproject
runem-0.7.0/PKG-INFO ADDED
@@ -0,0 +1,162 @@
1
+ Metadata-Version: 2.4
2
+ Name: runem
3
+ Version: 0.7.0
4
+ Summary: Awesome runem created by lursight
5
+ Author: lursight
6
+ License: Specify your license here
7
+ Project-URL: Homepage, https://github.com/lursight/runem/
8
+ Keywords: example,runem
9
+ Classifier: Programming Language :: Python :: 3.7
10
+ Classifier: Programming Language :: Python :: 3.8
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Requires-Python: >=3.7
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: packaging>=22.0
18
+ Requires-Dist: PyYAML>=5.0.0
19
+ Requires-Dist: jsonschema>=4.22
20
+ Requires-Dist: rich>10.0.0
21
+ Requires-Dist: typing_extensions>3.0.0
22
+ Provides-Extra: tests
23
+ Requires-Dist: coverage==7.5; extra == "tests"
24
+ Requires-Dist: flake8-bugbear==24.2.6; extra == "tests"
25
+ Requires-Dist: flake8==7.0.0; extra == "tests"
26
+ Requires-Dist: gitchangelog==3.0.4; extra == "tests"
27
+ Requires-Dist: mkdocs==1.5.3; extra == "tests"
28
+ Requires-Dist: mypy==1.9.0; extra == "tests"
29
+ Requires-Dist: pydocstyle==6.3.0; extra == "tests"
30
+ Requires-Dist: pylint==3.3.6; extra == "tests"
31
+ Requires-Dist: pylama==8.4.1; extra == "tests"
32
+ Requires-Dist: pytest-cov==6.1.1; extra == "tests"
33
+ Requires-Dist: pytest-profiling==1.7.0; extra == "tests"
34
+ Requires-Dist: pytest-xdist==3.6.1; extra == "tests"
35
+ Requires-Dist: pytest==8.3.5; extra == "tests"
36
+ Requires-Dist: ruff==0.11.6; extra == "tests"
37
+ Requires-Dist: setuptools; extra == "tests"
38
+ Requires-Dist: termplotlib==0.3.9; extra == "tests"
39
+ Requires-Dist: tox; extra == "tests"
40
+ Requires-Dist: types-PyYAML==6.0.12.20240311; extra == "tests"
41
+ Requires-Dist: requests-mock==1.11.0; extra == "tests"
42
+ Requires-Dist: types-jsonschema; extra == "tests"
43
+ Requires-Dist: types-setuptools; extra == "tests"
44
+ Dynamic: license-file
45
+
46
+ <!-- [![codecov](https://codecov.io/gh/lursight/runem/branch/main/graph/badge.svg?token=run-test_token_here)](https://codecov.io/gh/lursight/runem) -->
47
+ [![CI](https://github.com/lursight/runem/actions/workflows/main.yml/badge.svg)](https://github.com/lursight/runem/actions/workflows/main.yml)
48
+ [![DOCS](https://lursight.github.io/runem/docs/VIEW-DOCS-31c553.svg)](https://lursight.github.io/runem/)
49
+
50
+ # Run’em
51
+
52
+ **Your Blueprint of Commands. Your Engine of Parallel Execution.**
53
+ Run’em is your definitive blueprint of tasks and commands—instantly discoverable, effortlessly parallel, and elegantly extensible.
54
+
55
+ ## Core Strengths
56
+
57
+ **Blueprint** - discover tasks and onboard smoothly\
58
+ **Parallel** - get results quicker\
59
+ **Simple** - define task easily\
60
+ **Extensible** - add tasks quickly\
61
+ **Filters** - powerful task selection\
62
+ **Reports** - see metrics on tasks
63
+
64
+ ## Why Run’em?
65
+ - **Command Blueprint:** Instantly see and run all your tasks. No guesswork, no rummaging.
66
+ - **Effortless Parallelism:** Execute tasks side-by-side to obliterate downtime.
67
+ - **Simple YAML Declarations:** Define everything in one `.runem.yml`.
68
+ - **Extensible & Smart:** Adapt to monorepos, complex workflows, and evolving needs.
69
+ - **Discoverable by Design:** `runem --help` guides your team, new hires, or contributors to every defined command.
70
+
71
+ ## Contents
72
+ - [Run’em](#runem)
73
+ - [Core Strengths](#core-strengths)
74
+ - [Why Run’em?](#why-runem)
75
+ - [Contents](#contents)
76
+ - [Highlights](#highlights)
77
+ - [Quick Start](#quick-start)
78
+ - [Basic Use](#basic-use)
79
+ - [Advanced Use](#advanced-use)
80
+ - [Help & Discovery](#help--discovery)
81
+ - [Troubleshooting](#troubleshooting)
82
+ - [Contribute & Support](#contribute--support)
83
+ - [About Run’em](#about-runem)
84
+
85
+ # Highlights
86
+ ## Blueprint of Commands:
87
+ The blueprint (available via `--help`) gives you a manifest of all jobs and tasks in a
88
+ project. A single source of truth for all tasks.
89
+ ## Parallel Execution:
90
+ Maximise speed with automatic concurrency. Runem tries to run all tasks as quickly as
91
+ possible, looking at resources, with dependencies. It is not yet a full
92
+ dependency-execution graph, but by version 1.0.0 it will be.
93
+ ## Filtering:
94
+ Use powerful and flexible filtering. Select or excluded tasks by `tags`, `name` and
95
+ `phase`. Chose the task to be run based on your needs, right now.
96
+
97
+ You can also customise filtering by adding your own command `options`.
98
+
99
+ See `--tags`, `--not-tags`, `--jobs`, `--not-jobs`, `--phases` and `--not-phases`.
100
+ ## Powerful Insights:** Understand what ran, how fast, and what failed.
101
+ **Quiet by Default:** Focus on what matters, and reveal detail only when needed.
102
+
103
+ # Quick Start
104
+ **Install:**
105
+ ```bash
106
+ pip install runem
107
+ ```
108
+ **Define a task:**
109
+
110
+ ```yaml
111
+ `# .runem.yml
112
+ - job:
113
+ command: echo "hello world!"
114
+ ```
115
+
116
+ **Run:**
117
+
118
+ ```bash
119
+ runem
120
+ ```
121
+
122
+ Run multiple commands in parallel, see timing, and keep output minimal. Need detail?
123
+
124
+ ```bash
125
+ runem --verbose
126
+ ```
127
+
128
+ [Quick Start Docs](https://lursight.github.io/runem/docs/quick_start.html)
129
+
130
+ # Basic Use
131
+
132
+ Get comfortable with typical workflows:
133
+ [Basic Use Docs](https://lursight.github.io/runem/docs/basic_use.html)
134
+
135
+ # Advanced Use
136
+
137
+ Scale up with multi-phase configs, filtered execution, and custom reporting:
138
+ [Advanced Configuration](https://lursight.github.io/runem/docs/configuration.html)
139
+ [Custom Reporting](https://lursight.github.io/runem/docs/reports.html)
140
+
141
+ # Help & Discovery
142
+
143
+ `runem --help` is your radar—instantly mapping out every available task:
144
+ [Help & Job Discovery](https://lursight.github.io/runem/docs/help_and_job_discovery.html)
145
+
146
+ # Troubleshooting
147
+
148
+ Swift solutions to common issues:
149
+ [Troubleshooting & Known Issues](https://lursight.github.io/runem/docs/troubleshooting_known_issues.html)
150
+
151
+ ---
152
+
153
+ # Contribute & Support
154
+
155
+ Brought to you by [Lursight Ltd.](https://lursight.com) and an open community.
156
+ [CONTRIBUTING.md](CONTRIBUTING.md)
157
+ [❤️ Sponsor](https://github.com/sponsors/lursight/)
158
+
159
+ # About Run’em
160
+
161
+ Run’em exists to accelerate your team’s delivery and reduce complexity. Learn about our [Mission](https://lursight.github.io/runem/docs/mission.html).
162
+
runem-0.7.0/README.md ADDED
@@ -0,0 +1,117 @@
1
+ <!-- [![codecov](https://codecov.io/gh/lursight/runem/branch/main/graph/badge.svg?token=run-test_token_here)](https://codecov.io/gh/lursight/runem) -->
2
+ [![CI](https://github.com/lursight/runem/actions/workflows/main.yml/badge.svg)](https://github.com/lursight/runem/actions/workflows/main.yml)
3
+ [![DOCS](https://lursight.github.io/runem/docs/VIEW-DOCS-31c553.svg)](https://lursight.github.io/runem/)
4
+
5
+ # Run’em
6
+
7
+ **Your Blueprint of Commands. Your Engine of Parallel Execution.**
8
+ Run’em is your definitive blueprint of tasks and commands—instantly discoverable, effortlessly parallel, and elegantly extensible.
9
+
10
+ ## Core Strengths
11
+
12
+ **Blueprint** - discover tasks and onboard smoothly\
13
+ **Parallel** - get results quicker\
14
+ **Simple** - define task easily\
15
+ **Extensible** - add tasks quickly\
16
+ **Filters** - powerful task selection\
17
+ **Reports** - see metrics on tasks
18
+
19
+ ## Why Run’em?
20
+ - **Command Blueprint:** Instantly see and run all your tasks. No guesswork, no rummaging.
21
+ - **Effortless Parallelism:** Execute tasks side-by-side to obliterate downtime.
22
+ - **Simple YAML Declarations:** Define everything in one `.runem.yml`.
23
+ - **Extensible & Smart:** Adapt to monorepos, complex workflows, and evolving needs.
24
+ - **Discoverable by Design:** `runem --help` guides your team, new hires, or contributors to every defined command.
25
+
26
+ ## Contents
27
+ - [Run’em](#runem)
28
+ - [Core Strengths](#core-strengths)
29
+ - [Why Run’em?](#why-runem)
30
+ - [Contents](#contents)
31
+ - [Highlights](#highlights)
32
+ - [Quick Start](#quick-start)
33
+ - [Basic Use](#basic-use)
34
+ - [Advanced Use](#advanced-use)
35
+ - [Help & Discovery](#help--discovery)
36
+ - [Troubleshooting](#troubleshooting)
37
+ - [Contribute & Support](#contribute--support)
38
+ - [About Run’em](#about-runem)
39
+
40
+ # Highlights
41
+ ## Blueprint of Commands:
42
+ The blueprint (available via `--help`) gives you a manifest of all jobs and tasks in a
43
+ project. A single source of truth for all tasks.
44
+ ## Parallel Execution:
45
+ Maximise speed with automatic concurrency. Runem tries to run all tasks as quickly as
46
+ possible, looking at resources, with dependencies. It is not yet a full
47
+ dependency-execution graph, but by version 1.0.0 it will be.
48
+ ## Filtering:
49
+ Use powerful and flexible filtering. Select or excluded tasks by `tags`, `name` and
50
+ `phase`. Chose the task to be run based on your needs, right now.
51
+
52
+ You can also customise filtering by adding your own command `options`.
53
+
54
+ See `--tags`, `--not-tags`, `--jobs`, `--not-jobs`, `--phases` and `--not-phases`.
55
+ ## Powerful Insights:** Understand what ran, how fast, and what failed.
56
+ **Quiet by Default:** Focus on what matters, and reveal detail only when needed.
57
+
58
+ # Quick Start
59
+ **Install:**
60
+ ```bash
61
+ pip install runem
62
+ ```
63
+ **Define a task:**
64
+
65
+ ```yaml
66
+ `# .runem.yml
67
+ - job:
68
+ command: echo "hello world!"
69
+ ```
70
+
71
+ **Run:**
72
+
73
+ ```bash
74
+ runem
75
+ ```
76
+
77
+ Run multiple commands in parallel, see timing, and keep output minimal. Need detail?
78
+
79
+ ```bash
80
+ runem --verbose
81
+ ```
82
+
83
+ [Quick Start Docs](https://lursight.github.io/runem/docs/quick_start.html)
84
+
85
+ # Basic Use
86
+
87
+ Get comfortable with typical workflows:
88
+ [Basic Use Docs](https://lursight.github.io/runem/docs/basic_use.html)
89
+
90
+ # Advanced Use
91
+
92
+ Scale up with multi-phase configs, filtered execution, and custom reporting:
93
+ [Advanced Configuration](https://lursight.github.io/runem/docs/configuration.html)
94
+ [Custom Reporting](https://lursight.github.io/runem/docs/reports.html)
95
+
96
+ # Help & Discovery
97
+
98
+ `runem --help` is your radar—instantly mapping out every available task:
99
+ [Help & Job Discovery](https://lursight.github.io/runem/docs/help_and_job_discovery.html)
100
+
101
+ # Troubleshooting
102
+
103
+ Swift solutions to common issues:
104
+ [Troubleshooting & Known Issues](https://lursight.github.io/runem/docs/troubleshooting_known_issues.html)
105
+
106
+ ---
107
+
108
+ # Contribute & Support
109
+
110
+ Brought to you by [Lursight Ltd.](https://lursight.com) and an open community.
111
+ [CONTRIBUTING.md](CONTRIBUTING.md)
112
+ [❤️ Sponsor](https://github.com/sponsors/lursight/)
113
+
114
+ # About Run’em
115
+
116
+ Run’em exists to accelerate your team’s delivery and reduce complexity. Learn about our [Mission](https://lursight.github.io/runem/docs/mission.html).
117
+
@@ -23,7 +23,10 @@ classifiers = [
23
23
  dependencies = [
24
24
  # `packaging` is probably not needed after moving to pyproject.toml
25
25
  "packaging>=22.0",
26
+
27
+ # For yml passingg and validation
26
28
  "PyYAML>=5.0.0",
29
+ "jsonschema>=4.22",
27
30
 
28
31
  # For UI Elements
29
32
  "rich>10.0.0",
@@ -49,26 +52,25 @@ runem = ["VERSION"]
49
52
  [project.optional-dependencies]
50
53
  tests = [
51
54
  # This requirements are for development and testing only, not for production.
52
- "black==24.10.0",
53
55
  "coverage==7.5",
54
- "docformatter==1.7.5",
55
56
  "flake8-bugbear==24.2.6",
56
57
  "flake8==7.0.0",
57
58
  "gitchangelog==3.0.4",
58
- "isort==5.13.2",
59
59
  "mkdocs==1.5.3",
60
60
  "mypy==1.9.0",
61
61
  "pydocstyle==6.3.0",
62
- "pylint==3.1.0",
62
+ "pylint==3.3.6",
63
63
  "pylama==8.4.1",
64
- "pytest-cov==6.0.0",
64
+ "pytest-cov==6.1.1",
65
65
  "pytest-profiling==1.7.0",
66
66
  "pytest-xdist==3.6.1",
67
- "pytest==8.3.3",
67
+ "pytest==8.3.5",
68
+ "ruff==0.11.6",
68
69
  "setuptools",
69
70
  "termplotlib==0.3.9",
70
71
  "tox",
71
72
  "types-PyYAML==6.0.12.20240311",
72
73
  "requests-mock==1.11.0",
74
+ "types-jsonschema",
73
75
  "types-setuptools",
74
76
  ]
@@ -0,0 +1 @@
1
+ 0.7.0
@@ -13,7 +13,14 @@ def _reset_console() -> Console:
13
13
 
14
14
  RICH_CONSOLE = Console(
15
15
  log_path=False, # Do NOT print the source path.
16
- markup=False, # Do NOT print markup e.g. `[blink]Don't Panic![/blink]`.
16
+ # We allow markup here, BUT stdout/stderr from other procs should have
17
+ # `escape()` called on them so they don't error here.
18
+ # This means 'rich' effects/colors can be judiciously applied:
19
+ # e.g. `[blink]Don't Panic![/blink]`.
20
+ markup=True,
21
+ # `highlight` is what colourises string and number in print() calls.
22
+ # We do not want this to be auto-magic.
23
+ highlight=False,
17
24
  )
18
25
  return RICH_CONSOLE
19
26
 
@@ -31,7 +38,8 @@ def _reset_console_for_tests() -> None:
31
38
  RICH_CONSOLE = Console(
32
39
  log_path=False, # Do NOT print the source path.
33
40
  log_time=False, # Do not prefix with log time e.g. `[time] log message`.
34
- markup=False, # Do NOT print markup e.g. `[blink]Don't Panic![/blink]`.
41
+ markup=True, # Allow some markup e.g. `[blink]Don't Panic![/blink]`.
42
+ highlight=False,
35
43
  width=999, # A very wide width.
36
44
  )
37
45
 
@@ -13,7 +13,6 @@ def initialise_options(
13
13
 
14
14
  Returns the options dictionary
15
15
  """
16
-
17
16
  options: OptionsWritable = InformativeDict(
18
17
  {option["name"]: option["default"] for option in config_metadata.options_config}
19
18
  )
@@ -43,10 +43,8 @@ def _get_argparse_help_formatter() -> typing.Any:
43
43
 
44
44
  if use_fixed_width:
45
45
  # Use custom formatter with the width specified in the environment variable
46
- return (
47
- lambda prog: HelpFormatterFixedWidth( # pylint: disable=unnecessary-lambda
48
- prog
49
- )
46
+ return lambda prog: HelpFormatterFixedWidth( # pylint: disable=unnecessary-lambda
47
+ prog
50
48
  )
51
49
 
52
50
  # Use default formatter
@@ -294,12 +292,12 @@ def parse_args(
294
292
  error_on_log_logic(args.verbose, args.silent)
295
293
 
296
294
  if args.show_root_path_and_exit:
297
- log(str(config_metadata.cfg_filepath.parent), decorate=False)
295
+ log(str(config_metadata.cfg_filepath.parent), prefix=False)
298
296
  # cleanly exit
299
297
  sys.exit(0)
300
298
 
301
299
  if args.show_version_and_exit:
302
- log(str(get_runem_version()), decorate=False)
300
+ log(str(get_runem_version()), prefix=False)
303
301
  # cleanly exit
304
302
  sys.exit(0)
305
303
 
@@ -383,7 +381,6 @@ def initialise_options(
383
381
 
384
382
  Returns the options dictionary
385
383
  """
386
-
387
384
  options: OptionsWritable = InformativeDict(
388
385
  {option["name"]: option["default"] for option in config_metadata.options_config}
389
386
  )
@@ -2,9 +2,9 @@ import pathlib
2
2
  import sys
3
3
  import typing
4
4
 
5
- import yaml
6
5
  from packaging.version import Version
7
6
 
7
+ from runem.config_validate import validate_runem_file
8
8
  from runem.log import error, log
9
9
  from runem.runem_version import get_runem_version
10
10
  from runem.types.runem_config import (
@@ -13,6 +13,7 @@ from runem.types.runem_config import (
13
13
  GlobalSerialisedConfig,
14
14
  UserConfigMetadata,
15
15
  )
16
+ from runem.yaml_utils import load_yaml_object
16
17
 
17
18
  CFG_FILE_YAML = pathlib.Path(".runem.yml")
18
19
 
@@ -46,7 +47,7 @@ def _search_up_multiple_dirs_for_file(
46
47
 
47
48
 
48
49
  def _find_config_file(
49
- config_filename: typing.Union[str, pathlib.Path]
50
+ config_filename: typing.Union[str, pathlib.Path],
50
51
  ) -> typing.Tuple[typing.Optional[pathlib.Path], typing.Tuple[pathlib.Path, ...]]:
51
52
  """Searches up from the cwd for the given config file-name."""
52
53
  start_dirs = (pathlib.Path(".").absolute(),)
@@ -117,8 +118,11 @@ def _conform_global_config_types(
117
118
 
118
119
  def load_and_parse_config(cfg_filepath: pathlib.Path) -> Config:
119
120
  """For the given config file pass, project or user, load it & parse/conform it."""
120
- with cfg_filepath.open("r+", encoding="utf-8") as config_file_handle:
121
- all_config = yaml.full_load(config_file_handle)
121
+ all_config = load_yaml_object(cfg_filepath)
122
+ validate_runem_file(
123
+ cfg_filepath,
124
+ all_config,
125
+ )
122
126
 
123
127
  conformed_config: Config
124
128
  global_config: typing.Optional[GlobalConfig]
@@ -162,7 +162,8 @@ def parse_job_config(
162
162
  ("cwd" in job["ctx"]) and (job["ctx"]["cwd"] is not None)
163
163
  )
164
164
  if (not have_ctw_cwd) or isinstance(
165
- job["ctx"]["cwd"], str # type: ignore # handled above
165
+ job["ctx"]["cwd"], # type: ignore # handled above
166
+ str,
166
167
  ):
167
168
  # if
168
169
  # - we don't have a cwd, ctx
@@ -0,0 +1,47 @@
1
+ import pathlib
2
+ import typing
3
+
4
+ from runem.log import error, log
5
+ from runem.types.errors import SystemExitBad
6
+ from runem.yaml_utils import load_yaml_object
7
+ from runem.yaml_validation import ValidationErrors, validate_yaml
8
+
9
+
10
+ def _load_runem_schema() -> typing.Any:
11
+ """Loads and returns the yaml schema for runem.
12
+
13
+ Returns:
14
+ Any: the Draft202012Validator conformant schema.
15
+ """
16
+ schema_path: pathlib.Path = pathlib.Path(__file__).with_name("schema.yml")
17
+ if not schema_path.exists():
18
+ error(
19
+ (
20
+ "runem schema file not found, cannot continue! "
21
+ f"Is the install corrupt? {schema_path}"
22
+ )
23
+ )
24
+ raise SystemExitBad(1)
25
+ schema: typing.Any = load_yaml_object(schema_path)
26
+ return schema
27
+
28
+
29
+ def validate_runem_file(
30
+ cfg_filepath: pathlib.Path,
31
+ all_config: typing.Any,
32
+ ) -> None:
33
+ """Validates the config Loader object against the runem schema.
34
+
35
+ Exits if the files does not validate.
36
+ """
37
+ schema: typing.Any = _load_runem_schema()
38
+ errors: ValidationErrors = validate_yaml(all_config, schema)
39
+ if not errors:
40
+ # aok
41
+ return
42
+
43
+ error(f"failed to validate runem config [yellow]{cfg_filepath}[/yellow]")
44
+ for err in errors:
45
+ path = ".".join(map(str, err.path)) or "<root>"
46
+ log(f" [yellow]{path}[/yellow]: {err.message}")
47
+ raise SystemExit("Config validation failed.")
@@ -9,8 +9,7 @@ class InformativeDict(typing.Dict[K, V], typing.Generic[K, V]):
9
9
  """A dictionary type that prints out the available keys."""
10
10
 
11
11
  def __getitem__(self, key: K) -> V:
12
- """Attempt to retrieve an item, raising a detailed exception if the key is not
13
- found."""
12
+ """Attempt to get item, raising a detailed exception if the key is not found."""
14
13
  try:
15
14
  return super().__getitem__(key)
16
15
  except KeyError:
@@ -24,19 +23,25 @@ class ReadOnlyInformativeDict(InformativeDict[K, V], typing.Generic[K, V]):
24
23
  """A read-only variant of the above."""
25
24
 
26
25
  def __setitem__(self, key: K, value: V) -> None:
26
+ """Readonly object, setitem disallowed."""
27
27
  raise NotImplementedError("This dictionary is read-only")
28
28
 
29
29
  def __delitem__(self, key: K) -> None:
30
+ """Readonly object, delitem disallowed."""
30
31
  raise NotImplementedError("This dictionary is read-only")
31
32
 
32
33
  def pop(self, *args: typing.Any, **kwargs: typing.Any) -> V:
34
+ """Readonly object, pop disallowed."""
33
35
  raise NotImplementedError("This dictionary is read-only")
34
36
 
35
37
  def popitem(self) -> typing.Tuple[K, V]:
38
+ """Readonly object, popitem disallowed."""
36
39
  raise NotImplementedError("This dictionary is read-only")
37
40
 
38
41
  def clear(self) -> None:
42
+ """Readonly object, clear disallowed."""
39
43
  raise NotImplementedError("This dictionary is read-only")
40
44
 
41
45
  def update(self, *args: typing.Any, **kwargs: typing.Any) -> None:
46
+ """Readonly object, update disallowed."""
42
47
  raise NotImplementedError("This dictionary is read-only")
@@ -71,7 +71,6 @@ class Job:
71
71
 
72
72
  TODO: make a non-static member function
73
73
  """
74
-
75
74
  # default to all file-tags
76
75
  tags_for_files: typing.Iterable[str] = file_lists.keys()
77
76
  use_default_tags: bool = job_tags is None
@@ -91,7 +90,6 @@ class Job:
91
90
 
92
91
  TODO: make a non-static member function
93
92
  """
94
-
95
93
  # First try one of the following keys.
96
94
  valid_name_keys = ("label", "command")
97
95
  for candidate in valid_name_keys:
@@ -101,6 +99,6 @@ class Job:
101
99
 
102
100
  # The try the python-wrapper address
103
101
  try:
104
- return f'{job["addr"]["file"]}.{job["addr"]["function"]}'
102
+ return f"{job['addr']['file']}.{job['addr']['function']}"
105
103
  except KeyError:
106
104
  raise NoJobName() # pylint: disable=raise-missing-from