Dependency Audit #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: Dependency Audit | |
| on: | |
| schedule: | |
| - cron: "0 9 * * 1" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| issues: write | |
| jobs: | |
| audit: | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version-file: package.json | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: package.json | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Dependency tree | |
| run: bun pm ls --all | |
| - name: Check for outdated packages | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const { execSync } = require("child_process"); | |
| let result = {}; | |
| try { | |
| const output = execSync("bunx npm-check-updates --jsonUpgraded", { | |
| encoding: "utf-8", | |
| }); | |
| result = JSON.parse(output); | |
| } catch (error) { | |
| // npm-check-updates exits non-zero when updates are found | |
| try { | |
| result = JSON.parse(error.stdout); | |
| } catch { | |
| core.warning("Failed to parse npm-check-updates output"); | |
| return; | |
| } | |
| } | |
| const packages = Object.entries(result); | |
| if (packages.length === 0) { | |
| core.info("All dependencies are up to date."); | |
| await core.summary | |
| .addHeading("Dependency Audit", 2) | |
| .addRaw("All dependencies are up to date.") | |
| .write(); | |
| return; | |
| } | |
| const rows = packages.map(([name, version]) => [name, version]); | |
| const table = rows | |
| .map(([name, version]) => `| ${name} | ${version} |`) | |
| .join("\n"); | |
| const summaryBody = [ | |
| "## Dependency Audit", | |
| "", | |
| `Found **${packages.length}** outdated package(s):`, | |
| "", | |
| "| Package | Latest |", | |
| "| --- | --- |", | |
| table, | |
| ].join("\n"); | |
| await core.summary.addRaw(summaryBody).write(); | |
| // Determine if any updates look critical (major version bumps) | |
| const critical = packages.filter(([, version]) => { | |
| // npm-check-updates prefixes with ^ or ~ — strip to compare | |
| const clean = version.replace(/^[\^~]/, ""); | |
| const major = parseInt(clean.split(".")[0], 10); | |
| return major > 0; // heuristic: flag all for issue creation | |
| }); | |
| if (critical.length === 0) { | |
| return; | |
| } | |
| // Create or update a GitHub issue | |
| const issueTitle = "Dependency Audit: outdated packages found"; | |
| const issueBody = [ | |
| "The weekly dependency audit found outdated packages.", | |
| "", | |
| "| Package | Latest |", | |
| "| --- | --- |", | |
| table, | |
| "", | |
| `_Generated by the Dependency Audit workflow on ${new Date().toISOString().split("T")[0]}._`, | |
| ].join("\n"); | |
| const { data: issues } = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| labels: "dependencies", | |
| state: "open", | |
| per_page: 1, | |
| }); | |
| if (issues.length > 0) { | |
| await github.rest.issues.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issues[0].number, | |
| body: issueBody, | |
| }); | |
| core.info(`Updated existing issue #${issues[0].number}`); | |
| } else { | |
| const { data: created } = await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: issueTitle, | |
| body: issueBody, | |
| labels: ["dependencies"], | |
| }); | |
| core.info(`Created issue #${created.number}`); | |
| } |