lockdelta 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -5
- package/action.yml +18 -2
- package/dist/{action.js → action.cjs} +722 -571
- package/dist/action.cjs.map +1 -0
- package/dist/cli.js +130 -37
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +130 -37
- package/dist/index.js.map +1 -1
- package/package.json +17 -13
- package/dist/action.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
import { writeFileSync } from "fs";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
|
|
7
|
-
// src/index.ts
|
|
8
|
-
import { readFileSync } from "fs";
|
|
9
|
-
|
|
10
7
|
// src/core/report.ts
|
|
11
8
|
import { posix as posix2 } from "path";
|
|
12
9
|
|
|
@@ -60,7 +57,7 @@ function parseDenoLock(content) {
|
|
|
60
57
|
const { name, version } = splitSpecifier(specifier);
|
|
61
58
|
const resultKey = key === "jsr" ? `jsr:${name}` : name;
|
|
62
59
|
if (name && version && !result[resultKey]) {
|
|
63
|
-
result[resultKey] = version;
|
|
60
|
+
result[resultKey] = { version };
|
|
64
61
|
}
|
|
65
62
|
}
|
|
66
63
|
}
|
|
@@ -139,7 +136,7 @@ function parseBunLock(content) {
|
|
|
139
136
|
if (typeof nameAtVersion !== "string") continue;
|
|
140
137
|
const version = extractVersion(nameAtVersion);
|
|
141
138
|
if (!version || version.startsWith("workspace:")) continue;
|
|
142
|
-
result[name] = version;
|
|
139
|
+
result[name] = { version };
|
|
143
140
|
}
|
|
144
141
|
return result;
|
|
145
142
|
}
|
|
@@ -174,7 +171,10 @@ function parseV2Packages(packages) {
|
|
|
174
171
|
const name = key.slice("node_modules/".length);
|
|
175
172
|
const pkgVersion = pkg.version;
|
|
176
173
|
if (pkgVersion && !result[name]) {
|
|
177
|
-
|
|
174
|
+
const entry = { version: pkgVersion };
|
|
175
|
+
const registryUrl = resolvedToOrigin(pkg.resolved);
|
|
176
|
+
if (registryUrl !== void 0) entry.registryUrl = registryUrl;
|
|
177
|
+
result[name] = entry;
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
return result;
|
|
@@ -182,7 +182,10 @@ function parseV2Packages(packages) {
|
|
|
182
182
|
function parseV1Dependencies(deps, result = {}) {
|
|
183
183
|
for (const [name, pkg] of Object.entries(deps)) {
|
|
184
184
|
if (pkg.version && !result[name]) {
|
|
185
|
-
|
|
185
|
+
const entry = { version: pkg.version };
|
|
186
|
+
const registryUrl = resolvedToOrigin(pkg.resolved);
|
|
187
|
+
if (registryUrl !== void 0) entry.registryUrl = registryUrl;
|
|
188
|
+
result[name] = entry;
|
|
186
189
|
}
|
|
187
190
|
if (pkg.dependencies) {
|
|
188
191
|
parseV1Dependencies(pkg.dependencies, result);
|
|
@@ -190,6 +193,14 @@ function parseV1Dependencies(deps, result = {}) {
|
|
|
190
193
|
}
|
|
191
194
|
return result;
|
|
192
195
|
}
|
|
196
|
+
function resolvedToOrigin(resolved) {
|
|
197
|
+
if (!resolved) return void 0;
|
|
198
|
+
try {
|
|
199
|
+
return new URL(resolved).origin;
|
|
200
|
+
} catch {
|
|
201
|
+
return void 0;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
193
204
|
|
|
194
205
|
// src/ecosystems/javascript/parsers/pnpm.ts
|
|
195
206
|
import { parse as parseYaml } from "yaml";
|
|
@@ -209,7 +220,7 @@ function parseLockfileVersion(v) {
|
|
|
209
220
|
}
|
|
210
221
|
function parsePnpmV9(packages) {
|
|
211
222
|
const result = {};
|
|
212
|
-
for (const key of Object.
|
|
223
|
+
for (const [key, value] of Object.entries(packages)) {
|
|
213
224
|
let name;
|
|
214
225
|
let version;
|
|
215
226
|
if (key.startsWith("@")) {
|
|
@@ -225,14 +236,18 @@ function parsePnpmV9(packages) {
|
|
|
225
236
|
}
|
|
226
237
|
version = stripVersionSuffix(version);
|
|
227
238
|
if (name && version && !result[name]) {
|
|
228
|
-
|
|
239
|
+
const entry = { version };
|
|
240
|
+
const pkg = value;
|
|
241
|
+
const registryUrl = pkg?.resolution?.tarball ? resolvedToOrigin2(pkg.resolution.tarball) : void 0;
|
|
242
|
+
if (registryUrl !== void 0) entry.registryUrl = registryUrl;
|
|
243
|
+
result[name] = entry;
|
|
229
244
|
}
|
|
230
245
|
}
|
|
231
246
|
return result;
|
|
232
247
|
}
|
|
233
248
|
function parsePnpmLegacy(packages) {
|
|
234
249
|
const result = {};
|
|
235
|
-
for (const key of Object.
|
|
250
|
+
for (const [key, value] of Object.entries(packages)) {
|
|
236
251
|
const cleaned = key.startsWith("/") ? key.slice(1) : key;
|
|
237
252
|
let name;
|
|
238
253
|
let version;
|
|
@@ -263,7 +278,11 @@ function parsePnpmLegacy(packages) {
|
|
|
263
278
|
}
|
|
264
279
|
version = stripVersionSuffix(version);
|
|
265
280
|
if (name && version && !result[name]) {
|
|
266
|
-
|
|
281
|
+
const entry = { version };
|
|
282
|
+
const pkg = value;
|
|
283
|
+
const registryUrl = pkg?.resolution?.tarball ? resolvedToOrigin2(pkg.resolution.tarball) : void 0;
|
|
284
|
+
if (registryUrl !== void 0) entry.registryUrl = registryUrl;
|
|
285
|
+
result[name] = entry;
|
|
267
286
|
}
|
|
268
287
|
}
|
|
269
288
|
return result;
|
|
@@ -271,6 +290,13 @@ function parsePnpmLegacy(packages) {
|
|
|
271
290
|
function stripVersionSuffix(version) {
|
|
272
291
|
return version.split("(")[0].split("_")[0].trim();
|
|
273
292
|
}
|
|
293
|
+
function resolvedToOrigin2(url) {
|
|
294
|
+
try {
|
|
295
|
+
return new URL(url).origin;
|
|
296
|
+
} catch {
|
|
297
|
+
return void 0;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
274
300
|
|
|
275
301
|
// src/ecosystems/javascript/parsers/yarn.ts
|
|
276
302
|
import { parse as parseYaml2 } from "yaml";
|
|
@@ -301,7 +327,13 @@ function parseYarnV1(content) {
|
|
|
301
327
|
const firstSpecifier = headerLine.split(",")[0].trim().replace(/^"|"$/g, "");
|
|
302
328
|
const name = extractNameFromSpecifier(firstSpecifier);
|
|
303
329
|
if (name && !packages[name]) {
|
|
304
|
-
|
|
330
|
+
const entry = { version: versionMatch[1] };
|
|
331
|
+
const resolvedMatch = trimmed.match(/^[ \t]+resolved "([^"]+)"/m);
|
|
332
|
+
if (resolvedMatch) {
|
|
333
|
+
const registryUrl = resolvedToOrigin3(resolvedMatch[1]);
|
|
334
|
+
if (registryUrl !== void 0) entry.registryUrl = registryUrl;
|
|
335
|
+
}
|
|
336
|
+
packages[name] = entry;
|
|
305
337
|
}
|
|
306
338
|
}
|
|
307
339
|
return packages;
|
|
@@ -312,13 +344,16 @@ function parseYarnBerry(content) {
|
|
|
312
344
|
for (const [key, value] of Object.entries(data)) {
|
|
313
345
|
if (key === "__metadata") continue;
|
|
314
346
|
if (typeof value !== "object" || !value) continue;
|
|
315
|
-
const
|
|
316
|
-
if (
|
|
317
|
-
if (!
|
|
347
|
+
const berryEntry = value;
|
|
348
|
+
if (berryEntry.linkType === "soft") continue;
|
|
349
|
+
if (!berryEntry.version) continue;
|
|
318
350
|
const cleanKey = key.replace(/^"|"$/g, "");
|
|
319
351
|
const name = extractNameFromBerryKey(cleanKey);
|
|
320
352
|
if (name && !packages[name]) {
|
|
321
|
-
|
|
353
|
+
const entry = { version: berryEntry.version };
|
|
354
|
+
const registryUrl = extractBerryRegistryOrigin(berryEntry.resolution);
|
|
355
|
+
if (registryUrl !== void 0) entry.registryUrl = registryUrl;
|
|
356
|
+
packages[name] = entry;
|
|
322
357
|
}
|
|
323
358
|
}
|
|
324
359
|
return packages;
|
|
@@ -330,6 +365,23 @@ function extractNameFromBerryKey(key) {
|
|
|
330
365
|
}
|
|
331
366
|
return key.split("@")[0];
|
|
332
367
|
}
|
|
368
|
+
function extractBerryRegistryOrigin(resolution) {
|
|
369
|
+
if (!resolution) return void 0;
|
|
370
|
+
const atIdx = resolution.startsWith("@") ? resolution.indexOf("@", 1) : resolution.indexOf("@");
|
|
371
|
+
if (atIdx < 0) return void 0;
|
|
372
|
+
const spec = resolution.slice(atIdx + 1);
|
|
373
|
+
if (spec.startsWith("http://") || spec.startsWith("https://")) {
|
|
374
|
+
return resolvedToOrigin3(spec.split("#")[0]);
|
|
375
|
+
}
|
|
376
|
+
return void 0;
|
|
377
|
+
}
|
|
378
|
+
function resolvedToOrigin3(url) {
|
|
379
|
+
try {
|
|
380
|
+
return new URL(url).origin;
|
|
381
|
+
} catch {
|
|
382
|
+
return void 0;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
333
385
|
|
|
334
386
|
// src/ecosystems/javascript/index.ts
|
|
335
387
|
var SUPPORTED_LOCKFILES2 = [
|
|
@@ -376,7 +428,15 @@ function parseTomlPackages(content) {
|
|
|
376
428
|
const packages = {};
|
|
377
429
|
for (const pkg of [...data.package ?? [], ...data.packages ?? []]) {
|
|
378
430
|
if (typeof pkg.name === "string" && typeof pkg.version === "string") {
|
|
379
|
-
|
|
431
|
+
const entry = { version: pkg.version };
|
|
432
|
+
const sourceUrl = typeof pkg.source?.registry === "string" ? pkg.source.registry : typeof pkg.source?.url === "string" ? pkg.source.url : void 0;
|
|
433
|
+
if (sourceUrl !== void 0) {
|
|
434
|
+
try {
|
|
435
|
+
entry.registryUrl = new URL(sourceUrl).origin;
|
|
436
|
+
} catch {
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
packages[pkg.name] = entry;
|
|
380
440
|
}
|
|
381
441
|
}
|
|
382
442
|
return packages;
|
|
@@ -391,7 +451,17 @@ function parseTomlPackagesRegex(content) {
|
|
|
391
451
|
const nameMatch = block.match(/\nname\s*=\s*"([^"]+)"/);
|
|
392
452
|
const versionMatch = block.match(/\nversion\s*=\s*"([^"]+)"/);
|
|
393
453
|
if (nameMatch && versionMatch) {
|
|
394
|
-
|
|
454
|
+
const entry = { version: versionMatch[1] };
|
|
455
|
+
const sourceRegistryMatch = block.match(/source\s*=\s*\{[^}]*registry\s*=\s*"([^"]+)"/);
|
|
456
|
+
const sourceUrlMatch = block.match(/\nurl\s*=\s*"([^"]+)"/);
|
|
457
|
+
const sourceUrl = sourceRegistryMatch?.[1] ?? sourceUrlMatch?.[1];
|
|
458
|
+
if (sourceUrl !== void 0) {
|
|
459
|
+
try {
|
|
460
|
+
entry.registryUrl = new URL(sourceUrl).origin;
|
|
461
|
+
} catch {
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
packages[nameMatch[1]] = entry;
|
|
395
465
|
}
|
|
396
466
|
}
|
|
397
467
|
return packages;
|
|
@@ -542,18 +612,23 @@ function diffPackages(oldPkgs, newPkgs, directDeps, normalizeName) {
|
|
|
542
612
|
for (const name of [...allNames].sort()) {
|
|
543
613
|
const inOld = name in oldPkgs;
|
|
544
614
|
const inNew = name in newPkgs;
|
|
545
|
-
if (inOld && inNew && oldPkgs[name] === newPkgs[name]) continue;
|
|
615
|
+
if (inOld && inNew && oldPkgs[name].version === newPkgs[name].version) continue;
|
|
546
616
|
const normalized = normalizeName(name);
|
|
547
617
|
const isProd = directDeps.prod.has(normalized);
|
|
548
618
|
const isDev = directDeps.dev.has(normalized) && !isProd;
|
|
549
|
-
|
|
619
|
+
const change = {
|
|
550
620
|
name,
|
|
551
621
|
change_type: !inOld ? "added" : !inNew ? "removed" : "updated",
|
|
552
|
-
old_version: inOld ? oldPkgs[name] : null,
|
|
553
|
-
new_version: inNew ? newPkgs[name] : null,
|
|
622
|
+
old_version: inOld ? oldPkgs[name].version : null,
|
|
623
|
+
new_version: inNew ? newPkgs[name].version : null,
|
|
554
624
|
is_direct: isProd || isDev,
|
|
555
625
|
is_dev: isDev
|
|
556
|
-
}
|
|
626
|
+
};
|
|
627
|
+
const oldRegistryUrl = inOld ? oldPkgs[name].registryUrl : void 0;
|
|
628
|
+
const newRegistryUrl = inNew ? newPkgs[name].registryUrl : void 0;
|
|
629
|
+
if (oldRegistryUrl !== void 0) change.old_registry_url = oldRegistryUrl;
|
|
630
|
+
if (newRegistryUrl !== void 0) change.new_registry_url = newRegistryUrl;
|
|
631
|
+
changes.push(change);
|
|
557
632
|
}
|
|
558
633
|
return changes;
|
|
559
634
|
}
|
|
@@ -796,14 +871,29 @@ function gitLsTree(ref) {
|
|
|
796
871
|
// src/sources/github.ts
|
|
797
872
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
798
873
|
var API_BASE = "https://api.github.com";
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
if (
|
|
802
|
-
|
|
874
|
+
var cachedToken;
|
|
875
|
+
function resolveToken() {
|
|
876
|
+
if (cachedToken) return cachedToken;
|
|
877
|
+
if (process.env.GITHUB_TOKEN) {
|
|
878
|
+
cachedToken = process.env.GITHUB_TOKEN;
|
|
879
|
+
return cachedToken;
|
|
880
|
+
}
|
|
881
|
+
try {
|
|
882
|
+
const t = execFileSync2("gh", ["auth", "token"], {
|
|
883
|
+
encoding: "utf-8",
|
|
884
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
885
|
+
}).trim();
|
|
886
|
+
if (t) {
|
|
887
|
+
cachedToken = t;
|
|
888
|
+
return cachedToken;
|
|
889
|
+
}
|
|
890
|
+
} catch {
|
|
891
|
+
}
|
|
892
|
+
throw new Error("No GitHub token found. Set GITHUB_TOKEN or run `gh auth login`.");
|
|
803
893
|
}
|
|
804
894
|
function headers(accept = "application/vnd.github+json") {
|
|
805
895
|
return {
|
|
806
|
-
Authorization: `Bearer ${
|
|
896
|
+
Authorization: `Bearer ${resolveToken()}`,
|
|
807
897
|
Accept: accept,
|
|
808
898
|
"X-GitHub-Api-Version": "2022-11-28"
|
|
809
899
|
};
|
|
@@ -847,6 +937,16 @@ function detectRepo() {
|
|
|
847
937
|
throw new Error("Could not detect GitHub repo \u2014 set GITHUB_REPOSITORY or pass --repo");
|
|
848
938
|
}
|
|
849
939
|
|
|
940
|
+
// src/sources/local.ts
|
|
941
|
+
import { readFileSync } from "fs";
|
|
942
|
+
function readLocalFile(path) {
|
|
943
|
+
try {
|
|
944
|
+
return readFileSync(path, "utf-8");
|
|
945
|
+
} catch {
|
|
946
|
+
return null;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
850
950
|
// src/index.ts
|
|
851
951
|
async function resolveApiShas(options) {
|
|
852
952
|
if (options.baseSha && options.headSha) {
|
|
@@ -868,15 +968,8 @@ async function run(options = {}) {
|
|
|
868
968
|
if (options.oldFile && options.newFile) {
|
|
869
969
|
const oldPath = options.oldFile;
|
|
870
970
|
const newPath = options.newFile;
|
|
871
|
-
const
|
|
872
|
-
|
|
873
|
-
return readFileSync(filePath, "utf-8");
|
|
874
|
-
} catch {
|
|
875
|
-
return null;
|
|
876
|
-
}
|
|
877
|
-
};
|
|
878
|
-
const getBase2 = (path) => Promise.resolve(path === oldPath ? readLocal(oldPath) : null);
|
|
879
|
-
const getHead2 = (path) => Promise.resolve(path === newPath ? readLocal(newPath) : null);
|
|
971
|
+
const getBase2 = (path) => Promise.resolve(path === oldPath ? readLocalFile(oldPath) : null);
|
|
972
|
+
const getHead2 = (path) => Promise.resolve(path === newPath ? readLocalFile(newPath) : null);
|
|
880
973
|
const lockfiles2 = await collectLockfileEntries({
|
|
881
974
|
getBase: getBase2,
|
|
882
975
|
getHead: getHead2,
|