runem 0.5.0__tar.gz → 0.6.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.
- {runem-0.5.0 → runem-0.6.0}/HISTORY.md +70 -0
- runem-0.6.0/PKG-INFO +161 -0
- runem-0.6.0/README.md +117 -0
- runem-0.6.0/runem/VERSION +1 -0
- {runem-0.5.0 → runem-0.6.0}/runem/blocking_print.py +10 -2
- runem-0.6.0/runem/log.py +43 -0
- {runem-0.5.0 → runem-0.6.0}/runem/report.py +4 -1
- {runem-0.5.0 → runem-0.6.0}/runem/run_command.py +62 -26
- {runem-0.5.0 → runem-0.6.0}/runem/runem.py +37 -58
- {runem-0.5.0 → runem-0.6.0}/runem/types/__init__.py +2 -1
- runem-0.6.0/runem/utils.py +18 -0
- runem-0.6.0/runem.egg-info/PKG-INFO +161 -0
- runem-0.6.0/tests/intentional_test_error.py +8 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_hook_manager.py +2 -2
- {runem-0.5.0 → runem-0.6.0}/tests/test_run_command.py +9 -9
- runem-0.5.0/PKG-INFO +0 -164
- runem-0.5.0/README.md +0 -120
- runem-0.5.0/runem/VERSION +0 -1
- runem-0.5.0/runem/log.py +0 -24
- runem-0.5.0/runem/utils.py +0 -6
- runem-0.5.0/runem.egg-info/PKG-INFO +0 -164
- runem-0.5.0/tests/intentional_test_error.py +0 -5
- {runem-0.5.0 → runem-0.6.0}/Containerfile +0 -0
- {runem-0.5.0 → runem-0.6.0}/LICENSE +0 -0
- {runem-0.5.0 → runem-0.6.0}/MANIFEST.in +0 -0
- {runem-0.5.0 → runem-0.6.0}/pyproject.toml +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/__init__.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/__main__.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/base.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/cli/initialise_options.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/cli.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/command_line.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/config.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/config_metadata.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/config_parse.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/files.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/hook_manager.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/informative_dict.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/job.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/job_execute.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/job_filter.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/job_runner_simple_command.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/job_wrapper.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/job_wrapper_python.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/py.typed +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/runem_version.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/types/common.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/types/errors.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/types/filters.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/types/hooks.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/types/options.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/types/runem_config.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem/types/types_jobs.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem.egg-info/SOURCES.txt +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem.egg-info/dependency_links.txt +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem.egg-info/entry_points.txt +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem.egg-info/requires.txt +0 -0
- {runem-0.5.0 → runem-0.6.0}/runem.egg-info/top_level.txt +0 -0
- {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/__init__.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/json_validators.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/py.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/py.typed +0 -0
- {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/runem_hooks.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/yarn.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/setup.cfg +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/__init__.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/cli/test_initialise_options.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/conftest.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/data/help_output.3.10.txt +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/data/help_output.3.11.txt +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/sanitise_reports_footer.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_base.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_blocking_print.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_cli.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_config.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_config_parse.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_files.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_informative_dict.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_job.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_job_execute.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_job_filter.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_job_runner_simple_command.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_job_wrapper.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_job_wrapper_python.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_report.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_runem.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_types/__init__.py +0 -0
- {runem-0.5.0 → runem-0.6.0}/tests/test_types/test_public_api.py +0 -0
@@ -4,6 +4,76 @@ Changelog
|
|
4
4
|
|
5
5
|
(unreleased)
|
6
6
|
------------
|
7
|
+
- Merge pull request #78 from lursight/feat/better_error_display. [Frank
|
8
|
+
Harrison]
|
9
|
+
|
10
|
+
Feat/better error display
|
11
|
+
- Fix(spinner): fixes the Spinner show it only shows for --show-spinner.
|
12
|
+
[Frank Harrison]
|
13
|
+
|
14
|
+
Also, fixes it so that it shows only a single spinner
|
15
|
+
- Feat(colours): adds better colours to the terminal output. [Frank
|
16
|
+
Harrison]
|
17
|
+
|
18
|
+
This helps to reinfoce time-saved and other aspects of the tool.
|
19
|
+
- Feat(better-errors): makes finding the stderr in the list of errors
|
20
|
+
easier. [Frank Harrison]
|
21
|
+
|
22
|
+
We do this by colouring the text for the commands and wrapping the
|
23
|
+
errors with a red-box.
|
24
|
+
|
25
|
+
We colour:
|
26
|
+
- command-lines -> yellow
|
27
|
+
- job-labels -> blue
|
28
|
+
- errors -> red
|
29
|
+
- in-progress -> green box
|
30
|
+
- Merge pull request #77 from lursight/fix/log-verbosity. [Frank
|
31
|
+
Harrison]
|
32
|
+
|
33
|
+
fix(log-verbosity): fixes verbosity bug when not showing the spinner
|
34
|
+
- Fix(log-verbosity): fixes verbosity bug when not showing the spinner.
|
35
|
+
[Frank Harrison]
|
36
|
+
|
37
|
+
We were showing the running procs on every tick, instead of just the
|
38
|
+
changes to the running procs, if any.
|
39
|
+
- Merge pull request #76 from lursight/chore/types/job-return-type.
|
40
|
+
[Frank Harrison]
|
41
|
+
|
42
|
+
chore(types) fixes exports for JobReturn type
|
43
|
+
- Chore(types): exports the JobReturn type from the types submodule.
|
44
|
+
[Frank Harrison]
|
45
|
+
- Merge pull request #75 from lursight/chore/todos. [Frank Harrison]
|
46
|
+
|
47
|
+
chore(todos): adds TODOD.txt to track ideas for runem
|
48
|
+
- Chore(todos): adds TODOD.txt to track ideas for runem. [Frank
|
49
|
+
Harrison]
|
50
|
+
- Merge pull request #74 from lursight/chore/help_docs. [Frank Harrison]
|
51
|
+
|
52
|
+
chore(docs): removes help output from a details block
|
53
|
+
- Chore(docs): removes help output from a details block. [Frank
|
54
|
+
Harrison]
|
55
|
+
|
56
|
+
The details block broke the pre-formatted styling of the code-block.
|
57
|
+
- Merge pull request #73 from lursight/chore/update_contrib. [Frank
|
58
|
+
Harrison]
|
59
|
+
|
60
|
+
chore(docs): trying to add line-breaks to non-bulletpointed list
|
61
|
+
- Chore(docs): trying to add line-breaks to non-bulletpointed list.
|
62
|
+
[Frank Harrison]
|
63
|
+
- Merge pull request #72 from lursight/chore/update_contrib. [Frank
|
64
|
+
Harrison]
|
65
|
+
|
66
|
+
Chore/update CONTRIBUTING.md and README.md
|
67
|
+
- Chore(spell): adds 'pyenv' to dictionary. [Frank Harrison]
|
68
|
+
- Chore(docs): improves the README. [Frank Harrison]
|
69
|
+
- Docs(contrib): updates the contributing docs. [Frank Harrison]
|
70
|
+
|
71
|
+
We add some of the basics as well as some more recent changes
|
72
|
+
|
73
|
+
|
74
|
+
0.5.0 (2024-12-12)
|
75
|
+
------------------
|
76
|
+
- Release: version 0.5.0 🚀 [Frank Harrison]
|
7
77
|
- Merge pull request #71 from lursight/feat/pyproject. [Frank Harrison]
|
8
78
|
|
9
79
|
Feat/pyproject
|
runem-0.6.0/PKG-INFO
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
Metadata-Version: 2.2
|
2
|
+
Name: runem
|
3
|
+
Version: 0.6.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: rich>10.0.0
|
20
|
+
Requires-Dist: typing_extensions>3.0.0
|
21
|
+
Provides-Extra: tests
|
22
|
+
Requires-Dist: black==24.10.0; extra == "tests"
|
23
|
+
Requires-Dist: coverage==7.5; extra == "tests"
|
24
|
+
Requires-Dist: docformatter==1.7.5; extra == "tests"
|
25
|
+
Requires-Dist: flake8-bugbear==24.2.6; extra == "tests"
|
26
|
+
Requires-Dist: flake8==7.0.0; extra == "tests"
|
27
|
+
Requires-Dist: gitchangelog==3.0.4; extra == "tests"
|
28
|
+
Requires-Dist: isort==5.13.2; extra == "tests"
|
29
|
+
Requires-Dist: mkdocs==1.5.3; extra == "tests"
|
30
|
+
Requires-Dist: mypy==1.9.0; extra == "tests"
|
31
|
+
Requires-Dist: pydocstyle==6.3.0; extra == "tests"
|
32
|
+
Requires-Dist: pylint==3.1.0; extra == "tests"
|
33
|
+
Requires-Dist: pylama==8.4.1; extra == "tests"
|
34
|
+
Requires-Dist: pytest-cov==6.0.0; extra == "tests"
|
35
|
+
Requires-Dist: pytest-profiling==1.7.0; extra == "tests"
|
36
|
+
Requires-Dist: pytest-xdist==3.6.1; extra == "tests"
|
37
|
+
Requires-Dist: pytest==8.3.3; extra == "tests"
|
38
|
+
Requires-Dist: setuptools; extra == "tests"
|
39
|
+
Requires-Dist: termplotlib==0.3.9; extra == "tests"
|
40
|
+
Requires-Dist: tox; extra == "tests"
|
41
|
+
Requires-Dist: types-PyYAML==6.0.12.20240311; extra == "tests"
|
42
|
+
Requires-Dist: requests-mock==1.11.0; extra == "tests"
|
43
|
+
Requires-Dist: types-setuptools; extra == "tests"
|
44
|
+
|
45
|
+
<!-- [](https://codecov.io/gh/lursight/runem) -->
|
46
|
+
[](https://github.com/lursight/runem/actions/workflows/main.yml)
|
47
|
+
[](https://lursight.github.io/runem/)
|
48
|
+
|
49
|
+
# Run’em
|
50
|
+
|
51
|
+
**Your Blueprint of Commands. Your Engine of Parallel Execution.**
|
52
|
+
Run’em is your definitive blueprint of tasks and commands—instantly discoverable, effortlessly parallel, and elegantly extensible.
|
53
|
+
|
54
|
+
## Core Strengths
|
55
|
+
|
56
|
+
**Blueprint** - discover tasks and onboard smoothly\
|
57
|
+
**Parallel** - get results quicker\
|
58
|
+
**Simple** - define task easily\
|
59
|
+
**Extensible** - add tasks quickly\
|
60
|
+
**Filters** - powerful task selection\
|
61
|
+
**Reports** - see metrics on tasks
|
62
|
+
|
63
|
+
## Why Run’em?
|
64
|
+
- **Command Blueprint:** Instantly see and run all your tasks. No guesswork, no rummaging.
|
65
|
+
- **Effortless Parallelism:** Execute tasks side-by-side to obliterate downtime.
|
66
|
+
- **Simple YAML Declarations:** Define everything in one `.runem.yml`.
|
67
|
+
- **Extensible & Smart:** Adapt to monorepos, complex workflows, and evolving needs.
|
68
|
+
- **Discoverable by Design:** `runem --help` guides your team, new hires, or contributors to every defined command.
|
69
|
+
|
70
|
+
## Contents
|
71
|
+
- [Run’em](#runem)
|
72
|
+
- [Core Strengths](#core-strengths)
|
73
|
+
- [Why Run’em?](#why-runem)
|
74
|
+
- [Contents](#contents)
|
75
|
+
- [Highlights](#highlights)
|
76
|
+
- [Quick Start](#quick-start)
|
77
|
+
- [Basic Use](#basic-use)
|
78
|
+
- [Advanced Use](#advanced-use)
|
79
|
+
- [Help & Discovery](#help--discovery)
|
80
|
+
- [Troubleshooting](#troubleshooting)
|
81
|
+
- [Contribute & Support](#contribute--support)
|
82
|
+
- [About Run’em](#about-runem)
|
83
|
+
|
84
|
+
# Highlights
|
85
|
+
## Blueprint of Commands:
|
86
|
+
The blueprint (available via `--help`) gives you a manifest of all jobs and tasks in a
|
87
|
+
project. A single source of truth for all tasks.
|
88
|
+
## Parallel Execution:
|
89
|
+
Maximise speed with automatic concurrency. Runem tries to run all tasks as quickly as
|
90
|
+
possible, looking at resources, with dependencies. It is not yet a full
|
91
|
+
dependency-execution graph, but by version 1.0.0 it will be.
|
92
|
+
## Filtering:
|
93
|
+
Use powerful and flexible filtering. Select or excluded tasks by `tags`, `name` and
|
94
|
+
`phase`. Chose the task to be run based on your needs, right now.
|
95
|
+
|
96
|
+
You can also customise filtering by adding your own command `options`.
|
97
|
+
|
98
|
+
See `--tags`, `--not-tags`, `--jobs`, `--not-jobs`, `--phases` and `--not-phases`.
|
99
|
+
## Powerful Insights:** Understand what ran, how fast, and what failed.
|
100
|
+
**Quiet by Default:** Focus on what matters, and reveal detail only when needed.
|
101
|
+
|
102
|
+
# Quick Start
|
103
|
+
**Install:**
|
104
|
+
```bash
|
105
|
+
pip install runem
|
106
|
+
```
|
107
|
+
**Define a task:**
|
108
|
+
|
109
|
+
```yaml
|
110
|
+
`# .runem.yml
|
111
|
+
- job:
|
112
|
+
command: echo "hello world!"
|
113
|
+
```
|
114
|
+
|
115
|
+
**Run:**
|
116
|
+
|
117
|
+
```bash
|
118
|
+
runem
|
119
|
+
```
|
120
|
+
|
121
|
+
Run multiple commands in parallel, see timing, and keep output minimal. Need detail?
|
122
|
+
|
123
|
+
```bash
|
124
|
+
runem --verbose
|
125
|
+
```
|
126
|
+
|
127
|
+
[Quick Start Docs](https://lursight.github.io/runem/docs/quick_start.html)
|
128
|
+
|
129
|
+
# Basic Use
|
130
|
+
|
131
|
+
Get comfortable with typical workflows:
|
132
|
+
[Basic Use Docs](https://lursight.github.io/runem/docs/basic_use.html)
|
133
|
+
|
134
|
+
# Advanced Use
|
135
|
+
|
136
|
+
Scale up with multi-phase configs, filtered execution, and custom reporting:
|
137
|
+
[Advanced Configuration](https://lursight.github.io/runem/docs/configuration.html)
|
138
|
+
[Custom Reporting](https://lursight.github.io/runem/docs/reports.html)
|
139
|
+
|
140
|
+
# Help & Discovery
|
141
|
+
|
142
|
+
`runem --help` is your radar—instantly mapping out every available task:
|
143
|
+
[Help & Job Discovery](https://lursight.github.io/runem/docs/help_and_job_discovery.html)
|
144
|
+
|
145
|
+
# Troubleshooting
|
146
|
+
|
147
|
+
Swift solutions to common issues:
|
148
|
+
[Troubleshooting & Known Issues](https://lursight.github.io/runem/docs/troubleshooting_known_issues.html)
|
149
|
+
|
150
|
+
---
|
151
|
+
|
152
|
+
# Contribute & Support
|
153
|
+
|
154
|
+
Brought to you by [Lursight Ltd.](https://lursight.com) and an open community.
|
155
|
+
[CONTRIBUTING.md](CONTRIBUTING.md)
|
156
|
+
[❤️ Sponsor](https://github.com/sponsors/lursight/)
|
157
|
+
|
158
|
+
# About Run’em
|
159
|
+
|
160
|
+
Run’em exists to accelerate your team’s delivery and reduce complexity. Learn about our [Mission](https://lursight.github.io/runem/docs/mission.html).
|
161
|
+
|
runem-0.6.0/README.md
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
<!-- [](https://codecov.io/gh/lursight/runem) -->
|
2
|
+
[](https://github.com/lursight/runem/actions/workflows/main.yml)
|
3
|
+
[](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
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
0.6.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
|
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=
|
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
|
|
runem-0.6.0/runem/log.py
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from runem.blocking_print import blocking_print
|
4
|
+
|
5
|
+
|
6
|
+
def log(
|
7
|
+
msg: str = "",
|
8
|
+
decorate: bool = True,
|
9
|
+
end: typing.Optional[str] = None,
|
10
|
+
) -> None:
|
11
|
+
"""Thin wrapper around 'print', change the 'msg' & handles system-errors.
|
12
|
+
|
13
|
+
One way we change it is to decorate the output with 'runem'
|
14
|
+
|
15
|
+
Parameters:
|
16
|
+
msg: str - the message to log out. Any `rich` markup will be escaped
|
17
|
+
and not applied.
|
18
|
+
decorate: str - whether to add runem-specific prefix text. We do this
|
19
|
+
to identify text that comes from the app vs text that
|
20
|
+
comes from hooks or other third-parties.
|
21
|
+
end: Optional[str] - same as the end option used by `print()` and
|
22
|
+
`rich`
|
23
|
+
Returns:
|
24
|
+
Nothing
|
25
|
+
"""
|
26
|
+
# Remove any markup as it will probably error, if unsanitised.
|
27
|
+
# msg = escape(msg)
|
28
|
+
|
29
|
+
if decorate:
|
30
|
+
# Make it clear that the message comes from `runem` internals.
|
31
|
+
msg = f"[light_slate_grey]runem[/light_slate_grey]: {msg}"
|
32
|
+
|
33
|
+
# print in a blocking manner, waiting for system resources to free up if a
|
34
|
+
# runem job is contending on stdout or similar.
|
35
|
+
blocking_print(msg, end=end)
|
36
|
+
|
37
|
+
|
38
|
+
def warn(msg: str) -> None:
|
39
|
+
log(f"[yellow]WARNING[/yellow]: {msg}")
|
40
|
+
|
41
|
+
|
42
|
+
def error(msg: str) -> None:
|
43
|
+
log(f"[red]ERROR[/red]: {msg}")
|
@@ -211,7 +211,10 @@ def _print_reports_by_phase(
|
|
211
211
|
for job_report_url_info in report_urls:
|
212
212
|
if not job_report_url_info:
|
213
213
|
continue
|
214
|
-
log(
|
214
|
+
log(
|
215
|
+
f"report: [blue]{str(job_report_url_info[0])}[/blue]: "
|
216
|
+
f"{str(job_report_url_info[1])}"
|
217
|
+
)
|
215
218
|
|
216
219
|
|
217
220
|
def report_on_run(
|
@@ -7,17 +7,33 @@ from subprocess import STDOUT as SUBPROCESS_STDOUT
|
|
7
7
|
from subprocess import Popen
|
8
8
|
from timeit import default_timer as timer
|
9
9
|
|
10
|
+
from rich.markup import escape
|
11
|
+
|
10
12
|
from runem.log import log
|
11
13
|
|
12
14
|
TERMINAL_WIDTH = 86
|
13
15
|
|
14
16
|
|
15
|
-
class
|
16
|
-
|
17
|
+
class RunemJobError(RuntimeError):
|
18
|
+
"""An exception type that stores the stdout/stderr.
|
19
|
+
|
20
|
+
Designed so that we do not print the full stdout via the exception stack, instead,
|
21
|
+
allows an opportunity to parse the markup in it.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(self, friendly_message: str, stdout: str):
|
25
|
+
self.stdout = stdout
|
26
|
+
super().__init__(friendly_message)
|
17
27
|
|
18
28
|
|
19
|
-
class
|
20
|
-
|
29
|
+
class RunCommandBadExitCode(RunemJobError):
|
30
|
+
def __init__(self, stdout: str):
|
31
|
+
super().__init__(friendly_message="Bad exit-code", stdout=stdout)
|
32
|
+
|
33
|
+
|
34
|
+
class RunCommandUnhandledError(RunemJobError):
|
35
|
+
def __init__(self, stdout: str):
|
36
|
+
super().__init__(friendly_message="Unhandled job error", stdout=stdout)
|
21
37
|
|
22
38
|
|
23
39
|
# A function type for recording timing information.
|
@@ -27,25 +43,25 @@ RecordSubJobTimeType = typing.Callable[[str, timedelta], None]
|
|
27
43
|
def parse_stdout(stdout: str, prefix: str) -> str:
|
28
44
|
"""Prefixes each line of the output with a given label, except trailing new
|
29
45
|
lines."""
|
46
|
+
|
30
47
|
# Edge case: Return the prefix immediately for an empty string
|
31
48
|
if not stdout:
|
32
49
|
return prefix
|
33
50
|
|
34
|
-
#
|
35
|
-
|
51
|
+
# Stop errors in `rich` by parsing out anything that might look like
|
52
|
+
# rich-markup.
|
53
|
+
stdout = escape(stdout)
|
54
|
+
|
55
|
+
# Split stdout into lines
|
36
56
|
lines = stdout.split("\n")
|
37
57
|
|
38
58
|
# Apply prefix to all lines except the last if it's empty (due to a trailing newline)
|
39
|
-
modified_lines = [f"{prefix}{line}" for line in lines[:-1]] + (
|
40
|
-
[lines[-1]]
|
41
|
-
if lines[-1] == "" and ends_with_newline
|
42
|
-
else [f"{prefix}{lines[-1]}"]
|
59
|
+
modified_lines = [f"{prefix}{escape(line)}" for line in lines[:-1]] + (
|
60
|
+
[f"{prefix}{escape(lines[-1])}"]
|
43
61
|
)
|
44
62
|
|
45
63
|
# Join the lines back together, appropriately handling the final newline
|
46
|
-
modified_stdout = "\n".join(modified_lines)
|
47
|
-
# if ends_with_newline:
|
48
|
-
# modified_stdout += "\n"
|
64
|
+
modified_stdout: str = "\n".join(modified_lines)
|
49
65
|
|
50
66
|
return modified_stdout
|
51
67
|
|
@@ -69,24 +85,34 @@ def _log_command_execution(
|
|
69
85
|
label: str,
|
70
86
|
env_overrides: typing.Optional[typing.Dict[str, str]],
|
71
87
|
valid_exit_ids: typing.Optional[typing.Tuple[int, ...]],
|
88
|
+
decorate_logs: bool,
|
72
89
|
verbose: bool,
|
73
90
|
cwd: typing.Optional[pathlib.Path] = None,
|
74
91
|
) -> None:
|
75
92
|
"""Logs out useful debug information on '--verbose'."""
|
76
93
|
if verbose:
|
77
|
-
log(
|
94
|
+
log(
|
95
|
+
f"running: start: [blue]{label}[/blue]: [yellow]{cmd_string}[yellow]",
|
96
|
+
decorate=decorate_logs,
|
97
|
+
)
|
78
98
|
if valid_exit_ids is not None:
|
79
99
|
valid_exit_strs = ",".join(str(exit_code) for exit_code in valid_exit_ids)
|
80
|
-
log(
|
100
|
+
log(
|
101
|
+
f"\tallowed return ids are: [green]{valid_exit_strs}[/green]",
|
102
|
+
decorate=decorate_logs,
|
103
|
+
)
|
81
104
|
|
82
105
|
if env_overrides:
|
83
106
|
env_overrides_as_string = " ".join(
|
84
107
|
[f"{key}='{value}'" for key, value in env_overrides.items()]
|
85
108
|
)
|
86
|
-
log(
|
109
|
+
log(
|
110
|
+
f"ENV OVERRIDES: [yellow]{env_overrides_as_string} {cmd_string}[/yellow]",
|
111
|
+
decorate=decorate_logs,
|
112
|
+
)
|
87
113
|
|
88
114
|
if cwd:
|
89
|
-
log(f"cwd: {str(cwd)}")
|
115
|
+
log(f"cwd: {str(cwd)}", decorate=decorate_logs)
|
90
116
|
|
91
117
|
|
92
118
|
def run_command( # noqa: C901
|
@@ -98,6 +124,7 @@ def run_command( # noqa: C901
|
|
98
124
|
valid_exit_ids: typing.Optional[typing.Tuple[int, ...]] = None,
|
99
125
|
cwd: typing.Optional[pathlib.Path] = None,
|
100
126
|
record_sub_job_time: typing.Optional[RecordSubJobTimeType] = None,
|
127
|
+
decorate_logs: bool = True,
|
101
128
|
**kwargs: typing.Any,
|
102
129
|
) -> str:
|
103
130
|
"""Runs the given command, returning stdout or throwing on any error."""
|
@@ -115,6 +142,7 @@ def run_command( # noqa: C901
|
|
115
142
|
label,
|
116
143
|
env_overrides,
|
117
144
|
valid_exit_ids,
|
145
|
+
decorate_logs,
|
118
146
|
verbose,
|
119
147
|
cwd,
|
120
148
|
)
|
@@ -143,7 +171,12 @@ def run_command( # noqa: C901
|
|
143
171
|
stdout += line
|
144
172
|
if verbose:
|
145
173
|
# print each line of output, assuming that each has a newline
|
146
|
-
log(
|
174
|
+
log(
|
175
|
+
parse_stdout(
|
176
|
+
line, prefix=f"[green]| [/green][blue]{label}[/blue]: "
|
177
|
+
),
|
178
|
+
decorate=False,
|
179
|
+
)
|
147
180
|
|
148
181
|
# Wait for the subprocess to finish and get the exit code
|
149
182
|
process.wait()
|
@@ -154,15 +187,15 @@ def run_command( # noqa: C901
|
|
154
187
|
)
|
155
188
|
raise RunCommandBadExitCode(
|
156
189
|
(
|
157
|
-
f"non-zero exit {process.returncode} (allowed are "
|
158
|
-
f"{valid_exit_strs}) from {cmd_string}"
|
190
|
+
f"non-zero exit [red]{process.returncode}[/red] (allowed are "
|
191
|
+
f"[green]{valid_exit_strs}[/green]) from {cmd_string}"
|
159
192
|
)
|
160
193
|
)
|
161
194
|
except BaseException as err:
|
162
195
|
if ignore_fails:
|
163
196
|
return ""
|
164
197
|
parsed_stdout: str = (
|
165
|
-
parse_stdout(stdout, prefix=
|
198
|
+
parse_stdout(stdout, prefix="[red]| [/red]") if process else ""
|
166
199
|
)
|
167
200
|
env_overrides_as_string = ""
|
168
201
|
if env_overrides:
|
@@ -171,11 +204,11 @@ def run_command( # noqa: C901
|
|
171
204
|
)
|
172
205
|
env_overrides_as_string = f"{env_overrides_as_string} "
|
173
206
|
error_string = (
|
174
|
-
f"runem:
|
175
|
-
f"\n\t{env_overrides_as_string}{cmd_string}"
|
176
|
-
f"\
|
207
|
+
f"runem: [red bold]FATAL[/red bold]: command failed: [blue]{label}[/blue]"
|
208
|
+
f"\n\t[yellow]{env_overrides_as_string}{cmd_string}[/yellow]"
|
209
|
+
f"\n[red underline]| ERROR[/red underline]"
|
177
210
|
f"\n{str(parsed_stdout)}"
|
178
|
-
f"\
|
211
|
+
f"\n[red underline]| ERROR END[/red underline]"
|
179
212
|
)
|
180
213
|
|
181
214
|
if isinstance(err, RunCommandBadExitCode):
|
@@ -184,7 +217,10 @@ def run_command( # noqa: C901
|
|
184
217
|
raise RunCommandUnhandledError(error_string) from err
|
185
218
|
|
186
219
|
if verbose:
|
187
|
-
log(
|
220
|
+
log(
|
221
|
+
f"running: done: [blue]{label}[/blue]: [yellow]{cmd_string}[/yellow]",
|
222
|
+
decorate=decorate_logs,
|
223
|
+
)
|
188
224
|
|
189
225
|
if record_sub_job_time is not None:
|
190
226
|
# Capture how long this run took
|