Skip to content

infra: pypi trusted publishing ci#245

Open
ParticularlyPythonicBS wants to merge 1 commit intounstablefrom
infra/publish_ci
Open

infra: pypi trusted publishing ci#245
ParticularlyPythonicBS wants to merge 1 commit intounstablefrom
infra/publish_ci

Conversation

@ParticularlyPythonicBS
Copy link
Member

@ParticularlyPythonicBS ParticularlyPythonicBS commented Jan 6, 2026

Adds CI workflow for uploading tagged v commits to pypi when enabled through trusted publishing.

Also adds a simple smoke_test to ensure the build functions as intended

Summary by CodeRabbit

  • Chores
    • Updated package version to 4.0.0a1
    • Added automated release publishing workflow for tag-triggered releases
  • Tests
    • Added smoke tests to verify package import and CLI --version/--help behavior

@ParticularlyPythonicBS ParticularlyPythonicBS added the Infra workflow changes label Jan 6, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 274d76d6-4cfa-4f4b-913c-9172212dab0f

📥 Commits

Reviewing files that changed from the base of the PR and between e10e0f9 and 591772f.

📒 Files selected for processing (3)
  • .github/workflows/publish.yml
  • temoa/__about__.py
  • tests/smoke_test.py

Walkthrough

Adds a GitHub Actions workflow to publish on version tags, bumps package version constant, and introduces a smoke test validating package import and CLI outputs.

Changes

Cohort / File(s) Summary
Publishing Workflow
.github/workflows/publish.yml
New workflow triggered on v* tags: checks out code, installs uv, installs Python 3.12, builds dists, runs smoke tests (tests/smoke_test.py), and publishes via uv publish with token/contents permissions.
Version Update
temoa/__about__.py
Updated __version__ from '4.0.0a1.dev20251201' to '4.0.0a1'.
Smoke Tests
tests/smoke_test.py
New test file with checks for Python import and non-empty __version__, CLI --version exit code and output, and CLI --help content.

Sequence Diagram(s)

