diff --git a/.github/ghprcomment.yml b/.github/ghprcomment.yml index 20eed046975..2826c000830 100644 --- a/.github/ghprcomment.yml +++ b/.github/ghprcomment.yml @@ -170,7 +170,7 @@ # PR hygiene - jobName: 'Ensure that contributor is assigned (fails if not commented on issue)' - workflowName: 'On PR opened/updated' + workflowName: 'Link PR to Issue' message: > You did not assign yourself to the issue. Thus, it looks like you skipped reading our [CONTRIBUTING.md](https://github.com/JabRef/jabref/blob/main/CONTRIBUTING.md), which explains exactly how to participate. No worries, it happens to the best of us. @@ -196,7 +196,7 @@ 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: 'On PR opened/updated' + workflowName: 'Link PR to Issue' always: true message: | Your pull request needs to link an issue correctly. diff --git a/.github/workflows/link-issue.yml b/.github/workflows/link-issue.yml new file mode 100644 index 00000000000..1ca866195b3 --- /dev/null +++ b/.github/workflows/link-issue.yml @@ -0,0 +1,144 @@ +name: Link PR to Issue + +on: + pull_request_target: + types: [opened, reopened, edited] + +jobs: + determine_issue_number: + name: Determine issue number + runs-on: ubuntu-latest + if: > + (github.repository == 'JabRef/jabref') && + (github.event.pull_request.head.repo.full_name != 'JabRef/jabref') && + !( + (github.event.pull_request.user.login == 'dependabot[bot]') || (github.event.pull_request.user.login == 'renovate-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') + ) + ) + permissions: + contents: read + outputs: + issue_number: ${{ steps.get_issue_number.outputs.ticketNumber }} + steps: + - name: echo PR data + run: | + echo "PR Number: ${{ github.event.pull_request.number }}" + echo "PR URL: ${{ github.event.pull_request.html_url }}" + cat <\d+)' + branchRegex: '^(?\d+)' + # Matches GitHub's closes/fixes/resolves #{number}, but does not match our example `Closes #13109` in PULL_REQUEST_TEMPLATE + # Also matches URLs that are wrapped in `<>`. + bodyRegex: '(?fixes|closes|resolves|refs)\s+(?!13109\b)\d+)>?' + bodyRegexFlags: 'i' + outputOnly: true + - run: echo "${{ steps.get_issue_number.outputs.ticketNumber }}" + - name: Issue number present + if: steps.get_issue_number.outputs.ticketNumber == '-1' + run: | + echo "No valid ticket number found!" + exit 1 + + move_issue: + name: Mark issue as in progress + # after determine_issue_number to ensure that there is only one failure because of no ticket number + needs: determine_issue_number + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Move issue to "In Progress" in "Good First Issues" + uses: m7kvqbe1/github-action-move-issues/@main + with: + github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} + project-url: "https://github.com/orgs/JabRef/projects/5" + target-labels: "📍 Assigned" + target-column: "In Progress" + ignored-columns: "" + default-column: "In Progress" + issue-number: ${{ needs.determine_issue_number.outputs.issue_number }} + skip-if-not-in-project: true + - name: Move issue to "In Progress" in "Candidates for University Projects" + uses: m7kvqbe1/github-action-move-issues/@main + with: + github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} + project-url: "https://github.com/orgs/JabRef/projects/3" + target-labels: "📍 Assigned" + target-column: "In Progress" + ignored-columns: "" + default-column: "In Progress" + issue-number: ${{ needs.determine_issue_number.outputs.issue_number }} + skip-if-not-in-project: true + + ensure_assignment: + name: Ensure that contributor is assigned (fails if not commented on issue) + if: github.event.pull_request.head.repo.full_name != 'JabRef/jabref' + # after determine_issue_number to ensure that there is only one failure because of no ticket number + needs: determine_issue_number + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: actions/checkout@v5 + with: + show-progress: 'false' + - name: Assign PR creator to issue + run: | + set -e + + echo "Updating issue '${{ needs.determine_issue_number.outputs.issue_number }}'" + + # "gh issue edit" cannot be used - workaround found at https://github.com/cli/cli/issues/9620#issuecomment-2703135049 + + ASSIGNEES=$(gh api /repos/JabRef/jabref/issues/${{ needs.determine_issue_number.outputs.issue_number }} --jq '[.assignees[].login]') + + # Check if the user is already assigned + if echo "$ASSIGNEES" | jq -e '. | index("${{ github.event.pull_request.user.login }}")' >/dev/null; then + echo "User '${{ github.event.pull_request.user.login }}' is already an assignee. No update needed." + echo "Debug: $ASSIGNEES" + exit 0 + fi + + # Append the new assignee + UPDATED_ASSIGNEES=$(echo "$ASSIGNEES" | jq --arg new "${{ github.event.pull_request.user.login }}" '. + [$new]') + + LABELS=$(gh api repos/${{ github.repository }}/issues/${{ needs.determine_issue_number.outputs.issue_number }}/labels --jq '.[].name') + LABEL=$(echo "$LABELS" | grep -E '^good (first|second|third|forth) issue$' || true) + if [ -n "$LABEL" ]; then + echo "✅ Found label: $LABEL" + SILENT=false + # Apply label + gh issue edit "${{ github.event.pull_request.number }}" --add-label "$LABEL" + else + echo "🚫 Silent fail if not possible to add assignee" + SILENT=true + fi + + # Update issue with the new assignee list + echo "Updating issue #${{ needs.determine_issue_number.outputs.issue_number }} updated with assignees: $UPDATED_ASSIGNEES..." + if [ "$SILENT" = true ]; then + gh api -X PATCH /repos/JabRef/jabref/issues/${{ needs.determine_issue_number.outputs.issue_number }} --input <(echo "{\"assignees\": $UPDATED_ASSIGNEES}") || true + else + gh api -X PATCH /repos/JabRef/jabref/issues/${{ needs.determine_issue_number.outputs.issue_number }} --input <(echo "{\"assignees\": $UPDATED_ASSIGNEES}") + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Add label "📌 Pinned" + run: gh issue edit ${{ needs.determine_issue_number.outputs.issue_number }} --add-label "📌 Pinned" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/on-pr-opened-updated.yml b/.github/workflows/on-pr-opened-updated.yml index a2a1625e35c..1fad5d2aaec 100644 --- a/.github/workflows/on-pr-opened-updated.yml +++ b/.github/workflows/on-pr-opened-updated.yml @@ -6,141 +6,6 @@ on: # default: opened, synchronize, reopened jobs: - determine_issue_number: - name: Determine issue number - runs-on: ubuntu-latest - if: > - (github.repository == 'JabRef/jabref') && - (github.event.pull_request.head.repo.full_name != 'JabRef/jabref') && - !( - (github.event.pull_request.user.login == 'dependabot[bot]') || (github.event.pull_request.user.login == 'renovate-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') - ) - ) - permissions: - contents: read - outputs: - issue_number: ${{ steps.get_issue_number.outputs.ticketNumber }} - steps: - - name: echo PR data - run: | - echo "PR Number: ${{ github.event.pull_request.number }}" - echo "PR URL: ${{ github.event.pull_request.html_url }}" - cat <\d+)' - branchRegex: '^(?\d+)' - # Matches GitHub's closes/fixes/resolves #{number}, but does not match our example `Closes #13109` in PULL_REQUEST_TEMPLATE - # Also matches URLs that are wrapped in `<>`. - bodyRegex: '(?fixes|closes|resolves|refs)\s+(?!13109\b)\d+)>?' - bodyRegexFlags: 'i' - outputOnly: true - - run: echo "${{ steps.get_issue_number.outputs.ticketNumber }}" - - name: Issue number present - if: steps.get_issue_number.outputs.ticketNumber == '-1' - run: | - echo "No valid ticket number found!" - exit 1 - move_issue: - name: Mark issue as in progress - # after determine_issue_number to ensure that there is only one failure because of no ticket number - needs: determine_issue_number - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - name: Move issue to "In Progress" in "Good First Issues" - uses: m7kvqbe1/github-action-move-issues/@main - with: - github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} - project-url: "https://github.com/orgs/JabRef/projects/5" - target-labels: "📍 Assigned" - target-column: "In Progress" - ignored-columns: "" - default-column: "In Progress" - issue-number: ${{ needs.determine_issue_number.outputs.issue_number }} - skip-if-not-in-project: true - - name: Move issue to "In Progress" in "Candidates for University Projects" - uses: m7kvqbe1/github-action-move-issues/@main - with: - github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} - project-url: "https://github.com/orgs/JabRef/projects/3" - target-labels: "📍 Assigned" - target-column: "In Progress" - ignored-columns: "" - default-column: "In Progress" - issue-number: ${{ needs.determine_issue_number.outputs.issue_number }} - skip-if-not-in-project: true - ensure_assignment: - name: Ensure that contributor is assigned (fails if not commented on issue) - if: github.event.pull_request.head.repo.full_name != 'JabRef/jabref' - # after determine_issue_number to ensure that there is only one failure because of no ticket number - needs: determine_issue_number - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - uses: actions/checkout@v5 - with: - show-progress: 'false' - - name: Assign PR creator to issue - run: | - set -e - - echo "Updating issue '${{ needs.determine_issue_number.outputs.issue_number }}'" - - # "gh issue edit" cannot be used - workaround found at https://github.com/cli/cli/issues/9620#issuecomment-2703135049 - - ASSIGNEES=$(gh api /repos/JabRef/jabref/issues/${{ needs.determine_issue_number.outputs.issue_number }} --jq '[.assignees[].login]') - - # Check if the user is already assigned - if echo "$ASSIGNEES" | jq -e '. | index("${{ github.event.pull_request.user.login }}")' >/dev/null; then - echo "User '${{ github.event.pull_request.user.login }}' is already an assignee. No update needed." - echo "Debug: $ASSIGNEES" - exit 0 - fi - - # Append the new assignee - UPDATED_ASSIGNEES=$(echo "$ASSIGNEES" | jq --arg new "${{ github.event.pull_request.user.login }}" '. + [$new]') - - LABELS=$(gh api repos/${{ github.repository }}/issues/${{ needs.determine_issue_number.outputs.issue_number }}/labels --jq '.[].name') - LABEL=$(echo "$LABELS" | grep -E '^good (first|second|third|forth) issue$' || true) - if [ -n "$LABEL" ]; then - echo "✅ Found label: $LABEL" - SILENT=false - # Apply label - gh issue edit "${{ github.event.pull_request.number }}" --add-label "$LABEL" - else - echo "🚫 Silent fail if not possible to add assignee" - SILENT=true - fi - - # Update issue with the new assignee list - echo "Updating issue #${{ needs.determine_issue_number.outputs.issue_number }} updated with assignees: $UPDATED_ASSIGNEES..." - if [ "$SILENT" = true ]; then - gh api -X PATCH /repos/JabRef/jabref/issues/${{ needs.determine_issue_number.outputs.issue_number }} --input <(echo "{\"assignees\": $UPDATED_ASSIGNEES}") || true - else - gh api -X PATCH /repos/JabRef/jabref/issues/${{ needs.determine_issue_number.outputs.issue_number }} --input <(echo "{\"assignees\": $UPDATED_ASSIGNEES}") - fi - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Add label "📌 Pinned" - run: gh issue edit ${{ needs.determine_issue_number.outputs.issue_number }} --add-label "📌 Pinned" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} conflicts_with_target: if: github.repository == 'JabRef/jabref' name: Conflicts with target branch diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index 42ba6aba93d..4e47582a8a4 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -8,7 +8,7 @@ name: Comment on PR on: workflow_run: # 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", "Check PR Format", "Check PR Modifications", "Check PR CHANGELOG.md"] + workflows: ["Source Code Tests", "On PR opened/updated", "Check PR Format", "Link PR to Issue", "Check PR Modifications", "Check PR CHANGELOG.md"] # 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: