Skip to content
Merged
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
91 changes: 59 additions & 32 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -1,47 +1,74 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
# Build and publish the disdat package.
#
# - On a GitHub *release*: build (version derived from the release tag by
# setuptools_scm) and upload to PyPI.
# - On *manual dispatch*: build a dev version and upload to TestPyPI as a
# dry run (no real PyPI publish). Requires a TEST_PYPI_API_TOKEN secret.
#
# Builds use `uv build` (sdist + wheel); uploads use twine via `uvx`.

name: Upload Python Package

on:
workflow_dispatch:
inputs:
name:
description: 'Manual publish event'
required: true
default: 'default default string'

release:
types: [created]

jobs:
deploy:

publish-pypi:
# Real publish only happens for an actual release (clean tag version).
if: github.event_name == 'release'
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0 # setuptools_scm derives the version from tags

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
python-version: '3.13'

- name: Build sdist and wheel
run: uv build

- name: Check distributions
run: uvx twine check dist/*

- name: Publish to PyPI
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
echo "Cleaning up repo for sdist build ..."
rm -rf disdat/infrastructure/dockerizer/context.template/disdat-*.tar.gz
rm -rf dist/disdat-*.tar.gz
echo "Creating sdist without a copy of itself for dockerizer ..."
python setup.py sdist
echo "Copying sdist to dockerizer template..."
cp dist/disdat-*.tar.gz disdat/infrastructure/dockerizer/context.template/.
echo "Creating sdist with a copy of itself ..."
python setup.py sdist
echo "Uploading to PyPi ... (not yet)"
twine upload dist/disdat-*.tar.gz
run: uvx twine upload dist/*

testpypi-dry-run:
# Manual runs validate the full build+upload path against TestPyPI without
# touching real PyPI. Needs a TEST_PYPI_API_TOKEN repository secret.
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
python-version: '3.13'

- name: Build sdist and wheel
# No tag on HEAD -> a dev version. Strip setuptools_scm's local segment
# (+gHASH), which PyPI/TestPyPI reject, so the dev build is uploadable.
env:
SETUPTOOLS_SCM_OVERRIDES_FOR_DISDAT: '{ local_scheme = "no-local-version" }'
run: uv build

- name: Check distributions
run: uvx twine check dist/*

- name: Upload to TestPyPI (dry run)
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/
run: uvx twine upload --skip-existing dist/*
41 changes: 41 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Tests

on:
push:
branches: [master]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]

env:
# disdat uses forked multiprocessing; pin the start method (Python 3.14
# defaults to forkserver on Linux).
MP_CONTEXT_TYPE: fork
# moto mocks AWS; provide dummy credentials so boto3 never reaches out.
AWS_DEFAULT_REGION: us-east-1
AWS_ACCESS_KEY_ID: testing
AWS_SECRET_ACCESS_KEY: testing

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # setuptools_scm needs full history/tags

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install project and dev dependencies
run: |
uv venv --clear --python ${{ matrix.python-version }}
uv pip install -e ".[dev]"

- name: Run tests
run: .venv/bin/python -m pytest tests --disable-warnings -q
2 changes: 1 addition & 1 deletion design_docs/plans/PLAN_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ discipline. Status advances forward only: `created` → `implemented` →
| 3 | py314 / Phase 2: modernize dependency pins | `design_docs/plans/py-3.10-3.14-migration.plan.md` | 2026-06-11 | 2026-06-23 | `909253e` | committed |
| 4 | py314 / Phase 3: code changes for new deps | `design_docs/plans/py-3.10-3.14-migration.plan.md` | 2026-06-11 | 2026-06-23 | `22a1100` | committed |
| 5 | py314 / Phase 4: test & verify across versions | `design_docs/plans/py-3.10-3.14-migration.plan.md` | 2026-06-11 | 2026-06-23 | `22a1100` | committed |
| 6 | py314 / Phase 5: CI matrix + publish update | `design_docs/plans/py-3.10-3.14-migration.plan.md` | 2026-06-11 | - | - | created |
| 6 | py314 / Phase 5: CI matrix + publish update | `design_docs/plans/py-3.10-3.14-migration.plan.md` | 2026-06-11 | 2026-06-23 | `ba826ba` | committed |
35 changes: 35 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#
# Copyright 2024 Disdat
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import os

import pytest

from disdat.common import SYSTEM_CONFIG_DIR, DisdatConfig


@pytest.fixture(scope="session", autouse=True)
def ensure_disdat_initialized():
"""Ensure a Disdat configuration exists before the suite runs.

The tests assume an initialized Disdat (normally created once via
``dsdt init``). A fresh checkout or CI runner has none, so create it when
absent. Guarded on existence because ``DisdatConfig.init()`` exits the
process if the config directory already exists, so an existing developer
configuration is left untouched.
"""
if not os.path.exists(os.path.expanduser(SYSTEM_CONFIG_DIR)):
DisdatConfig.init()
yield
Loading