Skip to content

Commit b573919

Browse files
committed
Add unit-testing framework
1 parent a671e56 commit b573919

13 files changed

+1020
-17
lines changed

.github/workflows/autodeps.yml

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
name: Autodeps
2+
3+
on:
4+
workflow_dispatch:
5+
schedule:
6+
- cron: '0 0 1 * *'
7+
8+
jobs:
9+
Autodeps:
10+
if: github.repository_owner == 'CoolCat467'
11+
name: Autodeps
12+
timeout-minutes: 10
13+
runs-on: 'ubuntu-latest'
14+
# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions#changing-github_token-permissions
15+
permissions:
16+
pull-requests: write
17+
issues: write
18+
repository-projects: write
19+
contents: write
20+
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v4
24+
- name: Setup python
25+
uses: actions/setup-python@v5
26+
with:
27+
python-version: "3.12"
28+
29+
- name: Bump dependencies
30+
run: |
31+
python -m pip install -U pip pre-commit
32+
python -m pip install -r test-requirements.txt
33+
uv pip compile --universal --python-version=3.10 --upgrade test-requirements.in -o test-requirements.txt
34+
pre-commit autoupdate --jobs 0
35+
36+
- name: Install new requirements
37+
run: python -m pip install -r test-requirements.txt
38+
39+
# apply newer versions' formatting
40+
- name: Black
41+
run: black src/checkers
42+
43+
- name: uv
44+
run: |
45+
uv pip compile --universal --python-version=3.10 test-requirements.in -o test-requirements.txt
46+
47+
- name: Commit changes and create automerge PR
48+
env:
49+
GH_TOKEN: ${{ github.token }}
50+
run: |
51+
# setup git repo
52+
git switch --force-create autodeps/bump_from_${GITHUB_SHA:0:6}
53+
git config user.name 'github-actions[bot]'
54+
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
55+
56+
if ! git commit -am "Dependency updates"; then
57+
echo "No changes to commit!"
58+
exit 0
59+
fi
60+
61+
git push --force --set-upstream origin autodeps/bump_from_${GITHUB_SHA:0:6}
62+
63+
# git push returns before github is ready for a pr, so we poll until success
64+
for BACKOFF in 1 2 4 8 0; do
65+
sleep $BACKOFF
66+
if gh pr create \
67+
--label dependencies --body "" \
68+
--title "Bump dependencies from commit ${GITHUB_SHA:0:6}" \
69+
; then
70+
break
71+
fi
72+
done
73+
74+
if [ $BACKOFF -eq 0 ]; then
75+
echo "Could not create the PR"
76+
exit 1
77+
fi
78+
79+
# gh pr create returns before the pr is ready, so we again poll until success
80+
# https://github.com/cli/cli/issues/2619#issuecomment-1240543096
81+
for BACKOFF in 1 2 4 8 0; do
82+
sleep $BACKOFF
83+
if gh pr merge --auto --squash; then
84+
break
85+
fi
86+
done
87+
88+
if [ $BACKOFF -eq 0 ]; then
89+
echo "Could not set automerge"
90+
exit 1
91+
fi

