ry-tool 1.0.1__tar.gz → 1.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ry-tool
3
- Version: 1.0.1
3
+ Version: 1.2.0
4
4
  Summary: Pure YAML command orchestrator - CI/CD for humans
5
5
  Author: Fredrik Angelsen
6
6
  Author-email: Fredrik Angelsen <fredrikangelsen@gmail.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ry-tool"
3
- version = "1.0.1"
3
+ version = "1.2.0"
4
4
  description = "Pure YAML command orchestrator - CI/CD for humans"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -9,9 +9,12 @@ import subprocess
9
9
  import sys
10
10
  import os
11
11
  import json
12
+ import yaml
12
13
  from typing import Dict, Any, List, Optional
13
14
  from dataclasses import dataclass
14
15
  from io import StringIO
16
+ from pathlib import Path
17
+ import ry_tool.utils # Import ry_tool modules
15
18
 
16
19
 
17
20
  @dataclass
@@ -59,17 +62,19 @@ class Executor:
59
62
  Returns:
60
63
  ExecutionResult
61
64
  """
62
- # Merge environment
63
- env = step.get('env', {})
65
+ # Merge environment - extra_env takes precedence
66
+ env = {}
64
67
  if extra_env:
65
68
  env.update(extra_env)
69
+ if step.get('env'):
70
+ env.update(step['env'])
66
71
 
67
72
  if 'shell' in step:
68
73
  return self.execute_shell(step['shell'], env,
69
74
  interactive=step.get('interactive', False),
70
75
  capture_file=step.get('_capture_file'))
71
76
  elif 'python' in step:
72
- return self.execute_python(step['python'])
77
+ return self.execute_python(step['python'], extra_env=env)
73
78
  elif 'subprocess' in step:
74
79
  return self.execute_subprocess(step['subprocess'])
75
80
  elif 'ruby' in step:
@@ -203,7 +208,7 @@ class Executor:
203
208
  returncode=1
204
209
  )
205
210
 
206
- def execute_python(self, code: str) -> ExecutionResult:
211
+ def execute_python(self, code: str, extra_env: Dict[str, str] = None) -> ExecutionResult:
207
212
  """
208
213
  Execute Python code with context.
209
214
 
@@ -230,15 +235,45 @@ class Executor:
230
235
  original_env = safe_copy(self.context.get('env'), {})
231
236
  original_captured = safe_copy(self.context.get('captured'), {})
232
237
 
238
+ # Set up Python path from environment
239
+ # This allows library code to import from lib/ directories
240
+ if extra_env and 'PYTHONPATH' in extra_env:
241
+ for path in extra_env['PYTHONPATH'].split(':'):
242
+ if path and path not in sys.path:
243
+ sys.path.insert(0, path)
244
+
245
+ # Also add library directory if provided
246
+ if extra_env and 'RY_LIBRARY_DIR' in extra_env:
247
+ lib_path = os.path.join(extra_env['RY_LIBRARY_DIR'], 'lib')
248
+ if os.path.exists(lib_path) and lib_path not in sys.path:
249
+ sys.path.insert(0, lib_path)
250
+
251
+ # Add all sibling library lib/ directories for cross-library imports
252
+ # This allows e.g., uv library to import from git library
253
+ libraries_root = os.path.dirname(extra_env['RY_LIBRARY_DIR'])
254
+ if os.path.exists(libraries_root):
255
+ for item in os.listdir(libraries_root):
256
+ sibling_lib = os.path.join(libraries_root, item, 'lib')
257
+ if os.path.isdir(sibling_lib) and sibling_lib not in sys.path:
258
+ sys.path.insert(0, sibling_lib)
259
+
260
+ # Merge environment variables into env dict
261
+ merged_env = safe_copy(self.context.get('env'), {})
262
+ if extra_env:
263
+ merged_env.update(extra_env)
264
+
233
265
  # Prepare execution environment with mutable references
234
266
  exec_globals = {
235
267
  'sys': sys,
236
268
  'os': os,
237
269
  'subprocess': subprocess,
238
270
  'json': json,
271
+ 'yaml': yaml,
272
+ 'Path': Path,
273
+ 'ry_tool': ry_tool, # Make ry_tool module available
239
274
  'flags': safe_copy(self.context.get('flags'), {}),
240
275
  'arguments': safe_copy(self.context.get('arguments'), {}),
241
- 'env': safe_copy(self.context.get('env'), {}),
276
+ 'env': merged_env,
242
277
  'captured': safe_copy(self.context.get('captured'), {}),
243
278
  'remaining_args': self.context.get('remaining_args', []),
244
279
  'positionals': safe_copy(self.context.get('positionals'), []),
@@ -22,6 +22,7 @@ class LibraryConfig:
22
22
  commands: Dict[str, Any] = field(default_factory=dict)
23
23
  metadata: Dict[str, Any] = field(default_factory=dict)
24
24
  path: Optional[Path] = None
25
+ workflows: List[str] = field(default_factory=list) # Common workflow examples
25
26
 
26
27
 
27
28
  class LibraryLoader:
@@ -179,7 +180,8 @@ class LibraryLoader:
179
180
  description=data.get('description', ''),
180
181
  commands=commands,
181
182
  metadata=metadata,
182
- path=path
183
+ path=path,
184
+ workflows=data.get('workflows', [])
183
185
  )
184
186
 
185
187
  def _validate_command(self, name: str, config: Dict[str, Any]):
@@ -240,6 +240,14 @@ class CommandParser:
240
240
  if cmd_name != '*': # Skip catch-all
241
241
  desc = cmd_config.get('description', 'No description')
242
242
  help_lines.append(f" {cmd_name:<15} {desc}")
243
+
244
+ # Add common workflows if defined
245
+ if hasattr(library_config, 'workflows') and library_config.workflows:
246
+ help_lines.append("")
247
+ help_lines.append("Common workflow:")
248
+ for workflow in library_config.workflows:
249
+ help_lines.append(f" {workflow}")
250
+
243
251
  help_lines.append("")
244
252
  help_lines.append("Use: ry-next <library> <command> --help for command details")
245
253
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes