Publish CLI from release workflow

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
funnywolf
2026-07-04 23:20:30 +08:00
co-authored by Copilot
parent 22ae3c2eb2
commit 8b3b090ac5
4 changed files with 116 additions and 2 deletions
+47
View File
@@ -7,6 +7,7 @@ on:
permissions: permissions:
contents: write contents: write
id-token: write
packages: write packages: write
jobs: jobs:
@@ -116,3 +117,49 @@ jobs:
with: with:
body_path: dist/release-body.md body_path: dist/release-body.md
files: dist/asp-compose-${{ needs.prepare.outputs.version }}.tar.gz files: dist/asp-compose-${{ needs.prepare.outputs.version }}.tar.gz
publish-cli:
name: Publish CLI to PyPI
runs-on: ubuntu-latest
needs:
- prepare
- release
environment:
name: pypi
url: https://pypi.org/p/asp-cli
defaults:
run:
working-directory: cli
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.14"
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Check CLI version matches release tag
run: |
python - <<'PY'
import tomllib
from pathlib import Path
release_version = "${{ needs.prepare.outputs.version }}"
pyproject = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))
cli_version = pyproject["project"]["version"]
if cli_version != release_version:
raise SystemExit(
f"cli/pyproject.toml version {cli_version!r} must match release tag version {release_version!r}"
)
PY
- name: Build CLI package
run: uv build
- name: Check package metadata
run: uvx twine check dist/*
- name: Publish CLI package
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: cli/dist
+45
View File
@@ -25,3 +25,48 @@ For automation and skills, prefer stable JSON output:
```powershell ```powershell
asp case list --output json asp case list --output json
``` ```
## Publish to PyPI
The GitHub release workflow publishes `asp-cli` to PyPI automatically when a `v<version>` tag is pushed. The CLI package version does not include the leading `v` and must match the main release version, so update `version` in `pyproject.toml` before creating the tag.
For example, release tag `v0.1.0` publishes PyPI version `0.1.0`.
### Automatic publishing
The workflow uses PyPI Trusted Publishing, so it does not need a PyPI API token in the repository or GitHub Secrets. Configure PyPI once with a trusted publisher:
- PyPI project: `asp-cli`
- Owner/repository: `FunnyWolf/agentic-soc-platform`
- Workflow: `release.yml`
- Environment: `pypi`
If the PyPI project does not exist yet, add the same entry under PyPI's pending publishers before the first release.
Release steps:
```powershell
# Update cli\pyproject.toml first, for example: version = "0.1.0"
git tag v0.1.0
git push origin v0.1.0
```
### Manual fallback
Manual publishing requires a PyPI API token. Keep it local and do not commit it:
```powershell
cd cli
Remove-Item -Recurse -Force dist -ErrorAction SilentlyContinue
uv build
uvx twine check dist\*
$env:UV_PUBLISH_TOKEN = "pypi-..."
uv publish --token $env:UV_PUBLISH_TOKEN
```
After publishing, verify the package can be installed:
```powershell
pipx install --force asp-cli
asp --version
```
+23 -1
View File
@@ -1 +1,23 @@
__version__ = "0.1.0" from __future__ import annotations
import tomllib
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path
def _source_version() -> str | None:
pyproject_path = Path(__file__).resolve().parents[2] / "pyproject.toml"
if not pyproject_path.exists():
return None
pyproject = tomllib.loads(pyproject_path.read_text(encoding="utf-8"))
project_version = pyproject.get("project", {}).get("version")
if not isinstance(project_version, str):
raise RuntimeError("Missing project.version in cli pyproject.toml")
return project_version
try:
__version__ = _source_version() or version("asp-cli")
except PackageNotFoundError as exc:
raise RuntimeError("Cannot resolve asp-cli package version") from exc
+1 -1
View File
@@ -44,7 +44,7 @@ class RuntimeOptions:
verbose: bool verbose: bool
app = typer.Typer(no_args_is_help=True, help="ASP command line client.") app = typer.Typer(no_args_is_help=True, invoke_without_command=True, help="ASP command line client.")
auth_app = typer.Typer(no_args_is_help=True, help="Authenticate and inspect the current ASP session.") auth_app = typer.Typer(no_args_is_help=True, help="Authenticate and inspect the current ASP session.")
config_app = typer.Typer(no_args_is_help=True, help="Read and write ASP CLI settings.") config_app = typer.Typer(no_args_is_help=True, help="Read and write ASP CLI settings.")
completion_app = typer.Typer(no_args_is_help=True, help="Show shell completion installation commands.") completion_app = typer.Typer(no_args_is_help=True, help="Show shell completion installation commands.")