Create and run build.js

This commit is contained in:
Sander Declerck 2025-11-28 10:51:43 +01:00
parent 98231b8d25
commit 9c149f3bb3
No known key found for this signature in database
7 changed files with 126 additions and 37 deletions

View file

@ -3,9 +3,7 @@ name: Create binaries
on: pull_request
jobs:
create-binaries:
name: Create binary for ${{ matrix.os }}-${{ matrix.arch }}
runs-on: ${{ matrix.runner }}
@ -17,32 +15,32 @@ jobs:
arch: x64
runner: macos-15-intel
target: node22-macos-x64
extension: ''
extension: ""
- os: macos
arch: arm64
runner: macos-latest
target: node22-macos-arm64
extension: ''
extension: ""
- os: linux
arch: x64
runner: ubuntu-latest
target: node22-linux-x64
extension: ''
extension: ""
- os: linux
arch: arm64
runner: ubuntu-24.04-arm
target: node22-linux-arm64
extension: ''
extension: ""
- os: win
arch: x64
runner: windows-latest
target: node22-win-x64
extension: '.exe'
extension: ".exe"
- os: win
arch: arm64
runner: windows-11-arm
target: node22-win-arm64
extension: '.exe'
extension: ".exe"
steps:
- name: Checkout code
@ -51,10 +49,9 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: "lts/*"
node-version: "22.x"
- name: Setup safe-chain
if: matrix.os != 'win'
run: |
npm i -g @aikidosec/safe-chain
safe-chain setup-ci
@ -65,23 +62,10 @@ jobs:
- name: Create binary (Unix)
if: matrix.os != 'win'
run: |
npm i -g esbuild@0.27.0 @yao-pkg/pkg@6.10.1
mkdir -p "dist/${{ matrix.os }}-${{ matrix.arch }}"
esbuild "./packages/safe-chain/bin/safe-chain.js" --bundle --platform=node --target=node22 > "./dist/safe-chain.cjs"
pkg "./dist/safe-chain.cjs" --targets ${{ matrix.target }} --output "./dist/${{ matrix.os }}-${{ matrix.arch }}/safe-chain${{ matrix.extension }}"
shell: bash
- name: Create binary (Windows)
if: matrix.os == 'win'
run: |
npm i -g esbuild@0.27.0 @yao-pkg/pkg@6.10.1
New-Item -ItemType Directory -Force -Path "dist/${{ matrix.os }}-${{ matrix.arch }}"
esbuild "./packages/safe-chain/bin/safe-chain.js" --bundle --platform=node --target=node22 | Out-File -FilePath "./dist/safe-chain.cjs" -Encoding utf8
pkg "./dist/safe-chain.cjs" --targets ${{ matrix.target }} --output "./dist/${{ matrix.os }}-${{ matrix.arch }}/safe-chain${{ matrix.extension }}"
shell: powershell
node build.js ${{ matrix.target }}
- name: Upload binary artifact
uses: actions/upload-artifact@v4
with:
name: safe-chain-${{ matrix.os }}-${{ matrix.arch }}
path: dist/${{ matrix.os }}-${{ matrix.arch }}/*
path: dist/*

4
.gitignore vendored
View file

@ -144,3 +144,7 @@ vite.config.ts.timestamp-*
Claude.md
.claude
.reference
# Build files
build/
dist/

90
build.js Normal file
View file

@ -0,0 +1,90 @@
import { build } from "esbuild";
import { mkdir, cp, rm, readFile, writeFile } from "node:fs/promises";
import { spawn } from "node:child_process";
const target = process.argv[2];
if (!target) {
// eslint-disable-next-line no-console
console.error("Usage: node build.js <target>");
// eslint-disable-next-line no-console
console.error("Example: node build.js node22-macos-arm64");
process.exit(1);
}
(async function () {
await clearOutputFolder();
await bundleSafeChain();
await copyShellScripts();
await copyAndModifyPackageJson();
await buildSafeChainBinary(target);
})();
async function clearOutputFolder() {
await rm("./build", { recursive: true, force: true });
await mkdir("./build");
}
async function bundleSafeChain() {
await build({
entryPoints: ["./packages/safe-chain/bin/safe-chain.js"],
bundle: true,
platform: "node",
target: "node22",
outfile: "./build/bin/safe-chain.cjs",
});
}
async function copyShellScripts() {
await mkdir("./build/bin/startup-scripts", { recursive: true });
await cp(
"./packages/safe-chain/src/shell-integration/startup-scripts/",
"./build/bin/startup-scripts",
{ recursive: true }
);
}
async function copyAndModifyPackageJson() {
const packageJsonContent = await readFile(
"./packages/safe-chain/package.json",
"utf-8"
);
const packageJson = JSON.parse(packageJsonContent);
delete packageJson.main;
delete packageJson.scripts;
delete packageJson.exports;
delete packageJson.dependencies;
delete packageJson.devDependencies;
packageJson.bin = {
"safe-chain": "bin/safe-chain.cjs",
};
packageJson.type = "commonjs";
packageJson.pkg = {
outputPath: "dist",
assets: ["node_modules/certifi/**/*", "bin/startup-scripts/**/*"],
};
await writeFile("./build/package.json", JSON.stringify(packageJson, null, 2));
return packageJson;
}
function buildSafeChainBinary(target) {
return new Promise((resolve, reject) => {
const pkg = spawn(
"npx",
["pkg", "./build/package.json", `--target=${target}`],
{
stdio: "inherit",
}
);
pkg.on("close", (code) => {
if (code !== 0) {
reject(new Error(`pkg process exited with code ${code}`));
} else {
resolve();
}
});
});
}

