Skip to content

Release

Release #7

Workflow file for this run

name: Release
on:
# Trigger on stable version tags only (no prerelease suffixes)
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+' # Matches v2025.4.0 but not v2025.4.0a1
# Also allow manual trigger
workflow_dispatch:
inputs:
version:
description: 'Version to release (without v prefix, e.g., 2025.4.0)'
required: true
type: string
env:
DOCKER_IMAGE: gridappsd/app-base-container
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Determine version
id: version
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ inputs.version }}"
TAG="v$VERSION"
echo "NEEDS_VERSION_UPDATE=true" >> $GITHUB_ENV
else
TAG="${{ github.ref_name }}"
VERSION="${TAG#v}"
echo "NEEDS_VERSION_UPDATE=false" >> $GITHUB_ENV
fi
# Validate this is a stable version (no prerelease suffix)
if [[ "$VERSION" =~ (a|b|rc|dev|alpha|beta) ]]; then
echo "Error: This workflow is for stable releases only. Use 'Development Release' for prereleases."
exit 1
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "TAG=$TAG" >> $GITHUB_ENV
echo "Releasing stable version: $VERSION"
- name: Setup Pixi
uses: prefix-dev/setup-pixi@v0.8.1
with:
pixi-version: v0.61.0
- name: Update version (manual trigger only)
if: env.NEEDS_VERSION_UPDATE == 'true'
run: |
# Update version in pixi.toml
sed -i "s/^version = \".*\"/version = \"${{ env.VERSION }}\"/" pixi.toml
# Update version in sub-project pyproject.toml files
sed -i "s/^version = \".*\"/version = \"${{ env.VERSION }}\"/" gridappsd-python-lib/pyproject.toml
sed -i "s/^version = \".*\"/version = \"${{ env.VERSION }}\"/" gridappsd-field-bus-lib/pyproject.toml
- name: Update lock file
if: env.NEEDS_VERSION_UPDATE == 'true'
run: pixi install
- name: Run quality checks
run: pixi run check
- name: Run tests
run: pixi run test-all
- name: Build packages
run: pixi run build
- name: Commit and tag (manual trigger only)
if: env.NEEDS_VERSION_UPDATE == 'true'
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git add pixi.toml gridappsd-python-lib/pyproject.toml gridappsd-field-bus-lib/pyproject.toml
git commit -m "Release version ${{ env.VERSION }}"
git tag ${{ env.TAG }}
git push origin HEAD:${{ github.ref_name }}
git push origin ${{ env.TAG }}
- name: Publish to PyPI
if: github.repository_owner == 'GRIDAPPSD'
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: pixi run publish
- name: Create GitHub Release
uses: ncipollo/release-action@v1.15.0
with:
artifacts: "dist/*.tar.gz,dist/*.whl"
artifactErrorsFailBuild: true
generateReleaseNotes: true
prerelease: false
makeLatest: true
tag: ${{ env.TAG }}
name: "Release ${{ env.VERSION }}"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Verify package available on PyPI
if: github.repository_owner == 'GRIDAPPSD'
run: |
for i in $(seq 1 30); do
if pip index versions gridappsd-python 2>/dev/null | grep -q "${{ env.VERSION }}" || \
pip install --dry-run --no-deps "gridappsd-python==${{ env.VERSION }}" 2>/dev/null; then
echo "Package gridappsd-python==${{ env.VERSION }} is available on PyPI"
exit 0
fi
echo "Attempt $i/30: Package not yet available, waiting 10s..."
sleep 10
done
echo "Warning: Package not confirmed on PyPI after 5 minutes, proceeding anyway"
# Docker build and push
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
if: github.repository_owner == 'GRIDAPPSD'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
# Build default image (Python 3.12) with latest tag
- name: Build and push Docker image (Python 3.12 - default)
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.repository_owner == 'GRIDAPPSD' }}
build-args: |
PYTHON_VERSION=3.12
GRIDAPPSD_PYTHON_VERSION=${{ env.VERSION }}
tags: |
${{ env.DOCKER_IMAGE }}:${{ env.VERSION }}
${{ env.DOCKER_IMAGE }}:${{ env.VERSION }}-py312
${{ env.DOCKER_IMAGE }}:latest
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max
# Build Python 3.10 variant
- name: Build and push Docker image (Python 3.10)
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.repository_owner == 'GRIDAPPSD' }}
build-args: |
PYTHON_VERSION=3.10
GRIDAPPSD_PYTHON_VERSION=${{ env.VERSION }}
tags: |
${{ env.DOCKER_IMAGE }}:${{ env.VERSION }}-py310
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max
# Build Python 3.11 variant
- name: Build and push Docker image (Python 3.11)
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.repository_owner == 'GRIDAPPSD' }}
build-args: |
PYTHON_VERSION=3.11
GRIDAPPSD_PYTHON_VERSION=${{ env.VERSION }}
tags: |
${{ env.DOCKER_IMAGE }}:${{ env.VERSION }}-py311
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max