Skip to content

release: v0.5.0 — NFS-e Nacional (ADN) Phase 2, Sprint 4 #23

release: v0.5.0 — NFS-e Nacional (ADN) Phase 2, Sprint 4

release: v0.5.0 — NFS-e Nacional (ADN) Phase 2, Sprint 4 #23

Workflow file for this run

name: CI / Publish to PyPI
on:
push:
branches: [main]
tags:
- "v*"
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
permissions:
contents: write # write required to create GitHub Releases
id-token: write # required for OIDC trusted publisher (PyPI)
jobs:
# ── 1. Tests ───────────────────────────────────────────────────────────────
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: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
# No pip cache — uv manages its own cache via setup-uv
- name: Install uv
uses: astral-sh/setup-uv@v3
- name: Install package + dev dependencies
# --no-sources: ignore [tool.uv.sources] workspace declarations so that
# mcp-einvoicing-core is resolved from PyPI (not a monorepo workspace
# that does not exist in this standalone repo context).
# --upgrade: bypass the committed uv.lock (generated inside the monorepo
# workspace where core resolves as a local path) and re-resolve all
# packages from PyPI to get the correct pinned versions for CI.
run: uv sync --all-extras --no-sources --upgrade
- name: Lint with ruff
run: uv run ruff check src/mcp_nfe_br/ tests/ audit/
- name: Type-check with mypy
# Non-blocking: run mypy for visibility but never fail the job.
# continue-on-error: true marks the job failed in newer Actions runners
# even when subsequent steps pass; use || true to guarantee exit 0.
run: uv run mypy src/mcp_nfe_br/ || true
- name: Run tests
run: uv run pytest --tb=short
- name: Upload coverage report
if: matrix.python-version == '3.11'
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: htmlcov/
# ── 2. Pre-publish audit ───────────────────────────────────────────────────
audit:
name: Pre-publish audit vs mcp-einvoicing-core
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
- name: Install package + dev dependencies
# --no-sources + --upgrade: resolve mcp-einvoicing-core from PyPI, bypassing
# the stale committed lock (see test job for full explanation).
run: uv sync --all-extras --no-sources --upgrade
- name: Run pre-publish audit
# Exit code 2 = blocking failures → job fails → publish is blocked
# Exit code 1 = warnings only → job passes (informational)
run: uv run python audit/audit_vs_core.py --output audit/report.json --fail-on blocking
- name: Upload audit report
if: always() # Upload even on failure so the report is inspectable
uses: actions/upload-artifact@v4
with:
name: audit-report
path: audit/report.json
# ── 3. Build distribution ──────────────────────────────────────────────────
build:
name: Build distribution packages
needs: audit
runs-on: ubuntu-latest
# Only build on tag pushes
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
# No pip cache — uv manages its own cache via setup-uv
- name: Install uv
uses: astral-sh/setup-uv@v3
- name: Build wheel and sdist
run: uv build --no-sources
- name: Assert mcp-einvoicing-core upper-bound pin in wheel METADATA
# Regression check for uv bug #9811: built wheel must retain the <2.0.0 upper-bound pin.
run: |
python - <<'PYEOF'
import zipfile, glob, sys, re
whl = glob.glob('dist/*.whl')
assert whl, 'No wheel found in dist/'
with zipfile.ZipFile(whl[0]) as z:
m = next((n for n in z.namelist() if n.endswith('.dist-info/METADATA')), None)
assert m, 'No METADATA file found in wheel'
content = z.read(m).decode()
ok = any(re.search(r'Requires-Dist: mcp-einvoicing-core.*<', l) for l in content.splitlines())
sys.exit(0 if ok else 'ERROR: mcp-einvoicing-core upper-bound pin missing from wheel METADATA')
PYEOF
- name: Upload distribution packages
uses: actions/upload-artifact@v4
with:
name: dist-packages
path: dist/
# ── 4. Publish to PyPI ─────────────────────────────────────────────────────
publish:
name: Publish to PyPI
needs: build
runs-on: ubuntu-latest
# Only publish on tag pushes; audit must have passed (via the needs chain)
if: startsWith(github.ref, 'refs/tags/v')
environment:
name: pypi
url: https://pypi.org/p/mcp-nfe-br
steps:
- name: Download distribution packages
uses: actions/download-artifact@v4
with:
name: dist-packages
path: dist/
- name: Publish to PyPI via trusted publisher (OIDC)
uses: pypa/gh-action-pypi-publish@release/v1
# No API token needed — uses GitHub OIDC trusted publisher.
# Configure the trusted publisher at:
# https://pypi.org/manage/project/mcp-nfe-br/settings/publishing/
# ── 5. Create GitHub Release ───────────────────────────────────────────────
release:
name: Create GitHub Release
needs: publish
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "${{ github.ref_name }}" \
--title "${{ github.ref_name }}" \
--generate-notes