Release v4.10.0
#5433
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: Lint | |
"on": | |
workflow_call: | |
push: | |
branches: | |
- main | |
pull_request: | |
concurrency: | |
# Group workflow jobs so new commits cancels in-progress execution triggered by previous commits. | |
# Source: https://mail.python.org/archives/list/[email protected]/thread/PCBCQMJF64JGRBOX7E2EE4YLKHT4DI55/ | |
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} | |
cancel-in-progress: true | |
jobs: | |
project-metadata: | |
name: Project metadata | |
runs-on: ubuntu-24.04 | |
outputs: | |
python_files: ${{ steps.project-metadata.outputs.python_files }} | |
is_python_project: ${{ steps.project-metadata.outputs.is_python_project }} | |
mypy_params: ${{ steps.project-metadata.outputs.mypy_params }} | |
steps: | |
- uses: actions/[email protected] | |
with: | |
# Checkout pull request HEAD commit to ignore actions/checkout's merge commit. Fallback to push SHA. | |
ref: ${{ github.event.pull_request.head.sha || github.sha }} | |
# We're going to browse all new commits. | |
fetch-depth: 0 | |
- name: Install uv | |
run: | | |
python -m pip install -r https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/uv.txt | |
- name: Run gha-utils metadata | |
id: project-metadata | |
env: | |
GITHUB_CONTEXT: ${{ toJSON(github) }} | |
run: > | |
uvx | |
--with-requirements https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/gha-utils.txt | |
-- | |
gha-utils --verbosity DEBUG metadata --overwrite "$GITHUB_OUTPUT" | |
mypy-lint: | |
needs: | |
- project-metadata | |
# Skip linting on prepare-release branch as it points to a tagged URL that does not exist yet. | |
if: github.head_ref != 'prepare-release' && needs.project-metadata.outputs.python_files | |
runs-on: ubuntu-24.04 | |
steps: | |
- uses: actions/[email protected] | |
- name: Install uv | |
run: | | |
python -m pip install -r https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/uv.txt | |
- name: Install Mypy | |
run: | | |
uv --no-progress venv --python 3.13 | |
uv --no-progress pip install \ | |
--requirement https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/mypy.txt | |
- name: Install package | |
# Use --inexact so that uv doesn't try to remove the mypy package installed above. | |
run: | | |
uv --no-progress sync --frozen --all-extras --inexact | |
- name: Run Mypy | |
# --color-output - Force colorized output as in CI, Mypy defaults to no color in CI. | |
run: > | |
uv --no-progress run --frozen -- mypy --color-output ${{ needs.project-metadata.outputs.mypy_params }} | |
${{ needs.project-metadata.outputs.python_files }} | |
lint-yaml: | |
# Skip linting on prepare-release branch as it points to a tagged URL that does not exist yet. | |
if: github.head_ref != 'prepare-release' | |
runs-on: ubuntu-24.04 | |
steps: | |
- uses: actions/[email protected] | |
- name: Install uv | |
run: | | |
python -m pip install -r https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/uv.txt | |
- name: Install yamllint | |
run: > | |
uv tool install --with-requirements | |
https://raw.githubusercontent.com/kdeldycke/workflows/main/requirements/yamllint.txt yamllint | |
- name: Run yamllint | |
run: | | |
yamllint --strict --config-data "{rules: {line-length: {max: 120}}}" --format github . | |
lint-zsh: | |
runs-on: ubuntu-24.04 | |
steps: | |
- uses: actions/[email protected] | |
- name: Install Zsh | |
run: | | |
sudo apt update | |
sudo apt install --yes zsh | |
- name: Lint | |
run: | | |
find . -iname "*.sh" -exec zsh --no-exec "{}" \; | |
lint-github-action: | |
runs-on: ubuntu-24.04 | |
steps: | |
- uses: actions/[email protected] | |
- name: Install actionlint | |
id: install_actionlint | |
run: | | |
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) | |
- name: Install shellcheck | |
run: | | |
sudo apt update | |
sudo apt install --yes shellcheck | |
- name: Install problem matcher | |
# Source: https://github.com/rhysd/actionlint/blob/main/docs/usage.md#problem-matchers | |
run: > | |
curl -fsSL --output ./.github/labeller-file-based.yaml | |
https://raw.githubusercontent.com/rhysd/actionlint/main/.github/actionlint-matcher.json | |
- name: Register problem matcher | |
run: | | |
echo "::add-matcher::.github/labeller-file-based.yaml" | |
- name: Run actionlint | |
# XXX actionlint triggers this error: | |
# Error: .github/workflows/release.yaml:198:27: | |
# property "workflow_update_github_pat" is not defined in object type {actions_runner_debug: string; | |
# actions_step_debug: string; github_token: string; pypi_token: string} [expression] | |
# See: https://github.com/rhysd/actionlint/issues/148 | |
run: > | |
${{ steps.install_actionlint.outputs.executable }} | |
-color | |
-ignore 'property "workflow_update_github_pat" is not defined in .+' | |
broken-links: | |
# Skip checks on prepare-release branch as it contains commits in changelog and documentation that points to a tag | |
# that does not exist yet, rendering URLs artificially broken. Also skips the merge commit of the prepare-release | |
# branch, as if the URLs are good, the tag is created asynchronously by release.yaml:git-tag job. And as a | |
# precautionary measure, just skip any event that contains a post-release bump commit. | |
if: > | |
github.head_ref != 'prepare-release' | |
&& github.ref != 'refs/heads/prepare-release' | |
&& (! contains(github.event.commits.*.message, '[changelog] Post-release version bump')) | |
runs-on: ubuntu-24.04 | |
# XXX We need to manually manage the life-cycle of issues created in this job because the create-issue-from-file | |
# action blindly creates issues ad-nauseam. See: https://github.com/peter-evans/create-issue-from-file/issues/298 . | |
# This was also discussed at: https://github.com/lycheeverse/lychee-action/issues/74#issuecomment-1587089689 | |
steps: | |
- uses: actions/[email protected] | |
- uses: lycheeverse/[email protected] | |
id: lychee_run | |
with: | |
# XXX Skip HN because of rate-limiting. | |
# See: https://github.com/lycheeverse/lychee/issues/989#issuecomment-1587208730 | |
# https://github.com/lycheeverse/lychee/pull/1147 | |
args: > | |
--exclude ycombinator.com | |
--base . | |
--verbose | |
--no-progress | |
'./**/*.md' './**/*.html' './**/*.rst' | |
- name: List open issues | |
id: open_issues | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: > | |
echo "issues=$( | |
gh issue list | |
--state open | |
--author 'github-actions[bot]' | |
--json number,title,createdAt )" >> "$GITHUB_OUTPUT" | |
- name: Print open issues | |
run: | | |
echo '${{ steps.open_issues.outputs.issues }}' | |
jq -aR <<< echo '${{ steps.open_issues.outputs.issues }}' | |
- name: Filter issues | |
id: issue_groups | |
shell: python | |
run: | | |
import json | |
import os | |
from operator import itemgetter | |
from pathlib import Path | |
exit_code = """${{ steps.lychee_run.outputs.exit_code }}""" | |
print(f"Lychee exit code: {exit_code!r}") | |
broken_links_found = bool(int(exit_code)) | |
if broken_links_found: | |
print("Broken links found: create a new issue or update the existing one.") | |
else: | |
print("No broken link found: close all open issues.") | |
open_issues = json.loads("""${{ steps.open_issues.outputs.issues }}""") | |
issue_to_update: int | None = None | |
issues_to_close: set[int] = set() | |
for issue in sorted(open_issues, key=itemgetter("createdAt"), reverse=True): | |
print(f"Processing {issue!r} ...") | |
if issue["title"] != "Broken links": | |
print(f"{issue!r} is not a broken links issue, skip it.") | |
continue | |
if broken_links_found and not issue_to_update: | |
print(f"{issue!r} is the most recent open issue.") | |
issue_to_update = issue["number"] | |
else: | |
print(f"{issue!r} is an old open issue we have to close.") | |
issues_to_close.add(issue["number"]) | |
output = f"broken_links_found={str(broken_links_found).lower()}\n" | |
output += f"issue_to_update={issue_to_update}\n" | |
output += f"issues_to_close={' '.join(issues_to_close)}\n" | |
env_file = Path(os.getenv("GITHUB_OUTPUT")) | |
env_file.write_text(output) | |
- name: Print issue groups | |
run: | | |
echo "Broken links found: ${{ steps.issue_groups.outputs.broken_links_found }}" | |
echo "Issue to update: ${{ steps.issue_groups.outputs.issue_to_update }}" | |
echo "Issues to close: ${{ steps.issue_groups.outputs.issues_to_close }}" | |
- name: Close old issues | |
if: steps.issue_groups.outputs.issues_to_close | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
NUMBER_LIST="${{ steps.issue_groups.outputs.issues_to_close }}" | |
for number in $NUMBER_LIST; do | |
gh issue close "$number" --comment "Superseded by #${{ steps.issue_groups.outputs.issue_to_update }}."; | |
done | |
- name: Get label | |
if: fromJSON(steps.issue_groups.outputs.broken_links_found) | |
id: get_label | |
run: > | |
echo "label=${{ startsWith(github.event.repository.name, 'awesome-') | |
&& '🩹 fix link' || '📚 documentation' }}" >> "$GITHUB_OUTPUT" | |
- name: Create or update issue | |
if: fromJSON(steps.issue_groups.outputs.broken_links_found) | |
uses: peter-evans/[email protected] | |
with: | |
title: "Broken links" | |
issue-number: ${{ steps.issue_groups.outputs.issue_to_update }} | |
content-filepath: ./lychee/out.md | |
labels: ${{ steps.get_label.outputs.label }} | |
lint-awesome: | |
name: Lint Awesome list | |
if: > | |
startsWith(github.event.repository.name, 'awesome-') | |
&& github.event.repository.name != 'awesome-template' | |
runs-on: ubuntu-24.04 | |
steps: | |
- uses: actions/[email protected] | |
with: | |
# Fetch all history to please linter's age checks. | |
fetch-depth: 0 | |
- run: | | |
npx awesome-lint --version | |
npx awesome-lint | |
check-secrets: | |
runs-on: ubuntu-24.04 | |
steps: | |
- uses: actions/[email protected] | |
with: | |
fetch-depth: 0 | |
- uses: gitleaks/[email protected] | |
with: | |
config-path: .github/gitleaks.toml | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |