Skip to content

Commit 93947d4

Browse files
authored
Add PyPI publish stage (#3)
* CNF: add base workflows * CNF: use previous image * CNF: added tar based image build * CNF: pinned debian, changed pull request workflow * CNF: fixed env var referencing * CNF: updated os for runners * CNF: update upload version * CNF: added dev multistage * CNF: updated action versions * CNF: try new config * CNF: target dev stage * CNF: added coverage * CNF: only include source files for coverage * CNF: added source to the correct place * CNF: add PR comment and update coverage report toml settings * CNF: call with uv * CNF: enable caching * CNF: optimize docker cache and remove uid change * CNF: removed upload to artifact storage * CNF: add sticky comment to avoid spam * CNF: add build check stage * CNF: hi * CNF: try out 2 publishing stages * CNF: add publish to pypi automatically * CNF: using existing pypa job for upload * CNF: changed rules for test and main pypi * CNF: add verbose output * CNF: correct dev/main pypi push * CNF: always run the dev version
1 parent b8b2577 commit 93947d4

1 file changed

Lines changed: 113 additions & 30 deletions

File tree

.github/workflows/main.yml

Lines changed: 113 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
1-
name: CI - Run Unit Tests in Docker with Coverage
1+
name: CI, Test, and Tag-Based Release with Dev TestPyPI
22

33
on:
44
push:
5-
branches: [ main ]
5+
branches:
6+
- main # Trigger for pushes to main
7+
tags:
8+
- 'v*' # Trigger for pushes of tags like v1.0, v2.3.4
9+
610
pull_request:
7-
branches: [ main ]
11+
branches: [ main ] # Trigger for PRs targeting main
12+
types: [opened, synchronize, reopened]
813

914
jobs:
15+
# --- Test Job (Remains the same) ---
1016
test:
1117
runs-on: ubuntu-latest
12-
1318
steps:
1419
- name: Checkout code
1520
uses: actions/checkout@v4
21+
with:
22+
fetch-depth: 0
1623

1724
- name: Set up Docker Buildx
1825
uses: docker/setup-buildx-action@v3
@@ -21,22 +28,15 @@ jobs:
2128
uses: docker/build-push-action@v5
2229
with:
2330
context: .
24-
file: ./Dockerfile # Assuming Dockerfile is at the root
25-
# Build the 'dev' target stage
31+
file: ./Dockerfile
2632
target: dev
27-
# Tag the image locally so subsequent steps can use it
2833
tags: my-test-image:latest
29-
# IMPORTANT: Load the image into the local Docker daemon
3034
load: true
31-
# Enable layer caching using GitHub Actions cache
3235
cache-from: type=gha
3336
cache-to: type=gha,mode=max
3437

3538
- name: Run tests with dFBA extra
3639
run: |
37-
# Runs coverage collection via 'uv run' using --with pytest-cov.
38-
# Uses --parallel-mode for coverage data.
39-
# Generates uniquely named JUnit report.
4040
docker run --rm \
4141
-v "$(pwd):/app" \
4242
-w /app \
@@ -45,23 +45,15 @@ jobs:
4545
4646
- name: Run tests without dFBA extra
4747
run: |
48-
# Runs coverage collection via 'uv run' using --with pytest-cov.
49-
# Uses --parallel-mode for coverage data.
50-
# Generates uniquely named JUnit report.
5148
docker run --rm \
5249
-v "$(pwd):/app" \
5350
-w /app \
5451
my-test-image:latest \
5552
uv run --with pytest --with pytest-cov coverage run --parallel-mode -m pytest ./tests/core --junitxml=test-report-core.xml
5653
57-
# --- The step below only runs if BOTH test steps above succeeded ---
58-
5954
- name: Combine and Report Coverage
6055
if: success()
6156
run: |
62-
# Runs combine, report, and html generation in a single container
63-
# Saves the console summary to /app/coverage_summary.txt within the container
64-
# which maps to coverage_summary.txt on the runner host via the volume mount.
6557
docker run --rm \
6658
-v "$(pwd):/app" \
6759
-w /app \
@@ -74,30 +66,121 @@ jobs:
7466
echo "Generating HTML coverage report..." && \
7567
uv run --with pytest --with pytest-cov coverage html -d htmlcov \
7668
'
77-
# Also echo the summary to the main job log for easy viewing there
7869
echo "--- Coverage Summary ---"
7970
cat coverage_summary.txt
8071
echo "------------------------"
8172
8273
- name: Format Coverage Comment Body
83-
# Prepare the content for the comment in a file
84-
# Only run on successful PR builds
8574
if: success() && github.event_name == 'pull_request'
8675
run: |
8776
echo '### :test_tube: Coverage Report' > coverage_comment.md
8877
echo '' >> coverage_comment.md
8978
echo '```text' >> coverage_comment.md
9079
cat coverage_summary.txt >> coverage_comment.md
91-
echo '' >> coverage_comment.md # Ensure newline before closing fence
80+
echo '' >> coverage_comment.md
9281
echo '```' >> coverage_comment.md
93-
# Optional: Add a hidden HTML comment marker for extra safety/identification
94-
# echo "<!-- coverage-report-marker -->" >> coverage_comment.md
95-
82+
9683
- name: Post or Update Coverage Comment
97-
# Use the sticky comment action
98-
# Only run on successful PR builds
9984
if: success() && github.event_name == 'pull_request'
10085
uses: marocchino/sticky-pull-request-comment@v2
10186
with:
102-
# Tell the action to read the comment body from the file we just created
10387
path: coverage_comment.md
88+
89+
# --- Job: Publish DEV version to TestPyPI (Runs ONLY on tag pushes) ---
90+
publish-testpypi:
91+
name: Publish Dev Version to TestPyPI
92+
needs: test
93+
# Run ONLY when a tag is pushed, AFTER tests pass
94+
if: success()
95+
runs-on: ubuntu-latest
96+
environment:
97+
name: testpypi
98+
url: https://test.pypi.org/pypi
99+
permissions:
100+
id-token: write
101+
102+
steps:
103+
- name: Checkout code
104+
uses: actions/checkout@v4
105+
with:
106+
fetch-depth: 0
107+
108+
- name: Set up Python
109+
uses: actions/setup-python@v5
110+
with:
111+
python-version: '3.10'
112+
113+
- name: Install build dependencies
114+
run: python -m pip install build twine
115+
116+
# --- Add step to generate dev suffix ---
117+
- name: Generate development version suffix
118+
id: version_suffix
119+
# Using timestamp for uniqueness on TestPyPI for potentially repeated tag tests
120+
run: echo "suffix=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT
121+
122+
# --- Add step to update version ---
123+
- name: Update version in pyproject.toml for TestPyPI
124+
run: |
125+
# Add .dev<timestamp> suffix to the version line
126+
# This assumes version = "X.Y.Z" format in pyproject.toml
127+
VERSION_SUFFIX="${{ steps.version_suffix.outputs.suffix }}"
128+
# Use temp file for sed compatibility
129+
sed -i.bak "s/^\(version\s*=\s*\"\)\([^\"]*\)\"/\1\2.dev${VERSION_SUFFIX}\"/" pyproject.toml
130+
rm pyproject.toml.bak # Remove backup
131+
echo "Updated pyproject.toml with dev version suffix for TestPyPI build:"
132+
grep "^version" pyproject.toml
133+
134+
- name: Build package with dev version
135+
run: |
136+
echo "Building package for tag ${{ github.ref_name }} with dev suffix..."
137+
python -m build
138+
139+
- name: Publish package distributions to TestPyPI
140+
uses: pypa/gh-action-pypi-publish@release/v1
141+
with:
142+
repository-url: https://test.pypi.org/legacy/
143+
# skip-existing: true # Recommended for dev builds
144+
145+
# --- Job: Publish CLEAN version to PyPI (Runs ONLY on tag pushes, after TestPyPI) ---
146+
publish-pypi:
147+
name: Publish Clean Version to PyPI
148+
needs: publish-testpypi # Depends on the TestPyPI dev publish job
149+
# Run ONLY when a tag is pushed, AFTER TestPyPI publish succeeds
150+
if: success() && startsWith(github.ref, 'refs/tags/')
151+
runs-on: ubuntu-latest
152+
environment:
153+
name: pypi
154+
url: https://pypi.org/pypi
155+
permissions:
156+
id-token: write
157+
158+
steps:
159+
# --- Checkout code AGAIN to get the original version ---
160+
- name: Checkout ORIGINAL code for tag
161+
uses: actions/checkout@v4
162+
with:
163+
# Make sure we're checking out the code corresponding to the tag
164+
# This ensures we get the pyproject.toml WITHOUT the .dev suffix
165+
ref: ${{ github.ref }}
166+
fetch-depth: 0
167+
168+
- name: Set up Python
169+
uses: actions/setup-python@v5
170+
with:
171+
python-version: '3.10'
172+
173+
- name: Install build dependencies
174+
run: python -m pip install build twine
175+
176+
- name: Build package with CLEAN version
177+
run: |
178+
echo "Building package for tag ${{ github.ref_name }} for PyPI release (using original version)..."
179+
grep "^version" pyproject.toml
180+
# Builds the package using the version defined in the tagged commit's source
181+
# because we checked out the original code again.
182+
python -m build
183+
184+
- name: Publish package distributions to PyPI
185+
uses: pypa/gh-action-pypi-publish@release/v1
186+
# Defaults to PyPI, uses trusted publishing via OIDC

0 commit comments

Comments
 (0)