styleproof 4.4.6 → 4.4.8
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/CHANGELOG.md +25 -0
- package/bin/styleproof-init.mjs +2 -0
- package/dist/map-store.js +32 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,8 +7,33 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [4.4.8] - 2026-07-13
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Map-store restore now retrieves only the requested commit bundle.** Restore
|
|
15
|
+
clones branch metadata without a checkout, sparsely selects the requested SHA,
|
|
16
|
+
and, on partial-clone-capable remotes such as GitHub, downloads only that
|
|
17
|
+
bundle's blobs. Large long-lived map stores therefore no longer make every
|
|
18
|
+
cache lookup clone all historical bundles on supported remotes. Publishing
|
|
19
|
+
uses the same sparse checkout and stages only the requested bundle plus the
|
|
20
|
+
store README; Git's sparse index preserves unseen bundles without downloading
|
|
21
|
+
their blobs, so cache misses no longer materialise the complete store either.
|
|
22
|
+
|
|
23
|
+
## [4.4.7] - 2026-07-13
|
|
24
|
+
|
|
10
25
|
### Fixed
|
|
11
26
|
|
|
27
|
+
- **Generated CI authenticates map publication explicitly.** `styleproof-init`
|
|
28
|
+
passes the workflow's least-privilege `github.token` as
|
|
29
|
+
`STYLEPROOF_MAP_STORE_TOKEN`, so cold-cache uploads do not depend on private
|
|
30
|
+
`actions/checkout` credential-storage details. Local hooks continue to reuse
|
|
31
|
+
normal Git credentials without requiring this variable.
|
|
32
|
+
- **Map-store uploads now reuse credentials from `actions/checkout@v7`.**
|
|
33
|
+
Checkout v7 keeps its HTTP header in an included temporary config rather than
|
|
34
|
+
directly in `.git/config`; StyleProof now explicitly enables Git config includes
|
|
35
|
+
and falls back to its locally registered checkout config before carrying that
|
|
36
|
+
header into the isolated clone and push.
|
|
12
37
|
- **Map-store uploads now reuse credentials from `actions/checkout@v7`.**
|
|
13
38
|
Checkout v7 keeps its HTTP header in an included temporary config rather than
|
|
14
39
|
directly in `.git/config`; StyleProof now explicitly enables Git config includes
|
package/bin/styleproof-init.mjs
CHANGED
package/dist/map-store.js
CHANGED
|
@@ -69,7 +69,7 @@ function effectiveGitHttpExtraHeaders(cwd) {
|
|
|
69
69
|
if (effectiveHeaders.length > 0)
|
|
70
70
|
return effectiveHeaders;
|
|
71
71
|
const registeredIncludes = runGit(cwd, ['config', '--local', '--get-regexp', '^includeIf\\..*\\.path$'], 1 << 20);
|
|
72
|
-
|
|
72
|
+
const includedHeaders = registeredIncludes.stdout
|
|
73
73
|
.split('\n')
|
|
74
74
|
.filter(Boolean)
|
|
75
75
|
.flatMap((registeredInclude) => {
|
|
@@ -80,6 +80,17 @@ function effectiveGitHttpExtraHeaders(cwd) {
|
|
|
80
80
|
const includedHeaders = runGit(cwd, ['config', '--file', includedConfigPath, '--get-regexp', '^http\\..*\\.extraheader$'], 1 << 20);
|
|
81
81
|
return parseGitHttpExtraHeaders(includedHeaders.stdout);
|
|
82
82
|
});
|
|
83
|
+
if (includedHeaders.length > 0)
|
|
84
|
+
return includedHeaders;
|
|
85
|
+
const mapStoreToken = process.env.STYLEPROOF_MAP_STORE_TOKEN;
|
|
86
|
+
if (!mapStoreToken)
|
|
87
|
+
return [];
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
key: ['http.https:', '', 'github.com', '.extraheader'].join('/'),
|
|
91
|
+
value: `AUTHORIZATION: basic ${Buffer.from(`x-access-token:${mapStoreToken}`).toString('base64')}`,
|
|
92
|
+
},
|
|
93
|
+
];
|
|
83
94
|
}
|
|
84
95
|
function gitOutput(cwd, args) {
|
|
85
96
|
const r = runGit(cwd, args);
|
|
@@ -424,15 +435,27 @@ function copyDir(src, dest, includeHar) {
|
|
|
424
435
|
filter: (source) => includeHar || !source.endsWith('.har'),
|
|
425
436
|
});
|
|
426
437
|
}
|
|
427
|
-
function
|
|
438
|
+
function checkoutSparseSegment(tmp, branch, segment) {
|
|
439
|
+
const sparseCheckout = runGit(tmp, ['sparse-checkout', 'set', segment], 1 << 20);
|
|
440
|
+
const checkout = sparseCheckout.status === 0 ? runGit(tmp, ['checkout', '-q', branch], 1 << 20) : sparseCheckout;
|
|
441
|
+
if (checkout.status !== 0) {
|
|
442
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
443
|
+
throw new MapStoreError(checkout.stderr.trim() || `could not check out ${segment} from map store`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
function checkoutMapStore(cwd, remote, branch, sparseSegment) {
|
|
428
447
|
if (!remoteExists(remote, cwd))
|
|
429
448
|
throw new MapStoreError(`git remote ${remote} was not found`);
|
|
430
449
|
const remoteUrl = gitOutput(cwd, ['remote', 'get-url', remote]);
|
|
431
450
|
const httpExtraHeaders = effectiveGitHttpExtraHeaders(cwd);
|
|
432
451
|
const authenticationArguments = httpExtraHeaders.flatMap(({ key, value }) => ['-c', `${key}=${value}`]);
|
|
433
452
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'styleproof-map-store-'));
|
|
434
|
-
|
|
435
|
-
|
|
453
|
+
const branchExists = runGit(cwd, ['ls-remote', '--exit-code', '--heads', remote, branch], 1 << 20).status === 0;
|
|
454
|
+
if (branchExists) {
|
|
455
|
+
const cloneArguments = sparseSegment
|
|
456
|
+
? ['clone', '-q', '--filter=blob:none', '--no-checkout', '--depth', '1', '--single-branch', '--branch', branch]
|
|
457
|
+
: ['clone', '-q', '--depth', '1', '--branch', branch];
|
|
458
|
+
const clone = spawnSync('git', [...authenticationArguments, ...cloneArguments, remoteUrl, tmp], {
|
|
436
459
|
encoding: 'utf8',
|
|
437
460
|
maxBuffer: 1 << 20,
|
|
438
461
|
env: gitProcessEnvironment(),
|
|
@@ -448,6 +471,8 @@ function checkoutMapStore(cwd, remote, branch) {
|
|
|
448
471
|
}
|
|
449
472
|
for (const { key, value } of httpExtraHeaders)
|
|
450
473
|
runGit(tmp, ['config', '--local', key, value]);
|
|
474
|
+
if (sparseSegment && branchExists)
|
|
475
|
+
checkoutSparseSegment(tmp, branch, sparseSegment);
|
|
451
476
|
return tmp;
|
|
452
477
|
}
|
|
453
478
|
export function publishMapBundle(options) {
|
|
@@ -468,7 +493,7 @@ export function publishMapBundle(options) {
|
|
|
468
493
|
let ok = false;
|
|
469
494
|
let lastError = '';
|
|
470
495
|
for (let attempt = 1; attempt <= 5; attempt++) {
|
|
471
|
-
const tmp = checkoutMapStore(cwd, remote, branch);
|
|
496
|
+
const tmp = checkoutMapStore(cwd, remote, branch, sha);
|
|
472
497
|
try {
|
|
473
498
|
runGit(tmp, ['config', 'user.name', 'github-actions[bot]']);
|
|
474
499
|
runGit(tmp, ['config', 'user.email', '41898282+github-actions[bot]@users.noreply.github.com']);
|
|
@@ -478,7 +503,7 @@ export function publishMapBundle(options) {
|
|
|
478
503
|
if (!options.includeHar) {
|
|
479
504
|
fs.writeFileSync(path.join(tmp, target, MAP_MANIFEST), JSON.stringify({ ...manifest, har: false }, null, 2));
|
|
480
505
|
}
|
|
481
|
-
runGit(tmp, ['add', '-A']);
|
|
506
|
+
runGit(tmp, ['add', '-A', '--sparse', '--', 'README.md', target]);
|
|
482
507
|
runGit(tmp, ['commit', '-q', '-m', `StyleProof map ${sha.slice(0, 12)} ${compatibilityKey}`], 1 << 20);
|
|
483
508
|
const push = runGit(tmp, ['push', '-q', 'origin', `HEAD:${branch}`], 1 << 20);
|
|
484
509
|
if (push.status === 0) {
|
|
@@ -509,7 +534,7 @@ export function restoreMapBundle(options) {
|
|
|
509
534
|
if (runGit(cwd, ['ls-remote', '--exit-code', '--heads', remote, branch], 1 << 20).status !== 0) {
|
|
510
535
|
throw new MapStoreError(`map store branch ${branch} does not exist`);
|
|
511
536
|
}
|
|
512
|
-
const tmp = checkoutMapStore(cwd, remote, branch);
|
|
537
|
+
const tmp = checkoutMapStore(cwd, remote, branch, sha);
|
|
513
538
|
try {
|
|
514
539
|
const shaDir = path.join(tmp, sha);
|
|
515
540
|
if (!fs.existsSync(shaDir))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "styleproof",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.8",
|
|
4
4
|
"description": "Catch every CSS change before it ships — review PRs and certify refactors by the browser's computed styles, not pixels. Works with any styling system.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"playwright",
|