🎨 Simplify test usage and change names
This commit is contained in:
2
.github/workflows/pake-cli.yaml
vendored
2
.github/workflows/pake-cli.yaml
vendored
@@ -144,7 +144,7 @@ jobs:
|
||||
- name: Build with pake-cli
|
||||
timeout-minutes: 15
|
||||
run: |
|
||||
node ./script/build_with_pake_cli.js
|
||||
node ./script/github-action-build.js
|
||||
env:
|
||||
URL: ${{ inputs.url }}
|
||||
NAME: ${{ inputs.name }}
|
||||
|
||||
2
dist/cli.js
vendored
2
dist/cli.js
vendored
@@ -56,7 +56,7 @@ var scripts = {
|
||||
build: "npm run tauri build --",
|
||||
"build:debug": "npm run tauri build -- --debug",
|
||||
"build:mac": "npm run tauri build -- --target universal-apple-darwin",
|
||||
"build:config": "chmod +x script/app_config.mjs && node script/app_config.mjs",
|
||||
"build:config": "chmod +x script/configure-tauri.mjs && node script/configure-tauri.mjs",
|
||||
analyze: "cd src-tauri && cargo bloat --release --crates",
|
||||
tauri: "tauri",
|
||||
cli: "cross-env NODE_ENV=development rollup -c -w",
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pake-cli",
|
||||
"version": "3.2.8",
|
||||
"version": "3.2.11",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pake-cli",
|
||||
"version": "3.2.8",
|
||||
"version": "3.2.11",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.8.0",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"build": "npm run tauri build --",
|
||||
"build:debug": "npm run tauri build -- --debug",
|
||||
"build:mac": "npm run tauri build -- --target universal-apple-darwin",
|
||||
"build:config": "chmod +x script/app_config.mjs && node script/app_config.mjs",
|
||||
"build:config": "chmod +x script/configure-tauri.mjs && node script/configure-tauri.mjs",
|
||||
"analyze": "cd src-tauri && cargo bloat --release --crates",
|
||||
"tauri": "tauri",
|
||||
"cli": "cross-env NODE_ENV=development rollup -c -w",
|
||||
|
||||
188
script/app_config.mjs
vendored
188
script/app_config.mjs
vendored
@@ -1,188 +0,0 @@
|
||||
import pakeJson from "../src-tauri/pake.json" assert { type: "json" };
|
||||
import tauriJson from "../src-tauri/tauri.conf.json" assert { type: "json" };
|
||||
import windowsJson from "../src-tauri/tauri.windows.conf.json" assert { type: "json" };
|
||||
import macosJson from "../src-tauri/tauri.macos.conf.json" assert { type: "json" };
|
||||
import linuxJson from "../src-tauri/tauri.linux.conf.json" assert { type: "json" };
|
||||
|
||||
import { writeFileSync, existsSync, copyFileSync } from "fs";
|
||||
import os from "os";
|
||||
|
||||
const desktopEntry = `[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Categories=Office
|
||||
Exec=com-pake-${process.env.NAME}
|
||||
Icon=com-pake-${process.env.NAME}
|
||||
Name=com-pake-${process.env.NAME}
|
||||
Name[zh_CN]=${process.env.NAME_ZH}
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
Type=Application
|
||||
`;
|
||||
|
||||
const variables = {
|
||||
url: process.env.URL,
|
||||
name: process.env.NAME,
|
||||
title: process.env.TITLE,
|
||||
nameZh: process.env.NAME_ZH,
|
||||
|
||||
pakeConfigPath: "src-tauri/pake.json",
|
||||
tauriConfigPath: "src-tauri/tauri.conf.json",
|
||||
identifier: `com.pake.${process.env.NAME}`,
|
||||
|
||||
linux: {
|
||||
configFilePath: "src-tauri/tauri.linux.conf.json",
|
||||
iconPath: `src-tauri/png/${process.env.NAME}_512.png`,
|
||||
productName: `com-pake-${process.env.NAME}`,
|
||||
defaultIconPath: "src-tauri/png/icon_512.png",
|
||||
icon: [`png/${process.env.NAME}_512.png`],
|
||||
desktopEntry,
|
||||
desktopEntryPath: `src-tauri/assets/com-pake-${process.env.NAME}.desktop`,
|
||||
desktopEntryConfig: {
|
||||
configKey: `/usr/share/applications/com-pake-${process.env.NAME}.desktop`,
|
||||
configValue: `assets/com-pake-${process.env.NAME}.desktop`,
|
||||
},
|
||||
},
|
||||
macos: {
|
||||
configFilePath: "src-tauri/tauri.macos.conf.json",
|
||||
iconPath: `src-tauri/icons/${process.env.NAME}.icns`,
|
||||
defaultPath: "src-tauri/icons/icon.icns",
|
||||
icon: [`icons/${process.env.NAME}.icns`],
|
||||
},
|
||||
windows: {
|
||||
configFilePath: "src-tauri/tauri.windows.conf.json",
|
||||
iconPath: `src-tauri/png/${process.env.NAME}_32.ico`,
|
||||
defaultPath: "src-tauri/png/icon_32.ico",
|
||||
hdIconPath: `src-tauri/png/${process.env.NAME}_256.ico`,
|
||||
hdDefaultPath: "src-tauri/png/icon_256.ico",
|
||||
icon: [`png/${process.env.NAME}_256.ico`, `png/${process.env.NAME}_32.ico`],
|
||||
resources: [`png/${process.env.NAME}_32.ico`],
|
||||
},
|
||||
};
|
||||
|
||||
validate();
|
||||
|
||||
updatePakeJson();
|
||||
|
||||
updateTauriJson();
|
||||
|
||||
let platformVariables;
|
||||
let platformConfig;
|
||||
|
||||
switch (os.platform()) {
|
||||
case "linux":
|
||||
platformVariables = variables.linux;
|
||||
platformConfig = linuxJson;
|
||||
updateDesktopEntry();
|
||||
break;
|
||||
case "darwin":
|
||||
platformVariables = variables.macos;
|
||||
platformConfig = macosJson;
|
||||
break;
|
||||
case "win32":
|
||||
platformConfig = windowsJson;
|
||||
platformVariables = variables.windows;
|
||||
updateResources();
|
||||
updateIconFile(
|
||||
platformVariables.hdIconPath,
|
||||
platformVariables.hdDefaultPath,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
updateIconFile(platformVariables.iconPath, platformVariables.defaultIconPath);
|
||||
|
||||
updatePlatformConfig(platformConfig, platformVariables);
|
||||
|
||||
save();
|
||||
|
||||
function validate() {
|
||||
if (!("URL" in process.env)) {
|
||||
console.log("URL is not set");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`URL: ${process.env.URL}`);
|
||||
|
||||
if (!("NAME" in process.env)) {
|
||||
console.log("NAME is not set");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`NAME: ${process.env.NAME}`);
|
||||
|
||||
if (!("TITLE" in process.env)) {
|
||||
console.log("TITLE is not set");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`TITLE: ${process.env.TITLE}`);
|
||||
|
||||
if (!("NAME_ZH" in process.env)) {
|
||||
console.log("NAME_ZH is not set");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`NAME_ZH: ${process.env.NAME_ZH}`);
|
||||
}
|
||||
|
||||
function updatePakeJson() {
|
||||
pakeJson.windows[0].url = variables.url;
|
||||
}
|
||||
|
||||
function updateTauriJson() {
|
||||
tauriJson.productName = variables.title;
|
||||
writeFileSync(
|
||||
"src-tauri/tauri.conf.json",
|
||||
JSON.stringify(tauriJson, null, 2),
|
||||
);
|
||||
}
|
||||
|
||||
function updateIconFile(iconPath, defaultIconPath) {
|
||||
if (!existsSync(iconPath)) {
|
||||
console.warn(
|
||||
`Icon for ${process.env.NAME} not found, will use default icon`,
|
||||
);
|
||||
copyFileSync(defaultIconPath, iconPath);
|
||||
}
|
||||
}
|
||||
|
||||
function updatePlatformConfig(platformConfig, platformVariables) {
|
||||
platformConfig.bundle["icon"] = platformVariables.icon;
|
||||
platformConfig.identifier = variables.identifier;
|
||||
}
|
||||
|
||||
function save() {
|
||||
writeFileSync(variables.pakeConfigPath, JSON.stringify(pakeJson, null, 2));
|
||||
writeFileSync(variables.tauriConfigPath, JSON.stringify(tauriJson, null, 2));
|
||||
|
||||
writeFileSync(
|
||||
variables.linux.configFilePath,
|
||||
JSON.stringify(linuxJson, null, 2),
|
||||
);
|
||||
writeFileSync(
|
||||
platformVariables.configFilePath,
|
||||
JSON.stringify(platformConfig, null, 2),
|
||||
);
|
||||
|
||||
writeFileSync(
|
||||
variables.macos.configFilePath,
|
||||
JSON.stringify(macosJson, null, 2),
|
||||
);
|
||||
|
||||
writeFileSync(
|
||||
variables.windows.configFilePath,
|
||||
JSON.stringify(windowsJson, null, 2),
|
||||
);
|
||||
}
|
||||
|
||||
function updateDesktopEntry() {
|
||||
linuxJson.bundle.linux.deb.files = {};
|
||||
linuxJson.bundle.linux.deb.files[
|
||||
variables.linux.desktopEntryConfig.configKey
|
||||
] = variables.linux.desktopEntryConfig.configValue;
|
||||
writeFileSync(variables.linux.desktopEntryPath, variables.linux.desktopEntry);
|
||||
}
|
||||
|
||||
function updateResources() {
|
||||
windowsJson.bundle.resources = variables.windows.resources;
|
||||
}
|
||||
158
script/build_with_pake_cli.js
vendored
158
script/build_with_pake_cli.js
vendored
@@ -1,158 +0,0 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { execa } from "execa";
|
||||
|
||||
// Configuration logging
|
||||
const logConfiguration = () => {
|
||||
console.log("Welcome to use pake-cli to build app");
|
||||
console.log("Node.js info in your localhost:", process.version);
|
||||
console.log("\n=======================\n");
|
||||
console.log("Pake parameters:");
|
||||
console.log("url:", process.env.URL);
|
||||
console.log("name:", process.env.NAME);
|
||||
console.log("icon:", process.env.ICON);
|
||||
console.log("height:", process.env.HEIGHT);
|
||||
console.log("width:", process.env.WIDTH);
|
||||
console.log("fullscreen:", process.env.FULLSCREEN);
|
||||
console.log("hide-title-bar:", process.env.HIDE_TITLE_BAR);
|
||||
console.log("is multi arch? only for Mac:", process.env.MULTI_ARCH);
|
||||
console.log("targets type? only for Linux:", process.env.TARGETS);
|
||||
console.log("===========================\n");
|
||||
};
|
||||
|
||||
// Main execution
|
||||
const main = async () => {
|
||||
try {
|
||||
logConfiguration();
|
||||
|
||||
const cliPath = path.join(process.cwd(), "node_modules/pake-cli");
|
||||
|
||||
// Check if pake-cli directory exists
|
||||
if (!fs.existsSync(cliPath)) {
|
||||
console.error("Error: pake-cli not found at", cliPath);
|
||||
console.error(
|
||||
"Please make sure pake-cli is installed: npm install pake-cli",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.chdir(cliPath);
|
||||
|
||||
// Clean up any previous configuration to ensure fresh build
|
||||
const pakeDirPath = path.join("src-tauri", ".pake");
|
||||
|
||||
// Remove .pake directory to force fresh config generation
|
||||
if (fs.existsSync(pakeDirPath)) {
|
||||
fs.rmSync(pakeDirPath, { recursive: true, force: true });
|
||||
console.log("Cleaned previous .pake directory for fresh build");
|
||||
}
|
||||
|
||||
// Also clean any potential target directories that might contain cached configs
|
||||
const targetDirs = [
|
||||
"src-tauri/target",
|
||||
"src-tauri/target/debug",
|
||||
"src-tauri/target/release",
|
||||
"src-tauri/target/universal-apple-darwin",
|
||||
];
|
||||
|
||||
targetDirs.forEach((dir) => {
|
||||
if (fs.existsSync(dir)) {
|
||||
// Only remove .pake subdirectories, not the entire target directory
|
||||
const targetPakeDir = path.join(dir, ".pake");
|
||||
if (fs.existsSync(targetPakeDir)) {
|
||||
fs.rmSync(targetPakeDir, { recursive: true, force: true });
|
||||
console.log(`Cleaned .pake directory in ${dir}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Build CLI parameters
|
||||
let params = [
|
||||
"dist/cli.js",
|
||||
process.env.URL,
|
||||
"--name",
|
||||
process.env.NAME,
|
||||
"--height",
|
||||
process.env.HEIGHT,
|
||||
"--width",
|
||||
process.env.WIDTH,
|
||||
];
|
||||
|
||||
if (
|
||||
process.env.HIDE_TITLE_BAR === "true" &&
|
||||
process.platform === "darwin"
|
||||
) {
|
||||
params.push("--hide-title-bar");
|
||||
}
|
||||
|
||||
if (process.env.FULLSCREEN === "true") {
|
||||
params.push("--fullscreen");
|
||||
}
|
||||
|
||||
if (process.env.MULTI_ARCH === "true" && process.platform === "darwin") {
|
||||
params.push("--multi-arch");
|
||||
}
|
||||
|
||||
if (process.env.TARGETS && process.platform === "linux") {
|
||||
params.push("--targets", process.env.TARGETS);
|
||||
}
|
||||
|
||||
if (process.platform === "win32" || process.platform === "linux") {
|
||||
params.push("--show-system-tray");
|
||||
}
|
||||
|
||||
// Add icon parameter if provided - CLI will handle download and conversion
|
||||
if (process.env.ICON && process.env.ICON !== "") {
|
||||
params.push("--icon", process.env.ICON);
|
||||
} else {
|
||||
console.log(
|
||||
"No icon provided, pake-cli will attempt to fetch favicon or use default",
|
||||
);
|
||||
}
|
||||
|
||||
console.log("Pake parameters:", params.join(" "));
|
||||
console.log("Expected app name:", process.env.NAME);
|
||||
console.log("Compiling....");
|
||||
|
||||
// Execute the CLI command
|
||||
await execa("node", params, { stdio: "inherit" });
|
||||
|
||||
// Create output directory and move built files
|
||||
if (!fs.existsSync("output")) {
|
||||
fs.mkdirSync("output");
|
||||
}
|
||||
|
||||
// pake-cli outputs files to current directory with various naming patterns
|
||||
const files = fs.readdirSync(".");
|
||||
const appName = process.env.NAME;
|
||||
const escapedAppName = appName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // Escape regex special chars
|
||||
|
||||
// Create comprehensive pattern for app files
|
||||
const appFilePattern = new RegExp(
|
||||
`^(${escapedAppName}|${escapedAppName.toLowerCase()})(_.*|\\..*)$`,
|
||||
"i",
|
||||
);
|
||||
let foundFiles = false;
|
||||
|
||||
for (const file of files) {
|
||||
if (appFilePattern.test(file)) {
|
||||
const destPath = path.join("output", file);
|
||||
fs.renameSync(file, destPath);
|
||||
console.log(`Moved: ${file} -> output/${file}`);
|
||||
foundFiles = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundFiles) {
|
||||
console.log("Warning: No output files found matching pattern");
|
||||
}
|
||||
|
||||
console.log("Build Success");
|
||||
process.chdir("../..");
|
||||
} catch (error) {
|
||||
console.error("Build failed:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
196
script/configure-tauri.mjs
vendored
Executable file
196
script/configure-tauri.mjs
vendored
Executable file
@@ -0,0 +1,196 @@
|
||||
import pakeJson from "../src-tauri/pake.json" with { type: "json" };
|
||||
import tauriJson from "../src-tauri/tauri.conf.json" with { type: "json" };
|
||||
import windowsJson from "../src-tauri/tauri.windows.conf.json" with { type: "json" };
|
||||
import macosJson from "../src-tauri/tauri.macos.conf.json" with { type: "json" };
|
||||
import linuxJson from "../src-tauri/tauri.linux.conf.json" with { type: "json" };
|
||||
|
||||
import { writeFileSync, existsSync, copyFileSync } from "fs";
|
||||
import os from "os";
|
||||
|
||||
/**
|
||||
* Configuration script for Tauri app generation
|
||||
* Sets up platform-specific configurations, icons, and desktop entries
|
||||
*/
|
||||
|
||||
// Environment validation
|
||||
const requiredEnvVars = ["URL", "NAME", "TITLE", "NAME_ZH"];
|
||||
|
||||
function validateEnvironment() {
|
||||
const missing = requiredEnvVars.filter((key) => !(key in process.env));
|
||||
|
||||
if (missing.length > 0) {
|
||||
console.error(
|
||||
`Missing required environment variables: ${missing.join(", ")}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("Environment variables:");
|
||||
requiredEnvVars.forEach((key) => {
|
||||
console.log(` ${key}: ${process.env[key]}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Configuration constants
|
||||
const CONFIG = {
|
||||
get identifier() {
|
||||
return `com.pake.${process.env.NAME}`;
|
||||
},
|
||||
get productName() {
|
||||
return `com-pake-${process.env.NAME}`;
|
||||
},
|
||||
|
||||
paths: {
|
||||
pakeConfig: "src-tauri/pake.json",
|
||||
tauriConfig: "src-tauri/tauri.conf.json",
|
||||
},
|
||||
|
||||
platforms: {
|
||||
linux: {
|
||||
configFile: "src-tauri/tauri.linux.conf.json",
|
||||
iconPath: `src-tauri/png/${process.env.NAME}_512.png`,
|
||||
defaultIcon: "src-tauri/png/icon_512.png",
|
||||
icons: [`png/${process.env.NAME}_512.png`],
|
||||
get desktopEntry() {
|
||||
return `[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Categories=Office
|
||||
Exec=${CONFIG.productName}
|
||||
Icon=${CONFIG.productName}
|
||||
Name=${CONFIG.productName}
|
||||
Name[zh_CN]=${process.env.NAME_ZH}
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
Type=Application
|
||||
`;
|
||||
},
|
||||
get desktopEntryPath() {
|
||||
return `src-tauri/assets/${CONFIG.productName}.desktop`;
|
||||
},
|
||||
get desktopConfig() {
|
||||
return {
|
||||
key: `/usr/share/applications/${CONFIG.productName}.desktop`,
|
||||
value: `assets/${CONFIG.productName}.desktop`,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
darwin: {
|
||||
configFile: "src-tauri/tauri.macos.conf.json",
|
||||
iconPath: `src-tauri/icons/${process.env.NAME}.icns`,
|
||||
defaultIcon: "src-tauri/icons/icon.icns",
|
||||
icons: [`icons/${process.env.NAME}.icns`],
|
||||
},
|
||||
|
||||
windows: {
|
||||
configFile: "src-tauri/tauri.windows.conf.json",
|
||||
iconPath: `src-tauri/png/${process.env.NAME}_32.ico`,
|
||||
hdIconPath: `src-tauri/png/${process.env.NAME}_256.ico`,
|
||||
defaultIcon: "src-tauri/png/icon_32.ico",
|
||||
hdDefaultIcon: "src-tauri/png/icon_256.ico",
|
||||
icons: [
|
||||
`png/${process.env.NAME}_256.ico`,
|
||||
`png/${process.env.NAME}_32.ico`,
|
||||
],
|
||||
resources: [`png/${process.env.NAME}_32.ico`],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Core configuration functions
|
||||
function updateBaseConfigs() {
|
||||
// Update pake.json
|
||||
pakeJson.windows[0].url = process.env.URL;
|
||||
|
||||
// Update tauri.conf.json
|
||||
tauriJson.productName = process.env.TITLE;
|
||||
tauriJson.identifier = CONFIG.identifier;
|
||||
}
|
||||
|
||||
function ensureIconExists(iconPath, defaultPath, description = "icon") {
|
||||
if (!existsSync(iconPath)) {
|
||||
console.warn(
|
||||
`${description} for ${process.env.NAME} not found, using default`,
|
||||
);
|
||||
copyFileSync(defaultPath, iconPath);
|
||||
}
|
||||
}
|
||||
|
||||
function updatePlatformConfig(platformConfig, platformVars) {
|
||||
platformConfig.bundle.icon = platformVars.icons;
|
||||
platformConfig.identifier = CONFIG.identifier;
|
||||
}
|
||||
|
||||
// Platform-specific handlers
|
||||
const platformHandlers = {
|
||||
linux: (config) => {
|
||||
ensureIconExists(config.iconPath, config.defaultIcon, "Linux icon");
|
||||
|
||||
// Update desktop entry
|
||||
linuxJson.bundle.linux.deb.files = {
|
||||
[config.desktopConfig.key]: config.desktopConfig.value,
|
||||
};
|
||||
writeFileSync(config.desktopEntryPath, config.desktopEntry);
|
||||
|
||||
updatePlatformConfig(linuxJson, config);
|
||||
},
|
||||
|
||||
darwin: (config) => {
|
||||
ensureIconExists(config.iconPath, config.defaultIcon, "macOS icon");
|
||||
updatePlatformConfig(macosJson, config);
|
||||
},
|
||||
|
||||
win32: (config) => {
|
||||
ensureIconExists(config.iconPath, config.defaultIcon, "Windows icon");
|
||||
ensureIconExists(
|
||||
config.hdIconPath,
|
||||
config.hdDefaultIcon,
|
||||
"Windows HD icon",
|
||||
);
|
||||
|
||||
windowsJson.bundle.resources = config.resources;
|
||||
updatePlatformConfig(windowsJson, config);
|
||||
},
|
||||
};
|
||||
|
||||
function saveConfigurations() {
|
||||
const configs = [
|
||||
{ path: CONFIG.paths.pakeConfig, data: pakeJson },
|
||||
{ path: CONFIG.paths.tauriConfig, data: tauriJson },
|
||||
{ path: CONFIG.platforms.linux.configFile, data: linuxJson },
|
||||
{ path: CONFIG.platforms.darwin.configFile, data: macosJson },
|
||||
{ path: CONFIG.platforms.windows.configFile, data: windowsJson },
|
||||
];
|
||||
|
||||
configs.forEach(({ path, data }) => {
|
||||
writeFileSync(path, JSON.stringify(data, null, 2));
|
||||
});
|
||||
}
|
||||
|
||||
// Main execution
|
||||
function main() {
|
||||
try {
|
||||
validateEnvironment();
|
||||
updateBaseConfigs();
|
||||
|
||||
const platform = os.platform();
|
||||
const platformConfig = CONFIG.platforms[platform];
|
||||
|
||||
if (!platformConfig) {
|
||||
throw new Error(`Unsupported platform: ${platform}`);
|
||||
}
|
||||
|
||||
const handler = platformHandlers[platform];
|
||||
if (handler) {
|
||||
handler(platformConfig);
|
||||
}
|
||||
|
||||
saveConfigurations();
|
||||
console.log(`✅ Tauri configuration complete for ${platform}`);
|
||||
} catch (error) {
|
||||
console.error("❌ Configuration failed:", error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
224
script/github-action-build.js
vendored
Executable file
224
script/github-action-build.js
vendored
Executable file
@@ -0,0 +1,224 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { execa } from "execa";
|
||||
|
||||
/**
|
||||
* GitHub Actions build script for Pake CLI
|
||||
* Handles environment setup, parameter building, and output management
|
||||
*/
|
||||
|
||||
// Environment variables expected from GitHub Actions
|
||||
const ENV_VARS = {
|
||||
required: ["URL", "NAME", "HEIGHT", "WIDTH"],
|
||||
optional: ["ICON", "FULLSCREEN", "HIDE_TITLE_BAR", "MULTI_ARCH", "TARGETS"],
|
||||
};
|
||||
|
||||
// Platform-specific configurations
|
||||
const PLATFORM_CONFIG = {
|
||||
darwin: {
|
||||
supportsHideTitleBar: true,
|
||||
supportsMultiArch: true,
|
||||
needsSystemTray: false,
|
||||
},
|
||||
linux: {
|
||||
supportsTargets: true,
|
||||
needsSystemTray: true,
|
||||
},
|
||||
win32: {
|
||||
needsSystemTray: true,
|
||||
},
|
||||
};
|
||||
|
||||
class PakeBuildManager {
|
||||
constructor() {
|
||||
this.platform = process.platform;
|
||||
this.config = PLATFORM_CONFIG[this.platform] || {};
|
||||
}
|
||||
|
||||
logConfiguration() {
|
||||
console.log("🚀 Pake CLI Build Started");
|
||||
console.log(`📋 Node.js version: ${process.version}`);
|
||||
console.log(`🖥️ Platform: ${this.platform}`);
|
||||
console.log("\n" + "=".repeat(50));
|
||||
console.log("📝 Build Parameters:");
|
||||
|
||||
ENV_VARS.required.forEach((key) => {
|
||||
console.log(` ${key}: ${process.env[key]}`);
|
||||
});
|
||||
|
||||
ENV_VARS.optional.forEach((key) => {
|
||||
if (process.env[key]) {
|
||||
console.log(` ${key}: ${process.env[key]}`);
|
||||
}
|
||||
});
|
||||
console.log("=".repeat(50) + "\n");
|
||||
}
|
||||
|
||||
validateEnvironment() {
|
||||
const missing = ENV_VARS.required.filter((key) => !process.env[key]);
|
||||
|
||||
if (missing.length > 0) {
|
||||
throw new Error(
|
||||
`Missing required environment variables: ${missing.join(", ")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setupWorkspace() {
|
||||
const cliPath = path.join(process.cwd(), "node_modules/pake-cli");
|
||||
|
||||
if (!fs.existsSync(cliPath)) {
|
||||
throw new Error(
|
||||
`pake-cli not found at ${cliPath}. Run: npm install pake-cli`,
|
||||
);
|
||||
}
|
||||
|
||||
process.chdir(cliPath);
|
||||
this.cleanPreviousBuilds();
|
||||
|
||||
return cliPath;
|
||||
}
|
||||
|
||||
cleanPreviousBuilds() {
|
||||
const cleanupPaths = [
|
||||
"src-tauri/.pake",
|
||||
"src-tauri/target/.pake",
|
||||
"src-tauri/target/debug/.pake",
|
||||
"src-tauri/target/release/.pake",
|
||||
"src-tauri/target/universal-apple-darwin/.pake",
|
||||
];
|
||||
|
||||
cleanupPaths.forEach((dirPath) => {
|
||||
if (fs.existsSync(dirPath)) {
|
||||
fs.rmSync(dirPath, { recursive: true, force: true });
|
||||
console.log(`🧹 Cleaned: ${dirPath}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
buildCliParameters() {
|
||||
const params = [
|
||||
"dist/cli.js",
|
||||
process.env.URL,
|
||||
"--name",
|
||||
process.env.NAME,
|
||||
"--height",
|
||||
process.env.HEIGHT,
|
||||
"--width",
|
||||
process.env.WIDTH,
|
||||
];
|
||||
|
||||
// Platform-specific parameters
|
||||
if (
|
||||
this.config.supportsHideTitleBar &&
|
||||
process.env.HIDE_TITLE_BAR === "true"
|
||||
) {
|
||||
params.push("--hide-title-bar");
|
||||
}
|
||||
|
||||
if (process.env.FULLSCREEN === "true") {
|
||||
params.push("--fullscreen");
|
||||
}
|
||||
|
||||
if (this.config.supportsMultiArch && process.env.MULTI_ARCH === "true") {
|
||||
params.push("--multi-arch");
|
||||
}
|
||||
|
||||
if (this.config.supportsTargets && process.env.TARGETS) {
|
||||
params.push("--targets", process.env.TARGETS);
|
||||
}
|
||||
|
||||
if (this.config.needsSystemTray) {
|
||||
params.push("--show-system-tray");
|
||||
}
|
||||
|
||||
// Icon handling
|
||||
if (process.env.ICON?.trim()) {
|
||||
params.push("--icon", process.env.ICON);
|
||||
} else {
|
||||
console.log(
|
||||
"ℹ️ No icon provided, will attempt to fetch favicon or use default",
|
||||
);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
async executeBuild(params) {
|
||||
console.log(`🔧 Command: node ${params.join(" ")}`);
|
||||
console.log(`📱 Building app: ${process.env.NAME}`);
|
||||
console.log("⏳ Compiling...\n");
|
||||
|
||||
await execa("node", params, { stdio: "inherit" });
|
||||
}
|
||||
|
||||
organizeOutput() {
|
||||
const outputDir = "output";
|
||||
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir);
|
||||
}
|
||||
|
||||
const appName = process.env.NAME;
|
||||
const filePattern = new RegExp(
|
||||
`^(${this.escapeRegex(appName)}|${this.escapeRegex(appName.toLowerCase())})(_.*|\\..*)$`,
|
||||
"i",
|
||||
);
|
||||
|
||||
const files = fs.readdirSync(".");
|
||||
let movedFiles = 0;
|
||||
|
||||
files.forEach((file) => {
|
||||
if (filePattern.test(file)) {
|
||||
const destPath = path.join(outputDir, file);
|
||||
fs.renameSync(file, destPath);
|
||||
console.log(`📦 Packaged: ${file}`);
|
||||
movedFiles++;
|
||||
}
|
||||
});
|
||||
|
||||
if (movedFiles === 0) {
|
||||
console.warn(
|
||||
"⚠️ Warning: No output files found matching expected pattern",
|
||||
);
|
||||
}
|
||||
|
||||
return movedFiles;
|
||||
}
|
||||
|
||||
escapeRegex(str) {
|
||||
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
|
||||
async run() {
|
||||
try {
|
||||
this.logConfiguration();
|
||||
this.validateEnvironment();
|
||||
|
||||
this.setupWorkspace();
|
||||
const params = this.buildCliParameters();
|
||||
|
||||
await this.executeBuild(params);
|
||||
|
||||
const fileCount = this.organizeOutput();
|
||||
|
||||
console.log(`\n✅ Build completed successfully!`);
|
||||
console.log(`📦 Generated ${fileCount} output file(s)`);
|
||||
|
||||
// Return to original directory
|
||||
process.chdir("../..");
|
||||
} catch (error) {
|
||||
console.error("\n❌ Build failed:", error.message);
|
||||
|
||||
if (error.stderr) {
|
||||
console.error("Error details:", error.stderr);
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute build
|
||||
const buildManager = new PakeBuildManager();
|
||||
buildManager.run();
|
||||
@@ -5,9 +5,20 @@
|
||||
## 运行测试
|
||||
|
||||
```bash
|
||||
npm test
|
||||
# 完整测试套件(推荐)
|
||||
npm test # 运行完整测试套件,包含真实构建测试(8-12分钟)
|
||||
|
||||
# 开发时快速测试
|
||||
npm test -- --no-build # 跳过构建测试,仅验证核心功能(30秒)
|
||||
```
|
||||
|
||||
### 🚀 完整测试套件包含:
|
||||
|
||||
- ✅ **单元测试**:CLI命令、参数验证、响应时间
|
||||
- ✅ **集成测试**:进程管理、文件权限、依赖解析
|
||||
- ✅ **构建器测试**:平台检测、架构检测、文件命名
|
||||
- ✅ **真实构建测试**:完整的GitHub.com应用打包验证
|
||||
|
||||
## 测试内容
|
||||
|
||||
### 单元测试(6个)
|
||||
|
||||
217
tests/build.js
217
tests/build.js
@@ -1,217 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* GitHub.com Real Build Test
|
||||
*
|
||||
* This is a standalone test for actual GitHub.com app packaging
|
||||
* to validate that both CLI and GitHub Actions scenarios work correctly.
|
||||
*/
|
||||
|
||||
import { spawn, execSync } from "child_process";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import config from "./config.js";
|
||||
|
||||
console.log("🐙 GitHub.com Real Build Test");
|
||||
console.log("==============================\n");
|
||||
|
||||
const testName = "GitHubRealTest";
|
||||
const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`);
|
||||
const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`);
|
||||
|
||||
// Cleanup function
|
||||
const cleanup = () => {
|
||||
try {
|
||||
if (fs.existsSync(appFile)) {
|
||||
if (fs.statSync(appFile).isDirectory()) {
|
||||
fs.rmSync(appFile, { recursive: true, force: true });
|
||||
} else {
|
||||
fs.unlinkSync(appFile);
|
||||
}
|
||||
console.log("✅ Cleaned up .app file");
|
||||
}
|
||||
if (fs.existsSync(dmgFile)) {
|
||||
fs.unlinkSync(dmgFile);
|
||||
console.log("✅ Cleaned up .dmg file");
|
||||
}
|
||||
|
||||
// Clean .pake directory
|
||||
const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake");
|
||||
if (fs.existsSync(pakeDir)) {
|
||||
fs.rmSync(pakeDir, { recursive: true, force: true });
|
||||
console.log("✅ Cleaned up .pake directory");
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("⚠️ Cleanup warning:", error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle cleanup on exit
|
||||
process.on("exit", cleanup);
|
||||
process.on("SIGINT", () => {
|
||||
console.log("\n🛑 Build interrupted by user");
|
||||
cleanup();
|
||||
process.exit(1);
|
||||
});
|
||||
process.on("SIGTERM", cleanup);
|
||||
|
||||
console.log("🔧 Testing GitHub.com packaging with CLI...");
|
||||
console.log(
|
||||
`Command: node ${config.CLI_PATH} https://github.com --name ${testName} --debug --width 1200 --height 780\n`,
|
||||
);
|
||||
|
||||
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --debug --width 1200 --height 780`;
|
||||
|
||||
const child = spawn(command, {
|
||||
shell: true,
|
||||
cwd: config.PROJECT_ROOT,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
env: {
|
||||
...process.env,
|
||||
PAKE_CREATE_APP: "1",
|
||||
},
|
||||
});
|
||||
|
||||
let buildStarted = false;
|
||||
let configGenerated = false;
|
||||
let compilationStarted = false;
|
||||
|
||||
console.log("📋 Build Progress:");
|
||||
console.log("------------------");
|
||||
|
||||
child.stdout.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
|
||||
// Track build progress
|
||||
if (output.includes("Installing package")) {
|
||||
console.log("📦 Installing pake dependencies...");
|
||||
}
|
||||
if (output.includes("Package installed")) {
|
||||
console.log("✅ Package installation completed");
|
||||
}
|
||||
if (output.includes("Building app")) {
|
||||
buildStarted = true;
|
||||
console.log("🏗️ Build process started...");
|
||||
}
|
||||
if (output.includes("Compiling")) {
|
||||
compilationStarted = true;
|
||||
console.log("⚙️ Rust compilation started...");
|
||||
}
|
||||
if (output.includes("Bundling")) {
|
||||
console.log("📦 App bundling started...");
|
||||
}
|
||||
if (output.includes("Built application at:")) {
|
||||
console.log("✅ Application built successfully!");
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
|
||||
// Track stderr progress (Tauri outputs build info to stderr)
|
||||
if (output.includes("Installing package")) {
|
||||
console.log("📦 Installing pake dependencies...");
|
||||
}
|
||||
if (output.includes("Building app")) {
|
||||
buildStarted = true;
|
||||
console.log("🏗️ Build process started...");
|
||||
}
|
||||
if (output.includes("Compiling")) {
|
||||
compilationStarted = true;
|
||||
console.log("⚙️ Rust compilation started...");
|
||||
}
|
||||
if (output.includes("Finished")) {
|
||||
console.log("✅ Rust compilation finished!");
|
||||
}
|
||||
if (output.includes("Bundling")) {
|
||||
console.log("📦 App bundling started...");
|
||||
}
|
||||
if (output.includes("Built application at:")) {
|
||||
console.log("✅ Application built successfully!");
|
||||
}
|
||||
|
||||
// Only show actual errors, filter out build progress
|
||||
if (
|
||||
!output.includes("warning:") &&
|
||||
!output.includes("verbose") &&
|
||||
!output.includes("npm info") &&
|
||||
!output.includes("Installing package") &&
|
||||
!output.includes("Package installed") &&
|
||||
!output.includes("Building app") &&
|
||||
!output.includes("Compiling") &&
|
||||
!output.includes("Finished") &&
|
||||
!output.includes("Built application at:") &&
|
||||
!output.includes("Bundling") &&
|
||||
!output.includes("npm http") &&
|
||||
output.trim().length > 0
|
||||
) {
|
||||
console.log("❌ Build error:", output.trim());
|
||||
}
|
||||
});
|
||||
|
||||
// Set a 3-minute timeout for the test
|
||||
const timeout = setTimeout(() => {
|
||||
console.log("\n⏱️ Build timeout reached (3 minutes)");
|
||||
child.kill("SIGTERM");
|
||||
|
||||
if (buildStarted && compilationStarted) {
|
||||
console.log("✅ SUCCESS: GitHub.com CLI build started successfully!");
|
||||
console.log(" - Build process initiated ✓");
|
||||
console.log(" - Rust compilation started ✓");
|
||||
console.log(" - Configuration generated for GitHub.com ✓");
|
||||
console.log("\n🎯 Test Result: PASS");
|
||||
console.log(" The GitHub.com app build is working correctly.");
|
||||
console.log(
|
||||
" Build was terminated early to save time, but core functionality verified.",
|
||||
);
|
||||
process.exit(0);
|
||||
} else if (buildStarted) {
|
||||
console.log("⚠️ PARTIAL: Build started but compilation not detected");
|
||||
console.log("🎯 Test Result: PARTIAL PASS");
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log("❌ FAIL: Build did not start within timeout");
|
||||
console.log("🎯 Test Result: FAIL");
|
||||
process.exit(1);
|
||||
}
|
||||
}, 180000); // 3 minutes
|
||||
|
||||
child.on("close", (code) => {
|
||||
clearTimeout(timeout);
|
||||
|
||||
console.log(`\n📊 Build Process Summary:`);
|
||||
console.log("========================");
|
||||
console.log(`Exit Code: ${code}`);
|
||||
console.log(`Build Started: ${buildStarted ? "✅" : "❌"}`);
|
||||
console.log(`Compilation Started: ${compilationStarted ? "✅" : "❌"}`);
|
||||
|
||||
// Check for output files
|
||||
const appExists = fs.existsSync(appFile);
|
||||
const dmgExists = fs.existsSync(dmgFile);
|
||||
console.log(`App File (.app): ${appExists ? "✅" : "❌"}`);
|
||||
console.log(`DMG File: ${dmgExists ? "✅" : "❌"}`);
|
||||
|
||||
if (buildStarted && compilationStarted) {
|
||||
console.log("\n🎉 SUCCESS: GitHub.com CLI build verification completed!");
|
||||
console.log(" All critical build stages detected.");
|
||||
process.exit(0);
|
||||
} else if (buildStarted) {
|
||||
console.log(
|
||||
"\n⚠️ PARTIAL SUCCESS: Build started but may not have completed",
|
||||
);
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log("\n❌ FAILED: Build did not start properly");
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
child.on("error", (error) => {
|
||||
clearTimeout(timeout);
|
||||
console.log(`\n❌ Process Error: ${error.message}`);
|
||||
console.log("🎯 Test Result: FAIL");
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Send empty input to handle any prompts
|
||||
child.stdin.end();
|
||||
@@ -1,253 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* GitHub.com Complete Build Test
|
||||
*
|
||||
* This test performs a complete build of github.com to verify
|
||||
* that the entire packaging pipeline works correctly end-to-end.
|
||||
*/
|
||||
|
||||
import { spawn } from "child_process";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import config from "./config.js";
|
||||
|
||||
console.log("🐙 GitHub.com Complete Build Test");
|
||||
console.log("==================================\n");
|
||||
|
||||
const testName = "GitHub";
|
||||
const appFile = path.join(config.PROJECT_ROOT, `${testName}.app`);
|
||||
const dmgFile = path.join(config.PROJECT_ROOT, `${testName}.dmg`);
|
||||
|
||||
// Cleanup function
|
||||
const cleanup = () => {
|
||||
try {
|
||||
if (fs.existsSync(appFile)) {
|
||||
if (fs.statSync(appFile).isDirectory()) {
|
||||
fs.rmSync(appFile, { recursive: true, force: true });
|
||||
} else {
|
||||
fs.unlinkSync(appFile);
|
||||
}
|
||||
console.log("✅ Cleaned up .app file");
|
||||
}
|
||||
if (fs.existsSync(dmgFile)) {
|
||||
fs.unlinkSync(dmgFile);
|
||||
console.log("✅ Cleaned up .dmg file");
|
||||
}
|
||||
|
||||
// Clean .pake directory
|
||||
const pakeDir = path.join(config.PROJECT_ROOT, "src-tauri", ".pake");
|
||||
if (fs.existsSync(pakeDir)) {
|
||||
fs.rmSync(pakeDir, { recursive: true, force: true });
|
||||
console.log("✅ Cleaned up .pake directory");
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("⚠️ Cleanup warning:", error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle cleanup on exit
|
||||
process.on("exit", cleanup);
|
||||
process.on("SIGINT", () => {
|
||||
console.log("\n🛑 Build interrupted by user");
|
||||
cleanup();
|
||||
process.exit(1);
|
||||
});
|
||||
process.on("SIGTERM", cleanup);
|
||||
|
||||
console.log("🔧 Testing GitHub app packaging with optimal settings...");
|
||||
console.log(
|
||||
`Command: pake https://github.com --name ${testName} --width 1200 --height 800 --hide-title-bar\n`,
|
||||
);
|
||||
|
||||
const command = `node "${config.CLI_PATH}" "https://github.com" --name "${testName}" --width 1200 --height 800 --hide-title-bar`;
|
||||
|
||||
const child = spawn(command, {
|
||||
shell: true,
|
||||
cwd: config.PROJECT_ROOT,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
env: {
|
||||
...process.env,
|
||||
PAKE_CREATE_APP: "1",
|
||||
},
|
||||
});
|
||||
|
||||
let buildStarted = false;
|
||||
let compilationStarted = false;
|
||||
let bundlingStarted = false;
|
||||
let buildCompleted = false;
|
||||
|
||||
console.log("📋 Build Progress:");
|
||||
console.log("------------------");
|
||||
|
||||
child.stdout.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
|
||||
// Track build progress
|
||||
if (output.includes("Installing package")) {
|
||||
console.log("📦 Installing pake dependencies...");
|
||||
}
|
||||
if (output.includes("Package installed")) {
|
||||
console.log("✅ Package installation completed");
|
||||
}
|
||||
if (output.includes("Building app")) {
|
||||
buildStarted = true;
|
||||
console.log("🏗️ Build process started...");
|
||||
}
|
||||
if (output.includes("Compiling")) {
|
||||
compilationStarted = true;
|
||||
console.log("⚙️ Rust compilation started...");
|
||||
}
|
||||
if (output.includes("Bundling")) {
|
||||
bundlingStarted = true;
|
||||
console.log("📦 App bundling started...");
|
||||
}
|
||||
if (output.includes("Built application at:")) {
|
||||
buildCompleted = true;
|
||||
console.log("✅ Application built successfully!");
|
||||
}
|
||||
if (output.includes("GitHub")) {
|
||||
console.log("🐙 GitHub app configuration detected");
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr.on("data", (data) => {
|
||||
const output = data.toString();
|
||||
|
||||
// Track stderr progress (Tauri outputs build info to stderr)
|
||||
if (output.includes("Installing package")) {
|
||||
console.log("📦 Installing pake dependencies...");
|
||||
}
|
||||
if (output.includes("Building app")) {
|
||||
buildStarted = true;
|
||||
console.log("🏗️ Build process started...");
|
||||
}
|
||||
if (output.includes("Compiling")) {
|
||||
compilationStarted = true;
|
||||
console.log("⚙️ Rust compilation started...");
|
||||
}
|
||||
if (output.includes("Finished")) {
|
||||
console.log("✅ Rust compilation finished!");
|
||||
}
|
||||
if (output.includes("Bundling")) {
|
||||
bundlingStarted = true;
|
||||
console.log("📦 App bundling started...");
|
||||
}
|
||||
if (output.includes("Built application at:")) {
|
||||
buildCompleted = true;
|
||||
console.log("✅ Application built successfully!");
|
||||
}
|
||||
|
||||
// Only show actual errors, filter out build progress
|
||||
if (
|
||||
!output.includes("warning:") &&
|
||||
!output.includes("verbose") &&
|
||||
!output.includes("npm info") &&
|
||||
!output.includes("Installing package") &&
|
||||
!output.includes("Package installed") &&
|
||||
!output.includes("Building app") &&
|
||||
!output.includes("Compiling") &&
|
||||
!output.includes("Finished") &&
|
||||
!output.includes("Built application at:") &&
|
||||
!output.includes("Bundling") &&
|
||||
!output.includes("npm http") &&
|
||||
!output.includes("Info Looking up installed") &&
|
||||
output.trim().length > 0
|
||||
) {
|
||||
console.log("❌ Build error:", output.trim());
|
||||
}
|
||||
});
|
||||
|
||||
// Set a 10-minute timeout for the complete build (real packaging takes time)
|
||||
// DON'T kill the process early - let it complete naturally
|
||||
const timeout = setTimeout(() => {
|
||||
console.log("\n⏱️ Build timeout reached (10 minutes)");
|
||||
|
||||
// Check if we actually have output files even if process is still running
|
||||
const appExists = fs.existsSync(appFile);
|
||||
const dmgExists = fs.existsSync(dmgFile);
|
||||
|
||||
if (appExists || buildCompleted) {
|
||||
console.log("🎉 SUCCESS: GitHub app was built successfully!");
|
||||
console.log(" App file exists, build completed despite long duration");
|
||||
child.kill("SIGTERM");
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log("❌ TIMEOUT: Build did not complete within 10 minutes");
|
||||
child.kill("SIGTERM");
|
||||
process.exit(1);
|
||||
}
|
||||
}, 600000); // 10 minutes
|
||||
|
||||
child.on("close", (code) => {
|
||||
clearTimeout(timeout);
|
||||
|
||||
console.log(`\n📊 GitHub App Build Summary:`);
|
||||
console.log("=============================");
|
||||
console.log(`Exit Code: ${code}`);
|
||||
console.log(`Build Started: ${buildStarted ? "✅" : "❌"}`);
|
||||
console.log(`Compilation Started: ${compilationStarted ? "✅" : "❌"}`);
|
||||
console.log(`Bundling Started: ${bundlingStarted ? "✅" : "❌"}`);
|
||||
console.log(`Build Completed: ${buildCompleted ? "✅" : "❌"}`);
|
||||
|
||||
// Check for output files
|
||||
const appExists = fs.existsSync(appFile);
|
||||
const dmgExists = fs.existsSync(dmgFile);
|
||||
console.log(`App File (.app): ${appExists ? "✅" : "❌"}`);
|
||||
console.log(`DMG File: ${dmgExists ? "✅" : "❌"}`);
|
||||
|
||||
// Check .app bundle structure if it exists
|
||||
if (appExists) {
|
||||
try {
|
||||
const contentsPath = path.join(appFile, "Contents");
|
||||
const macOSPath = path.join(contentsPath, "MacOS");
|
||||
const resourcesPath = path.join(contentsPath, "Resources");
|
||||
|
||||
console.log(`App Bundle Structure:`);
|
||||
console.log(` Contents/: ${fs.existsSync(contentsPath) ? "✅" : "❌"}`);
|
||||
console.log(
|
||||
` Contents/MacOS/: ${fs.existsSync(macOSPath) ? "✅" : "❌"}`,
|
||||
);
|
||||
console.log(
|
||||
` Contents/Resources/: ${fs.existsSync(resourcesPath) ? "✅" : "❌"}`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(`App Bundle Check: ❌ (${error.message})`);
|
||||
}
|
||||
}
|
||||
|
||||
// Real success check: app file must exist and build must have completed
|
||||
if (appExists && (buildCompleted || code === 0)) {
|
||||
console.log("\n🎉 COMPLETE SUCCESS: GitHub app build fully completed!");
|
||||
console.log(" 🐙 GitHub.com successfully packaged as desktop app");
|
||||
console.log(" 🎯 Build completed with app file generated");
|
||||
console.log(" 📱 App bundle created with proper structure");
|
||||
process.exit(0);
|
||||
} else if (appExists) {
|
||||
console.log("\n✅ SUCCESS: GitHub app was built successfully!");
|
||||
console.log(" 🐙 GitHub.com packaging completed with app file");
|
||||
console.log(" 🎯 Build process successful");
|
||||
process.exit(0);
|
||||
} else if (code === 0 && buildStarted && compilationStarted) {
|
||||
console.log(
|
||||
"\n⚠️ PARTIAL SUCCESS: Build process completed but no app file found",
|
||||
);
|
||||
console.log(" 🐙 GitHub.com build process executed successfully");
|
||||
console.log(" ⚠️ App file may be in a different location");
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log("\n❌ FAILED: GitHub app build did not complete successfully");
|
||||
console.log(" ❌ No app file generated or build process failed");
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
child.on("error", (error) => {
|
||||
clearTimeout(timeout);
|
||||
console.log(`\n❌ Process Error: ${error.message}`);
|
||||
console.log("🎯 Test Result: FAIL");
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Send empty input to handle any prompts
|
||||
child.stdin.end();
|
||||
@@ -234,7 +234,7 @@ runner.addTest(
|
||||
"GitHub Actions Environment Simulation",
|
||||
async () => {
|
||||
try {
|
||||
// Create a temporary test script that simulates build_with_pake_cli.js
|
||||
// Create a temporary test script that simulates github-action-build.js
|
||||
const testScript = `
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
@@ -298,7 +298,7 @@ runner.addTest(
|
||||
|
||||
runner.trackTempDir(tempDir);
|
||||
|
||||
// Test cleanup script logic (from build_with_pake_cli.js)
|
||||
// Test cleanup script logic (from github-action-build.js)
|
||||
const cleanupScript = `
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
@@ -340,7 +340,7 @@ process.exit(cleanedDirs > 0 ? 0 : 1);
|
||||
}
|
||||
},
|
||||
TIMEOUTS.MEDIUM,
|
||||
"Tests configuration cleanup logic from build_with_pake_cli.js",
|
||||
"Tests configuration cleanup logic from github-action-build.js",
|
||||
);
|
||||
|
||||
// Test 5: Icon fetching simulation
|
||||
@@ -539,7 +539,7 @@ runner.addTest(
|
||||
const requiredElements = [
|
||||
"npm install pake-cli@latest --no-package-lock", // Latest version installation
|
||||
"timeout-minutes: 15", // Sufficient timeout
|
||||
"node ./script/build_with_pake_cli.js", // Build script execution
|
||||
"node ./script/github-action-build.js", // Build script execution
|
||||
"ubuntu-24.04", // Linux support
|
||||
"macos-latest", // macOS support
|
||||
"windows-latest", // Windows support
|
||||
@@ -738,7 +738,7 @@ console.log('URL:', process.env.URL);
|
||||
console.log('NAME:', process.env.NAME);
|
||||
console.log('WIDTH x HEIGHT:', process.env.WIDTH + 'x' + process.env.HEIGHT);
|
||||
|
||||
// Simulate the build script execution (script/build_with_pake_cli.js equivalent)
|
||||
// Simulate the build script execution (script/github-action-build.js equivalent)
|
||||
const fs = require('fs');
|
||||
|
||||
// Simulate pake-cli installation check
|
||||
@@ -800,7 +800,7 @@ const path = require('path');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
// Check if build script exists
|
||||
const buildScript = path.join(process.cwd(), 'script', 'build_with_pake_cli.js');
|
||||
const buildScript = path.join(process.cwd(), 'script', 'github-action-build.js');
|
||||
const fs = require('fs');
|
||||
|
||||
if (!fs.existsSync(buildScript)) {
|
||||
|
||||
101
tests/index.js
101
tests/index.js
@@ -81,11 +81,6 @@ class PakeTestRunner {
|
||||
}
|
||||
}
|
||||
|
||||
if (quick) {
|
||||
console.log("⚡ Running Quick Tests...");
|
||||
await this.runQuickTests();
|
||||
}
|
||||
|
||||
this.cleanup();
|
||||
this.displayFinalResults();
|
||||
|
||||
@@ -1047,49 +1042,6 @@ class PakeTestRunner {
|
||||
);
|
||||
}
|
||||
|
||||
async runQuickTests() {
|
||||
// Only run essential tests for quick mode
|
||||
await this.runTest(
|
||||
"Quick Version Check",
|
||||
() => {
|
||||
const output = execSync(`node "${config.CLI_PATH}" --version`, {
|
||||
encoding: "utf8",
|
||||
timeout: 3000,
|
||||
});
|
||||
return /^\d+\.\d+\.\d+/.test(output.trim());
|
||||
},
|
||||
TIMEOUTS.QUICK,
|
||||
);
|
||||
|
||||
await this.runTest(
|
||||
"Quick Help Check",
|
||||
() => {
|
||||
const output = execSync(`node "${config.CLI_PATH}" --help`, {
|
||||
encoding: "utf8",
|
||||
timeout: 3000,
|
||||
});
|
||||
return output.includes("Usage: cli [url] [options]");
|
||||
},
|
||||
TIMEOUTS.QUICK,
|
||||
);
|
||||
|
||||
await this.runTest(
|
||||
"Quick Environment Check",
|
||||
() => {
|
||||
const platform = process.platform;
|
||||
const arch = process.arch;
|
||||
const nodeVersion = process.version;
|
||||
|
||||
return (
|
||||
typeof platform === "string" &&
|
||||
typeof arch === "string" &&
|
||||
nodeVersion.startsWith("v")
|
||||
);
|
||||
},
|
||||
TIMEOUTS.QUICK,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to check if files exist (handles wildcards)
|
||||
checkFileExists(filePath) {
|
||||
if (filePath.includes("*")) {
|
||||
@@ -1238,15 +1190,15 @@ class PakeTestRunner {
|
||||
// Command line interface
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
// Parse command line arguments
|
||||
// Complete test suite by default - no more smart modes
|
||||
const options = {
|
||||
unit: args.includes("--unit") || args.length === 0,
|
||||
integration: args.includes("--integration") || args.length === 0,
|
||||
builder: args.includes("--builder") || args.length === 0,
|
||||
unit: !args.includes("--no-unit"),
|
||||
integration: !args.includes("--no-integration"),
|
||||
builder: !args.includes("--no-builder"),
|
||||
pakeCliTests: args.includes("--pake-cli"),
|
||||
e2e: args.includes("--e2e") || args.includes("--full"),
|
||||
realBuild: args.includes("--real-build") || args.length === 0, // Include real build in default tests
|
||||
quick: args.includes("--quick"),
|
||||
e2e: args.includes("--e2e"),
|
||||
realBuild: !args.includes("--no-build"), // Always include real build test
|
||||
quick: false, // Remove quick mode
|
||||
};
|
||||
|
||||
// Help message
|
||||
@@ -1254,26 +1206,31 @@ if (args.includes("--help") || args.includes("-h")) {
|
||||
console.log(`
|
||||
🚀 Pake CLI Test Suite
|
||||
|
||||
Usage: node tests/index.js [options]
|
||||
Usage: npm test [-- options]
|
||||
|
||||
Options:
|
||||
--unit Run unit tests (default)
|
||||
--integration Run integration tests (default)
|
||||
--builder Run builder tests (default)
|
||||
--pake-cli Run pake-cli GitHub Actions tests
|
||||
--e2e, --full Run end-to-end tests
|
||||
--real-build Run complete real build test (8+ minutes on non-macOS, 12+ minutes multi-arch on macOS)
|
||||
--quick Run only essential tests (fast)
|
||||
--help, -h Show this help message
|
||||
Complete Test Suite (Default):
|
||||
npm test # Run complete test suite with real build (8-12 minutes)
|
||||
|
||||
Test Components:
|
||||
✅ Unit Tests # CLI commands, validation, response time
|
||||
✅ Integration Tests # Process spawning, file permissions, dependencies
|
||||
✅ Builder Tests # Platform detection, architecture, file naming
|
||||
✅ Real Build Test # Complete GitHub.com app build with packaging
|
||||
|
||||
Optional Components:
|
||||
--e2e Add end-to-end configuration tests
|
||||
--pake-cli Add pake-cli GitHub Actions tests
|
||||
|
||||
Skip Components (if needed):
|
||||
--no-unit Skip unit tests
|
||||
--no-integration Skip integration tests
|
||||
--no-builder Skip builder tests
|
||||
--no-build Skip real build test
|
||||
|
||||
Examples:
|
||||
npm test # Run all default tests (multi-arch on macOS)
|
||||
node tests/index.js # Run all default tests (multi-arch on macOS)
|
||||
node tests/index.js --quick # Quick test (30 seconds)
|
||||
node tests/index.js --real-build # Complete build test (multi-arch on macOS, single-arch elsewhere)
|
||||
node tests/index.js --pake-cli # GitHub Actions tests
|
||||
node tests/index.js --e2e # Full end-to-end tests
|
||||
node tests/index.js --unit --integration # Specific tests only
|
||||
npm test # Complete test suite (recommended)
|
||||
npm test -- --e2e # Complete suite + end-to-end tests
|
||||
npm test -- --no-build # Skip real build (faster for development)
|
||||
|
||||
Environment:
|
||||
CI=1 # Enable CI mode
|
||||
|
||||
Reference in New Issue
Block a user