ci: fix package publishing + add dev/main packages #65
@@ -1,14 +1,15 @@
|
|||||||
name: publish
|
name: publish
|
||||||
|
|
||||||
# Build the Python package with uv and publish it to the self-hosted Gitea PyPI
|
# Build the Python package with uv and publish it to the self-hosted Gitea PyPI
|
||||||
# registry on a version tag. Gated on lint + tests so a release can never ship
|
# registry on merge. dev -> a dev package (aegis-gitea-mcp-dev, .devN versions);
|
||||||
# red. Publishing reuses the existing REGISTRY_TOKEN package secret (the same one
|
# main -> the stable package (aegis-gitea-mcp). Gated on lint + tests so a release
|
||||||
# docker.yml uses to push images); if it is absent the job fails loudly instead
|
# can never ship red. Reuses the REGISTRY_TOKEN package secret (same one docker.yml
|
||||||
# of publishing anonymously.
|
# uses); if it is absent the job fails loudly instead of publishing anonymously.
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
branches:
|
||||||
- 'v*'
|
- dev
|
||||||
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -55,6 +56,13 @@ jobs:
|
|||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# 3. Build with uv and publish to the Gitea PyPI registry.
|
# 3. Build with uv and publish to the Gitea PyPI registry.
|
||||||
|
#
|
||||||
|
# dev -> aegis-gitea-mcp-dev X.Y.Z.dev<run_number> (always unique)
|
||||||
|
# main -> aegis-gitea-mcp X.Y.Z (no-op if already there)
|
||||||
|
#
|
||||||
|
# The package name + version are patched into pyproject.toml at build time
|
||||||
|
# only — never committed. The committed file keeps name "aegis-gitea-mcp"
|
||||||
|
# and version "X.Y.Z".
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
publish:
|
publish:
|
||||||
needs: [lint, test]
|
needs: [lint, test]
|
||||||
@@ -77,11 +85,37 @@ jobs:
|
|||||||
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
if [ -z "${REGISTRY_TOKEN}" ]; then
|
if [ -z "${REGISTRY_TOKEN}" ]; then
|
||||||
echo "::error::REGISTRY_TOKEN secret is not set." >&2
|
echo "::error::REGISTRY_TOKEN secret is not set. Configure a PAT with write:package." >&2
|
||||||
echo "Configure a PAT with write:package as the REGISTRY_TOKEN Actions secret." >&2
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Compute channel (package name + version)
|
||||||
|
id: chan
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
BASE="$(grep -E '^version = ' pyproject.toml | head -1 | sed -E 's/^version = "([^"]+)".*/\1/')"
|
||||||
|
if [ "${GITHUB_REF_NAME}" = "main" ]; then
|
||||||
|
PKG_NAME="aegis-gitea-mcp"
|
||||||
|
PKG_VERSION="${BASE}"
|
||||||
|
CHANNEL="stable"
|
||||||
|
else
|
||||||
|
PKG_NAME="aegis-gitea-mcp-dev"
|
||||||
|
PKG_VERSION="${BASE}.dev${GITHUB_RUN_NUMBER}"
|
||||||
|
CHANNEL="dev"
|
||||||
|
fi
|
||||||
|
echo "pkg_name=${PKG_NAME}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "pkg_version=${PKG_VERSION}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "channel=${CHANNEL}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Publishing ${PKG_NAME} ${PKG_VERSION} (${CHANNEL})"
|
||||||
|
|
||||||
|
- name: Patch package name + version (build only, not committed)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sed -i -E "s/^name = \".*\"/name = \"${{ steps.chan.outputs.pkg_name }}\"/" pyproject.toml
|
||||||
|
sed -i -E "s/^version = \".*\"/version = \"${{ steps.chan.outputs.pkg_version }}\"/" pyproject.toml
|
||||||
|
echo "--- patched [project] header ---"
|
||||||
|
grep -E '^(name|version) = ' pyproject.toml
|
||||||
|
|
||||||
- name: Build sdist + wheel
|
- name: Build sdist + wheel
|
||||||
shell: bash
|
shell: bash
|
||||||
run: uv build
|
run: uv build
|
||||||
@@ -93,7 +127,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dist
|
name: dist-${{ steps.chan.outputs.channel }}
|
||||||
path: dist/*
|
path: dist/*
|
||||||
|
|
||||||
- name: Publish to Gitea PyPI registry
|
- name: Publish to Gitea PyPI registry
|
||||||
@@ -104,8 +138,11 @@ jobs:
|
|||||||
# username and the token is the password.
|
# username and the token is the password.
|
||||||
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
|
# --check-url makes uv skip files already in the registry, so a main
|
||||||
|
# push that did not bump the version is a clean no-op instead of a 409.
|
||||||
uv publish \
|
uv publish \
|
||||||
--publish-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi \
|
--publish-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi \
|
||||||
|
--check-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ \
|
||||||
--username "${GITHUB_ACTOR}" \
|
--username "${GITHUB_ACTOR}" \
|
||||||
--password "${REGISTRY_TOKEN}"
|
--password "${REGISTRY_TOKEN}"
|
||||||
|
|
||||||
|
|||||||
+54
-19
@@ -1,12 +1,23 @@
|
|||||||
# Packaging & publishing
|
# Packaging & publishing
|
||||||
|
|
||||||
AegisGitea-MCP is distributed as a single Python package, `aegis-gitea-mcp`,
|
AegisGitea-MCP is built with [`uv`](https://docs.astral.sh/uv/) and published to
|
||||||
built with [`uv`](https://docs.astral.sh/uv/) and published to the self-hosted
|
the self-hosted Gitea package registry on every merge. There are two channels:
|
||||||
Gitea package registry.
|
|
||||||
|
| Channel | Package | Published on | Versioning |
|
||||||
|
|---------|---------|--------------|------------|
|
||||||
|
| **stable** | `aegis-gitea-mcp` | merge to `main` | `X.Y.Z` |
|
||||||
|
| **dev** | `aegis-gitea-mcp-dev` | merge to `dev` | `X.Y.Z.devN` (N = CI run number, always unique) |
|
||||||
|
|
||||||
|
Both channels build from the same source and install the **same import module**,
|
||||||
|
`aegis_gitea_mcp`, with the same two console scripts. They differ only in the
|
||||||
|
distribution name and the version. Install one or the other in a given
|
||||||
|
environment, not both — they would collide on the module.
|
||||||
|
|
||||||
## Distribution layout
|
## Distribution layout
|
||||||
|
|
||||||
One package, two console scripts, one optional extra:
|
Each channel ships one distribution with two console scripts and one optional
|
||||||
|
extra (the stable and dev packages are identical here — only the dist name and
|
||||||
|
version differ):
|
||||||
|
|
||||||
| Console script | Entry point | Requires |
|
| Console script | Entry point | Requires |
|
||||||
|----------------|-------------|----------|
|
|----------------|-------------|----------|
|
||||||
@@ -39,30 +50,54 @@ GITEA_URL=https://git.hiddenden.cafe GITEA_TOKEN=<pat> \
|
|||||||
|
|
||||||
## Install from the Gitea registry
|
## Install from the Gitea registry
|
||||||
|
|
||||||
|
**Stable** (`aegis-gitea-mcp`, published from `main`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv pip install \
|
uv pip install \
|
||||||
--index-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple \
|
--index-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ \
|
||||||
aegis-gitea-mcp
|
aegis-gitea-mcp
|
||||||
|
|
||||||
|
# or run it one-off without installing into the environment:
|
||||||
|
uvx --index https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ aegis-gitea-mcp
|
||||||
```
|
```
|
||||||
|
|
||||||
(With `pip`, use `--index-url` the same way.)
|
**Dev** (`aegis-gitea-mcp-dev`, published from `dev` — newest pre-release build):
|
||||||
|
|
||||||
## Cutting a release
|
|
||||||
|
|
||||||
Releases are tag-driven. The publish workflow
|
|
||||||
(`.gitea/workflows/publish.yml`) triggers on a `v*` tag, runs lint + tests
|
|
||||||
first, builds with `uv`, and publishes to the Gitea PyPI registry.
|
|
||||||
|
|
||||||
1. Bump `version` in `pyproject.toml` (e.g. `0.2.0`).
|
|
||||||
2. Open a PR into `dev`, merge `dev` into `main`.
|
|
||||||
3. Tag the release commit and push the tag:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git tag v0.2.0
|
uv pip install \
|
||||||
git push origin v0.2.0
|
--index-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ \
|
||||||
|
aegis-gitea-mcp-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
4. The workflow publishes the wheel + sdist and attaches them to the run.
|
(With `pip`, use `--index-url` the same way.) Both packages expose the same
|
||||||
|
`aegis-gitea-mcp` / `aegis-gitea-mcp-server` console scripts and the same
|
||||||
|
`aegis_gitea_mcp` import module, so install one **or** the other per environment.
|
||||||
|
|
||||||
|
## Publishing channels
|
||||||
|
|
||||||
|
Publishing is merge-driven, not tag-driven. The publish workflow
|
||||||
|
(`.gitea/workflows/publish.yml`) triggers on a push to `dev` or `main`, runs
|
||||||
|
lint + tests first, then builds with `uv` and publishes to the Gitea PyPI
|
||||||
|
registry. The package name + version are patched into `pyproject.toml` **at build
|
||||||
|
time only** (never committed):
|
||||||
|
|
||||||
|
- **`dev` push** → `aegis-gitea-mcp-dev` at `X.Y.Z.dev<run_number>`. The CI run
|
||||||
|
number is monotonic, so every merge to `dev` yields a unique pre-release.
|
||||||
|
- **`main` push** → `aegis-gitea-mcp` at the plain `X.Y.Z` from `pyproject.toml`.
|
||||||
|
Publishing uses `uv publish --check-url`, so a `main` push that did **not** bump
|
||||||
|
the version is a clean no-op (the existing files are skipped) rather than a 409.
|
||||||
|
|
||||||
|
### Cutting a stable release
|
||||||
|
|
||||||
|
1. Bump `version` in `pyproject.toml` (e.g. `0.2.0` → `0.3.0`) on a branch off
|
||||||
|
`dev`.
|
||||||
|
2. Open a PR into `dev` and merge it (this publishes a fresh
|
||||||
|
`aegis-gitea-mcp-dev` build).
|
||||||
|
3. Promote `dev` → `main`. The push to `main` publishes the new stable
|
||||||
|
`aegis-gitea-mcp X.Y.Z`.
|
||||||
|
|
||||||
|
Re-pushing `main` at an unchanged version is harmless — `--check-url` skips the
|
||||||
|
already-published files.
|
||||||
|
|
||||||
### Required CI secrets
|
### Required CI secrets
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user