Maintenance #1
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: Maintenance | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "0 9 * * 1" # Weekly link check (Monday) | |
| - cron: "0 9 1 * *" # Monthly stale-entry review issue | |
| permissions: | |
| contents: read | |
| issues: write | |
| jobs: | |
| link-check: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Run link checker | |
| id: lychee | |
| continue-on-error: true | |
| run: | | |
| npx lychee \ | |
| --verbose \ | |
| --no-progress \ | |
| --max-concurrency 8 \ | |
| --accept 200,429 \ | |
| --format markdown \ | |
| README.md > lychee-report.md | |
| - name: Count dead links | |
| id: dead-links | |
| run: | | |
| if [ "${{ steps.lychee.outcome }}" = "success" ]; then | |
| echo "dead_count=0" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| dead_count=$(awk '/^\s*\[✗\]/{count++} END {print count+0}' lychee-report.md) | |
| echo "dead_count=${dead_count:-0}" >> "$GITHUB_OUTPUT" | |
| - name: Open or update dead-link issue | |
| if: steps.dead-links.outputs.dead_count != '0' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const fs = require("fs"); | |
| const title = "Automated dead link report"; | |
| const report = fs.readFileSync("lychee-report.md", "utf8"); | |
| const body = [ | |
| "## Dead links detected", | |
| "", | |
| `Detected by scheduled maintenance run on ${new Date().toISOString()}.`, | |
| "", | |
| `Dead links found: ${process.env.DEAD_COUNT}`, | |
| "", | |
| "### Report", | |
| "", | |
| report | |
| ].join("\n"); | |
| const { data: issues } = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: "open" | |
| }); | |
| const existing = issues.find((issue) => issue.title === title); | |
| if (existing) { | |
| await github.rest.issues.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: existing.number, | |
| body | |
| }); | |
| } else { | |
| await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title, | |
| body, | |
| labels: ["type:maintenance", "area:links", "priority:high"] | |
| }); | |
| } | |
| env: | |
| DEAD_COUNT: ${{ steps.dead-links.outputs.dead_count }} | |
| monthly-stale-entry-review: | |
| if: github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && github.event.schedule == '0 9 1 * *') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Open or update monthly stale-entry review issue | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const now = new Date().toISOString().slice(0, 10); | |
| const title = `Monthly stale entry review (${now.slice(0, 7)})`; | |
| const body = [ | |
| "## Monthly stale entry review", | |
| "", | |
| "Review the list for stale or lower-signal entries and open targeted clean-up PRs.", | |
| "", | |
| "### Checklist", | |
| "- [ ] Verify links for recently changed tooling websites.", | |
| "- [ ] Remove or replace deprecated, acquired, or sunset products.", | |
| "- [ ] Refresh descriptions that are no longer accurate.", | |
| "- [ ] Re-check category fit for newly added entries.", | |
| "- [ ] Mark reviewed entries with updated trust metadata.", | |
| "", | |
| "### Suggested labels", | |
| "- `type:maintenance`", | |
| "- `priority:medium`", | |
| "- `status:triage`" | |
| ].join("\\n"); | |
| await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title, | |
| body, | |
| labels: ["type:maintenance", "priority:medium", "status:triage"] | |
| }); |