sequenceDiagram
    participant Tag as "Git Tag (v*)"
    participant GH as "GitHub Actions"
    participant Runner as "Runner (ubuntu-latest)"
    participant PyPI as "PyPI (uv publish)"

    Tag->>GH: Tag push triggers workflow
    GH->>Runner: Start job (checkout)
    Runner->>Runner: install astral-sh/setup-uv\ninstall Python 3.12\nbuild sdist & wheel
    Runner->>Runner: run tests/smoke_test.py (import, --version, --help)
    Runner->>PyPI: uv publish (uses token)
    PyPI-->>Runner: publish result
    Runner-->>GH: Job completes
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: a CI workflow for PyPI trusted publishing. It directly relates to the primary changeset which adds a GitHub Actions publish workflow.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch infra/publish_ci

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ParticularlyPythonicBS ParticularlyPythonicBS force-pushed the infra/publish_ci branch 4 times, most recently from e261834 to e10e0f9 Compare January 6, 2026 18:25
@ParticularlyPythonicBS
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 6, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI Agents
In @.github/workflows/publish.yml:
- Around line 31-32: Add a pre-publish verification step before the "Publish"
run that extracts the tag version from GITHUB_REF (e.g. strip "refs/tags/v"),
reads the package version by running python -c "import temoa;
print(temoa.__version__)", compares the two, and fails the job (exit 1) with a
clear error if they differ; if they match, allow the workflow to continue to the
existing uv publish step and emit a success message.
- Around line 27-30: Add a timeout to the two smoke test workflow steps ("Smoke
test (wheel)" and "Smoke test (source distribution)") so a hung CLI won't stall
the run; update each job step to include a timeout-minutes (e.g.,
timeout-minutes: 10) alongside the existing name and run keys to ensure the
subprocess in tests/smoke_test.py is bounded.

In @tests/smoke_test.py:
- Around line 17-21: The test_help function uses subprocess.run without a
timeout which can hang; update the subprocess.run call in test_help to include a
timeout (match the value used in test_cli, e.g., timeout=10) and optionally
catch subprocess.TimeoutExpired to fail the test with a clear message; target
the subprocess.run invocation inside test_help.
- Around line 5-7: The test_import test currently only asserts temoa.__version__
is not None; strengthen it to ensure temoa.__version__ is a non-empty string by
checking its type and that its length is > 0 (e.g., assert
isinstance(temoa.__version__, str) and assert temoa.__version__.strip() != ""),
referencing the test_import function and temoa.__version__ to locate and update
the assertion.
- Around line 9-15: The subprocess.run call in test_cli can hang indefinitely;
add a timeout (e.g., timeout=10) to the subprocess.run invocation in the
test_cli function and handle subprocess.TimeoutExpired by failing the test
(raise or pytest.fail) with a clear message; update the call from
subprocess.run([...], capture_output=True, text=True) to include timeout=10 and
wrap it in try/except subprocess.TimeoutExpired to provide a deterministic test
failure if the CLI is unresponsive.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1eefec4 and e10e0f9.

📒 Files selected for processing (3)
  • .github/workflows/publish.yml
  • temoa/__about__.py
  • tests/smoke_test.py
🧰 Additional context used
🪛 Ruff (0.14.10)
tests/smoke_test.py

11-11: Starting a process with a partial executable path

(S607)


19-19: Starting a process with a partial executable path

(S607)


29-29: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (5)
.github/workflows/publish.yml (2)

3-7: LGTM! Appropriate trigger configuration.

The tag-based trigger for version releases follows conventional patterns for publishing workflows.


10-16: LGTM! Correct permissions for trusted publishing.

The id-token: write permission is properly configured for OIDC-based trusted publishing to PyPI.

temoa/__about__.py (1)

3-3: LGTM! Version bump aligns with release workflow.

The version change from development (4.0.0a1.dev20251201) to alpha (4.0.0a1) is appropriate for the new publishing workflow targeting stable releases.

tests/smoke_test.py (2)

1-3: LGTM! Imports are appropriate for smoke tests.

The direct import of temoa is correct for this use case, as the workflow installs the package before running tests.


23-31: LGTM! Exception handling is appropriate for smoke tests.

The bare except Exception is acceptable in this context, as the smoke test needs to catch and report any failure. The static analysis warning (BLE001) can be safely ignored here.

Comment on lines +27 to +30
- name: Smoke test (wheel)
run: uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py
- name: Smoke test (source distribution)
run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider adding timeouts to smoke test steps.

The subprocess calls in tests/smoke_test.py don't have explicit timeouts, which could cause the workflow to hang if the CLI commands fail to respond. Consider adding a timeout-minutes directive to these steps as a safeguard.

🔎 Proposed enhancement
      # Check that basic features work and we didn't miss to include crucial files
      - name: Smoke test (wheel)
+       timeout-minutes: 5
        run: uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py
      - name: Smoke test (source distribution)
+       timeout-minutes: 5
        run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @.github/workflows/publish.yml around lines 27 - 30, Add a timeout to the two
smoke test workflow steps ("Smoke test (wheel)" and "Smoke test (source
distribution)") so a hung CLI won't stall the run; update each job step to
include a timeout-minutes (e.g., timeout-minutes: 10) alongside the existing
name and run keys to ensure the subprocess in tests/smoke_test.py is bounded.

Comment on lines +31 to +32
- name: Publish
run: uv publish
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider adding version tag verification before publishing.

The workflow doesn't verify that the Git tag matches the version in temoa/__about__.py. This could lead to publishing artifacts with mismatched version metadata.

🔎 Proposed verification step

Add this step before the publish step:

      - name: Verify version matches tag
        run: |
          TAG_VERSION="${GITHUB_REF#refs/tags/v}"
          PACKAGE_VERSION=$(uv run python -c "import temoa; print(temoa.__version__)")
          if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then
            echo "Error: Tag version ($TAG_VERSION) doesn't match package version ($PACKAGE_VERSION)"
            exit 1
          fi
          echo "✅ Version verified: $PACKAGE_VERSION"
🤖 Prompt for AI Agents
In @.github/workflows/publish.yml around lines 31 - 32, Add a pre-publish
verification step before the "Publish" run that extracts the tag version from
GITHUB_REF (e.g. strip "refs/tags/v"), reads the package version by running
python -c "import temoa; print(temoa.__version__)", compares the two, and fails
the job (exit 1) with a clear error if they differ; if they match, allow the
workflow to continue to the existing uv publish step and emit a success message.

Comment on lines +5 to +7
def test_import() -> None:
print(f"Importing temoa version: {temoa.__version__}")
assert temoa.__version__ is not None
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider strengthening the version assertion.

The current assertion only checks for None. Consider verifying it's a non-empty string to catch more potential issues.

🔎 Proposed enhancement
 def test_import() -> None:
     print(f"Importing temoa version: {temoa.__version__}")
-    assert temoa.__version__ is not None
+    assert temoa.__version__ is not None
+    assert isinstance(temoa.__version__, str)
+    assert len(temoa.__version__) > 0
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_import() -> None:
print(f"Importing temoa version: {temoa.__version__}")
assert temoa.__version__ is not None
def test_import() -> None:
print(f"Importing temoa version: {temoa.__version__}")
assert temoa.__version__ is not None
assert isinstance(temoa.__version__, str)
assert len(temoa.__version__) > 0
🤖 Prompt for AI Agents
In @tests/smoke_test.py around lines 5 - 7, The test_import test currently only
asserts temoa.__version__ is not None; strengthen it to ensure temoa.__version__
is a non-empty string by checking its type and that its length is > 0 (e.g.,
assert isinstance(temoa.__version__, str) and assert temoa.__version__.strip()
!= ""), referencing the test_import function and temoa.__version__ to locate and
update the assertion.

Comment on lines +9 to +15
def test_cli() -> None:
print("Running temoa --version CLI command...")
result = subprocess.run(["temoa", "--version"], capture_output=True, text=True)
print(f"CLI output: {result.stdout.strip()}")
assert result.returncode == 0
assert "Temoa Version:" in result.stdout
assert temoa.__version__ in result.stdout
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add timeout to subprocess calls to prevent hangs.

While the test logic is sound, subprocess calls without timeouts could cause the CI to hang indefinitely if the CLI becomes unresponsive.

🔎 Proposed fix
 def test_cli() -> None:
     print("Running temoa --version CLI command...")
-    result = subprocess.run(["temoa", "--version"], capture_output=True, text=True)
+    result = subprocess.run(["temoa", "--version"], capture_output=True, text=True, timeout=30)
     print(f"CLI output: {result.stdout.strip()}")
     assert result.returncode == 0
     assert "Temoa Version:" in result.stdout
     assert temoa.__version__ in result.stdout
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_cli() -> None:
print("Running temoa --version CLI command...")
result = subprocess.run(["temoa", "--version"], capture_output=True, text=True)
print(f"CLI output: {result.stdout.strip()}")
assert result.returncode == 0
assert "Temoa Version:" in result.stdout
assert temoa.__version__ in result.stdout
def test_cli() -> None:
print("Running temoa --version CLI command...")
result = subprocess.run(["temoa", "--version"], capture_output=True, text=True, timeout=30)
print(f"CLI output: {result.stdout.strip()}")
assert result.returncode == 0
assert "Temoa Version:" in result.stdout
assert temoa.__version__ in result.stdout
🧰 Tools
🪛 Ruff (0.14.10)

11-11: Starting a process with a partial executable path

(S607)

🤖 Prompt for AI Agents
In @tests/smoke_test.py around lines 9 - 15, The subprocess.run call in test_cli
can hang indefinitely; add a timeout (e.g., timeout=10) to the subprocess.run
invocation in the test_cli function and handle subprocess.TimeoutExpired by
failing the test (raise or pytest.fail) with a clear message; update the call
from subprocess.run([...], capture_output=True, text=True) to include timeout=10
and wrap it in try/except subprocess.TimeoutExpired to provide a deterministic
test failure if the CLI is unresponsive.

Comment on lines +17 to +21
def test_help() -> None:
print("Running temoa --help CLI command...")
result = subprocess.run(["temoa", "--help"], capture_output=True, text=True)
assert result.returncode == 0
assert "The Temoa Project" in result.stdout
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add timeout to subprocess call.

Same recommendation as test_cli() - add a timeout parameter to prevent potential hangs.

🔎 Proposed fix
 def test_help() -> None:
     print("Running temoa --help CLI command...")
-    result = subprocess.run(["temoa", "--help"], capture_output=True, text=True)
+    result = subprocess.run(["temoa", "--help"], capture_output=True, text=True, timeout=30)
     assert result.returncode == 0
     assert "The Temoa Project" in result.stdout
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_help() -> None:
print("Running temoa --help CLI command...")
result = subprocess.run(["temoa", "--help"], capture_output=True, text=True)
assert result.returncode == 0
assert "The Temoa Project" in result.stdout
def test_help() -> None:
print("Running temoa --help CLI command...")
result = subprocess.run(["temoa", "--help"], capture_output=True, text=True, timeout=30)
assert result.returncode == 0
assert "The Temoa Project" in result.stdout
🧰 Tools
🪛 Ruff (0.14.10)

19-19: Starting a process with a partial executable path

(S607)

🤖 Prompt for AI Agents
In @tests/smoke_test.py around lines 17 - 21, The test_help function uses
subprocess.run without a timeout which can hang; update the subprocess.run call
in test_help to include a timeout (match the value used in test_cli, e.g.,
timeout=10) and optionally catch subprocess.TimeoutExpired to fail the test with
a clear message; target the subprocess.run invocation inside test_help.

@ParticularlyPythonicBS ParticularlyPythonicBS added the Maintenance Code quality fixes and deprecation management label Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Infra workflow changes Maintenance Code quality fixes and deprecation management

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant