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.
Files changed (88) hide show
  1. {runem-0.5.0 → runem-0.6.0}/HISTORY.md +70 -0
  2. runem-0.6.0/PKG-INFO +161 -0
  3. runem-0.6.0/README.md +117 -0
  4. runem-0.6.0/runem/VERSION +1 -0
  5. {runem-0.5.0 → runem-0.6.0}/runem/blocking_print.py +10 -2
  6. runem-0.6.0/runem/log.py +43 -0
  7. {runem-0.5.0 → runem-0.6.0}/runem/report.py +4 -1
  8. {runem-0.5.0 → runem-0.6.0}/runem/run_command.py +62 -26
  9. {runem-0.5.0 → runem-0.6.0}/runem/runem.py +37 -58
  10. {runem-0.5.0 → runem-0.6.0}/runem/types/__init__.py +2 -1
  11. runem-0.6.0/runem/utils.py +18 -0
  12. runem-0.6.0/runem.egg-info/PKG-INFO +161 -0
  13. runem-0.6.0/tests/intentional_test_error.py +8 -0
  14. {runem-0.5.0 → runem-0.6.0}/tests/test_hook_manager.py +2 -2
  15. {runem-0.5.0 → runem-0.6.0}/tests/test_run_command.py +9 -9
  16. runem-0.5.0/PKG-INFO +0 -164
  17. runem-0.5.0/README.md +0 -120
  18. runem-0.5.0/runem/VERSION +0 -1
  19. runem-0.5.0/runem/log.py +0 -24
  20. runem-0.5.0/runem/utils.py +0 -6
  21. runem-0.5.0/runem.egg-info/PKG-INFO +0 -164
  22. runem-0.5.0/tests/intentional_test_error.py +0 -5
  23. {runem-0.5.0 → runem-0.6.0}/Containerfile +0 -0
  24. {runem-0.5.0 → runem-0.6.0}/LICENSE +0 -0
  25. {runem-0.5.0 → runem-0.6.0}/MANIFEST.in +0 -0
  26. {runem-0.5.0 → runem-0.6.0}/pyproject.toml +0 -0
  27. {runem-0.5.0 → runem-0.6.0}/runem/__init__.py +0 -0
  28. {runem-0.5.0 → runem-0.6.0}/runem/__main__.py +0 -0
  29. {runem-0.5.0 → runem-0.6.0}/runem/base.py +0 -0
  30. {runem-0.5.0 → runem-0.6.0}/runem/cli/initialise_options.py +0 -0
  31. {runem-0.5.0 → runem-0.6.0}/runem/cli.py +0 -0
  32. {runem-0.5.0 → runem-0.6.0}/runem/command_line.py +0 -0
  33. {runem-0.5.0 → runem-0.6.0}/runem/config.py +0 -0
  34. {runem-0.5.0 → runem-0.6.0}/runem/config_metadata.py +0 -0
  35. {runem-0.5.0 → runem-0.6.0}/runem/config_parse.py +0 -0
  36. {runem-0.5.0 → runem-0.6.0}/runem/files.py +0 -0
  37. {runem-0.5.0 → runem-0.6.0}/runem/hook_manager.py +0 -0
  38. {runem-0.5.0 → runem-0.6.0}/runem/informative_dict.py +0 -0
  39. {runem-0.5.0 → runem-0.6.0}/runem/job.py +0 -0
  40. {runem-0.5.0 → runem-0.6.0}/runem/job_execute.py +0 -0
  41. {runem-0.5.0 → runem-0.6.0}/runem/job_filter.py +0 -0
  42. {runem-0.5.0 → runem-0.6.0}/runem/job_runner_simple_command.py +0 -0
  43. {runem-0.5.0 → runem-0.6.0}/runem/job_wrapper.py +0 -0
  44. {runem-0.5.0 → runem-0.6.0}/runem/job_wrapper_python.py +0 -0
  45. {runem-0.5.0 → runem-0.6.0}/runem/py.typed +0 -0
  46. {runem-0.5.0 → runem-0.6.0}/runem/runem_version.py +0 -0
  47. {runem-0.5.0 → runem-0.6.0}/runem/types/common.py +0 -0
  48. {runem-0.5.0 → runem-0.6.0}/runem/types/errors.py +0 -0
  49. {runem-0.5.0 → runem-0.6.0}/runem/types/filters.py +0 -0
  50. {runem-0.5.0 → runem-0.6.0}/runem/types/hooks.py +0 -0
  51. {runem-0.5.0 → runem-0.6.0}/runem/types/options.py +0 -0
  52. {runem-0.5.0 → runem-0.6.0}/runem/types/runem_config.py +0 -0
  53. {runem-0.5.0 → runem-0.6.0}/runem/types/types_jobs.py +0 -0
  54. {runem-0.5.0 → runem-0.6.0}/runem.egg-info/SOURCES.txt +0 -0
  55. {runem-0.5.0 → runem-0.6.0}/runem.egg-info/dependency_links.txt +0 -0
  56. {runem-0.5.0 → runem-0.6.0}/runem.egg-info/entry_points.txt +0 -0
  57. {runem-0.5.0 → runem-0.6.0}/runem.egg-info/requires.txt +0 -0
  58. {runem-0.5.0 → runem-0.6.0}/runem.egg-info/top_level.txt +0 -0
  59. {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/__init__.py +0 -0
  60. {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/json_validators.py +0 -0
  61. {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/py.py +0 -0
  62. {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/py.typed +0 -0
  63. {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/runem_hooks.py +0 -0
  64. {runem-0.5.0 → runem-0.6.0}/scripts/test_hooks/yarn.py +0 -0
  65. {runem-0.5.0 → runem-0.6.0}/setup.cfg +0 -0
  66. {runem-0.5.0 → runem-0.6.0}/tests/__init__.py +0 -0
  67. {runem-0.5.0 → runem-0.6.0}/tests/cli/test_initialise_options.py +0 -0
  68. {runem-0.5.0 → runem-0.6.0}/tests/conftest.py +0 -0
  69. {runem-0.5.0 → runem-0.6.0}/tests/data/help_output.3.10.txt +0 -0
  70. {runem-0.5.0 → runem-0.6.0}/tests/data/help_output.3.11.txt +0 -0
  71. {runem-0.5.0 → runem-0.6.0}/tests/sanitise_reports_footer.py +0 -0
  72. {runem-0.5.0 → runem-0.6.0}/tests/test_base.py +0 -0
  73. {runem-0.5.0 → runem-0.6.0}/tests/test_blocking_print.py +0 -0
  74. {runem-0.5.0 → runem-0.6.0}/tests/test_cli.py +0 -0
  75. {runem-0.5.0 → runem-0.6.0}/tests/test_config.py +0 -0
  76. {runem-0.5.0 → runem-0.6.0}/tests/test_config_parse.py +0 -0
  77. {runem-0.5.0 → runem-0.6.0}/tests/test_files.py +0 -0
  78. {runem-0.5.0 → runem-0.6.0}/tests/test_informative_dict.py +0 -0
  79. {runem-0.5.0 → runem-0.6.0}/tests/test_job.py +0 -0
  80. {runem-0.5.0 → runem-0.6.0}/tests/test_job_execute.py +0 -0
  81. {runem-0.5.0 → runem-0.6.0}/tests/test_job_filter.py +0 -0
  82. {runem-0.5.0 → runem-0.6.0}/tests/test_job_runner_simple_command.py +0 -0
  83. {runem-0.5.0 → runem-0.6.0}/tests/test_job_wrapper.py +0 -0
  84. {runem-0.5.0 → runem-0.6.0}/tests/test_job_wrapper_python.py +0 -0
  85. {runem-0.5.0 → runem-0.6.0}/tests/test_report.py +0 -0
  86. {runem-0.5.0 → runem-0.6.0}/tests/test_runem.py +0 -0
  87. {runem-0.5.0 → runem-0.6.0}/tests/test_types/__init__.py +0 -0
  88. {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
+ <!-- [![codecov](https://codecov.io/gh/lursight/runem/branch/main/graph/badge.svg?token=run-test_token_here)](https://codecov.io/gh/lursight/runem) -->
46
+ [![CI](https://github.com/lursight/runem/actions/workflows/main.yml/badge.svg)](https://github.com/lursight/runem/actions/workflows/main.yml)
47
+ [![DOCS](https://lursight.github.io/runem/docs/VIEW-DOCS-31c553.svg)](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
+ <!-- [![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
+
@@ -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=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
 
@@ -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(f"report: {str(job_report_url_info[0])}: {str(job_report_url_info[1])}")
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 RunCommandBadExitCode(RuntimeError):
16
- pass
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 RunCommandUnhandledError(RuntimeError):
20
- pass
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
- # Split stdout into lines, noting if it ends with a newline
35
- ends_with_newline = stdout.endswith("\n")
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(f"running: start: {label}: {cmd_string}")
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(f"\tallowed return ids are: {valid_exit_strs}")
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(f"ENV OVERRIDES: {env_overrides_as_string} {cmd_string}")
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(parse_stdout(line, prefix=f"{label}: "))
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=f"{label}: ERROR: ") if process else ""
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: test: FATAL: command failed: {label}"
175
- f"\n\t{env_overrides_as_string}{cmd_string}"
176
- f"\nERROR"
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"\nERROR END"
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(f"running: done: {label}: {cmd_string}")
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