.github/workflows/ci.yml

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches-ignore:
6+
- "dependabot/**"
7+
pull_request:
8+
9+
concurrency:
10+
group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && format('-{0}', github.sha) || '' }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
## Windows:
15+
## name: 'Windows (${{ matrix.python }}, ${{ matrix.arch }}${{ matrix.extra_name }})'
16+
## timeout-minutes: 20
17+
## runs-on: 'windows-latest'
18+
## strategy:
19+
## fail-fast: false
20+
## matrix:
21+
## python: ['3.10', '3.11', '3.12']
22+
## arch: ['x86', 'x64']
23+
## continue-on-error: >-
24+
## ${{
25+
## (
26+
## endsWith(matrix.python, '-dev')
27+
## || endsWith(matrix.python, '-nightly')
28+
## )
29+
## && true
30+
## || false
31+
## }}
32+
## steps:
33+
## - name: Checkout
34+
## uses: actions/checkout@v4
35+
## - name: Setup python
36+
## uses: actions/setup-python@v5
37+
## with:
38+
## # This allows the matrix to specify just the major.minor version while still
39+
## # expanding it to get the latest patch version including alpha releases.
40+
## # This avoids the need to update for each new alpha, beta, release candidate,
41+
## # and then finally an actual release version. actions/setup-python doesn't
42+
## # support this for PyPy presently so we get no help there.
43+
## #
44+
## # 'CPython' -> '3.9.0-alpha - 3.9.X'
45+
## # 'PyPy' -> 'pypy-3.9'
46+
## python-version: ${{ fromJSON(format('["{0}", "{1}"]', format('{0}.0-alpha - {0}.X', matrix.python), matrix.python))[startsWith(matrix.python, 'pypy')] }}
47+
## architecture: '${{ matrix.arch }}'
48+
## cache: pip
49+
## cache-dependency-path: test-requirements.txt
50+
## - name: Run tests
51+
## run: ./ci.sh
52+
## shell: bash
53+
54+
Ubuntu:
55+
name: 'Ubuntu (${{ matrix.python }}${{ matrix.extra_name }})'
56+
timeout-minutes: 10
57+
runs-on: 'ubuntu-latest'
58+
# Only run for PRs or pushes to main
59+
if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
60+
strategy:
61+
fail-fast: false
62+
matrix:
63+
python: ['3.10', '3.11', '3.12', '3.13']
64+
check_formatting: ['0']
65+
extra_name: ['']
66+
include:
67+
- python: '3.12'
68+
check_formatting: '1'
69+
extra_name: ', check formatting'
70+
continue-on-error: >-
71+
${{
72+
(
73+
endsWith(matrix.python, '-dev')
74+
|| endsWith(matrix.python, '-nightly')
75+
)
76+
&& true
77+
|| false
78+
}}
79+
steps:
80+
- name: Checkout
81+
uses: actions/checkout@v4
82+
- name: Setup python
83+
uses: actions/setup-python@v5
84+
if: "!endsWith(matrix.python, '-dev')"
85+
with:
86+
python-version: ${{ fromJSON(format('["{0}", "{1}"]', format('{0}.0-alpha - {0}.X', matrix.python), matrix.python))[startsWith(matrix.python, 'pypy')] }}
87+
cache: pip
88+
cache-dependency-path: test-requirements.txt
89+
- name: Setup python (dev)
90+
uses: deadsnakes/action@v2.0.2
91+
if: endsWith(matrix.python, '-dev')
92+
with:
93+
python-version: '${{ matrix.python }}'
94+
- name: Run tests
95+
run: ./ci.sh
96+
env:
97+
CHECK_FORMATTING: '${{ matrix.check_formatting }}'
98+
99+
## macOS:
100+
## name: 'macOS (${{ matrix.python }})'
101+
## timeout-minutes: 15
102+
## runs-on: 'macos-latest'
103+
## strategy:
104+
## fail-fast: false
105+
## matrix:
106+
## python: ['3.10', '3.11', '3.12']
107+
## continue-on-error: >-
108+
## ${{
109+
## (
110+
## endsWith(matrix.python, '-dev')
111+
## || endsWith(matrix.python, '-nightly')
112+
## )
113+
## && true
114+
## || false
115+
## }}
116+
## steps:
117+
## - name: Checkout
118+
## uses: actions/checkout@v4
119+
## - name: Setup python
120+
## uses: actions/setup-python@v5
121+
## with:
122+
## python-version: ${{ fromJSON(format('["{0}", "{1}"]', format('{0}.0-alpha - {0}.X', matrix.python), matrix.python))[startsWith(matrix.python, 'pypy')] }}
123+
## cache: pip
124+
## cache-dependency-path: test-requirements.txt
125+
## - name: Run tests
126+
## run: ./ci.sh
127+
128+
## # https://github.com/marketplace/actions/alls-green#why
129+
## check: # This job does nothing and is only used for the branch protection
130+
##
131+
## if: always()
132+
##
133+
## needs:
134+
## - Windows
135+
## - Ubuntu
136+
## - macOS
137+
##
138+
## runs-on: ubuntu-latest
139+
##
140+
## steps:
141+
## - name: Decide whether the needed jobs succeeded or failed
142+
## uses: re-actors/alls-green@release/v1
143+
## with:
144+
## jobs: ${{ toJSON(needs) }}

