Skip to content

Commit 0d8be0b

Browse files
author
Francisco
committed
fix: streamline workflows for linting, testing, releasing, and publishing to PyPI
1 parent 3033e6b commit 0d8be0b

1 file changed

Lines changed: 82 additions & 170 deletions

File tree

.github/workflows/ci.yml

Lines changed: 82 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Lint, Test, Build, and Publish Docker Images
1+
name: Lint, Release & Publish
22

33
on:
44
push:
@@ -7,221 +7,133 @@ on:
77
branches: [main, master]
88

99
permissions:
10-
contents: write # semantic-release & auto-formatter commits
11-
packages: write # push to Docker Hub / GHCR
10+
contents: write
1211

1312
jobs:
1413
# ──────────────────────────────────────────────────────────────────────────
15-
# 🧹 Lint
14+
# Lint & Test
1615
# ──────────────────────────────────────────────────────────────────────────
1716
lint:
18-
name: "🧹 Lint Code & Dockerfiles"
17+
name: Lint, Test & Validate Compose Files
1918
runs-on: ubuntu-latest
20-
2119
steps:
22-
- name: "🕺 Checkout repository"
23-
uses: actions/checkout@v5
24-
with:
25-
token: ${{ secrets.GITHUB_TOKEN }}
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
2622

27-
- name: "🐍 Set up Python"
23+
- name: Set up Python
2824
uses: actions/setup-python@v5
2925
with:
30-
python-version: "3.11"
26+
python-version: '3.11'
3127

32-
- name: "📦 Cache pip dependencies"
33-
uses: actions/cache@v5
28+
- name: Cache pip dependencies
29+
uses: actions/cache@v4
3430
with:
3531
path: ~/.cache/pip
36-
key: ${{ runner.os }}-pip-lint-${{ hashFiles('**/*_reqs_*.txt', '**/pyproject.toml') }}
32+
key: ${{ runner.os }}-pip-lint-${{ hashFiles('requirements.txt', 'pyproject.toml') }}
3733
restore-keys: |
3834
${{ runner.os }}-pip-lint-
3935
40-
- name: "⚙️ Install Linting Tools"
36+
- name: Install tools and project dependencies
4137
run: |
42-
python -m pip install --upgrade pip
43-
pip install "ruff==0.4.0" black
44-
sudo wget -qO /usr/local/bin/hadolint \
45-
https://github.com/hadolint/hadolint/releases/latest/download/hadolint-Linux-x86_64
46-
sudo chmod +x /usr/local/bin/hadolint
38+
pip install --upgrade pip
39+
pip install -r requirements.txt
40+
pip install -e .
41+
pip install ruff==0.4.0 black pytest
4742
48-
- name: "✨ Run Ruff Linter"
49-
run: |
50-
if [ "${{ github.event_name }}" = "pull_request" ]; then
51-
ruff check . --output-format=github
52-
else
53-
ruff check . --fix --output-format=github || true
54-
fi
43+
- name: Run Ruff Linter
44+
run: ruff check . --output-format=github
5545

56-
- name: "⚫️ Run Black Formatter"
57-
run: |
58-
if [ "${{ github.event_name }}" = "pull_request" ]; then
59-
black --check .
60-
else
61-
black .
62-
git diff --exit-code || true
63-
fi
64-
65-
- name: "🐳 Lint Dockerfiles"
46+
- name: Run Black Formatter Check
47+
run: black --check .
48+
49+
- name: Run Tests
50+
run: pytest tests/ --tb=short -q
51+
52+
- name: Validate Compose Files
6653
run: |
67-
hadolint docker/api/Dockerfile || true
68-
hadolint docker/sandbox/Dockerfile || true
54+
docker compose -f docker-compose.yml config --quiet --no-interpolate
55+
docker compose -f docker-compose.yml -f docker-compose.gpu.yml config --quiet --no-interpolate
6956
7057
# ──────────────────────────────────────────────────────────────────────────
71-
# ✅ Tests
58+
# Release — semantic versioning, changelog, and GitHub release
59+
# Uses cycjimmy/semantic-release-action which correctly exposes step outputs
60+
# so the publish job can gate on whether a release was actually cut.
7261
# ──────────────────────────────────────────────────────────────────────────
73-
test:
74-
name: "✅ Run Unit Tests"
62+
release:
63+
name: Git Version & Changelog
7564
runs-on: ubuntu-latest
7665
needs: lint
77-
strategy:
78-
fail-fast: false
79-
matrix:
80-
python-version: ["3.11", "3.12"]
81-
66+
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
67+
outputs:
68+
new_release_published: ${{ steps.semantic.outputs.new_release_published }}
69+
new_release_version: ${{ steps.semantic.outputs.new_release_version }}
8270
steps:
83-
- name: "🕺 Checkout repository"
84-
uses: actions/checkout@v5
71+
- name: Checkout repository with full history
72+
uses: actions/checkout@v4
8573
with:
74+
fetch-depth: 0
75+
persist-credentials: true
8676
token: ${{ secrets.GITHUB_TOKEN }}
8777

