release_notes.yml
1 name: Check Release Notes 2 3 on: 4 pull_request: 5 types: 6 - opened 7 - reopened 8 - synchronize 9 - ready_for_review 10 - labeled 11 - unlabeled 12 paths: 13 - "**.py" 14 - "pyproject.toml" 15 - "!.github/**/*.py" 16 - "releasenotes/notes/*.yaml" 17 18 jobs: 19 reno: 20 runs-on: ubuntu-slim 21 env: 22 PYTHON_VERSION: "3.10" 23 steps: 24 - name: Checkout 25 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 26 with: 27 # With the default value of 1, there are corner cases where tj-actions/changed-files 28 # fails with a `no merge base` error 29 fetch-depth: 0 30 31 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 32 with: 33 python-version: "${{ env.PYTHON_VERSION }}" 34 - name: Get release note files 35 id: changed-files 36 uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6 37 with: 38 files: releasenotes/notes/*.yaml 39 40 - name: Check release notes 41 if: steps.changed-files.outputs.any_changed == 'false' && !contains( github.event.pull_request.labels.*.name, 'ignore-for-release-notes') 42 run: | 43 # Check if any of the commit messages contain tags ci/docs/test 44 if git log --pretty=%s origin/main..HEAD | grep -E '^(ci:|docs:|test:)' > /dev/null; then 45 echo "Skipping release note check for commits with 'ci:', 'docs:', or 'test:' tags." 46 else 47 echo "::error::The release notes file is missing, please add one or attach the label 'ignore-for-release-notes' to this PR." 48 exit 1 49 fi 50 51 - name: Verify release notes formatting 52 if: steps.changed-files.outputs.any_changed == 'true' && !contains( github.event.pull_request.labels.*.name, 'ignore-for-release-notes') 53 run: | 54 pip install "reno<5" 55 reno lint . # it is not possible to pass a list of files to reno lint 56 57 - name: Check reStructuredText code formatting 58 if: steps.changed-files.outputs.any_changed == 'true' && !contains( github.event.pull_request.labels.*.name, 'ignore-for-release-notes') 59 shell: python 60 run: | 61 files = "${{ steps.changed-files.outputs.all_changed_files }}".split() 62 errors = [] 63 64 for filepath in files: 65 with open(filepath) as f: 66 for line_no, line in enumerate(f, start=1): 67 # Check for triple backticks (Markdown code blocks) 68 if "```" in line: 69 err = (f"Format error in {filepath}:{line_no}: " 70 "Found triple backticks. Use reStructuredText code block directive instead: .. code:: python") 71 errors.append(err) 72 73 # Check for single backticks (Markdown inline code) 74 if "`" in line.replace("```", "").replace("``", ""): 75 err = (f"Format error in {filepath}:{line_no}: " 76 "Found single backticks. Use double backticks (``code``) for inline code.") 77 errors.append(err) 78 79 if errors: 80 raise Exception("\n".join(errors))