1
package-lock.json generated
View file

@ -12,6 +12,7 @@
"test/e2e"
],
"devDependencies": {
"esbuild": "^0.27.0",
"oxlint": "^1.22.0"
}
},

View file

@ -19,6 +19,7 @@
"author": "Aikido Security",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"oxlint": "^1.22.0"
"oxlint": "^1.22.0",
"esbuild": "^0.27.0"
}
}

View file

@ -1,7 +1,6 @@
#!/usr/bin/env node
import chalk from "chalk";
import { createRequire } from "module";
import { ui } from "../src/environment/userInteraction.js";
import { setup } from "../src/shell-integration/setup.js";
import { teardown } from "../src/shell-integration/teardown.js";
@ -10,6 +9,8 @@ import { initializeCliArguments } from "../src/config/cliArguments.js";
import { ECOSYSTEM_JS, setEcoSystem } from "../src/config/settings.js";
import { initializePackageManager } from "../src/packagemanager/currentPackageManager.js";
import { main } from "../src/main.js";
import path from "path";
import fs from "fs";
if (process.argv.length < 3) {
ui.writeError("No command provided. Please provide a command to execute.");
@ -25,6 +26,7 @@ const command = process.argv[2];
const pkgManagerCommands = ["npm", "npx", "yarn"];
if (pkgManagerCommands.includes(command)) {
ui.writeInformation(process.argv.join(", "));
setEcoSystem(ECOSYSTEM_JS);
initializePackageManager(command);
(async () => {
@ -41,7 +43,9 @@ if (pkgManagerCommands.includes(command)) {
} else if (command === "setup-ci") {
setupCi();
} else if (command === "--version" || command === "-v" || command === "-v") {
ui.writeInformation(`Current safe-chain version: ${getVersion()}`);
(async () => {
ui.writeInformation(`Current safe-chain version: ${await getVersion()}`);
})();
} else {
ui.writeError(`Unknown command: ${command}.`);
ui.emptyLine();
@ -97,8 +101,15 @@ function writeHelp() {
ui.emptyLine();
}
function getVersion() {
const require = createRequire(import.meta.url);
const packageJson = require("../package.json");
return packageJson.version;
async function getVersion() {
const packageJsonPath = path.join(__dirname, "..", "package.json");
const data = await fs.promises.readFile(packageJsonPath);
const json = JSON.parse(data.toString("utf8"));
if (json && json.version) {
return json.version;
}
return "1.0.0";
}

View file

@ -103,9 +103,7 @@ function copyStartupFiles() {
}
// Use absolute path for source
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const sourcePath = path.resolve(
const sourcePath = path.join(
__dirname,
includePython() ? "startup-scripts/include-python" : "startup-scripts",
file