-
Notifications
You must be signed in to change notification settings - Fork 0
feat: migrate build/release tooling to uv + python-semantic-release #67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6ac9a42
9cc0fa8
f8a11a4
8d013d6
9a48cbc
3a2180a
8fa8935
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| name: Test and Release | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ main ] | ||
| paths-ignore: | ||
| - 'docs/**' | ||
| - '*.md' | ||
| pull_request: | ||
| branches: [ main ] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: both triggers here ( |
||
| paths-ignore: | ||
| - 'docs/**' | ||
| - '*.md' | ||
| workflow_dispatch: | ||
|
|
||
| jobs: | ||
| lint: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
file=".github/workflows/release.yml"
printf '%s\n' '--- workflow context ---'
nl -ba "$file" | sed -n '1,95p'
printf '%s\n' '--- checkout and pull_request occurrences ---'
rg -n -C 3 'pull_request|actions/checkout|uv sync|uv run pytest|persist-credentials|GITHUB_TOKEN|semantic-release' "$file"Repository: deployml-core/deployml Length of output: 2495 🏁 Script executed: #!/bin/bash
set -eu
file=".github/workflows/release.yml"
printf '%s\n' '--- workflow ---'
sed -n '1,110p' "$file"
printf '%s\n' '--- repository references to this workflow ---'
rg -n -C 2 'release\.yml|pull_request|persist-credentials' .github README.md 2>/dev/null || true
printf '%s\n' '--- bounded workflow verifier ---'
python3 - <<'PY'
from pathlib import Path
p = Path(".github/workflows/release.yml")
lines = p.read_text().splitlines()
event = None
job = None
checkouts = []
commands = []
for i, raw in enumerate(lines, 1):
s = raw.strip()
if s == "pull_request:":
event = "pull_request"
if raw.startswith(" ") and not raw.startswith(" ") and s.endswith(":"):
job = s[:-1]
if s.startswith("- uses: actions/checkout@"):
with_block = []
for nxt in lines[i:i+5]:
if nxt.startswith(" ") or nxt.strip() == "":
with_block.append(nxt.strip())
else:
break
checkouts.append((i, job, event, with_block))
if s.startswith("run:"):
commands.append((i, job, event, s[4:].strip()))
print({"pull_request_event_seen": event == "pull_request"})
print({"checkouts": checkouts})
print({"commands": [x for x in commands if x[1] in {"lint", "test", "release"}]})
PYRepository: deployml-core/deployml Length of output: 3946 Sensitive Data Exposure (CWE-522): Insufficiently Protected Credentials Reachability: External · Exploitability: Trivial Disable credential persistence in pull-request jobs. Add 🧰 Tools🪛 zizmor (1.29.0)[warning] 20-20: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) 📍 Affects 1 file
🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
|
|
||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v5 | ||
| with: | ||
| python-version: "3.11" | ||
| enable-cache: true | ||
|
|
||
| - name: Sync dependencies | ||
| run: uv sync | ||
|
Comment on lines
+28
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- workflow ---'
cat -n .github/workflows/release.yml | sed -n '1,105p'
printf '%s\n' '--- uv configuration and lock usage ---'
rg -n --hidden -g '!**/.git/**' 'uv (sync|lock)|locked|frozen|uv\.lock|PACKAGE_NAME' .Repository: deployml-core/deployml Length of output: 5201 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- pyproject release configuration ---'
cat -n pyproject.toml | sed -n '1,95p'
printf '%s\n' '--- lockfile and project metadata ---'
ls -l uv.lock pyproject.toml
sed -n '1,45p' uv.lockRepository: deployml-core/deployml Length of output: 5825 🌐 Web query:
💡 Result: When you use the --locked flag with uv sync, it instructs uv to assert that the existing uv.lock file is up-to-date with your current project configuration (such as pyproject.toml) [1][2]. If the lockfile is missing or is not up-to-date—meaning your project's dependency constraints have changed in a way that requires the lockfile to be regenerated—uv will exit with an error instead of attempting to update the lockfile [1][2][3]. This behavior is designed to ensure that the environment is strictly reproducible and to prevent unintended modifications to the lockfile in environments where that is restricted, such as CI/CD pipelines or production deployments [1][2]. In summary: * Behavior: uv verifies the lockfile against current project metadata [1][4]. * Stale Lockfile: If the lockfile is stale (out of sync with dependencies), the command fails with an error [1][3]. * Use Case: This is best for environments where you want to ensure the installation matches the existing lockfile exactly and fail if it does not [2][4]. If you intend to bypass the requirement that the lockfile must match the project's dependency constraints and simply want to install based on the existing lockfile without modification, you should use --frozen instead [2][4][3]. While --locked validates the lockfile's integrity, --frozen treats the lockfile as the immutable source of truth and ignores any potential drifts in the project's dependency definitions [2][3]. Citations:
🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
workflow = Path(".github/workflows/release.yml").read_text()
pyproject = Path("pyproject.toml").read_text()
sync_runs = [line.strip() for line in workflow.splitlines() if line.strip() == "run: uv sync"]
print("plain uv sync steps:", len(sync_runs))
print("all expected sync sites present:", len(sync_runs) == 3)
print('semantic-release retains uv lock upgrade:', 'uv lock --upgrade-package "$PACKAGE_NAME"' in pyproject)
PY
if command -v uv >/dev/null 2>&1; then
uv --version
uv sync --help | grep -E -- '--locked|--frozen' || true
else
echo "uv is not available in the verifier sandbox"
fiRepository: deployml-core/deployml Length of output: 312 Make CI reject a stale Use 📍 Affects 1 file
🤖 Prompt for AI Agents |
||
|
|
||
| # Check only, never fix. Contributors auto-fix locally via the pre-commit hook. | ||
| - name: Ruff lint | ||
| run: uv run ruff check . | ||
|
|
||
| - name: Ruff format | ||
| run: uv run ruff format --check . | ||
|
|
||
| test: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v5 | ||
| with: | ||
| python-version: "3.11" | ||
| enable-cache: true | ||
|
|
||
| - name: Sync dependencies | ||
| run: uv sync | ||
|
|
||
| - name: Run tests | ||
| run: uv run pytest | ||
|
Comment on lines
+52
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- workflow ---'
cat -n .github/workflows/release.yml | sed -n '1,120p'
printf '%s\n' '--- project files ---'
git ls-files | sed -n '1,160p'
printf '%s\n' '--- packaging and test configuration ---'
for f in pyproject.toml setup.cfg setup.py tox.ini noxfile.py; do
if [ -f "$f" ]; then
printf '%s\n' "--- $f ---"
cat -n "$f" | sed -n '1,220p'
fi
done
printf '%s\n' '--- smoke test ---'
if [ -f tests/test_smoke.py ]; then
cat -n tests/test_smoke.py | sed -n '1,220p'
fiRepository: deployml-core/deployml Length of output: 14974 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
workflow = Path(".github/workflows/release.yml").read_text()
pyproject = Path("pyproject.toml").read_text()
tests = sorted(str(p) for p in Path("tests").glob("test_*.py"))
print("smoke_test_present:", Path("tests/test_smoke.py").is_file())
print("test_files:", tests)
print("test_job_syncs:", bool(re.search(r"(?ms)^ test:.*?^\s+run: uv sync$", workflow)))
print("test_job_runs_pytest:", bool(re.search(r"(?ms)^ test:.*?^\s+run: uv run pytest$", workflow)))
print("release_builds_wheel:", "uv build" in pyproject)
print("release_build_command:")
match = re.search(r'(?ms)^\s*build_command\s*=\s*"""\n(.*?)\n\s*"""', pyproject)
print(match.group(1) if match else "<not found>")
PY
printf '%s\n' '--- repository status ---'
git status --short
printf '%s\n' '--- test references ---'
rg -n 'test_smoke|uv sync|uv build|semantic-release|editable' .github pyproject.toml tests README.md docs || trueRepository: deployml-core/deployml Length of output: 1631 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- smoke test and related tests ---'
cat -n tests/test_smoke.py | sed -n '1,140p'
printf '%s\n' '--- lockfile project entry ---'
rg -n -A18 -B4 'name = "deployml-core"|source = \{ editable' uv.lock || true
printf '%s\n' '--- relevant packaging docs ---'
cat -n docs/contributing.md | sed -n '1,60p'
printf '%s\n' '--- uv availability ---'
if command -v uv >/dev/null 2>&1; then
uv --version
else
printf '%s\n' 'uv unavailable in sandbox'
fiRepository: deployml-core/deployml Length of output: 5794 Test the built wheel before release.
🧰 Tools🪛 zizmor (1.29.0)[warning] 38-53: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block (excessive-permissions) 🤖 Prompt for AI Agents |
||
|
|
||
| release: | ||
| needs: [lint, test] | ||
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | ||
| runs-on: ubuntu-latest | ||
| concurrency: | ||
| group: release | ||
| cancel-in-progress: false | ||
| permissions: | ||
| contents: write # semantic-release pushes the version commit + tag + GitHub Release | ||
| id-token: write # OIDC trusted publishing to PyPI (no token needed) | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 # semantic-release needs full history to analyse commits | ||
|
|
||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v5 | ||
| with: | ||
| python-version: "3.11" | ||
| enable-cache: true | ||
|
|
||
| - name: Sync dependencies | ||
| run: uv sync | ||
|
|
||
| - name: Python Semantic Release (bump, changelog, tag, build) | ||
| id: release | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| rm -rf dist | ||
| uv run semantic-release version | ||
| if ls dist/*.whl >/dev/null 2>&1; then | ||
| echo "released=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "released=false" >> "$GITHUB_OUTPUT" | ||
| echo "No release-worthy commits since the last tag; skipping publish." | ||
| fi | ||
|
|
||
| - name: Publish to PyPI (trusted publishing) | ||
| if: steps.release.outputs.released == 'true' | ||
| run: uv publish | ||
|
|
||
| - name: Attach artifacts to the GitHub Release | ||
| if: steps.release.outputs.released == 'true' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: uv run semantic-release publish | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,4 @@ | ||
| __pycache__ | ||
| poetry.lock | ||
| .DS_Store | ||
| .terraform | ||
| .terraform.lock.hcl | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # Install with: uv run pre-commit install | ||
| # Installs both the pre-commit (ruff) and commit-msg (commitizen) hooks. | ||
| default_install_hook_types: [pre-commit, commit-msg] | ||
| repos: | ||
| - repo: https://github.com/astral-sh/ruff-pre-commit | ||
| # Ruff version. Keep in sync with the dev-group ruff pin in pyproject.toml. | ||
| rev: v0.15.21 | ||
| hooks: | ||
| # Run the linter. | ||
| - id: ruff-check | ||
| args: [ --fix ] | ||
| # Run the formatter. | ||
| - id: ruff-format | ||
| - repo: https://github.com/commitizen-tools/commitizen | ||
| rev: v4.10.1 | ||
| hooks: | ||
| # Validate Conventional Commit messages (semantic-release parses these). | ||
| - id: commitizen | ||
| stages: [commit-msg] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: deployml-core/deployml
Length of output: 5901
Security Misconfiguration (CWE-269): Improper Privilege Management
Reachability: External
Set explicit baseline token permissions.
Add workflow-level
permissions: { contents: read }for the lint and test jobs. Keep the existing release-job override for publishing and release commits.🤖 Prompt for AI Agents
Source: Linters/SAST tools