|
| 1 | +--- |
| 2 | +name: "Pull Request Labeler" |
| 3 | +'on': |
| 4 | + pull_request_target: |
| 5 | + types: [opened, synchronize, reopened, edited] |
| 6 | +permissions: read-all |
| 7 | + |
| 8 | +jobs: |
| 9 | + labeler: |
| 10 | + runs-on: ubuntu-latest |
| 11 | + permissions: |
| 12 | + contents: read |
| 13 | + pull-requests: write |
| 14 | + outputs: |
| 15 | + labels: ${{ steps.labeler.outputs.all-labels }} |
| 16 | + steps: |
| 17 | + - name: Label the PR |
| 18 | + id: labeler |
| 19 | + uses: actions/labeler@v5 |
| 20 | + with: |
| 21 | + repo-token: ${{ secrets.GITHUB_TOKEN }} |
| 22 | + sync-labels: true |
| 23 | + title-prefix-checker: |
| 24 | + runs-on: ubuntu-latest |
| 25 | + permissions: |
| 26 | + contents: read |
| 27 | + pull-requests: write |
| 28 | + needs: labeler |
| 29 | + steps: |
| 30 | + - name: Check the PR title prefix |
| 31 | + id: check-prefix |
| 32 | + env: |
| 33 | + title: ${{ github.event.pull_request.title }} |
| 34 | + labels: ${{ needs.labeler.outputs.labels }} |
| 35 | + shell: python |
| 36 | + run: | |
| 37 | + import os |
| 38 | + import re |
| 39 | + import sys |
| 40 | + title = os.environ['title'] |
| 41 | + labels = os.environ['labels'] |
| 42 | + tags = { |
| 43 | + "infrastructure": "Infrastructure", |
| 44 | + "common": "Common", |
| 45 | + "alice3": "ALICE3", |
| 46 | + "pwgcf": "PWGCF", |
| 47 | + "pwgdq": "PWGDQ", |
| 48 | + "pwgem": "PWGEM", |
| 49 | + "pwghf": "PWGHF", |
| 50 | + "pwgje": "PWGJE", |
| 51 | + "pwglf": "PWGLF", |
| 52 | + "pwgud": "PWGUD", |
| 53 | + "dpg": "DPG", |
| 54 | + "trigger": "Trigger", |
| 55 | + "tutorial": "Tutorial", |
| 56 | + } |
| 57 | + print(f'PR title: "{title}"') |
| 58 | + print(f'PR labels: "{labels}"') |
| 59 | + tags_relevant = [tags[label] for label in tags if label in labels.split(",")] |
| 60 | + print("Relevant title tags:", ",".join(tags_relevant)) |
| 61 | + passed = True |
| 62 | + prefix_good = ",".join(tags_relevant) |
| 63 | + prefix_good = f"[{prefix_good}] " |
| 64 | + print(f"Generated prefix: {prefix_good}") |
| 65 | + replace_title = 0 |
| 66 | + title_new = title |
| 67 | + # If there is a prefix which contains a known tag, check it for correct tags, and reformat it if needed. |
| 68 | + # If there is a prefix which does not contain any known tag, add the tag prefix. |
| 69 | + # If there is no prefix, add the tag prefix. |
| 70 | + if match := re.match(r"\[?(\w[\w, /\+-]+)[\]:]+ ", title): |
| 71 | + prefix_title = match.group(1) |
| 72 | + words_prefix_title = prefix_title.replace(",", " ").replace("/", " ").split() |
| 73 | + title_stripped = title[len(match.group()) :] |
| 74 | + print(f'PR title prefix: "{prefix_title}" -> tags: {words_prefix_title}') |
| 75 | + print(f'Stripped PR title: "{title_stripped}"') |
| 76 | + if any(tag in words_prefix_title for tag in tags.values()): |
| 77 | + for tag in tags.values(): |
| 78 | + if tag in tags_relevant and tag not in words_prefix_title: |
| 79 | + print(f'::error::Relevant tag "{tag}" not found in the prefix of the PR title.') |
| 80 | + passed = False |
| 81 | + if tag not in tags_relevant and tag in words_prefix_title: |
| 82 | + print(f'::error::Irrelevant tag "{tag}" found in the prefix of the PR title.') |
| 83 | + passed = False |
| 84 | + # Format a valid prefix. |
| 85 | + if passed: |
| 86 | + prefix_good = ",".join(w for w in prefix_title.replace(",", " ").split() if w) |
| 87 | + prefix_good = f"[{prefix_good}] " |
| 88 | + print(f"::notice::Reformatted prefix: {prefix_good}") |
| 89 | + if match.group() != prefix_good: |
| 90 | + replace_title = 1 |
| 91 | + title_new = prefix_good + title_stripped |
| 92 | + else: |
| 93 | + print("::warning::No known tags found in the prefix.") |
| 94 | + if tags_relevant: |
| 95 | + replace_title = 1 |
| 96 | + title_new = prefix_good + title |
| 97 | + else: |
| 98 | + print("::warning::No valid prefix found in the PR title.") |
| 99 | + if tags_relevant: |
| 100 | + replace_title = 1 |
| 101 | + title_new = prefix_good + title |
| 102 | + if not passed: |
| 103 | + print("::error::Problems were found in the PR title prefix.") |
| 104 | + print('::notice::Use the form "tags: title" or "[tags] title".') |
| 105 | + sys.exit(1) |
| 106 | + if replace_title: |
| 107 | + print("::warning::The PR title prefix with tags needs to be added or adjusted.") |
| 108 | + print(f'::warning::New title: "{title_new}".') |
| 109 | + else: |
| 110 | + print("::notice::The PR title prefix is fine.") |
| 111 | + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh: |
| 112 | + print(f"replace={replace_title}", file=fh) |
| 113 | + print(f"title={title_new}", file=fh) |
| 114 | + - name: Fix the PR title prefix |
| 115 | + if: ${{ steps.check-prefix.outputs.replace == 1 }} |
| 116 | + uses: the-wright-jamie/Update-PR-Info-Action@v1.1.0 |
| 117 | + with: |
| 118 | + repo-token: "${{ secrets.GITHUB_TOKEN }}" |
| 119 | + base-branch-regex: master |
| 120 | + error-on-fail: false |
| 121 | + title-template: "${{ steps.check-prefix.outputs.title }}" |
| 122 | + title-update-action: replace |
0 commit comments