release: v0.5.0 — NFS-e Nacional (ADN) Phase 2, Sprint 4 #23
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |