Skip to content

Python CI/CD Workflow #373

Python CI/CD Workflow

Python CI/CD Workflow #373

Workflow file for this run

name: Python CI/CD Workflow
# Grant permission to create releases
permissions:
contents: write
checks: write
on:
push:
# keep tests on every branch push
branches:
- '**'
# and also react to version tags for release builds
tags:
- 'v*'
pull_request:
schedule: # Nightly at midnight UTC
- cron: '0 0 * * *'
workflow_dispatch: {}
jobs:
test:
name: Unit Tests (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
# os: [ubuntu-latest, macos-latest, windows-latest]
os: [macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
CI: true
APPLE_SIGN_IDENTITY: ${{ secrets.APPLE_SIGN_IDENTITY }}
steps:
- name: Checkout code (no LFS)
if: ${{ github.event_name == 'schedule' }}
uses: actions/checkout@v3
with:
ref: dev
lfs: false
- name: Checkout code (no LFS)
if: ${{ github.event_name != 'schedule' }}
uses: actions/checkout@v3
with:
lfs: false
# Install Git LFS and disable auto-smudge on each OS
- name: Install Git LFS & disable auto-smudge (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install git-lfs -y
git lfs install --skip-smudge
- name: Install Git LFS & disable auto-smudge (macOS)
if: runner.os == 'macOS'
run: |
brew install git-lfs
git lfs install --skip-smudge
- name: Install Git LFS & disable auto-smudge (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
choco install git-lfs -y
git lfs install --skip-smudge
# ← Cache all LFS objects between runs
- name: Cache Git LFS objects
uses: actions/cache@v3
with:
path: .git/lfs/objects
key: ${{ runner.os }}-git-lfs-${{ hashFiles('**/.gitattributes') }}
restore-keys: |
${{ runner.os }}-git-lfs-
# Fetch only the LFS objects you need
- name: Fetch specific LFS folders (non-Windows)
if: runner.os != 'Windows'
run: |
git lfs fetch \
--include="tests/test_open_vp_cal/resources/TEST_EXR_OPENVPCAL_balanced/**,tests/test_open_vp_cal/resources/TEST_EXR_OPENVPCAL_UNBALANCED_WHITE/**,tests/test_open_vp_cal/resources/export/patches/OpenVPCal_Wall1_ITU_R_BT_2020_ST_2084/**,packages/open_vp_cal/src/open_vp_cal/resources/**,tests/tests_spg/resources/**,tests/tests_spgicvfxpatterns/resources/**"
- name: Fetch specific LFS folders (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
git lfs fetch --include='tests/test_open_vp_cal/resources/TEST_EXR_OPENVPCAL_balanced/**,tests/test_open_vp_cal/resources/TEST_EXR_OPENVPCAL_UNBALANCED_WHITE/**,tests/test_open_vp_cal/resources/export/patches/OpenVPCal_Wall1_ITU_R_BT_2020_ST_2084/**,packages/open_vp_cal/src/open_vp_cal/resources/**,tests/tests_spg/resources/**,tests/tests_spgicvfxpatterns/resources/**'
# Checkout only those paths
- name: Checkout LFS files (non-Windows)
if: runner.os != 'Windows'
run: |
git lfs checkout \
tests/test_open_vp_cal/resources/TEST_EXR_OPENVPCAL_balanced/** \
tests/test_open_vp_cal/resources/TEST_EXR_OPENVPCAL_UNBALANCED_WHITE/** \
tests/test_open_vp_cal/resources/export/patches/OpenVPCal_Wall1_ITU_R_BT_2020_ST_2084/** \
packages/open_vp_cal/src/open_vp_cal/resources/** \
tests/tests_spg/resources/** \
tests/tests_spgicvfxpatterns/resources/**
- name: Checkout LFS files (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
git lfs checkout `
tests/test_open_vp_cal/resources/TEST_EXR_OPENVPCAL_balanced/** `
tests/test_open_vp_cal/resources/TEST_EXR_OPENVPCAL_UNBALANCED_WHITE/** `
tests/test_open_vp_cal/resources/export/patches/OpenVPCal_Wall1_ITU_R_BT_2020_ST_2084/** `
packages/open_vp_cal/src/open_vp_cal/resources/** `
tests/tests_spg/resources/** `
tests/tests_spgicvfxpatterns/resources/**
# Install EGL dependency on Ubuntu so libEGL.so.1 is available
- name: Install EGL dependencies (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
libegl1 \
libgl1 \
libglx-mesa0
# Common Python setup + build + test
- name: Set up Python 3.11
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install UV CLI
run: |
python -m pip install --upgrade pip
pip install uv
- name: Build Python environment
run: uv build
- name: Lint code with Ruff
run: uv run ruff check ./packages ./tests
- name: Run tests (verbose, stop on fail)
run: uv run pytest ./tests -vv --junitxml=test-results/junit-report.xml
- name: Report test results (${{ matrix.os }})
if: always()
uses: dorny/test-reporter@v1
with:
name: pytest results (${{matrix.os }})
path: test-results/junit-report.xml
reporter: java-junit
nightly_compile:
name: Nightly Build & Artifact Upload (${{ matrix.os }})
needs: test
if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
CI: true
APPLE_SIGN_IDENTITY: ${{ secrets.APPLE_SIGN_IDENTITY }}
steps:
- name: Checkout code (no LFS)
if: ${{ github.event_name == 'schedule' }}
uses: actions/checkout@v3
with:
ref: dev
lfs: false
- name: Checkout code (no LFS)
if: ${{ github.event_name != 'schedule' }}
uses: actions/checkout@v3
with:
lfs: false
# Common Python setup + build + test
- name: Set up Python 3.11
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install UV CLI
run: |
python -m pip install --upgrade pip
pip install uv
# Install Git LFS and disable auto-smudge on each OS
- name: Install Git LFS & disable auto-smudge (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install git-lfs -y
git lfs install --skip-smudge
- name: Install Git LFS & disable auto-smudge (macOS)
if: runner.os == 'macOS'
run: |
brew install git-lfs
git lfs install --skip-smudge
- name: Install Git LFS & disable auto-smudge (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
choco install git-lfs -y
git lfs install --skip-smudge
# ← Cache LFS objects for nightly packaging too
- name: Cache Git LFS objects
uses: actions/cache@v3
with:
path: .git/lfs/objects
key: nightly-${{ runner.os }}-git-lfs-${{ hashFiles('**/.gitattributes') }}
restore-keys: |
nightly-${{ runner.os }}-git-lfs-
- name: Fetch only needed LFS resources
run: |
git lfs fetch --include="packages/open_vp_cal/src/open_vp_cal/resources/**"
git lfs checkout packages/open_vp_cal/src/open_vp_cal/resources/**
- name: Stamp version with date and build ID
shell: python
run: |
import re, os, pathlib
from datetime import datetime
build_id = os.getenv("GITHUB_SHA", "")[:8] or "local"
date_str = datetime.utcnow().strftime("%d_%m_%Y")
init_py = pathlib.Path("packages/open_vp_cal/src/open_vp_cal/__init__.py")
text = init_py.read_text(encoding="utf8")
# 1: prefix (`__version__ = "`), 2: existing version, 3: closing quote
pattern = re.compile(r'(__version__\s*=\s*")([^"]+)(")')
def add_date_and_build(m):
prefix, version, suffix = m.group(1), m.group(2), m.group(3)
# append +DD_MM_YYYY.BUILDID
return f"{prefix}{version}+{date_str}.{build_id}{suffix}"
new_text = pattern.sub(add_date_and_build, text)
init_py.write_text(new_text, encoding="utf8")
# confirm
ver = re.search(r'__version__\s*=\s*"([^"]+)"', new_text).group(1)
print(f"Bumped version to: {ver}")
# Create a temporary keychain and make it default
- name: Create & unlock keychain
if: runner.os == 'macOS'
run: |
security create-keychain -p "" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
# Decode & import your P12 into that keychain
- name: Import signing certificate
if: runner.os == 'macOS'
run: |
echo "${{ secrets.APPLE_CERTIFICATE_P12 }}" | base64 --decode > cert.p12
security import cert.p12 \
-k ~/Library/Keychains/build.keychain \
-P "${{ secrets.APPLE_CERTIFICATE_PASSWORD }}" \
-T /usr/bin/codesign
security set-key-partition-list \
-S apple-tool:,apple: \
-s -k "" build.keychain
# On Windows, run build.bat via PowerShell
- name: Run Windows Build
if: runner.os == 'Windows'
shell: pwsh
run: .\build.bat
# On macOS/Linux, run build.sh via Bash
- name: Run Build
if: runner.os != 'Windows'
run: |
chmod +x build.sh
./build.sh
- name: Upload macOS nightly artifact
if: runner.os == 'macOS'
uses: actions/upload-artifact@v4
with:
name: nightly-macos
path: './dist/OpenVPCal-*.dmg'
- name: Upload Windows nightly artifact - Zip
if: runner.os == 'Windows'
uses: actions/upload-artifact@v4
with:
name: nightly-windows-setup
path: 'Output/OpenVPCal*.exe'
- name: Upload Windows nightly artifact - Setup
if: runner.os == 'Windows'
uses: actions/upload-artifact@v4
with:
name: nightly-windows-zip
path: 'Output/OpenVPCal*.zip'
- name: Upload Linux nightly artifact
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4
with:
name: nightly-linux
path: 'Output/OpenVPCal*.zip'
- name: Delete temporary keychain
if: runner.os == 'macOS'
run: |
security delete-keychain build.keychain
release_build:
name: Release Build & Artifact Upload (${{ matrix.os }})
needs: test
# Only run on tag pushes
if: startsWith(github.ref, 'refs/tags/')
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
CI: true
APPLE_SIGN_IDENTITY: ${{ secrets.APPLE_SIGN_IDENTITY }}
steps:
- name: Checkout tagged commit (no LFS, full history for branch check)
uses: actions/checkout@v3
with:
ref: ${{ github.ref }}
lfs: false
fetch-depth: 0
# Ensure the tag points to a commit reachable from main
- name: Verify tag belongs to main
shell: bash
run: |
git fetch origin main --depth=1
if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then
echo "Tag ${GITHUB_REF_NAME} is not on the main branch history. Aborting release."
exit 1
fi
echo "Tag commit is on main."
# Common Python setup
- name: Set up Python 3.11
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install UV CLI
run: |
python -m pip install --upgrade pip
pip install uv
# Install Git LFS and disable auto-smudge on each OS
- name: Install Git LFS & disable auto-smudge (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install git-lfs -y
git lfs install --skip-smudge
- name: Install Git LFS & disable auto-smudge (macOS)
if: runner.os == 'macOS'
run: |
brew install git-lfs
git lfs install --skip-smudge
- name: Install Git LFS & disable auto-smudge (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
choco install git-lfs -y
git lfs install --skip-smudge
# ← Cache LFS objects for release packaging
- name: Cache Git LFS objects
uses: actions/cache@v3
with:
path: .git/lfs/objects
key: release-${{ runner.os }}-git-lfs-${{ hashFiles('**/.gitattributes') }}
restore-keys: |
release-${{ runner.os }}-git-lfs-
- name: Fetch only needed LFS resources
run: |
git lfs fetch --include="packages/open_vp_cal/src/open_vp_cal/resources/**"
git lfs checkout packages/open_vp_cal/src/open_vp_cal/resources/**
# Create a temporary keychain and make it default
- name: Create & unlock keychain
if: runner.os == 'macOS'
run: |
security create-keychain -p "" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
# Decode & import your P12 into that keychain
- name: Import signing certificate
if: runner.os == 'macOS'
run: |
echo "${{ secrets.APPLE_CERTIFICATE_P12 }}" | base64 --decode > cert.p12
security import cert.p12 \
-k ~/Library/Keychains/build.keychain \
-P "${{ secrets.APPLE_CERTIFICATE_PASSWORD }}" \
-T /usr/bin/codesign
security set-key-partition-list \
-S apple-tool:,apple: \
-s -k "" build.keychain
# On Windows, run build.bat via PowerShell
- name: Run Windows Build
if: runner.os == 'Windows'
shell: pwsh
run: .\build.bat
# On macOS/Linux, run build.sh via Bash
- name: Run Build
if: runner.os != 'Windows'
run: |
chmod +x build.sh
./build.sh
# Upload artifacts for release
- name: Upload macOS release artifact
if: runner.os == 'macOS'
uses: actions/upload-artifact@v4
with:
name: release-macos
path: './dist/OpenVPCal-*.dmg'
- name: Upload Windows release artifact - Setup
if: runner.os == 'Windows'
uses: actions/upload-artifact@v4
with:
name: release-windows-setup
path: 'Output/OpenVPCal*.exe'
- name: Upload Windows release artifact - Zip
if: runner.os == 'Windows'
uses: actions/upload-artifact@v4
with:
name: release-windows-zip
path: 'Output/OpenVPCal*.zip'
- name: Upload Linux release artifact
if: runner.os == 'Linux'
uses: actions/upload-artifact@v4
with:
name: release-linux
path: 'Output/OpenVPCal*.zip'
- name: Delete temporary keychain
if: runner.os == 'macOS'
run: |
security delete-keychain build.keychain
publish_release:
name: Create GitHub Release & Attach Artifacts
needs: release_build
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download all build artifacts
uses: actions/download-artifact@v4
with:
path: release-assets
merge-multiple: true
- name: Create Release and upload assets
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
generate_release_notes: true
draft: false
prerelease: false
files: |
release-assets/**