88-
- name: "🐍 Set up Python ${{ matrix.python-version }}"
78+
- name: Set up Python (needed for prepareCmd in .releaserc.json)
8979
uses: actions/setup-python@v5
9080
with:
91-
python-version: ${{ matrix.python-version }}
81+
python-version: '3.11'
9282

93-
- name: "📦 Cache pip dependencies"
94-
uses: actions/cache@v5
83+
- name: Run semantic-release
84+
id: semantic
85+
uses: cycjimmy/semantic-release-action@v4
9586
with:
96-
path: ~/.cache/pip
97-
key: ${{ runner.os }}-pip-test-${{ matrix.python-version }}-${{ hashFiles('**/*_reqs_*.txt', '**/pyproject.toml') }}
98-
restore-keys: |
99-
${{ runner.os }}-pip-test-${{ matrix.python-version }}-
87+
extra_plugins: |
88+
@semantic-release/commit-analyzer
89+
@semantic-release/release-notes-generator
90+
@semantic-release/changelog
91+
@semantic-release/exec
92+
@semantic-release/git
93+
@semantic-release/github
94+
env:
95+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
10096

101-
- name: "⚙️ Install Project & Test Deps"
97+
- name: Report release outcome
98+
if: steps.semantic.outputs.new_release_published == 'true'
10299
run: |
103-
python -m pip install --upgrade pip
104-
pip install -r api_unhashed_reqs.txt
105-
pip install --require-hashes -r api_reqs_hashed.txt
106-
pip install -r sandbox_reqs_unhashed.txt
107-
pip install --require-hashes -r sandbox_reqs_hashed.txt
108-
pip install pytest pytest-cov
109-
110-
- name: "✅ Run Pytest with Coverage"
111-
run: pytest tests/ --cov=src --cov-report=term-missing
100+
echo "New release: v${{ steps.semantic.outputs.new_release_version }}"
112101
113102
# ──────────────────────────────────────────────────────────────────────────
114-
# 🚀 Build & Publish Docker images
103+
# Publish — build wheel and push to PyPI
104+
# Only runs when semantic-release actually cut a new release
115105
# ──────────────────────────────────────────────────────────────────────────
116-
build_and_publish:
117-
name: "🚀 Build, Tag, and Publish Images to Docker Hub"
106+
publish:
107+
name: Build & Publish to PyPI
118108
runs-on: ubuntu-latest
119-
needs: test
120-
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
109+
needs: release
110+
if: needs.release.outputs.new_release_published == 'true'
121111

122112
steps:
123-
- name: "🕺 Checkout repository"
124-
uses: actions/checkout@v5
113+
- name: Checkout repository at new release tag
114+
uses: actions/checkout@v4
125115
with:
126-
fetch-depth: 0
127-
persist-credentials: true
128-
token: ${{ secrets.GITHUB_TOKEN }}
129-
130-
- name: "⚙️ Setup QEMU"
131-
uses: docker/setup-qemu-action@v3
132-
133-
- name: "⚙️ Setup Docker Buildx"
134-
uses: docker/setup-buildx-action@v3
116+
# Check out the bumped tag so pyproject.toml already has the new version
117+
ref: v${{ needs.release.outputs.new_release_version }}
135118

