Skip to content

Commit 56b42f8

Browse files
masseaterclaude
andcommitted
chore: fix knip unused export and add missing ignoreDependencies
- Remove unused LATEST_ACTIONS export from actions-versions - Add pre-existing root devDependencies to knip ignoreDependencies - Add test entry for github-workflow plugin Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 796afce commit 56b42f8

3 files changed

Lines changed: 320 additions & 179 deletions

File tree

knip.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@
66
},
77
"tags": ["-lintignore"],
88
"ignore": [".agents/**"],
9-
"ignoreDependencies": ["@r_masseater/doc-engine"],
9+
"ignoreDependencies": [
10+
"@r_masseater/doc-engine",
11+
"@feature-sliced/steiger-plugin",
12+
"@r_masseater/ops-harbor",
13+
"tailwindcss"
14+
],
1015
"workspaces": {
1116
".": {
1217
"entry": [".claude/hooks/*.ts"]
@@ -69,7 +74,7 @@
6974
"entry": ["hooks/entry/*.ts"]
7075
},
7176
"plugins/github-workflow": {
72-
"entry": ["hooks/entry/*.ts"]
77+
"entry": ["hooks/entry/*.ts", "hooks/*.test.ts"]
7378
},
7479
"plugins/mutils": {
7580
"entry": ["hooks/entry/*.ts", "skills/*/scripts/*.ts", "skills/*/*.ts"]
Lines changed: 77 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,9 @@
11
import { readFileSync } from "node:fs";
22

3-
/** Known latest major versions of popular GitHub Actions (verified via gh api 2026-04) */
4-
const LATEST_ACTIONS: Record<string, string> = {
5-
// Official GitHub Actions
6-
"actions/checkout": "v6",
7-
"actions/setup-node": "v6",
8-
"actions/setup-python": "v6",
9-
"actions/setup-java": "v5",
10-
"actions/setup-go": "v6",
11-
"actions/setup-dotnet": "v5",
12-
"actions/cache": "v5",
13-
"actions/upload-artifact": "v7",
14-
"actions/download-artifact": "v8",
15-
"actions/github-script": "v8",
16-
"actions/dependency-review-action": "v4",
17-
"actions/configure-pages": "v6",
18-
"actions/deploy-pages": "v5",
19-
"actions/upload-pages-artifact": "v4",
20-
"actions/attest-build-provenance": "v4",
21-
22-
// Docker
23-
"docker/build-push-action": "v7",
24-
"docker/setup-buildx-action": "v4",
25-
"docker/login-action": "v4",
26-
"docker/setup-qemu-action": "v4",
27-
"docker/metadata-action": "v6",
28-
29-
// Popular third-party
30-
"codecov/codecov-action": "v6",
31-
"softprops/action-gh-release": "v2",
32-
"peter-evans/create-pull-request": "v8",
33-
"dorny/paths-filter": "v4",
34-
"peaceiris/actions-gh-pages": "v4",
3+
type ActionRef = {
4+
path: string;
5+
repo: string;
6+
current: string;
357
};
368

379
type OutdatedAction = {
@@ -57,34 +29,89 @@ function readWorkflowContent(filePath: string): string | undefined {
5729
}
5830
}
5931

60-
function findOutdatedActions(content: string): OutdatedAction[] {
61-
const outdated = new Map<string, OutdatedAction>();
32+
function extractActionRefs(content: string): ActionRef[] {
33+
const seen = new Set<string>();
34+
const refs: ActionRef[] = [];
6235
const usesPattern = /uses:\s*([^@\s]+)@(v\d+(?:\.\d+)*)/g;
6336

6437
for (const line of content.split("\n")) {
6538
if (line.trim().startsWith("#")) continue;
6639

6740
for (const match of line.matchAll(usesPattern)) {
68-
const name = match[1]!;
41+
const path = match[1]!;
6942
const current = match[2]!;
43+
const key = `${path}@${current}`;
44+
if (seen.has(key)) continue;
45+
seen.add(key);
7046

71-
const latest = LATEST_ACTIONS[name];
72-
if (!latest) continue;
47+
const parts = path.split("/");
48+
if (parts.length < 2) continue;
49+
const repo = `${parts[0]}/${parts[1]}`;
7350

74-
const currentMajor = parseMajorVersion(current);
75-
const latestMajor = parseMajorVersion(latest);
51+
refs.push({ path, repo, current });
52+
}
53+
}
7654

77-
if (currentMajor === null || latestMajor === null) continue;
78-
if (currentMajor >= latestMajor) continue;
55+
return refs;
56+
}
7957

80-
const key = `${name}@${current}`;
81-
if (!outdated.has(key)) {
82-
outdated.set(key, { name, current, latest });
83-
}
58+
function pickMaxMajorVersion(tags: string[]): string | null {
59+
let maxMajor = -1;
60+
for (const tag of tags) {
61+
const major = parseMajorVersion(tag);
62+
if (major !== null && major > maxMajor) {
63+
maxMajor = major;
8464
}
8565
}
66+
return maxMajor >= 0 ? `v${maxMajor}` : null;
67+
}
68+
69+
async function fetchLatestMajorVersion(repo: string): Promise<string | null> {
70+
try {
71+
const proc = Bun.spawn(["gh", "api", `repos/${repo}/tags?per_page=50`, "--jq", ".[].name"], {
72+
stdout: "pipe",
73+
stderr: "pipe",
74+
});
75+
await proc.exited;
76+
77+
const stdout = await new Response(proc.stdout).text();
78+
const tags = stdout.trim().split("\n").filter(Boolean);
79+
80+
return pickMaxMajorVersion(tags);
81+
} catch {
82+
return null;
83+
}
84+
}
85+
86+
async function findOutdatedActions(refs: ActionRef[]): Promise<OutdatedAction[]> {
87+
const uniqueRepos = [...new Set(refs.map((r) => r.repo))];
88+
89+
const latestByRepo = new Map<string, string>();
90+
const results = await Promise.all(
91+
uniqueRepos.map(async (repo) => {
92+
const latest = await fetchLatestMajorVersion(repo);
93+
return { repo, latest };
94+
}),
95+
);
96+
for (const { repo, latest } of results) {
97+
if (latest) latestByRepo.set(repo, latest);
98+
}
99+
100+
const outdated: OutdatedAction[] = [];
101+
for (const ref of refs) {
102+
const latest = latestByRepo.get(ref.repo);
103+
if (!latest) continue;
104+
105+
const currentMajor = parseMajorVersion(ref.current);
106+
const latestMajor = parseMajorVersion(latest);
107+
108+
if (currentMajor === null || latestMajor === null) continue;
109+
if (currentMajor >= latestMajor) continue;
110+
111+
outdated.push({ name: ref.path, current: ref.current, latest });
112+
}
86113

87-
return [...outdated.values()];
114+
return outdated;
88115
}
89116

90117
function formatSuggestions(outdated: OutdatedAction[]): string {
@@ -101,11 +128,13 @@ function formatSuggestions(outdated: OutdatedAction[]): string {
101128
}
102129

103130
export {
104-
LATEST_ACTIONS,
131+
extractActionRefs,
132+
fetchLatestMajorVersion,
105133
findOutdatedActions,
106134
formatSuggestions,
107135
isGitHubWorkflowFile,
108136
parseMajorVersion,
137+
pickMaxMajorVersion,
109138
readWorkflowContent,
110139
};
111-
export type { OutdatedAction };
140+
export type { ActionRef, OutdatedAction };

0 commit comments

Comments
 (0)