Skip to content

3.12.2

3.12.2 #793

Workflow file for this run

# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Trestle Deploy
on:
push:
branches:
- main
- 'v[0-9]*'
permissions: {}
jobs:
set-versions:
runs-on: ubuntu-latest
outputs:
min: ${{ steps.versions.outputs.min }}
max: ${{ steps.versions.outputs.max }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- id: versions
run: |
min_version=$(jq '.PYTHON_MIN' -r version.json)
max_version=$(jq '.PYTHON_MAX' -r version.json)
echo "min=$min_version"
echo "max=$max_version"
echo "min=$min_version" >> $GITHUB_OUTPUT
echo "max=$max_version" >> $GITHUB_OUTPUT
build:
needs: set-versions
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: ubuntu-latest
pip-cache: ~/.cache/pip
hatch-cache: ~/.cache/hatch
hatch-data: ~/.local/share/hatch
- os: macos-latest
pip-cache: ~/Library/Caches/pip
hatch-cache: ~/Library/Caches/hatch
hatch-data: ~/Library/Application Support/hatch
- os: windows-latest
pip-cache: ~\AppData\Local\pip\Cache
hatch-cache: ~\AppData\Local\hatch\Cache
hatch-data: ~\AppData\Local\hatch
python-version: [ '${{ needs.set-versions.outputs.min }}', '${{ needs.set-versions.outputs.max }}']
steps:
- name: Don't mess with line endings
run: |
git config --global core.autocrlf false
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: ${{ matrix.python-version }}
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: |
${{ matrix.pip-cache }}
${{ matrix.hatch-cache }}
${{ matrix.hatch-data }}
key: ${{ matrix.os }}-${{ matrix.python-version }}-hatch-${{ hashFiles('pyproject.toml') }}
restore-keys: |
${{ matrix.os }}-${{ matrix.python-version }}-hatch-
- name: Is core test version
id: core-version
run: echo "core=${{ (matrix.os == 'ubuntu-latest' && matrix.python-version == needs.set-versions.outputs.max ) }}" >> $GITHUB_OUTPUT
- name: Install build tools
run: |
make develop
- name: Setup pre-commit
if: steps.core-version.outputs.core == 'true'
run: |
make pre-commit
- name: Run md document formatting (mdformat)
if: steps.core-version.outputs.core == 'true'
run: |
make mdformat
- name: Run code formatting (ruff)
if: steps.core-version.outputs.core == 'true'
run: |
make code-format
- name: Run code linting (ruff)
if: steps.core-version.outputs.core == 'true'
run: |
make code-lint
- name: Run code typing check (mypy)
if: steps.core-version.outputs.core == 'true'
continue-on-error: true
run: |
make code-typing
- name: Install documentation dependencies
if: steps.core-version.outputs.core == 'true'
run: |
make docs-ubuntu-deps
- name: Validate website content (mkdocs)
if: steps.core-version.outputs.core == 'true'
run: |
make docs-validate
- name: Pytest Fast
if: steps.core-version.outputs.core != 'true'
run: |
make test
- name: Pytest Cov
if: steps.core-version.outputs.core == 'true'
run: |
make test-cov
deploy:
runs-on: ubuntu-latest
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false
needs: [ build, set-versions ]
permissions:
id-token: write
attestations: write
contents: write # <<< REQUIRED to attach provenance to GitHub Release
environment:
name: release
url: https://pypi.org/p/compliance-trestle
if: >-
github.repository == 'oscal-compass/compliance-trestle'
&& (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/v'))
steps:
- name: Validate branch name
if: github.ref != 'refs/heads/main'
run: |
if [[ ! "$GITHUB_REF_NAME" =~ ^v[0-9]+$ ]]; then
echo "::error::Branch '$GITHUB_REF_NAME' does not match required pattern ^v[0-9]+$"
exit 1
fi
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: true
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- name: Set up Python ${{ needs.set-versions.outputs.max }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: ${{ needs.set-versions.outputs.max }}
- name: Install build tools
run: |
make develop
- name: Validate build command
if: github.ref != 'refs/heads/main'
run: |
BUILD_CMD=$(python -c "
import tomllib, sys
with open('pyproject.toml', 'rb') as f:
cfg = tomllib.load(f)
cmd = cfg.get('tool', {}).get('semantic_release', {}).get('build_command', '')
sys.stdout.write(cmd)
")
ALLOWED='
python -m pip install build --upgrade
python -m build
'
NORM_BUILD=$(echo "$BUILD_CMD" | tr -s '[:space:]' ' ' | sed 's/^ *//;s/ *$//')
NORM_ALLOW=$(echo "$ALLOWED" | tr -s '[:space:]' ' ' | sed 's/^ *//;s/ *$//')
if [ "$NORM_BUILD" != "$NORM_ALLOW" ]; then
echo "::error::build_command in pyproject.toml has been modified from the expected value."
echo "::error::Expected: $NORM_ALLOW"
echo "::error::Got: $NORM_BUILD"
exit 1
fi
- name: Validate version matches branch
if: github.ref != 'refs/heads/main'
run: |
BRANCH_MAJOR="${GITHUB_REF_NAME#v}"
FILE_VERSION=$(python -c "
import re
with open('trestle/__init__.py') as f:
m = re.search(r\"__version__\s*=\s*['\\\"]([^'\\\"]+)\", f.read())
print(m.group(1) if m else '')
")
FILE_MAJOR="${FILE_VERSION%%.*}"
if [ "$BRANCH_MAJOR" != "$FILE_MAJOR" ]; then
echo "::error::Version mismatch: branch $GITHUB_REF_NAME expects major version $BRANCH_MAJOR but trestle/__init__.py has $FILE_VERSION (major: $FILE_MAJOR)"
exit 1
fi
- name: Validate commit types on maintenance branch
if: github.ref != 'refs/heads/main'
run: |
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
LAST_TAG=$(git merge-base HEAD origin/main)
echo "No tag found; scanning commits since merge-base with main ($LAST_TAG)"
fi
ALLOWED_TYPES='^(fix|perf|chore|ci|docs|build|refactor|style|test|revert)(\(.*\))?:'
BAD_COMMITS=$(git log "$LAST_TAG"..HEAD --no-merges --format='%s' | grep -iEvx "$ALLOWED_TYPES.*" || true)
if [ -n "$BAD_COMMITS" ]; then
echo "::error::All commits on maintenance branches must use an allowed type: fix, perf, chore, ci, docs, build, refactor, style, test, revert."
echo "::error::The following commits do not match:"
echo "$BAD_COMMITS"
exit 1
fi
- name: Python Semantic Release
id: release
uses: python-semantic-release/python-semantic-release@350c48fcb3ffcdfd2e0a235206bc2ecea6b69df0 # v10.5.3
with:
github_token: ${{ steps.app-token.outputs.token }}
# --- Generate provenance for the ACTUAL RELEASE ARTIFACTS ---
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
# NOTE: DO NOT wrap the conditional in ${{ }} as it will always evaluate to true.
# See https://github.com/actions/runner/issues/1173
if: steps.release.outputs.released == 'true'
# Sign artifacts to be uploaded to github releases after pypi. Pypi signs it's own
- uses: sigstore/gh-action-sigstore-python@04cffa1d795717b140764e8b640de88853c92acc # v3.3.0
if: steps.release.outputs.released == 'true'
with:
inputs: "dist/*"
- name: Publish package distributions to GitHub Releases
uses: python-semantic-release/upload-to-gh-release@0a92b5d7ebfc15a84f9801ebd1bf706343d43711 # v9.8.9
if: steps.release.outputs.released == 'true'
with:
github_token: ${{ steps.app-token.outputs.token }}
merge-main-to-develop:
name: Merge main -> develop
runs-on: ubuntu-latest
needs: deploy
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}-${{ github.job }}-main
cancel-in-progress: true
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: true
ref: main
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- name: Get GitHub App User ID
id: get-user-id
run: echo "user-id=$(gh api "/users/${{ env.SLUG }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
SLUG: ${{ steps.app-token.outputs.app-slug }}
- name: Configure Git
run: |
git config --global user.name '${{ env.SLUG }}[bot]'
git config --global user.email '${{ env.ID }}+${{ env.SLUG }}[bot]@users.noreply.github.com'
env:
SLUG: ${{ steps.app-token.outputs.app-slug }}
ID: ${{ steps.get-user-id.outputs.user-id }}
# https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
- name: Merge Main to Develop
run: |
git checkout develop
git merge --no-ff main -m "chore: Merge back version tags and changelog into develop."
git push origin develop