Sync Issue to CSV #278
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Sync Issue to CSV | |
| on: | |
| issues: | |
| types: [opened, edited] | |
| issue_comment: | |
| types: [created] | |
| workflow_dispatch: | |
| permissions: | |
| issues: read | |
| contents: read | |
| jobs: | |
| sync: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v4 | |
| - name: Sync Issue to CSV | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| let csv = fs.existsSync('tasks.csv') | |
| ? fs.readFileSync('tasks.csv', 'utf8') | |
| : "Project,Repo,Issue,Owner,PR,Status,Source\n"; | |
| let lines = csv.split('\n').filter(line => line.trim() !== ''); | |
| const header = lines[0]; | |
| let rows = lines.slice(1); | |
| if (!context.payload.issue) { | |
| console.log("Skip (no issue)"); | |
| return; | |
| } | |
| const issue = context.payload.issue; | |
| const title = issue.title; | |
| const body = issue.body || ""; | |
| const issueNumber = issue.number; | |
| const issueUrl = `https://github.com/${owner}/${repo}/issues/${issueNumber}`; | |
| // ===== Repo ===== | |
| const repoMatch = body.match(/https:\/\/github\.com\/[^\s]+/); | |
| const repoUrl = repoMatch ? repoMatch[0] : ""; | |
| // ===== Owner ===== | |
| const ownerMatch = body.match(/Owner:\s*@([^\s]+)/); | |
| const taskOwner = ownerMatch ? ownerMatch[1] : ""; | |
| // ===== PR ===== | |
| const prMatch = body.match(/PR:\s*(https:\/\/[^\s]+)/); | |
| const prUrl = prMatch ? prMatch[1] : ""; | |
| // ===== Status ===== | |
| let status = prUrl ? "open" : ""; | |
| // ===== Source ===== | |
| const sourceMatch = body.match(/Source:\s*(\w+)/i); | |
| let source = sourceMatch ? sourceMatch[1].toLowerCase() : "official"; | |
| if (!["official", "community"].includes(source)) { | |
| source = "official"; | |
| } | |
| let found = false; | |
| rows = rows.map(row => { | |
| let parts = row.split(','); | |
| while (parts.length < 7) parts.push(''); | |
| if (parts[2] === issueUrl) { | |
| parts[3] = taskOwner; | |
| parts[4] = prUrl; | |
| parts[5] = status; | |
| parts[6] = source; | |
| found = true; | |
| } | |
| return parts.join(','); | |
| }); | |
| if (!found) { | |
| const project = title.replace("[Task]", "").trim(); | |
| const newRow = [ | |
| project, | |
| repoUrl, | |
| issueUrl, | |
| taskOwner, | |
| prUrl, | |
| status, | |
| source | |
| ].join(','); | |
| rows.push(newRow); | |
| } | |
| const newCsv = [header, ...rows].join('\n'); | |
| fs.writeFileSync('tasks.csv', newCsv); | |
| - name: Show CSV | |
| run: cat tasks.csv | |
| - name: Upload CSV artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: tasks-csv | |
| path: tasks.csv |