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