Skip to content

Publish Python 🐍 distributions 📦 to PyPI and TestPyPI #26

Publish Python 🐍 distributions 📦 to PyPI and TestPyPI

Publish Python 🐍 distributions 📦 to PyPI and TestPyPI #26

Workflow file for this run

name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI
on:
push:
tags:
- "v*" # Push events to matching v*, i.e. v1.0, v20.15.10
# Allows to run this workflow manually from the Actions tab on GitHub UI
workflow_dispatch:
jobs:
check-quality-gate:
name: Check 🛡️ Bastion Quality Gates
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
with:
fetch-depth: 0
- name: Wait for 🛡️ Bastion Quality Gates to complete
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
PROJECT_KEY: DavidOsipov_PostQuantum-Feldman-VSS
GITHUB_SHA: ${{ github.sha }}
run: |
echo "Waiting for 🛡️ Bastion Quality Gates analysis to complete for commit: $GITHUB_SHA"
MAX_ATTEMPTS=30 # 30 attempts × 30 seconds = 15 minutes maximum wait time
ATTEMPT=1
while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do
echo "Attempt $ATTEMPT of $MAX_ATTEMPTS: Checking for completed analysis..."
# Use the qualitygates/project_status endpoint instead
ANALYSIS_RESPONSE=$(curl --silent --fail --show-error \
--header "Authorization: Bearer ${SONAR_TOKEN}" \
"${SONAR_HOST_URL}/api/qualitygates/project_status?projectKey=${PROJECT_KEY}")
# Check if request was successful
if [ $? -ne 0 ]; then
echo "Failed to query SonarQube API for project status"
sleep 30
ATTEMPT=$((ATTEMPT+1))
continue
fi
# Extract status
STATUS=$(echo $ANALYSIS_RESPONSE | jq -r '.projectStatus.status')
if [ "$STATUS" == "OK" ] || [ "$STATUS" == "ERROR" ] || [ "$STATUS" == "WARN" ]; then
echo "✅ Analysis complete with status: $STATUS"
if [ "$STATUS" == "OK" ]; then
exit 0
else
echo "::warning::Analysis completed but with status: $STATUS"
exit 0 # Still allow the workflow to continue
fi
fi
echo "Analysis not yet complete. Waiting 30 seconds before next check..."
sleep 30
ATTEMPT=$((ATTEMPT+1))
done
echo "::error::Timed out waiting for SonarQube analysis to complete after $(($MAX_ATTEMPTS * 30)) seconds"
echo "::error::Please ensure the SonarQube analysis is configured correctly."
exit 1
- name: Check 🛡️ Bastion Quality Gates
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
PROJECT_KEY: DavidOsipov_PostQuantum-Feldman-VSS
run: |
echo "Checking quality gate status for project: ${PROJECT_KEY}"
# Get quality gate status using the projectKey parameter
QUALITY_GATE_RESPONSE=$(curl --silent --fail --show-error \
--header "Authorization: Bearer ${SONAR_TOKEN}" \
"${SONAR_HOST_URL}/api/qualitygates/project_status?projectKey=${PROJECT_KEY}")
# Check if request was successful
if [ $? -ne 0 ]; then
echo "::error::Failed to query SonarQube quality gate status"
exit 1
fi
# Extract and check quality gate status
STATUS=$(echo $QUALITY_GATE_RESPONSE | jq -r '.projectStatus.status')
echo "Quality Gate Status: $STATUS"
# Print detailed condition information when status is not OK
if [ "$STATUS" != "OK" ]; then
echo "::group::Quality Gate Failure Details"
echo "Failed conditions:"
echo $QUALITY_GATE_RESPONSE | jq -r '.projectStatus.conditions[] | select(.status != "OK") | "- Metric: \(.metricKey), Status: \(.status), Error threshold: \(.errorThreshold), Actual value: \(.actualValue)"'
echo "::endgroup::"
# Get project issues summary
ISSUES_RESPONSE=$(curl --silent --fail --show-error \
--header "Authorization: Bearer ${SONAR_TOKEN}" \
"${SONAR_HOST_URL}/api/issues/search?projectKeys=${PROJECT_KEY}&resolved=false&severities=BLOCKER,CRITICAL&ps=10")
echo "::group::Critical Issues (showing up to 10)"
echo $ISSUES_RESPONSE | jq -r '.issues[] | "- [\(.severity)] \(.message) | In file: \(.component)"'
echo "::endgroup::"
echo "::error::Quality Gate check failed with status: $STATUS"
echo "::error::Please check SonarQube analysis at ${SONAR_HOST_URL}/dashboard?id=${PROJECT_KEY}"
exit 1
fi
echo "✅ Quality Gate passed successfully"
build-n-publish:
name: pypi-publish
needs: check-quality-gate
runs-on: ubuntu-latest
environment:
name: pypi
permissions:
id-token: write
steps:
- uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
- name: Set up Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55
with:
python-version: "3.13"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install hatch
- name: Build a binary wheel and a source tarball
run: |
hatch build
- name: Publish distribution 📦 to PyPI
if: startsWith(github.ref, 'refs/tags/v')
uses: pypa/gh-action-pypi-publish@db8f07d3871a0a180efa06b95d467625c19d5d5f
with:
print-hash: true
verbose: true