check.sh

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/bin/bash
2+
3+
set -ex
4+
5+
ON_GITHUB_CI=true
6+
EXIT_STATUS=0
7+
PROJECT='subtitle_translate'
8+
9+
# If not running on Github's CI, discard the summaries
10+
if [ -z "${GITHUB_STEP_SUMMARY+x}" ]; then
11+
GITHUB_STEP_SUMMARY=/dev/null
12+
ON_GITHUB_CI=false
13+
fi
14+
15+
# Autoformatter *first*, to avoid double-reporting errors
16+
# (we'd like to run further autoformatters but *after* merging;
17+
# see https://forum.bors.tech/t/pre-test-and-pre-merge-hooks/322)
18+
# autoflake --recursive --in-place .
19+
# pyupgrade --py3-plus $(find . -name "*.py")
20+
echo "::group::Black"
21+
if ! black --check src/$PROJECT; then
22+
echo "* Black found issues" >> "$GITHUB_STEP_SUMMARY"
23+
EXIT_STATUS=1
24+
black --diff src/$PROJECT
25+
echo "::endgroup::"
26+
echo "::error:: Black found issues"
27+
else
28+
echo "::endgroup::"
29+
fi
30+
31+
# Run ruff, configured in pyproject.toml
32+
echo "::group::Ruff"
33+
if ! ruff check .; then
34+
echo "* ruff found issues." >> "$GITHUB_STEP_SUMMARY"
35+
EXIT_STATUS=1
36+
if $ON_GITHUB_CI; then
37+
ruff check --output-format github --diff .
38+
else
39+
ruff check --diff .
40+
fi
41+
echo "::endgroup::"
42+
echo "::error:: ruff found issues"
43+
else
44+
echo "::endgroup::"
45+
fi
46+
47+
# Run mypy on all supported platforms
48+
# MYPY is set if any of them fail.
49+
MYPY=0
50+
echo "::group::Mypy"
51+
# Cleanup previous runs.
52+
rm -f mypy_annotate.dat
53+
# Pipefail makes these pipelines fail if mypy does, even if mypy_annotate.py succeeds.
54+
set -o pipefail
55+
mypy --show-error-end --platform linux | python ./tools/mypy_annotate.py --dumpfile mypy_annotate.dat --platform Linux \
56+
|| { echo "* Mypy (Linux) found type errors." >> "$GITHUB_STEP_SUMMARY"; MYPY=1; }
57+
# Darwin tests FreeBSD too
58+
mypy --show-error-end --platform darwin | python ./tools/mypy_annotate.py --dumpfile mypy_annotate.dat --platform Mac \
59+
|| { echo "* Mypy (Mac) found type errors." >> "$GITHUB_STEP_SUMMARY"; MYPY=1; }
60+
mypy --show-error-end --platform win32 | python ./tools/mypy_annotate.py --dumpfile mypy_annotate.dat --platform Windows \
61+
|| { echo "* Mypy (Windows) found type errors." >> "$GITHUB_STEP_SUMMARY"; MYPY=1; }
62+
set +o pipefail
63+
# Re-display errors using Github's syntax, read out of mypy_annotate.dat
64+
python ./tools/mypy_annotate.py --dumpfile mypy_annotate.dat
65+
# Then discard.
66+
rm -f mypy_annotate.dat
67+
echo "::endgroup::"
68+
# Display a big error if we failed, outside the group so it can't be collapsed.
69+
if [ $MYPY -ne 0 ]; then
70+
echo "::error:: Mypy found type errors."
71+
EXIT_STATUS=1
72+
fi
73+
74+
# Check pip compile is consistent
75+
echo "::group::Pip Compile - Tests"
76+
uv pip compile --universal --python-version=3.10 test-requirements.in -o test-requirements.txt
77+
echo "::endgroup::"
78+
79+
if git status --porcelain | grep -q "requirements.txt"; then
80+
echo "::error::requirements.txt changed."
81+
echo "::group::requirements.txt changed"
82+
echo "* requirements.txt changed" >> "$GITHUB_STEP_SUMMARY"
83+
git status --porcelain
84+
git --no-pager diff --color ./*requirements.txt
85+
EXIT_STATUS=1
86+
echo "::endgroup::"
87+
fi
88+
89+
codespell || EXIT_STATUS=$?
90+
91+
# Finally, leave a really clear warning of any issues and exit
92+
if [ $EXIT_STATUS -ne 0 ]; then
93+
cat <<EOF
94+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
95+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
96+
97+
Problems were found by static analysis (listed above).
98+
To fix formatting and see remaining errors, run
99+
100+
uv pip install -r test-requirements.txt
101+
black src/$PROJECT
102+
ruff check src/$PROJECT
103+
./check.sh
104+
105+
in your local checkout.
106+
107+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
108+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
109+
EOF
110+
exit 1
111+
fi
112+
echo "# Formatting checks succeeded." >> "$GITHUB_STEP_SUMMARY"
113+
exit 0

0 commit comments

Comments
 (0)