136-
- name: "🔑 Login to Docker Hub"
137-
uses: docker/login-action@v3
119+
- name: Set up Python
120+
uses: actions/setup-python@v5
138121
with:
139-
username: thanosprime
140-
password: ${{ secrets.DOCKERHUB_THANOSPRIME }}
122+
python-version: '3.11'
141123

142-
# quick cleanup of any dangling layers on the runner
143-
- name: "🧼 Prune Docker System Cache"
144-
run: docker system prune -af || true
124+
- name: Install build tools
125+
run: |
126+
pip install --upgrade pip
127+
pip install build twine
145128
146-
# ----- semantic-release -------------------------------------------------
147-
- name: "🚀 Setup Node.js"
148-
uses: actions/setup-node@v4
149-
with:
150-
node-version: "20"
129+
- name: Build wheel and source distribution
130+
run: python -m build
151131

152-
- name: "⚙️ Install semantic-release"
153-
run: |
154-
npm install -g semantic-release \
155-
@semantic-release/commit-analyzer \
156-
@semantic-release/release-notes-generator \
157-
@semantic-release/changelog \
158-
@semantic-release/exec \
159-
@semantic-release/git \
160-
@semantic-release/github
132+
- name: Verify distribution contents
133+
run: twine check dist/*
161134

162-
- name: "🚀 Run semantic-release"
163-
id: semantic
135+
- name: Publish to PyPI
164136
env:
165-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
166-
run: npx semantic-release
167-
168-
- name: "🏷️ Extract Git Tag Version"
169-
id: get_version
170-
run: |
171-
git fetch --tags origin
172-
VERSION=$(git describe --tags --exact-match HEAD 2>/dev/null || git describe --tags --abbrev=0 HEAD 2>/dev/null)
173-
if [ -z "$VERSION" ]; then
174-
echo "::error::Could not determine version tag after semantic-release."
175-
exit 1
176-
fi
177-
VERSION=${VERSION#v}
178-
echo "Detected version: $VERSION"
179-
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
180-
181-
# ---------------- API image metadata ----------------
182-
- name: "🔧 Define API Image Metadata"
183-
id: meta_api
184-
uses: docker/metadata-action@v5
185-
with:
186-
images: thanosprime/entities-api-api
187-
tags: |
188-
type=semver,pattern={{version}},value=${{ steps.get_version.outputs.VERSION }}
189-
type=raw,value=latest,enable={{is_default_branch}}
190-
type=sha,prefix=sha-
191-
192-
# ---------------- Sandbox image metadata ------------
193-
- name: "🔧 Define Sandbox Image Metadata"
194-
id: meta_sandbox
195-
uses: docker/metadata-action@v5
196-
with:
197-
images: thanosprime/entities-api-sandbox
198-
tags: |
199-
type=semver,pattern={{version}},value=${{ steps.get_version.outputs.VERSION }}
200-
type=raw,value=latest,enable={{is_default_branch}}
201-
type=sha,prefix=sha-
202-
203-
# ---------------- Build / Push API ------------------
204-
- name: "🏗️ Build & Push API Image"
205-
uses: docker/build-push-action@v5
206-
with:
207-
context: .
208-
file: ./docker/api/Dockerfile
209-
push: true
210-
tags: ${{ steps.meta_api.outputs.tags }}
211-
labels: ${{ steps.meta_api.outputs.labels }}
212-
platforms: linux/amd64
213-
cache-from: type=gha
214-
# no cache-to: export disabled
215-
216-
# ---------------- Build / Push Sandbox --------------
217-
- name: "🏗️ Build & Push Sandbox Image"
218-
uses: docker/build-push-action@v5
219-
with:
220-
context: .
221-
file: ./docker/sandbox/Dockerfile
222-
push: true
223-
tags: ${{ steps.meta_sandbox.outputs.tags }}
224-
labels: ${{ steps.meta_sandbox.outputs.labels }}
225-
platforms: linux/amd64
226-
cache-from: type=gha
227-
# no cache-to: export disabled
137+
TWINE_USERNAME: __token__
138+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
139+
run: twine upload dist/*

0 commit comments

Comments
 (0)