Release #7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |