Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
version: 2

updates:
- package-ecosystem: pip
directory: "/"
schedule:
interval: weekly
day: monday
groups:
minor-and-patch:
update-types:
- minor
- patch
labels:
- dependencies

- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
day: monday
groups:
actions-minor-patch:
update-types:
- minor
- patch
labels:
- dependencies
- github-actions
41 changes: 41 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --extra dev

- name: Run tests with coverage
run: uv run pytest --cov=src/foreman --cov-report=xml --cov-report=term-missing

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
if: matrix.python-version == '3.11'
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
fail_ci_if_error: false
155 changes: 155 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
name: Publish to PyPI

on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+a[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+b[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
workflow_dispatch:
inputs:
target:
description: "Publish target"
required: true
default: "testpypi"
type: choice
options:
- testpypi
- pypi

jobs:
test:
name: Test before publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Run tests
run: |
uv python install 3.11
uv sync --extra dev
uv run pytest

build:
name: Build distribution
runs-on: ubuntu-latest
needs: test
outputs:
version: ${{ steps.version.outputs.version }}
is_prerelease: ${{ steps.version.outputs.is_prerelease }}
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Extract version
id: version
run: |
VERSION=$(uv run python -c "import tomllib; d=tomllib.loads(open('pyproject.toml').read()); print(d['project']['version'])")
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
if [[ "$VERSION" =~ (a|b|rc)[0-9]+ ]]; then
echo "is_prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "is_prerelease=false" >> "$GITHUB_OUTPUT"
fi

- name: Assert tag matches pyproject.toml version
if: startsWith(github.ref, 'refs/tags/')
run: |
TAG="${GITHUB_REF_NAME#v}"
PKG="${{ steps.version.outputs.version }}"
if [ "$TAG" != "$PKG" ]; then
echo "Tag $TAG does not match pyproject.toml version $PKG" >&2
exit 1
fi

- name: Build sdist and wheel
run: uv build

- name: Validate with twine
run: |
uv run --with twine twine check dist/*

- name: Upload dist artifacts
uses: actions/upload-artifact@v7
with:
name: dist
path: dist/

publish-testpypi:
name: Publish to TestPyPI
runs-on: ubuntu-latest
needs: build
if: |
needs.build.outputs.is_prerelease == 'true' ||
github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'testpypi'
environment:
name: testpypi
url: https://test.pypi.org/p/foreman-orchestrator
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/

publish-pypi:
name: Publish to PyPI
runs-on: ubuntu-latest
needs: build
if: |
startsWith(github.ref, 'refs/tags/') &&
needs.build.outputs.is_prerelease == 'false'
environment:
name: pypi
url: https://pypi.org/p/foreman-orchestrator
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [build, publish-pypi]
if: startsWith(github.ref, 'refs/tags/') && needs.build.outputs.is_prerelease == 'false'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: "v${{ needs.build.outputs.version }}"
generate_release_notes: true
files: dist/*
prerelease: false
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

`plan → ADR/PRD → issues → TDD build → e2e`

[![CI](https://github.com/VisionForge-OU/foreman/actions/workflows/ci.yml/badge.svg)](https://github.com/VisionForge-OU/foreman/actions/workflows/ci.yml)
[![Coverage](https://codecov.io/gh/VisionForge-OU/foreman/branch/main/graph/badge.svg)](https://codecov.io/gh/VisionForge-OU/foreman)
[![PyPI version](https://img.shields.io/pypi/v/foreman-orchestrator.svg)](https://pypi.org/project/foreman-orchestrator/)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/foreman-orchestrator.svg)](https://pypi.org/project/foreman-orchestrator/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/foreman-orchestrator.svg)](https://pypi.org/project/foreman-orchestrator/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
[![Version](https://img.shields.io/badge/version-0.6.0-blueviolet.svg)](./CHANGELOG.md)
[![TUI: Textual](https://img.shields.io/badge/TUI-Textual-5a3fd6.svg)](https://textual.textualize.io/)
[![No database](https://img.shields.io/badge/database-none-lightgrey.svg)](#how-it-works)
[![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](#contributing)

[Why Foreman?](#why-foreman) · [Demo](#demo) · [Quickstart](#5-minute-quickstart) · [Guide](#guide--driving-the-tui) · [How it works](#how-it-works) · [Roadmap](#roadmap) · [Contributing](#contributing)
Expand Down
13 changes: 12 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,25 @@ description = "A Boris-style agentic orchestrator TUI that supervises headless C
readme = "README.md"
requires-python = ">=3.11"
license = { text = "MIT" }
authors = [{ name = "Foreman" }]
authors = [{ name = "ehsantg", email = "me@ehsan.ee" }]
keywords = ["claude", "claude-code", "tui", "agents", "orchestrator", "textual", "tdd"]
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Build Tools",
]

[project.urls]
Homepage = "https://github.com/VisionForge-OU/foreman"
Repository = "https://github.com/VisionForge-OU/foreman"
Issues = "https://github.com/VisionForge-OU/foreman/issues"
Changelog = "https://github.com/VisionForge-OU/foreman/blob/main/CHANGELOG.md"
dependencies = [
"textual>=0.79",
"pyyaml>=6.0",
Expand All @@ -27,6 +37,7 @@ dependencies = [
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.23",
"pytest-cov>=5.0",
"pytest-textual-snapshot>=1.0",
"textual-dev>=1.5",
]
Expand Down
Loading