Skip to content

Commit

Permalink
CI workflows for quality checks, testing and publishing
Browse files Browse the repository at this point in the history
* Add workflow for quality checks (all commits)
* Add workflow for test execution (all commits)
* Add workflow to test build package (PR and main)
  with basic functionality test on Linux
* Add worflow to release package to PyPI (tags on main)
  • Loading branch information
cstub committed Jan 14, 2025
1 parent c834583 commit 8ea802a
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 10 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Code Quality

on:
push: {}
pull_request:
branches: [ main ]

jobs:
code-quality-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ vars.CI_PYTHON_VERSION }}

- name: Run pre-commit
uses: pre-commit/action@v3.0.1
72 changes: 72 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Release Package

on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+*'

jobs:
release-build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true

- name: Verify current tag is on main branch
run: |
# Exit with error if current tag is not on main
git merge-base --is-ancestor ${{ github.sha }} origin/main || exit 1
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ vars.CI_PYTHON_VERSION }}

- name: Install Poetry
uses: abatilo/actions-poetry@v3
with:
poetry-version: ${{ vars.CI_POETRY_VERSION }}

- name: Install Poetry plugins
run: |
poetry self add "poetry-dynamic-versioning[plugin]"
- name: Build package
run: |
poetry build
ls -la dist/
- name: Upload distributions
uses: actions/upload-artifact@v4
with:
name: release-dists
path: dist/
retention-days: 1

pypi-publish:
runs-on: ubuntu-latest

needs:
- release-build

permissions:
id-token: write

environment:
name: pypi
url: https://pypi.org/project/ipybox/

steps:
- name: Retrieve release distributions
uses: actions/download-artifact@v4
with:
name: release-dists
path: dist/

- name: Publish package distributions to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
verbose: true
44 changes: 44 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Tests

on:
push: {}
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Cache conda
uses: actions/cache@v4
env:
CACHE_NUMBER: 0
with:
path: ~/conda_pkgs_dir
key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ hashFiles('environment.yml') }}

- name: Setup Conda
uses: conda-incubator/setup-miniconda@v3
with:
auto-update-conda: true
environment-file: environment.yml

- name: Install Poetry
uses: abatilo/actions-poetry@v3
with:
poetry-version: ${{ vars.CI_POETRY_VERSION }}

- name: Install dependencies
shell: bash -l {0}
run: |
poetry env info
poetry install
pip list
- name: Run tests
shell: bash -l {0}
run: |
poetry run pytest -s
109 changes: 109 additions & 0 deletions .github/workflows/test_package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: Package Installation Tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
package-build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ vars.CI_PYTHON_VERSION }}

- name: Install Poetry
uses: abatilo/actions-poetry@v3
with:
poetry-version: ${{ vars.CI_POETRY_VERSION }}

- name: Install Poetry plugins
run: |
poetry self add "poetry-dynamic-versioning[plugin]"
- name: Build package
run: |
poetry build
- name: Upload dist artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 1

package-test:
needs: package-build

strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.11', '3.12']

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Download package
uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Test wheel installation (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$wheel = Get-ChildItem dist/*.whl | Select-Object -First 1
pip install $wheel
python -c "import ipybox"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
pip uninstall -y ipybox
- name: Test wheel installation (Unix)
if: runner.os != 'Windows'
run: |
pip install dist/*.whl
python -c "import ipybox"
pip uninstall -y ipybox
- name: Test tarball installation (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$tarball = Get-ChildItem dist/*.tar.gz | Select-Object -First 1
pip install $tarball
python -c "import ipybox"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
pip uninstall -y ipybox
- name: Test tarball installation (Unix)
if: runner.os != 'Windows'
run: |
pip install dist/*.tar.gz
python -c "import ipybox"
pip uninstall -y ipybox
- name: Run smoke test (Linux)
if: runner.os == 'Linux'
run: |
pip install dist/*.whl
pip install pytest pytest-asyncio
pytest tests/test_basic.py
pip uninstall -y ipybox
12 changes: 9 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"]
build-backend = "poetry_dynamic_versioning.backend"

[tool.poetry]
name = "ipybox"
version = "0.3.1"
version = "0.0.0"
description = "Python code execution sandbox based on IPython and Docker"
homepage = "https://github.com/gradion-ai/ipybox"
readme = "README.md"
Expand Down Expand Up @@ -60,3 +60,9 @@ module = [
"aiofiles.os",
]
ignore_missing_imports = true

[tool.poetry-dynamic-versioning]
enable = true
vcs = "git"
pattern = "default-unprefixed"
style = "pep440"
9 changes: 9 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import tempfile

import pytest


@pytest.fixture(scope="module")
async def workspace():
with tempfile.TemporaryDirectory() as temp_dir:
yield temp_dir
19 changes: 19 additions & 0 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import pytest

from ipybox import ExecutionClient, ExecutionContainer


@pytest.fixture(scope="module")
async def executor(workspace: str):
async with ExecutionContainer(
tag="ghcr.io/gradion-ai/ipybox:minimal",
binds={workspace: "workspace"},
) as container:
async with ExecutionClient(host="localhost", port=container.port) as client:
yield client


@pytest.mark.asyncio(loop_scope="module")
async def test_basic_functionality(executor):
result = await executor.execute("print('Hello, world!')")
assert result.text == "Hello, world!"
7 changes: 0 additions & 7 deletions tests/ipybox_test.py → tests/test_ipybox.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import asyncio
import re
import subprocess
import tempfile
from pathlib import Path
from typing import Generator

Expand All @@ -12,12 +11,6 @@
from ipybox import DEFAULT_TAG, ExecutionClient, ExecutionContainer, ExecutionError


@pytest.fixture(scope="module")
async def workspace():
with tempfile.TemporaryDirectory() as temp_dir:
yield temp_dir


@pytest.fixture(
scope="module",
params=["test-root", "test"],
Expand Down

0 comments on commit 8ea802a

Please sign in to comment.