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 an automated release publishing workflow triggered by version tags
  • Tests
    • Added smoke tests to verify package import and CLI (--version and --help) behavior and basic runtime sanity

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

coderabbitai bot commented Jan 6, 2026

Warning

Rate limit exceeded

@ParticularlyPythonicBS has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 16 minutes and 48 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ee1209f4-76a5-40db-8f4d-c14efee81374

📥 Commits

Reviewing files that changed from the base of the PR and between d1ca3a6 and c79f90c.

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

Walkthrough

Adds a publish GitHub Actions workflow triggered by tag pushes, bumps the package __version__ constant, and adds a smoke test module exercising package import and CLI --version / --help.

Changes

Cohort / File(s) Summary
Publishing Workflow
.github/workflows/publish.yml
New GitHub Actions workflow triggered on push tags v*; checks out repo, installs astral-sh/setup-uv, uses Python 3.12, runs uv build, executes tests/smoke_test.py against built dists and sdist, then runs uv publish.
Version Update
temoa/__about__.py
Updated __version__ from '4.0.0a1.dev20251201' to '4.0.0a1' (no other logic changes).
Smoke Tests
tests/smoke_test.py
New test module adding test_import(), test_cli(), and test_help() that import temoa, assert non-empty version, and run temoa --version and temoa --help subprocess checks; also runnable as a script.

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: push tag triggers workflow
    GH->>Runner: start job (pypi env)
    Runner->>Runner: checkout repo\ninstall setup-uv\nsetup Python 3.12\nuv build
    Runner->>Runner: run tests/smoke_test.py (wheel & sdist)
    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 directly describes the main change: adding a CI workflow for PyPI trusted publishing, which matches the primary purpose of the changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • 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.

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.

♻️ Duplicate comments (2)
tests/smoke_test.py (2)

9-15: 🧹 Nitpick | 🔵 Trivial

Add explicit check=False to document intent and add timeout.

Since you're manually checking returncode, adding explicit check=False documents this intent and silences the linter warning (PLW1510). The timeout concern from prior feedback also remains applicable.

🔧 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, check=False, 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

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/smoke_test.py` around lines 9 - 15, In test_cli update the
subprocess.run call inside test_cli to pass explicit check=False and a
reasonable timeout (e.g., timeout=10) so the test documents that return codes
are checked manually and cannot hang; locate the subprocess.run invocation in
the test_cli function and add these kwargs while keeping capture_output=True and
text=True unchanged.

17-21: 🧹 Nitpick | 🔵 Trivial

Same recommendations apply: explicit check=False and timeout.

🔧 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, check=False, timeout=30)
     assert result.returncode == 0
     assert "The Temoa Project" in result.stdout

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/smoke_test.py` around lines 17 - 21, The subprocess.run invocation in
test_help (function test_help) should explicitly pass check=False and a
reasonable timeout to avoid hanging tests; update the call to
subprocess.run(["temoa", "--help"], capture_output=True, text=True, check=False,
timeout=30) so the test explicitly opts out of raising on nonzero exit and fails
fast on hangs while keeping the existing assertions on result.returncode and
result.stdout.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@tests/smoke_test.py`:
- Around line 9-15: In test_cli update the subprocess.run call inside test_cli
to pass explicit check=False and a reasonable timeout (e.g., timeout=10) so the
test documents that return codes are checked manually and cannot hang; locate
the subprocess.run invocation in the test_cli function and add these kwargs
while keeping capture_output=True and text=True unchanged.
- Around line 17-21: The subprocess.run invocation in test_help (function
test_help) should explicitly pass check=False and a reasonable timeout to avoid
hanging tests; update the call to subprocess.run(["temoa", "--help"],
capture_output=True, text=True, check=False, timeout=30) so the test explicitly
opts out of raising on nonzero exit and fails fast on hangs while keeping the
existing assertions on result.returncode and result.stdout.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 45d3af42-a00d-437e-8f01-3d66a1cb33ed

📥 Commits

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

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

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