-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathbuild-post.ts
140 lines (115 loc) · 3.74 KB
/
build-post.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import spawn from "cross-spawn";
import crx3 from "crx3";
import type { EventEmitter } from "events";
import fs from "fs";
import path from "path";
import readdirp from "readdirp";
import { ZipFile } from "yazl";
import config from "../project.config";
const BASE_DIR = path.join(__dirname, "..");
const DIST = path.join(BASE_DIR, config.dist);
const DIST_FILE_BASE = path.join(DIST, config.meta.webExtBaseName);
const ZIP_FILE = `${DIST_FILE_BASE}.zip`;
const XPI_FILE = `${DIST_FILE_BASE}.xpi`;
const CRX_FILE = `${DIST_FILE_BASE}.crx`;
const KEY_FILE = path.join(DIST, "key.pem");
const SOURCE_CODE_FILE = path.join(DIST, "source.zip");
async function run(): Promise<void> {
switch (config.browser) {
case "chrome":
await crx3(fs.createReadStream(ZIP_FILE), {
keyPath: KEY_FILE,
crxPath: CRX_FILE,
});
console.log("Created .crx file:", relative(CRX_FILE));
console.log("Using key:", relative(KEY_FILE));
break;
case "firefox":
fs.copyFileSync(ZIP_FILE, XPI_FILE);
await makeSourceCodeBundle();
console.log("Created .xpi file:", relative(XPI_FILE));
console.log("Created source code bundle:", relative(SOURCE_CODE_FILE));
break;
case undefined:
throw new Error(
`Invalid BROWSER environment variable: ${String(process.env.BROWSER)}`
);
}
}
function relative(filePath: string): string {
return path.relative(BASE_DIR, filePath);
}
async function makeSourceCodeBundle(): Promise<void> {
const files = [
".eslintignore",
".eslintrc.js",
".prettierignore",
".prettierrc.json",
"LICENSE",
"package-lock.json",
"package.json",
"project.config.ts",
"rollup.config.js",
"tsconfig.json",
"web-ext-config.cjs",
].map((file) => path.join(BASE_DIR, file));
const dirs = ["@types", "docs", "patches", "scripts", "src"];
const asyncFiles = await Promise.all(
dirs.map((dir) => getAllFilesInDir(dir))
);
const allFiles = files.concat(...asyncFiles);
// `ZipFile` extends `EventEmitter`, but that’s missing in the type definition.
const zip = new ZipFile() as EventEmitter & ZipFile;
zip.addBuffer(Buffer.from(makeSourceCodeReadme()), "README.md");
for (const file of allFiles) {
zip.addFile(file, path.relative(BASE_DIR, file));
}
zip.end();
return new Promise((resolve, reject) => {
const writeStream = fs.createWriteStream(SOURCE_CODE_FILE);
writeStream.on("finish", resolve);
writeStream.on("error", reject);
zip.on("error", reject);
zip.outputStream.pipe(writeStream);
});
}
function makeSourceCodeReadme(): string {
return `
Steps to reproduce this build:
1. Install [Node.js] 18 with npm 8.
2. Run \`npm ci\`.
3. Run \`npm run build:firefox\`.
4. Output is now available in \`dist-firefox/\`.
Commit: ${getGitCommit()}
Repo: ${config.meta.repo}
[node.js]: https://nodejs.org/
`.replace(/^ *\n| *$/g, "");
}
function getGitCommit(): string {
const result = spawn.sync("git", ["rev-parse", "HEAD"], {
encoding: "utf-8",
});
// The type annotation says `.error` is optional, but it seems to be set to
// `null` on success.
if (result.error !== null && result.error !== undefined) {
throw result.error;
}
if (result.stderr !== "") {
if (result.stderr.includes("not a git repository")) {
return "(outside git repository)";
}
throw new Error(result.stderr);
}
return result.stdout.toString().trim();
}
async function getAllFilesInDir(dir: string): Promise<Array<string>> {
const results = await readdirp.promise(dir);
return results.map(({ fullPath }) => fullPath);
}
run().catch((error: Error) => {
console.error(
"Failed to run post build operations. Remember to build first!"
);
console.error(error.message);
process.exit(1);
});