mirror of
https://github.com/yaklang/yaklang-chrome-extension.git
synced 2026-09-22 03:10:43 +08:00
fix(ci): make release zips reproducible and bump version to 0.2.1
adm-zip stamps entries with file mtimes, i.e. the git checkout time on CI, so two builds of the same commit differed byte-wise and tripped the immutable no-overwrite guard on workflow re-runs. Pin every entry to the commit date (SOURCE_DATE_EPOCH convention) instead. 0.2.0 was never published (no manifest entry, no GitHub release), but a stale chrome-store zip from the first failed run occupies its immutable slot; move the release to 0.2.1 rather than deleting the object.
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
"name": "yakit-chrome-client",
|
"name": "yakit-chrome-client",
|
||||||
"description": "Yakit Browser Extension",
|
"description": "Yakit Browser Extension",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "[email protected]",
|
"packageManager": "[email protected]",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -67,12 +67,21 @@ const pkg = JSON.parse(await readFile(resolve(root, 'package.json'), 'utf8'));
|
|||||||
const { version } = pkg;
|
const { version } = pkg;
|
||||||
|
|
||||||
let commit = null;
|
let commit = null;
|
||||||
|
let commitTime = null;
|
||||||
try {
|
try {
|
||||||
const { stdout } = await execFileAsync('git', ['rev-parse', 'HEAD'], { cwd: root });
|
const { stdout } = await execFileAsync('git', ['rev-parse', 'HEAD'], { cwd: root });
|
||||||
commit = stdout.trim();
|
commit = stdout.trim();
|
||||||
|
const { stdout: iso } = await execFileAsync('git', ['show', '-s', '--format=%cI', 'HEAD'], { cwd: root });
|
||||||
|
commitTime = new Date(iso.trim());
|
||||||
} catch {
|
} catch {
|
||||||
// Not fatal: local runs outside a git worktree still package fine.
|
// Not fatal: local runs outside a git worktree still package fine.
|
||||||
}
|
}
|
||||||
|
// adm-zip stamps every entry with the file mtime, which is the checkout time
|
||||||
|
// on CI — two builds of the same commit would differ byte-wise and trip the
|
||||||
|
// immutable no-overwrite guard on re-runs. Pin all entries to the commit
|
||||||
|
// date (SOURCE_DATE_EPOCH convention) so artifacts are reproducible.
|
||||||
|
const sourceDateEpoch = Number(process.env.SOURCE_DATE_EPOCH)
|
||||||
|
|| (commitTime && !Number.isNaN(commitTime.getTime()) ? commitTime.getTime() : 0);
|
||||||
|
|
||||||
const versionDir = resolve(distDir, version);
|
const versionDir = resolve(distDir, version);
|
||||||
await mkdir(versionDir, { recursive: true });
|
await mkdir(versionDir, { recursive: true });
|
||||||
@@ -94,6 +103,8 @@ for (const target of VARIANTS) {
|
|||||||
// zip root, which is what browsers expect from a sideloaded extension.
|
// zip root, which is what browsers expect from a sideloaded extension.
|
||||||
const zip = new AdmZip();
|
const zip = new AdmZip();
|
||||||
zip.addLocalFolder(outputDir);
|
zip.addLocalFolder(outputDir);
|
||||||
|
const pinned = new Date(Math.floor(sourceDateEpoch / 2000) * 2000); // DOS time has 2s granularity
|
||||||
|
for (const entry of zip.getEntries()) entry.header.time = pinned;
|
||||||
await zip.writeZipPromise(zipPath);
|
await zip.writeZipPromise(zipPath);
|
||||||
const sha256 = await sha256File(zipPath);
|
const sha256 = await sha256File(zipPath);
|
||||||
const size = (await stat(zipPath)).size;
|
const size = (await stat(zipPath)).size;
|
||||||
|
|||||||
Reference in New Issue
Block a user