Skip to content

Expand CLI with run and more options #99

Expand CLI with run and more options

Expand CLI with run and more options #99

Workflow file for this run

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/discord-webhook@v5.3.0
with:
webhook-url: ${{ secrets.DISCORD_CODING_WEBHOOK_URL }}
content: "${{ github.repository }} - [${{ github.actor }}] ${{ github.workflow }} - started\n"
- name: Post Slack start notification
id: slack
uses: slackapi/slack-github-action@v1.24.0
with:
payload: |
{
"workflow": "${{ github.workflow }}",
"repo": "${{ github.repository }}",
"status": "Started"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CODING_WEBHOOK_URL }}
test:
name: Python ${{ matrix.python-version }} (${{ matrix.os }})
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.python-version == '3.13.0-alpha.1' }}
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.0-alpha.1"
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
needs: [validate_tag, validate_version]
runs-on: ubuntu-latest
environment: deployment
# 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/discord-webhook@v5.3.0
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/slack-github-action@v1.24.0
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/discord-webhook@v5.3.0
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
id: slack
uses: slackapi/slack-github-action@v1.24.0
with:
payload: |
{
"workflow": "${{ github.workflow }}",
"repo": "${{ github.repository }}",
"status": "Finished"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CODING_WEBHOOK_URL }}