shellflow 0.1.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.
- shellflow-0.1.0/.github/workflows/ci.yml +70 -0
- shellflow-0.1.0/.github/workflows/release.yml +73 -0
- shellflow-0.1.0/.gitignore +43 -0
- shellflow-0.1.0/.python-version +1 -0
- shellflow-0.1.0/.rumdl.toml +24 -0
- shellflow-0.1.0/AGENTS.md +67 -0
- shellflow-0.1.0/CHANGELOG.md +11 -0
- shellflow-0.1.0/CLAUDE.md +1 -0
- shellflow-0.1.0/Justfile +90 -0
- shellflow-0.1.0/PKG-INFO +253 -0
- shellflow-0.1.0/README.md +231 -0
- shellflow-0.1.0/assets/shellflow-run.png +0 -0
- shellflow-0.1.0/behave_runner.py +50 -0
- shellflow-0.1.0/cliff.toml +78 -0
- shellflow-0.1.0/context7.json +4 -0
- shellflow-0.1.0/features/__init__.py +1 -0
- shellflow-0.1.0/features/environment.py +73 -0
- shellflow-0.1.0/features/parser.feature +25 -0
- shellflow-0.1.0/features/runner.feature +57 -0
- shellflow-0.1.0/features/steps/__init__.py +1 -0
- shellflow-0.1.0/features/steps/shellflow_steps.py +237 -0
- shellflow-0.1.0/playbooks/hello.sh +8 -0
- shellflow-0.1.0/pyproject.toml +72 -0
- shellflow-0.1.0/ruff.toml +110 -0
- shellflow-0.1.0/specs/2026-03-13-01-shellflow-runner/REFINEMENT_SUMMARY.md +165 -0
- shellflow-0.1.0/specs/2026-03-13-01-shellflow-runner/design.md +1011 -0
- shellflow-0.1.0/specs/2026-03-13-01-shellflow-runner/features/config.feature +115 -0
- shellflow-0.1.0/specs/2026-03-13-01-shellflow-runner/features/parser.feature +131 -0
- shellflow-0.1.0/specs/2026-03-13-01-shellflow-runner/features/runner.feature +119 -0
- shellflow-0.1.0/specs/2026-03-13-01-shellflow-runner/features/steps/shellflow_steps.py +463 -0
- shellflow-0.1.0/specs/2026-03-13-01-shellflow-runner/tasks.md +146 -0
- shellflow-0.1.0/src/shellflow.py +802 -0
- shellflow-0.1.0/tests/__init__.py +1 -0
- shellflow-0.1.0/tests/fixtures/local_only.sh +6 -0
- shellflow-0.1.0/tests/test_shellflow.py +1356 -0
- shellflow-0.1.0/uv.lock +623 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version:
|
|
16
|
+
- "3.12"
|
|
17
|
+
- "3.13"
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout repository
|
|
21
|
+
uses: actions/checkout@v5
|
|
22
|
+
|
|
23
|
+
- name: Set up uv
|
|
24
|
+
uses: astral-sh/setup-uv@v7
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
enable-cache: true
|
|
28
|
+
cache-dependency-glob: |
|
|
29
|
+
pyproject.toml
|
|
30
|
+
uv.lock
|
|
31
|
+
|
|
32
|
+
- name: Install dependencies
|
|
33
|
+
run: uv sync --all-groups
|
|
34
|
+
|
|
35
|
+
- name: Run tests
|
|
36
|
+
run: uv run pytest -q
|
|
37
|
+
|
|
38
|
+
- name: Run BDD scenarios
|
|
39
|
+
run: uv run behave features
|
|
40
|
+
|
|
41
|
+
quality:
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
|
|
44
|
+
steps:
|
|
45
|
+
- name: Checkout repository
|
|
46
|
+
uses: actions/checkout@v5
|
|
47
|
+
|
|
48
|
+
- name: Set up uv
|
|
49
|
+
uses: astral-sh/setup-uv@v7
|
|
50
|
+
with:
|
|
51
|
+
python-version: "3.12"
|
|
52
|
+
enable-cache: true
|
|
53
|
+
cache-dependency-glob: |
|
|
54
|
+
pyproject.toml
|
|
55
|
+
uv.lock
|
|
56
|
+
|
|
57
|
+
- name: Install dependencies
|
|
58
|
+
run: uv sync --all-groups
|
|
59
|
+
|
|
60
|
+
- name: Run formatting check
|
|
61
|
+
run: uv run ruff format --check .
|
|
62
|
+
|
|
63
|
+
- name: Run lint
|
|
64
|
+
run: uv run ruff check .
|
|
65
|
+
|
|
66
|
+
- name: Run type check
|
|
67
|
+
run: uv run ty check src tests
|
|
68
|
+
|
|
69
|
+
- name: Build distributions
|
|
70
|
+
run: uv build
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
release:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
|
|
20
|
+
- name: Setup uv
|
|
21
|
+
uses: astral-sh/setup-uv@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.12"
|
|
24
|
+
|
|
25
|
+
- name: Get version from tag
|
|
26
|
+
id: tag_version
|
|
27
|
+
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
|
28
|
+
|
|
29
|
+
- name: Check pyproject.toml version
|
|
30
|
+
run: |
|
|
31
|
+
FILE_VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
32
|
+
|
|
33
|
+
echo "pyproject.toml version: $FILE_VERSION"
|
|
34
|
+
echo "Tag version: ${{ env.VERSION }}"
|
|
35
|
+
|
|
36
|
+
if [ "$FILE_VERSION" != "${{ env.VERSION }}" ]; then
|
|
37
|
+
echo "Error: pyproject.toml version ($FILE_VERSION) does not match tag version (${{ env.VERSION }})"
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
- name: Generate Changelog
|
|
42
|
+
uses: orhun/git-cliff-action@v4
|
|
43
|
+
id: git-cliff
|
|
44
|
+
with:
|
|
45
|
+
config: cliff.toml
|
|
46
|
+
args: --verbose --latest --strip header
|
|
47
|
+
env:
|
|
48
|
+
OUTPUT: CHANGELOG.md
|
|
49
|
+
|
|
50
|
+
- name: Create GitHub Release
|
|
51
|
+
uses: softprops/action-gh-release@v2
|
|
52
|
+
with:
|
|
53
|
+
body: ${{ steps.git-cliff.outputs.content }}
|
|
54
|
+
prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') }}
|
|
55
|
+
|
|
56
|
+
- name: Install dependencies
|
|
57
|
+
run: uv sync --all-groups
|
|
58
|
+
|
|
59
|
+
- name: Run release verification
|
|
60
|
+
run: |
|
|
61
|
+
uv run ruff format --check .
|
|
62
|
+
uv run ruff check .
|
|
63
|
+
uv run ty check src tests
|
|
64
|
+
uv run pytest -q
|
|
65
|
+
uv run behave features
|
|
66
|
+
|
|
67
|
+
- name: Build Package
|
|
68
|
+
run: uv build
|
|
69
|
+
|
|
70
|
+
- name: Publish to PyPI
|
|
71
|
+
env:
|
|
72
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
73
|
+
run: uv publish
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
|
|
12
|
+
# Virtual environment
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# Testing / coverage
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
.tox/
|
|
22
|
+
.nox/
|
|
23
|
+
|
|
24
|
+
# Ruff
|
|
25
|
+
.ruff_cache/
|
|
26
|
+
|
|
27
|
+
# ty
|
|
28
|
+
.ty/
|
|
29
|
+
|
|
30
|
+
# IDE
|
|
31
|
+
.idea/
|
|
32
|
+
.vscode/
|
|
33
|
+
*.swp
|
|
34
|
+
*.swo
|
|
35
|
+
|
|
36
|
+
# OS
|
|
37
|
+
.DS_Store
|
|
38
|
+
Thumbs.db
|
|
39
|
+
|
|
40
|
+
# Environment variables
|
|
41
|
+
.env
|
|
42
|
+
.env.local
|
|
43
|
+
.rumdl_cache/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# rumdl configuration file
|
|
2
|
+
|
|
3
|
+
# Global configuration options
|
|
4
|
+
[global]
|
|
5
|
+
# List of rules to disable (uncomment and modify as needed)
|
|
6
|
+
disable = ["MD013", "MD033", "MD041", "MD036"]
|
|
7
|
+
|
|
8
|
+
# List of file/directory patterns to exclude from linting
|
|
9
|
+
exclude = [
|
|
10
|
+
# Common directories to exclude
|
|
11
|
+
".git",
|
|
12
|
+
".github",
|
|
13
|
+
"node_modules",
|
|
14
|
+
"vendor",
|
|
15
|
+
"dist",
|
|
16
|
+
"build",
|
|
17
|
+
".venv",
|
|
18
|
+
"venv",
|
|
19
|
+
"__pycache__",
|
|
20
|
+
"*.egg-info",
|
|
21
|
+
|
|
22
|
+
# Specific files or patterns
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Shellflow Agent Instructions
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
Shellflow is a minimal shell script orchestrator with SSH support. It allows users to write shell scripts that execute across local and remote environments using simple comment markers.
|
|
6
|
+
|
|
7
|
+
## Project Structure
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
shellflow/
|
|
11
|
+
├── src/shellflow.py # Main module with all functionality
|
|
12
|
+
├── tests/ # Unit tests (pytest)
|
|
13
|
+
├── features/ # BDD acceptance tests (behave)
|
|
14
|
+
│ ├── parser.feature
|
|
15
|
+
│ ├── runner.feature
|
|
16
|
+
│ ├── steps/shellflow_steps.py
|
|
17
|
+
│ └── environment.py
|
|
18
|
+
├── behave_runner.py # Wrapper for running behave
|
|
19
|
+
├── pyproject.toml # Project configuration
|
|
20
|
+
├── README.md # Documentation
|
|
21
|
+
└── AGENTS.md # This file
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Core Concepts
|
|
25
|
+
|
|
26
|
+
### Script Block Markers
|
|
27
|
+
|
|
28
|
+
- `# @LOCAL` - Start a local execution block
|
|
29
|
+
- `# @REMOTE <host>` - Start a remote execution block
|
|
30
|
+
|
|
31
|
+
### Key Modules
|
|
32
|
+
|
|
33
|
+
- `Block` - Represents an execution block (local or remote)
|
|
34
|
+
- `ExecutionContext` - Passes state between block executions
|
|
35
|
+
- `ExecutionResult` - Result of executing a single block
|
|
36
|
+
- `RunResult` - Result of running a complete script
|
|
37
|
+
- `SSHConfig` - SSH configuration for remote hosts
|
|
38
|
+
|
|
39
|
+
### CLI Commands
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
shellflow run <script> # Run a shellflow script
|
|
43
|
+
shellflow run <script> -v # Run with verbose output
|
|
44
|
+
shellflow --version # Show version
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Development Commands
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
just format # Format code with ruff
|
|
51
|
+
just lint # Lint with ruff
|
|
52
|
+
just test # Run pytest
|
|
53
|
+
just bdd # Run behave BDD tests
|
|
54
|
+
just test-all # Run format, lint, test, and bdd
|
|
55
|
+
just typecheck # Type check with ty
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Testing
|
|
59
|
+
|
|
60
|
+
- Unit tests: `pytest` under `tests/`
|
|
61
|
+
- BDD tests: `behave` under `features/`
|
|
62
|
+
- Run all: `just test-all`
|
|
63
|
+
|
|
64
|
+
## Dependencies
|
|
65
|
+
|
|
66
|
+
- Runtime: `paramiko>=3.0.0`
|
|
67
|
+
- Dev: `pytest`, `behave`, `ruff`, `ty`, `hypothesis`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
shellflow-0.1.0/Justfile
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Default recipe to display help
|
|
2
|
+
default:
|
|
3
|
+
@just --list
|
|
4
|
+
|
|
5
|
+
# Sync all dependencies
|
|
6
|
+
sync:
|
|
7
|
+
uv sync --all-groups
|
|
8
|
+
|
|
9
|
+
# Format all code
|
|
10
|
+
format:
|
|
11
|
+
rumdl fmt .
|
|
12
|
+
uv run ruff format .
|
|
13
|
+
uv run ruff check --fix .
|
|
14
|
+
|
|
15
|
+
# Auto-fix linting issues
|
|
16
|
+
fix:
|
|
17
|
+
rumdl check --fix .
|
|
18
|
+
uv run ruff check --fix .
|
|
19
|
+
|
|
20
|
+
# Run all lints
|
|
21
|
+
lint:
|
|
22
|
+
typos
|
|
23
|
+
rumdl check .
|
|
24
|
+
uv run ruff check .
|
|
25
|
+
uv run ruff format --check .
|
|
26
|
+
uv run ty check src tests
|
|
27
|
+
|
|
28
|
+
# Run tests
|
|
29
|
+
test:
|
|
30
|
+
uv run pytest
|
|
31
|
+
|
|
32
|
+
# Run BDD scenarios
|
|
33
|
+
bdd:
|
|
34
|
+
uv run behave
|
|
35
|
+
|
|
36
|
+
# Run both TDD and BDD suites
|
|
37
|
+
test-all:
|
|
38
|
+
uv run pytest
|
|
39
|
+
uv run behave
|
|
40
|
+
|
|
41
|
+
# Run tests with coverage
|
|
42
|
+
test-coverage:
|
|
43
|
+
uv run pytest --cov=uv_app --cov-report=term-missing --cov-report=html
|
|
44
|
+
|
|
45
|
+
# Run benchmarks
|
|
46
|
+
bench:
|
|
47
|
+
uv run pytest -m benchmark --benchmark-only
|
|
48
|
+
|
|
49
|
+
# Build the package
|
|
50
|
+
build:
|
|
51
|
+
uv build
|
|
52
|
+
|
|
53
|
+
# Publish the package to PyPI
|
|
54
|
+
publish:
|
|
55
|
+
uv build
|
|
56
|
+
uv publish
|
|
57
|
+
|
|
58
|
+
# Type check with ty
|
|
59
|
+
typecheck:
|
|
60
|
+
uv run ty check src tests
|
|
61
|
+
|
|
62
|
+
# Check for Chinese characters
|
|
63
|
+
check-cn:
|
|
64
|
+
rg --line-number --column "\p{Han}"
|
|
65
|
+
|
|
66
|
+
# Full CI check
|
|
67
|
+
ci: lint test-all build
|
|
68
|
+
|
|
69
|
+
# ============================================================
|
|
70
|
+
# Maintenance & Tools
|
|
71
|
+
# ============================================================
|
|
72
|
+
|
|
73
|
+
# Clean build artifacts
|
|
74
|
+
clean:
|
|
75
|
+
rm -rf dist/ .pytest_cache/ .ruff_cache/ htmlcov/ .coverage
|
|
76
|
+
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
|
|
77
|
+
find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
|
|
78
|
+
|
|
79
|
+
# Install all required development tools
|
|
80
|
+
setup:
|
|
81
|
+
uv sync --all-groups
|
|
82
|
+
cargo install typos-cli
|
|
83
|
+
|
|
84
|
+
# Lock dependencies
|
|
85
|
+
lock:
|
|
86
|
+
uv lock
|
|
87
|
+
|
|
88
|
+
# Update all dependencies
|
|
89
|
+
update:
|
|
90
|
+
uv lock --upgrade
|
shellflow-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: shellflow
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A minimal shell script orchestrator with SSH support
|
|
5
|
+
Project-URL: Homepage, https://github.com/longcipher/shellflow
|
|
6
|
+
Project-URL: Repository, https://github.com/longcipher/shellflow
|
|
7
|
+
Project-URL: Issues, https://github.com/longcipher/shellflow/issues
|
|
8
|
+
Author: Bob Liu
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Keywords: automation,orchestration,shell,ssh
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: System :: Systems Administration
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Requires-Dist: paramiko>=3.0.0
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# ShellFlow
|
|
24
|
+
|
|
25
|
+
[](https://deepwiki.com/longcipher/shellflow)
|
|
26
|
+
[](https://context7.com/longcipher/shellflow)
|
|
27
|
+
[](https://www.python.org/downloads/)
|
|
28
|
+
[](LICENSE)
|
|
29
|
+
[](https://pypi.org/project/shellflow/)
|
|
30
|
+
|
|
31
|
+

|
|
32
|
+
|
|
33
|
+
ShellFlow is a minimal shell script orchestrator for mixed local and remote execution. You write one shell script, mark execution boundaries with comments, and ShellFlow runs each block in order while resolving remote targets from your SSH configuration.
|
|
34
|
+
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
## What It Does
|
|
38
|
+
|
|
39
|
+
- Split a shell script into `@LOCAL` and `@REMOTE` execution blocks.
|
|
40
|
+
- Run each block fail-fast, in order.
|
|
41
|
+
- Reuse the shared prelude before the first marker for every block.
|
|
42
|
+
- Pass the previous block output forward as `SHELLFLOW_LAST_OUTPUT`.
|
|
43
|
+
- Resolve remote targets from `~/.ssh/config` or a custom SSH config path.
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
git clone https://github.com/longcipher/shellflow.git
|
|
49
|
+
cd shellflow
|
|
50
|
+
uv sync --all-groups # uv sync --refresh --reinstall --no-cache
|
|
51
|
+
uv tool install --force --reinstall --refresh --no-cache .
|
|
52
|
+
|
|
53
|
+
shellflow run playbooks/hello.sh
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
If you do not want a global tool install, use `uv run shellflow run playbooks/hello.sh`.
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
### Development checkout
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://github.com/longcipher/shellflow.git
|
|
64
|
+
cd shellflow
|
|
65
|
+
uv sync --all-groups # uv sync --refresh --reinstall --no-cache
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Install as a local tool
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv tool install --force .
|
|
72
|
+
shellflow --version
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Install into the active environment
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv pip install -e .
|
|
79
|
+
shellflow --version
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Script Format
|
|
83
|
+
|
|
84
|
+
Shellflow recognizes two markers:
|
|
85
|
+
|
|
86
|
+
- `# @LOCAL`
|
|
87
|
+
- `# @REMOTE <ssh-host>`
|
|
88
|
+
|
|
89
|
+
`<ssh-host>` must match a `Host` entry in your SSH config. Shellflow then connects using that SSH host definition, which means the actual machine can be resolved through the configured `HostName`, `User`, `Port`, and `IdentityFile` values.
|
|
90
|
+
|
|
91
|
+
Example:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
#!/bin/bash
|
|
95
|
+
set -euo pipefail
|
|
96
|
+
|
|
97
|
+
# @LOCAL
|
|
98
|
+
echo "runs locally"
|
|
99
|
+
|
|
100
|
+
# @REMOTE sui
|
|
101
|
+
uname -a
|
|
102
|
+
|
|
103
|
+
# @LOCAL
|
|
104
|
+
echo "remote output: $SHELLFLOW_LAST_OUTPUT"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## SSH Configuration
|
|
108
|
+
|
|
109
|
+
Example `~/.ssh/config` entry:
|
|
110
|
+
|
|
111
|
+
```sshconfig
|
|
112
|
+
Host sui
|
|
113
|
+
HostName 192.168.1.100
|
|
114
|
+
User deploy
|
|
115
|
+
Port 22
|
|
116
|
+
IdentityFile ~/.ssh/id_ed25519
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
With that config, this block is valid:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# @REMOTE sui
|
|
123
|
+
hostname
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This is intentional:
|
|
127
|
+
|
|
128
|
+
- Shellflow accepts configured SSH host names, not arbitrary free-form targets.
|
|
129
|
+
- Unknown remote targets fail early with a clear error before spawning `ssh`.
|
|
130
|
+
- You can override the default config path with `--ssh-config`.
|
|
131
|
+
|
|
132
|
+
## Execution Model
|
|
133
|
+
|
|
134
|
+
Each block runs in a fresh shell.
|
|
135
|
+
|
|
136
|
+
- Shell options from the prelude are copied into every block.
|
|
137
|
+
- Shell state like `cd`, shell variables, aliases, and `export` commands does not persist across blocks.
|
|
138
|
+
- Explicit context values are passed forward through environment variables.
|
|
139
|
+
|
|
140
|
+
Example:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# @LOCAL
|
|
144
|
+
echo "build-123"
|
|
145
|
+
|
|
146
|
+
# @LOCAL
|
|
147
|
+
echo "last output = $SHELLFLOW_LAST_OUTPUT"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Lines before the first marker are treated as a shared prelude and prepended to every executable block:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
#!/bin/bash
|
|
154
|
+
set -euo pipefail
|
|
155
|
+
|
|
156
|
+
# @LOCAL
|
|
157
|
+
echo "prelude is active"
|
|
158
|
+
|
|
159
|
+
# @REMOTE sui
|
|
160
|
+
echo "prelude is also active here"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## CLI
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
shellflow run <script>
|
|
167
|
+
shellflow run <script> --verbose
|
|
168
|
+
shellflow run <script> --ssh-config ./ssh_config
|
|
169
|
+
shellflow --version
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Examples:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
shellflow run playbooks/hello.sh
|
|
176
|
+
shellflow run playbooks/hello.sh -v
|
|
177
|
+
shellflow run playbooks/hello.sh --ssh-config ~/.ssh/config.work
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Development
|
|
181
|
+
|
|
182
|
+
Useful commands:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
just sync
|
|
186
|
+
just test
|
|
187
|
+
just bdd
|
|
188
|
+
just test-all
|
|
189
|
+
just typecheck
|
|
190
|
+
just build
|
|
191
|
+
just publish
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Direct verification commands:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
uv run pytest -q
|
|
198
|
+
uv run behave features
|
|
199
|
+
uv run ruff check .
|
|
200
|
+
uv run ty check src tests
|
|
201
|
+
uv build
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Release Process
|
|
205
|
+
|
|
206
|
+
Shellflow supports both local publishing and GitHub Actions release publishing.
|
|
207
|
+
|
|
208
|
+
### Local publish
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
just publish
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`uv publish` uses standard `uv` authentication mechanisms such as `UV_PUBLISH_TOKEN`, or PyPI trusted publishing when supported by the environment.
|
|
215
|
+
|
|
216
|
+
### GitHub Actions publish on tag push
|
|
217
|
+
|
|
218
|
+
The repository includes:
|
|
219
|
+
|
|
220
|
+
- `.github/workflows/ci.yml` for lint, type-check, test, and build verification.
|
|
221
|
+
- `.github/workflows/release.yml` for publishing to PyPI when a tag like `v0.1.0` is pushed.
|
|
222
|
+
|
|
223
|
+
Recommended release flow:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
git tag v0.1.0
|
|
227
|
+
git push origin v0.1.0
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
To use trusted publishing with PyPI:
|
|
231
|
+
|
|
232
|
+
1. Create a `pypi` environment in GitHub repository settings.
|
|
233
|
+
2. Add this repository as a trusted publisher in the PyPI project settings.
|
|
234
|
+
3. Push a `v*` tag.
|
|
235
|
+
|
|
236
|
+
The release workflow then runs verification, builds distributions with `uv build`, and uploads them with `uv publish`.
|
|
237
|
+
|
|
238
|
+
## Project Layout
|
|
239
|
+
|
|
240
|
+
```text
|
|
241
|
+
shellflow/
|
|
242
|
+
├── src/shellflow.py
|
|
243
|
+
├── tests/
|
|
244
|
+
├── features/
|
|
245
|
+
├── playbooks/
|
|
246
|
+
├── pyproject.toml
|
|
247
|
+
├── Justfile
|
|
248
|
+
└── README.md
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## License
|
|
252
|
+
|
|
253
|
+
Apache-2.0
|