diff --git a/.github/ghprcomment.yml b/.github/ghprcomment.yml index ecb265e046c..7e5f9de7092 100644 --- a/.github/ghprcomment.yml +++ b/.github/ghprcomment.yml @@ -168,25 +168,25 @@ Give it a read, and you’ll discover the ancient wisdom of assigning issues to yourself. Trust me, it’s worth it. πŸš€ -- jobName: 'PR title must not start with "Fix for issue "' - workflowName: 'PR Tests' +- jobName: 'PR title must not contain "issue "' + workflowName: 'PR Format' always: true message: > The title of the pull request must not start with "Fix for issue xyz". Please use a concise one-line summary that explains what the fix or change actually does. Example of a good title: "Prevent crash when importing malformed BibTeX entries". - jobName: 'Mandatory Checks present' - workflowName: 'PR Tests' + workflowName: 'PR Format' always: true message: > You have removed the "Mandatory Checks" section from your pull request description. Please adhere to our [pull request template](https://github.com/JabRef/jabref/blob/main/.github/PULL_REQUEST_TEMPLATE.md?plain=1#L10). - jobName: 'PR checklist OK' - workflowName: 'PR Tests' + workflowName: 'PR Format' always: true message: > Note that your PR will not be reviewed/accepted until you have gone through the mandatory checks in the description and marked each of them them exactly in the format of `[x]` (done), `[ ]` (not done yet) or `[/]` (not applicable). - jobName: 'Determine issue number' - workflowName: 'PR Tests' + workflowName: 'On PR opened/updated' always: true message: | Your pull request needs to link an issue correctly. diff --git a/.github/workflows/on-pr-opened.yml b/.github/workflows/on-pr-opened.yml index 562fe2512e8..2ac63a1843d 100644 --- a/.github/workflows/on-pr-opened.yml +++ b/.github/workflows/on-pr-opened.yml @@ -2,7 +2,7 @@ name: Welcome a first-time contributor on: pull_request_target: - types: opened + types: [opened] jobs: welcome-first-time-contributor: diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index cc57b081f17..df7689810ed 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -7,7 +7,8 @@ name: Comment on PR on: workflow_run: - workflows: ["Source Code Tests", "On PR opened/updated", "PR Tests"] + # note when updating via a PR and testing - `workflow_run` executes from the `main` branch and not the PR branch + workflows: ["Source Code Tests", "On PR opened/updated", "PR Tests", "PR Format"] # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#running-a-workflow-based-on-the-conclusion-of-another-workflow types: [completed] workflow_dispatch: diff --git a/.github/workflows/pr-format.yml b/.github/workflows/pr-format.yml new file mode 100644 index 00000000000..2774452f795 --- /dev/null +++ b/.github/workflows/pr-format.yml @@ -0,0 +1,124 @@ +name: PR Format + +on: + pull_request: + types: [opened, reopened, edited] + +permissions: + pull-requests: write + +jobs: + check_title_format: + name: PR title must not contain "issue " + if: github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name != 'JabRef/jabref' + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@v5 + with: + submodules: 'false' + show-progress: 'false' + - name: Check PR title + run: | + TITLE=$(gh pr view "${{ github.event.number }}" --json title --template '{{.title}}') + echo "Title: $TITLE" + + if echo "$TITLE" | grep -Eiq 'issue ?#?[0-9]+.+'; then + echo "❌ Title contains 'issue ' β€” not allowed." + exit 1 + fi + + echo "βœ… Title format OK" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + mandatory-checks-section-exists: + if: > + (github.event.pull_request.head.repo.full_name != 'JabRef/jabref') && !( + (github.actor == 'dependabot[bot]') || + ( + startsWith(github.event.pull_request.title, '[Bot] ') || + startsWith(github.event.pull_request.title, 'Bump ') || + startsWith(github.event.pull_request.title, 'New Crowdin updates') || + startsWith(github.event.pull_request.title, 'Update Gradle Wrapper from') + ) + ) + name: Mandatory Checks present + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@v5 + with: + submodules: 'false' + show-progress: 'false' + + - name: Check for existence of Mandatory Checks section + id: check_mandatory_section + run: | + set -e + + BODY=$(gh pr view "${{ github.event.number }}" --json body --template '{{.body}}') + + if echo "$BODY" | grep -q "### Mandatory checks"; then + echo "βœ… '### Mandatory checks' section found." + else + echo "❌ '### Mandatory checks' section is missing!" + exit 1 + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + checklist-checked: + if: > + (github.event.pull_request.head.repo.full_name != 'JabRef/jabref') && + !( + (github.actor == 'dependabot[bot]') || + ( + startsWith(github.event.pull_request.title, '[Bot] ') || + startsWith(github.event.pull_request.title, 'Bump ') || + startsWith(github.event.pull_request.title, 'New Crowdin updates') || + startsWith(github.event.pull_request.title, 'Update Gradle Wrapper from') + ) + ) + name: PR checklist OK + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@v5 + with: + submodules: 'false' + show-progress: 'false' + - name: Check for PR checklist + id: check_changelog_modification + run: | + set -e + + BODY=$(gh pr view "${{ github.event.number }}" --json body --template '{{.body}}' | grep -A5000 '### Mandatory checks') + echo "Found body: $BODY" + + # Ensure the section exists + if ! printf '%s\n' "$BODY" | grep -q "### Mandatory checks"; then + echo "❌ '### Mandatory checks' section is missing!" + exit 1 + fi + + BOXES=$(printf '%s\n' "$BODY" | grep "^- \[") + echo "Found boxes: $BOXES" + + while IFS= read -r line; do + if ! printf '%s\n' "$line" | grep -Eq "^- \[(x|/| )\] "; then + echo "❌ Found improperly formatted checkbox: '$line'" + exit 1 + fi + done <<< "$BOXES" + + LINE_COUNT=$(echo "$BOXES" | wc -l) + + if [ "$LINE_COUNT" -ne 6 ]; then + echo "❌ Found $LINE_COUNT lines instead of 6 required lines" + exit 1 + fi + + echo "βœ… All checkboxes are present and in the correct format." + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tests-pr.yml b/.github/workflows/tests-pr.yml index 48ce3916e1a..332480d7994 100644 --- a/.github/workflows/tests-pr.yml +++ b/.github/workflows/tests-pr.yml @@ -2,6 +2,7 @@ name: PR Tests on: pull_request: + types: [opened, reopened, synchronize] concurrency: group: "${{ github.workflow }}-${{ github.head_ref || github.ref }}" @@ -21,122 +22,6 @@ jobs: name: pr_number path: pr_number.txt - check_title_format: - name: PR title must not contain "issue " - if: github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name != 'JabRef/jabref' - runs-on: ubuntu-latest - steps: - - name: Checkout source - uses: actions/checkout@v5 - with: - submodules: 'false' - show-progress: 'false' - - name: Check PR title - run: | - TITLE=$(gh pr view "${{ github.event.number }}" --json title --template '{{.title}}') - echo "Title: $TITLE" - - if echo "$TITLE" | grep -Eiq 'issue ?#?[0-9]+.+'; then - echo "❌ Title contains 'issue ' β€” not allowed." - exit 1 - fi - - echo "βœ… Title format OK" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - mandatory-checks-section-exists: - if: > - (github.event.pull_request.head.repo.full_name != 'JabRef/jabref') && !( - (github.actor == 'dependabot[bot]') || - ( - startsWith(github.event.pull_request.title, '[Bot] ') || - startsWith(github.event.pull_request.title, 'Bump ') || - startsWith(github.event.pull_request.title, 'New Crowdin updates') || - startsWith(github.event.pull_request.title, 'Update Gradle Wrapper from') - ) - ) - name: Mandatory Checks present - runs-on: ubuntu-latest - steps: - - name: Checkout source - uses: actions/checkout@v5 - with: - submodules: 'false' - show-progress: 'false' - - - name: Check for existence of Mandatory Checks section - id: check_mandatory_section - run: | - set -e - - BODY=$(gh pr view "${{ github.event.number }}" --json body --template '{{.body}}') - - if echo "$BODY" | grep -q "### Mandatory checks"; then - echo "βœ… '### Mandatory checks' section found." - else - echo "❌ '### Mandatory checks' section is missing!" - exit 1 - fi - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - checklist-checked: - if: > - (github.event.pull_request.head.repo.full_name != 'JabRef/jabref') && - !( - (github.actor == 'dependabot[bot]') || - ( - startsWith(github.event.pull_request.title, '[Bot] ') || - startsWith(github.event.pull_request.title, 'Bump ') || - startsWith(github.event.pull_request.title, 'New Crowdin updates') || - startsWith(github.event.pull_request.title, 'Update Gradle Wrapper from') - ) - ) - name: PR checklist OK - runs-on: ubuntu-latest - steps: - - name: Checkout source - uses: actions/checkout@v5 - with: - submodules: 'false' - show-progress: 'false' - - name: Check for PR checklist - id: check_changelog_modification - run: | - set -e - - BODY=$(gh pr view "${{ github.event.number }}" --json body --template '{{.body}}' | grep -A5000 '### Mandatory checks') - echo "Found body: $BODY" - - # Ensure the section exists - if ! printf '%s\n' "$BODY" | grep -q "### Mandatory checks"; then - echo "❌ '### Mandatory checks' section is missing!" - exit 1 - fi - - BOXES=$(printf '%s\n' "$BODY" | grep "^- \[") - echo "Found boxes: $BOXES" - - while IFS= read -r line; do - if ! printf '%s\n' "$line" | grep -Eq "^- \[(x|/| )\] "; then - echo "❌ Found improperly formatted checkbox: '$line'" - exit 1 - fi - done <<< "$BOXES" - - LINE_COUNT=$(echo "$BOXES" | wc -l) - - if [ "$LINE_COUNT" -ne 6 ]; then - echo "❌ Found $LINE_COUNT lines instead of 6 required lines" - exit 1 - fi - - echo "βœ… All checkboxes are present and in the correct format." - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - changelog_modified: name: CHANGELOG.md needs to be modified if: github.actor != 'dependabot[bot]' && github.event.pull_request.head.repo.full_name != 'JabRef/jabref'