Skip to content

fix(vendor): drop the bracketed [UNSPECIFIED] from ESP Integrity comments (#2294) #3547

fix(vendor): drop the bracketed [UNSPECIFIED] from ESP Integrity comments (#2294)

fix(vendor): drop the bracketed [UNSPECIFIED] from ESP Integrity comments (#2294) #3547

name: "Python Compatibility"
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 4 * * 6'
permissions:
contents: read
# Only pull-request runs may be superseded. GitHub cancels a *pending* run when
# a newer one joins its group, whatever `cancel-in-progress` says, so a shared
# group for main's pushes would leave commits unvalidated; other events key on
# the run id.
concurrency:
group: python-compatibility-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
# #1660: the matrix below, from .github/python-versions.toml -- see the job of
# the same name in unit-tests.yml.
python-versions:
name: Read the Python versions
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
compatibility: ${{ steps.read.outputs.compatibility }}
compatibility-supported: ${{ steps.read.outputs.compatibility-supported }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
sparse-checkout: |
.github/python-versions.toml
util/_actions.py
util/python_versions.py
sparse-checkout-cone-mode: false
persist-credentials: false
- name: Read .github/python-versions.toml
id: read
run: python3 util/python_versions.py --github-output
# #2243, the owner's option B: unit-tests.yml's `changes`, the same
# util/classify_changes.py step. This workflow is never called, so its own
# pull_request run is every pull_request run, and every other event, a push
# to main included, runs everything. `light` is `true` on a docs-only or a
# test-only diff, neither of which can change what this workflow checks:
# pcapkit/ and util/ compile and import as on the base branch.
changes:
name: Classify changed files
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
light: ${{ steps.classify.outputs.code == 'false' || steps.classify.outputs.test-only == 'true' }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 2
- name: Classify the diff
id: classify
env:
OWN_PR: ${{ github.event_name == 'pull_request' }}
run: python3 util/classify_changes.py
compatibility:
# `Compat`, so `gh pr checks` cannot show two `Python 3.N` rows, this and
# Unit Tests', with nothing to tell them apart.
#
# #1633's tiers. A supported leg keeps the plain name, one of ruleset
# 23497679's required contexts. A KTLO leg is suffixed ` (KTLO)`, so no
# required context can match it, and its steps carry `continue-on-error`,
# as in unit-tests.yml's `test` job: job-level, a failed leg's check run
# concludes `failure`, so every commit shows red (#1672). Nothing below
# `requires-python`'s 3.8 runs (#2051).
#
# #2243: the supported legs are required contexts, so a docs-only or
# test-only pull request still runs them, by name, but they skip every
# step that sets up, installs or checks, and pass. A job-level `if:` would
# not do: a matrix job it skips reports one check under its unexpanded
# name, as Unit Tests' docs-only run 40238795866 did, which matches no
# required context, so each would stay pending.
# The KTLO legs, required by nothing, are left out of that matrix.
# `!cancelled()` replaces the implicit `success()`, so a failed `changes`,
# whose `light` is then empty, runs every leg in full.
name: Compat Python ${{ matrix.python-version }}${{ matrix.ktlo && ' (KTLO)' || '' }}
needs: [python-versions, changes]
if: ${{ !cancelled() && needs.python-versions.result == 'success' }}
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
env:
ANNOTATION_LEVEL: ${{ matrix.ktlo && 'warning' || 'error' }}
strategy:
fail-fast: false
# Both tiers, as for unit-tests.yml's `test` job (#1660), which explains
# the `os` pins: a KTLO leg carries `ktlo: true`, and `os` where
# `ubuntu-latest` has no setup-python build for it. A tier change edits
# ruleset 23497679 too.
matrix: ${{ fromJSON(needs.changes.outputs.light == 'true' && needs.python-versions.outputs.compatibility-supported || needs.python-versions.outputs.compatibility) }}
steps:
- name: Skip on a docs-only or test-only diff
if: ${{ needs.changes.outputs.light == 'true' }}
env:
LEG: Python ${{ matrix.python-version }}
run: echo "::notice title=Nothing to check on ${LEG}::A docs-only or test-only diff leaves pcapkit/ and util/ as on the base branch, so this leg passes without checking them (#2243)."
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
id: checkout
if: ${{ needs.changes.outputs.light != 'true' }}
continue-on-error: ${{ matrix.ktlo == true }}
# Every later step waits on this one's `outcome`, so on a light diff,
# where it skips, they skip too.
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
id: python
if: ${{ needs.changes.outputs.light != 'true' }}
continue-on-error: ${{ matrix.ktlo == true }}
with:
python-version: ${{ matrix.python-version }}
# The install needs this leg's interpreter, and the check below needs the
# install, as in unit-tests.yml's `test` job: on a KTLO leg a failed step
# does not stop the job, so each one waits on the `outcome` it needs.
# util/pip_install.py annotates a failed install, as in `test` (#1967).
- name: Install package
id: install
if: ${{ steps.python.outcome == 'success' }}
continue-on-error: ${{ matrix.ktlo == true }}
env:
LEG: Python ${{ matrix.python-version }}${{ matrix.ktlo && ' (KTLO, non-blocking)' || '' }}
run: python util/pip_install.py -e .
# One annotation saying why, so a failed leg -- an install that succeeds
# with sources that do not compile -- is legible from the run summary; a
# warning on a KTLO leg (#1672). Each title escapes `,` as
# `%2C`: the runner splits a command's properties on `,`, so the KTLO
# title would stop at "(KTLO" (actions/runner `ActionCommand.TryParseV2`
# in src/Runner.Common/ActionCommand.cs, at 5f0b3ddcc).
- name: Verify package
id: verify
if: ${{ steps.install.outcome == 'success' }}
continue-on-error: ${{ matrix.ktlo == true }}
shell: bash
env:
LEG: Python ${{ matrix.python-version }}${{ matrix.ktlo && ' (KTLO, non-blocking)' || '' }}
run: |
log="$RUNNER_TEMP/compileall.log"
if ! python -m compileall -q pcapkit > "$log" 2>&1; then
cat "$log"
count=$(awk '/^\*\*\* Error compiling /{n++} END{print n+0}' "$log")
first=$(awk '/^ File "/{sub(/^ /, ""); print; exit}' "$log")
echo "::${ANNOTATION_LEVEL} title=pcapkit does not compile on ${LEG//,/%2C}::$count modules fail to compile, the first at ${first:-an unreported place}; see this step's log."
exit 1
fi
if ! python -c 'import pcapkit; print(pcapkit.__version__)'; then
echo "::${ANNOTATION_LEVEL} title=pcapkit does not import on ${LEG//,/%2C}::See the traceback in this step's log."
exit 1
fi
# #2206: the util/ scripts held to requires-python's 3.8, compiled by 3.8's
# own parser. Their tests' `ast.parse(..., feature_version=(3, 8))` is
# best-effort on a newer interpreter, so this leg is the check. The list is
# the scripts those tests parse at the floor, as
# tests/project/test_compat_util_floor_2206.py pins; the version, an
# exemption in .github/python-versions.toml.
- name: Compile the 3.8-floor util scripts
id: compile-util
if: ${{ steps.install.outcome == 'success' && matrix.python-version == '3.8' }}
continue-on-error: ${{ matrix.ktlo == true }}
shell: bash
env:
LEG: Python ${{ matrix.python-version }}${{ matrix.ktlo && ' (KTLO, non-blocking)' || '' }}
run: |
log="$RUNNER_TEMP/compileall-util.log"
if ! python -m compileall -q \
util/_actions.py util/release_conda.py util/release_published.py \
util/release_reset_build.py util/release_status.py util/release_tags.py \
util/release_tiers.py util/release_upload.py > "$log" 2>&1; then
cat "$log"
count=$(awk '/^\*\*\* Error compiling /{n++} END{print n+0}' "$log")
first=$(awk '/^ File "/{sub(/^ /, ""); print; exit}' "$log")
echo "::${ANNOTATION_LEVEL} title=util/ does not compile on ${LEG//,/%2C}::$count scripts fail to compile, the first at ${first:-an unreported place}; see this step's log."
exit 1
fi
# #1672: the KTLO leg's report -- the same step ends every KTLO matrix
# job; see unit-tests.yml's `test` job for how it works.
- name: KTLO summary
if: ${{ !cancelled() && matrix.ktlo == true }}
continue-on-error: ${{ matrix.ktlo == true }}
shell: bash
env:
LEG: Python ${{ matrix.python-version }}${{ matrix.ktlo && ' (KTLO, non-blocking)' || '' }}
STEPS: ${{ toJSON(steps) }}
JOB_SUMMARY_COPY: ${{ runner.temp }}/job-summary.md
run: /usr/bin/python3 util/leg_summary.py ktlo
# #2030: the job's summary, for the report ci-reports.yml posts, as in
# unit-tests.yml's `test` job: `KTLO summary` copies its lines to
# job-summary.md, and these name the job and upload both.
- name: Name the job summary
if: ${{ always() }}
continue-on-error: true
shell: bash
env:
JOB_NAME: Compat Python ${{ matrix.python-version }}${{ matrix.ktlo && ' (KTLO)' || '' }}
run: if [ -s "$RUNNER_TEMP/job-summary.md" ]; then printf '%s\n' "$JOB_NAME" > "$RUNNER_TEMP/job-summary.name"; fi
- name: Upload the job summary
if: ${{ always() }}
continue-on-error: true
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: job-summary-${{ github.job }}-${{ strategy.job-index }}
path: |
${{ runner.temp }}/job-summary.md
${{ runner.temp }}/job-summary.name
if-no-files-found: ignore
retention-days: 7