Fix Python 13 version in GitHub Action #109
This file contains 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: Test & Deploy | |
on: | |
push: | |
pull_request: | |
defaults: | |
run: | |
shell: bash | |
env: | |
# regexr.com/7mmq7 | |
VERSION_TAG_REGEX: '^v(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))((a|b|rc)(0|[1-9][0-9]*))?(\.(dev|post)(0|[1-9][0-9]*))?$' | |
DEV_TAG_REGEX: '\.(dev|post)(0|[1-9][0-9]*)$' | |
TOOL_PYTHON_VERSION: ${{ vars.TOOL_PYTHON_VERSION }} | |
jobs: | |
on_start: | |
name: Report Start | |
runs-on: ubuntu-latest | |
steps: | |
- name: Log start | |
run: echo "Started..." | |
- name: Post Discord start notification | |
# noinspection SpellCheckingInspection | |
uses: tsickert/[email protected] | |
with: | |
webhook-url: ${{ secrets.DISCORD_CODING_WEBHOOK_URL }} | |
content: "${{ github.repository }} - [${{ github.actor }}] ${{ github.workflow }} - started" | |
- name: Post Slack start notification | |
uses: slackapi/[email protected] | |
with: | |
payload: | | |
{ | |
"workflow": "${{ github.workflow }}", | |
"repo": "${{ github.repository }}", | |
"status": "Started" | |
} | |
env: | |
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CODING_WEBHOOK_URL }} | |
test: | |
name: Test - Python ${{ matrix.python-version }} (${{ matrix.os }}) | |
runs-on: ${{ matrix.os }} | |
continue-on-error: ${{ matrix.python-version == '3.13' }} | |
strategy: | |
matrix: | |
os: [ubuntu-latest, macos-latest, windows-latest, macos-13] | |
python-version: ["3.12", "3.10", "3.11"] | |
include: | |
- os: macos-13 | |
python-version: "3.13" | |
steps: | |
- name: Checkout repo | |
uses: actions/checkout@v4 | |
- name: Set up Python | |
uses: actions/setup-python@v4 | |
with: | |
python-version: ${{ matrix.python-version }} | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install -r requirements.txt | |
- name: Display Python version (${{ matrix.python-version }}) | |
run: python -c "import sys; print(sys.version)" | |
# Skip for Windows; path setting there isn't worth the trouble | |
- name: Run eyeball checks | |
if: runner.os != 'Windows' | |
run: | | |
pip install termcolor | |
PYTHONPATH=. python tests/eyeball.py | |
- name: Test with pytest | |
# noinspection SpellCheckingInspection | |
run: | | |
pip install pytest | |
pytest tests/ --maxfail=3 --showlocals --color=yes -v | |
validate_version: | |
name: Validate Package Version | |
runs-on: ubuntu-latest | |
needs: test | |
outputs: | |
PACKAGE_VERSION: ${{ steps.get_version.outputs.PACKAGE_VERSION }} | |
PACKAGE_VALID: ${{ steps.get_version.outputs.PACKAGE_VALID }} | |
steps: | |
- name: Checkout repo | |
uses: actions/checkout@v4 | |
- name: Set up Python (${{ env.TOOL_PYTHON_VERSION }}) | |
uses: actions/setup-python@v4 | |
with: | |
python-version: ${{ env.TOOL_PYTHON_VERSION }} | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install -r requirements.txt | |
- name: Validate package version | |
id: get_version | |
run: | | |
# Get the package version and confirm it is valid | |
PACKAGE_VERSION=$(python -c 'import automata; print(automata.__version__)') | |
echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> $GITHUB_OUTPUT | |
# Check if the tag name matches the version pattern | |
if [[ v"${PACKAGE_VERSION}" =~ ${VERSION_TAG_REGEX} ]]; then PACKAGE_VALID="true"; else PACKAGE_VALID="false"; fi | |
echo "PACKAGE_VALID=$PACKAGE_VALID" >> $GITHUB_OUTPUT | |
if [[ $PACKAGE_VALID == "true" ]]; then | |
echo "Valid package version: $PACKAGE_VERSION" | |
else | |
echo "Invalid package version: $PACKAGE_VERSION" | |
exit 1 # Tests fail if the package version is invalid | |
fi | |
validate_tag: | |
name: Validate Tag | |
runs-on: ubuntu-latest | |
needs: validate_version | |
if: >- | |
needs.validate_version.outputs.PACKAGE_VALID == 'true' | |
outputs: | |
IS_TAG: ${{ steps.validate.outputs.IS_TAG }} | |
TAG_VALID: ${{ steps.validate.outputs.TAG_VALID }} | |
TAG_IS_RELEASE: ${{ steps.validate.outputs.TAG_IS_RELEASE }} | |
TAG_VERSION_MATCH: ${{ steps.validate.outputs.TAG_VERSION_MATCH }} | |
steps: | |
- name: Checkout repo | |
uses: actions/checkout@v4 | |
- name: Validate version tag | |
id: validate | |
run: | | |
# Validate the version tag and determine whether it matches the package version | |
VERSION_TAG_REGEX="${{ env.VERSION_TAG_REGEX }}" | |
DEV_TAG_REGEX="${{ env.DEV_TAG_REGEX }}" | |
PACKAGE_VERSION=${{ needs.validate_version.outputs.PACKAGE_VERSION }} | |
# Check if the this is a tagged commit and save the tag or ref name | |
if [[ "${GITHUB_REF}" =~ "refs/tags/" ]]; then IS_TAG="true"; else IS_TAG="false"; fi | |
echo "IS_TAG=$IS_TAG" >> $GITHUB_OUTPUT | |
if [[ ${IS_TAG} == "true" ]]; then TAG_NAME=${GITHUB_REF#refs/tags/}; else TAG_NAME=${GITHUB_REF}; fi | |
# Check if the tag name matches the version pattern | |
if [[ "${TAG_NAME}" =~ ${VERSION_TAG_REGEX} ]]; then TAG_VALID="${IS_TAG}"; else TAG_VALID="false"; fi | |
echo "TAG_VALID=$TAG_VALID" >> $GITHUB_OUTPUT | |
# Check if the tag name matches the dev version pattern | |
if [[ !("${TAG_NAME}" =~ ${DEV_TAG_REGEX}) ]]; then TAG_IS_RELEASE="${TAG_VALID}"; else TAG_IS_RELEASE="false"; fi | |
echo "TAG_IS_RELEASE=$TAG_IS_RELEASE" >> $GITHUB_OUTPUT | |
# Check if the tag and package versions match | |
if [[ ${TAG_NAME#v} == $PACKAGE_VERSION ]]; then TAG_VERSION_MATCH="${TAG_VALID}"; else TAG_VERSION_MATCH="false"; fi | |
echo "TAG_VERSION_MATCH=$TAG_VERSION_MATCH" >> $GITHUB_OUTPUT | |
# Report tag validation results | |
if [[ ${IS_TAG} == "true" ]]; then | |
echo "Tag: $TAG_NAME" | |
if [[ ${TAG_VALID} == "true" ]]; then | |
echo "Valid version tag" | |
if [[ ${TAG_IS_RELEASE} == "true" ]]; then | |
echo "Release version tag" | |
else | |
echo "Development version tag" | |
fi | |
if [[ ${TAG_VERSION_MATCH} == "true" ]]; then | |
echo "Version in tag matches package version: $PACKAGE_VERSION = ${TAG_NAME#v}" | |
else | |
echo "Version in tag does not match package version: $PACKAGE_VERSION != ${TAG_NAME#v}" | |
fi | |
else | |
echo "Invalid (remember the v) or missing version tag" | |
fi | |
else | |
echo "Not a tag: $TAG_NAME" | |
fi | |
publish: | |
name: Build and Publish | |
runs-on: ubuntu-latest | |
environment: deployment | |
needs: [validate_tag, validate_version] | |
# Includes redundant check for PACKAGE_VALID | |
if: >- | |
needs.validate_version.outputs.PACKAGE_VALID == 'true' && | |
needs.validate_tag.outputs.IS_TAG == 'true' && | |
needs.validate_tag.outputs.TAG_VALID == 'true' && | |
needs.validate_tag.outputs.TAG_VERSION_MATCH == 'true' && | |
github.event_name == 'push' | |
permissions: | |
id-token: write # Mandatory for trusted publishing | |
steps: | |
- name: DEBUG Check inputs | |
run: | | |
IS_TAG=${{ needs.validate_tag.outputs.IS_TAG }} | |
TEST_TAG_VALID=${{ needs.validate_tag.outputs.TAG_VALID }} | |
TEST_TAG_VERSION_MATCH=${{ needs.validate_tag.outputs.TAG_VERSION_MATCH }} | |
TAG_IS_RELEASE=${{ needs.validate_tag.outputs.TAG_IS_RELEASE }} | |
echo "IS_TAG: IS_TAG" | |
echo "TEST_TAG_VALID: $TEST_TAG_VALID" | |
echo "TEST_TAG_VERSION_MATCH: $TEST_TAG_VERSION_MATCH" | |
echo "TAG_IS_RELEASE: $TAG_IS_RELEASE" | |
- name: Checkout repo | |
uses: actions/checkout@v4 | |
- name: Set up Python (${{ env.TOOL_PYTHON_VERSION }}) | |
uses: actions/setup-python@v4 | |
with: | |
python-version: ${{ env.TOOL_PYTHON_VERSION }} | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install -r requirements.txt | |
- name: Determine PyPI repository URL | |
id: pypi_repository | |
run: | | |
TAG_IS_RELEASE=${{ needs.validate_tag.outputs.TAG_IS_RELEASE }} | |
if [[ "${TAG_IS_RELEASE}" == 'true' ]]; then | |
echo "Will publish to production PyPI..." | |
echo "REPOSITORY_LEVEL=Production" >> $GITHUB_OUTPUT | |
echo "REPOSITORY_URL=https://upload.pypi.org/legacy/" >> $GITHUB_OUTPUT | |
else | |
echo "Will publish to test PyPI..." | |
echo "REPOSITORY_LEVEL=Test" >> $GITHUB_OUTPUT | |
echo "REPOSITORY_URL=https://test.pypi.org/legacy/" >> $GITHUB_OUTPUT | |
fi | |
- name: Install Flit | |
run: | | |
python -m pip install --upgrade pip | |
python -m pip install flit | |
flit --version | |
- name: Build the package | |
run: flit build --no-use-vcs | |
- name: Publish to PyPI (${{ steps.pypi_repository.outputs.REPOSITORY_LEVEL }}) | |
uses: pypa/gh-action-pypi-publish@release/v1 | |
with: | |
repository-url: ${{ steps.pypi_repository.outputs.REPOSITORY_URL }} | |
on_failure: | |
name: Report Failure | |
runs-on: ubuntu-latest | |
needs: [test, validate_version, validate_tag, publish] | |
if: failure() | |
steps: | |
- name: Check which job failed | |
id: failed_job | |
run: | | |
if [ ${{ contains(needs.test.result, 'failure') }} == 'true' ]; then | |
FAILED_JOB="Tests" | |
fi | |
if [ ${{ contains(needs.validate_version.result, 'failure') }} == 'true' ]; then | |
FAILED_JOB="Version Validation" | |
fi | |
if [ ${{ contains(needs.validate_tag.result, 'failure') }} == 'true' ]; then | |
FAILED_JOB="Tag Validation" | |
fi | |
if [ ${{ contains(needs.publish.result, 'failure') }} == 'true' ]; then | |
FAILED_JOB="Publication" | |
fi | |
echo "FAILED_JOB=${FAILED_JOB}" >> $GITHUB_OUTPUT | |
echo "${FAILED_JOB} Failure!" | |
- name: Post Discord failure notification | |
# noinspection SpellCheckingInspection | |
uses: tsickert/[email protected] | |
with: | |
webhook-url: ${{ secrets.DISCORD_CODING_WEBHOOK_URL }} | |
content: "${{ github.repository }} - [${{ github.actor }}] ${{ github.workflow }} - ${{ steps.failed_job.outputs.FAILED_JOB }} FAILED!\n<@${{ secrets.DISCORD_USER_ID }}>" | |
embed-title: "Failure Details" | |
embed-url: "https://github.com/${{ github.repository }}/actions/workflows/test-and-deploy.yml" | |
embed-description: "${{ steps.failed_job.outputs.FAILED_JOB }} failed" | |
embed-color: 15548997 | |
- name: Post Slack failure notification | |
id: slack | |
uses: slackapi/[email protected] | |
with: | |
payload: | | |
{ | |
"workflow": "${{ github.workflow }}", | |
"repo": "${{ github.repository }}", | |
"status": "FAILED!" | |
} | |
env: | |
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CODING_WEBHOOK_URL }} | |
on_success: | |
name: Report Success | |
runs-on: ubuntu-latest | |
needs: [test, validate_version, validate_tag, publish] | |
if: ${{ !failure() }} | |
steps: | |
- name: Log success | |
run: echo "Success!" | |
- name: Post Discord success notification | |
# noinspection SpellCheckingInspection | |
uses: tsickert/[email protected] | |
with: | |
webhook-url: ${{ secrets.DISCORD_CODING_WEBHOOK_URL }} | |
content: "${{ github.repository }} - [${{ github.actor }}] ${{ github.workflow }} - succeeded\n<@${{ secrets.DISCORD_USER_ID }}>" | |
- name: Post Slack success notification | |
uses: slackapi/[email protected] | |
with: | |
payload: | | |
{ | |
"workflow": "${{ github.workflow }}", | |
"repo": "${{ github.repository }}", | |
"status": "Finished" | |
} | |
env: | |
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CODING_WEBHOOK_URL }} |