Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Test and Release

on:
push:
branches: [ main ]
paths-ignore:
- 'docs/**'
- '*.md'
pull_request:
branches: [ main ]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Question: both triggers here (push and pull_request) are scoped to branches: [ main ] only. Is folding dev in (e.g. branches: [main, dev] on the pull_request trigger) out of scope for this migration, or intentionally deferred? As-is, PRs into dev still get zero CI from this workflow — same gap the old test-pypi.yml had.

paths-ignore:
- 'docs/**'
- '*.md'
workflow_dispatch:

jobs:
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

release:
needs: 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
135 changes: 0 additions & 135 deletions .github/workflows/test-pypi.yml

This file was deleted.

1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
__pycache__
poetry.lock
.DS_Store
.terraform
.terraform.lock.hcl
Expand Down
19 changes: 19 additions & 0 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ You can help improve the project in several ways:
2. Follow the setup instructions in the main README to install dependencies and configure your environment.
3. Create a new branch for your work with a descriptive name (e.g., fix-deployment-logging or add-example-yaml).

## Development

This project uses [uv](https://docs.astral.sh/uv/) for dependency management, building, and publishing.

- Install dependencies (including the `dev` group): `uv sync`
- Run the tests: `uv run pytest`
- Build the package locally: `uv build`

## Releases and Commit Messages

Releases are fully automated with [python-semantic-release](https://python-semantic-release.readthedocs.io/). The next version, changelog, git tag, GitHub Release, and PyPI upload are all derived from commit messages on `main`, so **do not bump the version by hand**.

Use [Conventional Commits](https://www.conventionalcommits.org/) so the version bump is correct:

- `fix:` → patch release (e.g. `0.1.0` → `0.1.1`)
- `feat:` → minor release (e.g. `0.1.0` → `0.2.0`)
- `feat!:` or a `BREAKING CHANGE:` footer → major release
- `docs:`, `chore:`, `refactor:`, `test:`, etc. → no release on their own

## Submitting a Pull Request

1. Push your changes to your fork.
Expand Down
2 changes: 0 additions & 2 deletions poetry.toml

This file was deleted.

46 changes: 35 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

[project]
name = "deployml-core"
version = "0.0.42"
version = "0.0.60"
description = "Infra for academia"
authors = [
{name = "Drew Hoang", email = "codentell@gmail.com"},
Expand All @@ -27,17 +27,41 @@ dependencies = [
[project.scripts]
deployml = "deployml.cli.cli:main"

[tool.poetry]
packages = [{include = "deployml", from = "src"}]
[build-system]
requires = ["uv_build>=0.8,<0.9"]
build-backend = "uv_build"

[tool.setuptools]
include-package-data = true
[tool.uv.build-backend]
# Distribution is "deployml-core" but the import package is "deployml".
module-root = "src"
module-name = "deployml"
# Keep local Terraform artifacts out of the sdist/wheel (they are gitignored but
# uv_build packages the working tree, not just tracked files).
source-exclude = [
"**/.terraform",
"**/.terraform/**",
"**/.terraform.lock.hcl",
"**/*.tfstate",
"**/*.tfstate.backup",
]

[tool.setuptools.package-data]
mlops_infra = [
"docker/**"
[dependency-groups]
dev = [
"pytest>=8",
"python-semantic-release>=10",
]

[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.pytest.ini_options]
testpaths = ["tests"]

[tool.semantic_release]
version_toml = ["pyproject.toml:project.version"]
allow_zero_version = true
build_command = """
uv lock --upgrade-package "$PACKAGE_NAME"
git add uv.lock
uv build
"""

[tool.semantic_release.branches.main]
match = "main"
23 changes: 23 additions & 0 deletions tests/test_smoke.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Smoke tests: verify the package installs and its version resolves.

These are intentionally minimal and run against whatever source is on `main`.
The broader unit suite currently lives on the `dev` branch and targets modules
not yet merged to `main`; it should be wired in once those land here.
"""

import importlib.metadata


def test_distribution_is_installed():
"""The built/installed distribution exposes a version (packaging works)."""
assert importlib.metadata.version("deployml-core")


def test_cli_get_version_resolves():
"""The CLI resolves its version from package metadata, not the fallback."""
from deployml.cli.cli import get_version

version = get_version()
assert isinstance(version, str)
assert version not in ("", "version unknown")
assert version == importlib.metadata.version("deployml-core")
Loading
Loading