1name: Checklist 2 3# Produce a list of things that need to be changed 4# for the submission to align with CONTRIBUTING.md 5 6on: 7 pull_request: 8 types: [ opened, reopened, edited, synchronize ] 9 10permissions: 11 pull-requests: write 12 13jobs: 14 checklist: 15 name: commit 16 runs-on: ubuntu-latest 17 steps: 18 - uses: actions/github-script@v7 19 with: 20 # An asynchronous javascript function 21 script: | 22 /* 23 * Github's API returns the results in pages of 30, so 24 * pass the function we want, along with it's arguments, 25 * to paginate() which will handle gathering all the results. 26 */ 27 const comments = await github.paginate(github.rest.issues.listComments, { 28 owner: context.repo.owner, 29 repo: context.repo.repo, 30 issue_number: context.issue.number 31 }); 32 33 const commits = await github.paginate(github.rest.pulls.listCommits, { 34 owner: context.repo.owner, 35 repo: context.repo.repo, 36 pull_number: context.issue.number 37 }); 38 39 let checklist = {}; 40 let checklist_len = 0; 41 let comment_id = -1; 42 43 const msg_prefix = "Thank you for taking the time to contribute to FreeBSD!\n"; 44 const addToChecklist = (msg, sha) => { 45 if (!checklist[msg]) { 46 checklist[msg] = []; 47 checklist_len++; 48 } 49 checklist[msg].push(sha); 50 } 51 52 for (const commit of commits) { 53 const sob_lines = commit.commit.message.match(/^[^\S\r\n]*signed-off-by:.*/gim); 54 55 if (sob_lines == null && !commit.commit.author.email.toLowerCase().endsWith("freebsd.org")) 56 addToChecklist("Missing Signed-off-by lines", commit.sha); 57 else if (sob_lines != null) { 58 let author_signed = false; 59 for (const line of sob_lines) { 60 if (!line.includes("Signed-off-by: ")) 61 /* Only display the part we care about. */ 62 addToChecklist("Expected `Signed-off-by: `, got `" + line.match(/^[^\S\r\n]*signed-off-by:./i) + "`", commit.sha); 63 if (line.includes(commit.commit.author.email)) 64 author_signed = true; 65 } 66 67 if (!author_signed) 68 console.log("::warning title=Missing-Author-Signature::Missing Signed-off-by from author"); 69 } 70 71 if (commit.commit.author.email.toLowerCase().includes("noreply")) 72 addToChecklist("Real email address is needed", commit.sha); 73 } 74 75 /* Check if we've commented before. */ 76 for (const comment of comments) { 77 if (comment.user.login == "github-actions[bot]") { 78 comment_id = comment.id; 79 break; 80 } 81 } 82 83 if (checklist_len != 0) { 84 let msg = msg_prefix + 85 "There " + (checklist_len > 1 ? "are a few issues that need " : "is an issue that needs ") + 86 "to be fixed:\n"; 87 let comment_func = comment_id == -1 ? github.rest.issues.createComment : github.rest.issues.updateComment; 88 89 /* Loop for each key in "checklist". */ 90 for (const c in checklist) 91 msg += "- " + c + "<sup>" + checklist[c].join(", ") + "</sup>\n"; 92 93 comment_func({ 94 owner: context.repo.owner, 95 repo: context.repo.repo, 96 body: msg, 97 ...(comment_id == -1 ? {issue_number: context.issue.number} : {comment_id: comment_id}) 98 }); 99 } else if (comment_id != -1) { 100 github.rest.issues.updateComment({ 101 owner: context.repo.owner, 102 repo: context.repo.repo, 103 comment_id: comment_id, 104 body: msg_prefix + "All issues resolved." 105 }); 106 } 107